From ef8c5042bd81bf49d49ca18387f57aed2071b161 Mon Sep 17 00:00:00 2001 From: "Thomas D. Economon" Date: Tue, 3 Nov 2015 01:46:23 -0800 Subject: [PATCH] More warning fixes. Fixed line endings for many files. --- Common/include/dual_grid_structure.hpp | 2176 +- Common/include/dual_grid_structure.inl | 678 +- Common/include/geometry_structure.inl | 586 +- Common/include/grid_adaptation_structure.hpp | 690 +- Common/include/grid_adaptation_structure.inl | 66 +- Common/include/grid_movement_structure.hpp | 2896 +- Common/include/grid_movement_structure.inl | 426 +- Common/include/matrix_structure.hpp | 1390 +- Common/include/matrix_structure.inl | 256 +- Common/include/option_structure.hpp | 6154 ++-- Common/include/primal_grid_structure.hpp | 2434 +- Common/include/primal_grid_structure.inl | 496 +- Common/include/vector_structure.hpp | 1 - Common/src/dual_grid_structure.cpp | 1102 +- Common/src/geometry_structure.cpp | 30502 ++++++++-------- Common/src/grid_adaptation_structure.cpp | 7262 ++-- Common/src/grid_movement_structure.cpp | 15118 ++++---- Common/src/matrix_structure.cpp | 3972 +- Common/src/primal_grid_structure.cpp | 1208 +- SU2_CFD/include/driver_structure.hpp | 818 +- SU2_CFD/include/integration_structure.hpp | 1280 +- SU2_CFD/include/integration_structure.inl | 172 +- SU2_CFD/include/numerics_structure.hpp | 9882 ++--- SU2_CFD/include/numerics_structure.inl | 916 +- SU2_CFD/include/variable_structure.hpp | 7672 ++-- SU2_CFD/include/variable_structure.inl | 2006 +- SU2_CFD/src/definition_structure.cpp | 738 +- SU2_CFD/src/integration_time.cpp | 1874 +- SU2_CFD/src/iteration_structure.cpp | 3932 +- SU2_CFD/src/numerics_structure.cpp | 5494 +-- SU2_CFD/src/output_cgns.cpp | 1026 +- SU2_CFD/src/output_fieldview.cpp | 1572 +- SU2_CFD/src/output_structure.cpp | 15698 ++++---- SU2_CFD/src/output_su2.cpp | 448 +- SU2_CFD/src/output_tecplot.cpp | 5314 +-- SU2_CFD/src/solver_adjoint_levelset.cpp | 2210 +- SU2_CFD/src/solver_adjoint_mean.cpp | 14192 +++---- SU2_CFD/src/solver_adjoint_turbulent.cpp | 1764 +- SU2_CFD/src/solver_direct_elasticity.cpp | 4874 +-- SU2_CFD/src/solver_direct_heat.cpp | 1170 +- SU2_CFD/src/solver_direct_mean.cpp | 27434 +++++++------- SU2_CFD/src/solver_direct_poisson.cpp | 1076 +- SU2_CFD/src/solver_direct_turbulent.cpp | 6442 ++-- SU2_CFD/src/solver_direct_wave.cpp | 1558 +- SU2_CFD/src/solver_structure.cpp | 3994 +- SU2_CFD/src/variable_adjoint_levelset.cpp | 160 +- SU2_CFD/src/variable_adjoint_mean.cpp | 676 +- SU2_CFD/src/variable_adjoint_turbulent.cpp | 144 +- SU2_CFD/src/variable_direct_elasticity.cpp | 496 +- SU2_CFD/src/variable_direct_heat.cpp | 140 +- SU2_CFD/src/variable_direct_mean.cpp | 1540 +- SU2_CFD/src/variable_direct_poisson.cpp | 130 +- SU2_CFD/src/variable_direct_transition.cpp | 104 +- SU2_CFD/src/variable_direct_turbulent.cpp | 400 +- SU2_CFD/src/variable_direct_wave.cpp | 140 +- SU2_CFD/src/variable_structure.cpp | 834 +- SU2_CFD/src/variable_template.cpp | 78 +- .../Xcode/SU2_CFD.xcodeproj/project.pbxproj | 164 +- 58 files changed, 102987 insertions(+), 102988 deletions(-) diff --git a/Common/include/dual_grid_structure.hpp b/Common/include/dual_grid_structure.hpp index 1fc2a7d3c5e..0cf13bbcc00 100644 --- a/Common/include/dual_grid_structure.hpp +++ b/Common/include/dual_grid_structure.hpp @@ -1,1088 +1,1088 @@ -/*! - * \file dual_grid_structure.hpp - * \brief Headers of the main subroutines for doing the complete dual grid structure. - * The subroutines and functions are in the dual_grid_structure.cpp file. - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -#include "./mpi_structure.hpp" - -#include -#include -#include -#include - -#include "config_structure.hpp" - -using namespace std; - -/*! - * \class CDualGrid - * \brief Class for controlling the dual volume definition. The dual volume is compose by - * three main elements: points, edges, and vertices. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CDualGrid{ -protected: - static unsigned short nDim; /*!< \brief Number of dimensions of the problem. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - */ - CDualGrid(unsigned short val_nDim); - - /*! - * \brief Destructor of the class. - */ - ~CDualGrid(void); - - /*! - * \brief A pure virtual member. - */ - virtual su2double *GetCoord(void) = 0; - - /*! - * \brief A pure virtual member. - * \param[in] val_coord - Coordinate of the point. - */ - virtual void SetCoord(su2double *val_coord) = 0; - - /*! - * \brief A pure virtual member. - * \param[in] val_coord_Edge_CG - Coordinates of the centre of gravity of the edge. - * \param[in] val_coord_FaceElem_CG - Coordinates of the centre of gravity of the face of an element. - * \param[in] val_coord_Elem_CG - Coordinates of the centre of gravity of the element. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG) = 0; - - /*! - * \overload - * \param[in] val_coord_Edge_CG - Coordinates of the centre of gravity of the edge. - * \param[in] val_coord_Elem_CG - Coordinates of the centre of gravity of the element. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG) = 0; - - /*! - * \brief A pure virtual member. - * \param[in] val_normal - Coordinates of the normal. - */ - virtual void GetNormal(su2double *val_normal) = 0; - - /*! - * \brief A pure virtual member. - */ - virtual su2double *GetNormal(void) = 0; - - /*! - * \brief A pure virtual member. - * \param[in] val_face_normal - Coordinates of the normal. - */ - virtual void SetNormal(su2double *val_face_normal) = 0; - - /*! - * \brief A pure virtual member. - */ - virtual unsigned short GetnNodes(void) = 0; - - /*! - * \brief A pure virtual member. - */ - virtual void SetZeroValues(void) = 0; - - /*! - * \brief A pure virtual member. - * \param[in] val_face_normal - Normal vector to be added. - */ - virtual void AddNormal(su2double *val_face_normal) = 0; -}; - -/*! - * \class CPoint - * \brief Class for point definition (including control volume definition). - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CPoint : public CDualGrid { -private: - unsigned short nElem, /*!< \brief Number of elements that set up the control volume. */ - nPoint; /*!< \brief Number of points that set up the control volume */ - vector Elem; /*!< \brief Elements that set up a control volume around a node. */ - vector Point; /*!< \brief Points surrounding the central node of the control volume. */ - vector Edge; /*!< \brief Edges that set up a control volume. */ - su2double *Volume; /*!< \brief Volume or Area of the control volume in 3D and 2D. */ - bool Domain, /*!< \brief Indicates if a point must be computed or belong to another boundary */ - Boundary, /*!< \brief To see if a point belong to the boundary (including MPI). */ - PhysicalBoundary, /*!< \brief To see if a point belong to the physical boundary (without includin MPI). */ - SolidBoundary; /*!< \brief To see if a point belong to the physical boundary (without includin MPI). */ - long *Vertex; /*!< \brief Index of the vertex that correspond which the control volume (we need one for each marker in the same node). */ - su2double *Coord, /*!< \brief vector with the coordinates of the node. */ - *Coord_Old, /*!< \brief Old coordinates vector for geometry smoothing. */ - *Coord_Sum, /*!< \brief Sum of coordinates vector for geometry smoothing. */ - *Coord_n, /*!< \brief Coordinates at time n for use with dynamic meshes. */ - *Coord_n1, /*!< \brief Coordinates at time n-1 for use with dynamic meshes. */ - *Coord_p1; /*!< \brief Coordinates at time n+1 for use with dynamic meshes. */ - su2double *GridVel; /*!< \brief Velocity of the grid for dynamic mesh cases. */ - su2double **GridVel_Grad; /*!< \brief Gradient of the grid velocity for dynamic meshes. */ - unsigned long Parent_CV; /*!< \brief Index of the parent control volume in the agglomeration process. */ - unsigned short nChildren_CV; /*!< \brief Number of children in the agglomeration process. */ - vector Children_CV; /*!< \brief Index of the children control volumes in the agglomeration process. */ - bool Agglomerate_Indirect, /*!< \brief This flag indicates if the indirect points can be agglomerated. */ - Agglomerate; /*!< \brief This flag indicates if the element has been agglomerated. */ - bool Move; /*!< \brief This flag indicates if the point is going to be move in the grid deformation process. */ - unsigned short color; /*!< \brief Color of the point in the partitioning strategy. */ - su2double Wall_Distance; /*!< \brief Distance to the nearest wall. */ - su2double SharpEdge_Distance; /*!< \brief Distance to a sharp edge. */ - su2double Curvature; /*!< \brief Value of the surface curvature (SU2_GEO). */ - unsigned long GlobalIndex; /*!< \brief Global index in the parallel simulation. */ - unsigned short nNeighbor; /*!< \brief Number of neighbors. */ - bool Flip_Orientation; /*!< \brief Flip the orientation of the normal. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_globalindex Global index in the parallel simulation. - * \param[in] config - Definition of the particular problem. - */ - CPoint(unsigned short val_nDim, unsigned long val_globalindex, CConfig *config); - - /*! - * \overload - * \param[in] val_coord_0 First coordinate of the point. - * \param[in] val_coord_1 Second coordinate of the point. - * \param[in] val_globalindex Global index in the parallel simulation. - * \param[in] config - Definition of the particular problem. - */ - CPoint(su2double val_coord_0, su2double val_coord_1, unsigned long val_globalindex, CConfig *config); - - /*! - * \overload - * \param[in] val_coord_0 First coordinate of the point. - * \param[in] val_coord_1 Second coordinate of the point. - * \param[in] val_coord_2 Third coordinate of the point. - * \param[in] val_globalindex Global index in the parallel simulation. - * \param[in] config - Definition of the particular problem. - */ - CPoint(su2double val_coord_0, su2double val_coord_1, su2double val_coord_2, unsigned long val_globalindex, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CPoint(void); - - /*! - * \brief For parallel computation, its indicates if a point must be computed or not. - * \param[in] val_domain - TRUE if the point belong to the domain; otherwise FALSE. - */ - void SetDomain(bool val_domain); - - /*! - * \brief For parallel computation, its indicates if a point must be computed or not. - * \return TRUE if the node belong to the physical domain; otherwise FALSE. - */ - bool GetDomain(void); - - /*! - * \brief Set the value of the distance to the nearest wall. - * \param[in] val_distance - Value of the distance. - */ - void SetWall_Distance(su2double val_distance); - - /*! - * \brief Set the value of the distance to a sharp edge. - * \param[in] val_distance - Value of the distance. - */ - void SetSharpEdge_Distance(su2double val_distance); - - /*! - * \brief Get the value of the distance to the nearest wall. - * \return Value of the distance to the nearest wall. - */ - su2double GetWall_Distance(void); - - /*! - * \brief Set the value of the curvature at a surface node. - * \param[in] val_curvature - Value of the curvature. - */ - void SetCurvature(su2double val_curvature); - - /*! - * \brief Get the value of the curvature at a surface node. - * \return Value of the curvature. - */ - su2double GetCurvature(void); - - /*! - * \brief Get the value of the distance to a sharp edge - * \return Value of the distance to the nearest wall. - */ - su2double GetSharpEdge_Distance(void); - - /*! - * \brief Set the number of elements that compose the control volume. - * \param[in] val_nElem - Number of elements that make the control volume around a node. - */ - void SetnElem(unsigned short val_nElem); - - /*! - * \brief Set the number of points that compose the control volume. - * \param[in] val_nPoint - Number of points that compose the control volume (points surrounding points). - */ - void SetnPoint(unsigned short val_nPoint); - - /*! - * \brief Get the coordinates dor the control volume. - * \param[in] val_dim - Number of dimensions of the problem. - * \return Coordinate that correspond with val_dim. - */ - su2double GetCoord(unsigned short val_dim); - - /*! - * \brief Get the coordinates of the control volume. - * \return pointer to the coordinate of the point. - */ - su2double *GetCoord(void); - - /*! - * \brief Set the coordinates for the control volume. - * \param[in] val_dim - Position to store the coordinate. - * \param[in] val_coord - Coordinate for val_dim. - */ - void SetCoord(unsigned short val_dim, su2double val_coord); - - /*! - * \brief Get the coordinates of the control volume. - * \return pointer to the coordinate of the point. - */ - bool GetFlip_Orientation(void); - - /*! - * \brief Set the coordinates for the control volume. - * \param[in] val_dim - Position to store the coordinate. - * \param[in] val_coord - Coordinate for val_dim. - */ - void SetFlip_Orientation(void); - - /*! - * \brief Set the coordinates for the control volume. - * \param[in] val_dim - Position to store the coordinate. - * \param[in] val_coord - Coordinate for val_dim. - */ - void AddCoord(unsigned short val_dim, su2double val_coord); - - /*! - * \overload - * \param[in] val_coord - Coordinate of the point. - */ - void SetCoord(su2double *val_coord); - - /*! - * \brief Get the number of elements that compose the control volume. - * \return Number of elements that compose the control volume. - */ - unsigned short GetnElem(void); - - /*! - * \brief Get the number of points that compose the control volume. - * \return Number of points that compose the control volume. - */ - unsigned short GetnPoint(void); - - /*! - * \brief Set the elements that set the control volume. - * \param[in] val_elem - Element to be added. - */ - void SetElem(unsigned long val_elem); - - /*! - * \brief Reset the elements of a control volume. - */ - void ResetElem(void); - - /*! - * \brief Reset the points that compose the control volume. - */ - void ResetPoint(void); - - /*! - * \brief Set the points that compose the control volume. - * \param[in] val_point - Point to be added. - */ - void SetPoint(unsigned long val_point); - - /*! - * \brief Set the edges that compose the control volume. - * \param[in] val_edge - Edge to be added. - * \param[in] val_nEdge - Position in which is going to be stored the edge for each control volume. - */ - void SetEdge(long val_edge, unsigned short val_nEdge); - - /*! - * \brief Set the boundary vertex that compose the control volume. - * \param[in] val_vertex - Vertex to be added. - * \param[in] val_nMarker - Marker of the vertex to be added (position where is going to be stored). - */ - void SetVertex(long val_vertex, unsigned short val_nMarker); - - /*! - * \brief Get all the elements that compose the control volume. - * \param[in] val_elem - Position where the element is stored. - * \return Index of the element. - */ - unsigned long GetElem(unsigned short val_elem); - - /*! - * \brief Get all the points that compose the control volume. - * \param[in] val_point - Position where the point is stored. - * \return Index of the point. - */ - unsigned long GetPoint(unsigned short val_point); - - /*! - * \brief Get all the edges that compose the control volume. - * \param[in] val_edge - Position where the edge is stored. - * \return Index of the edge. - */ - long GetEdge(unsigned short val_edge); - - /*! - * \brief Get the vertex that compose the control volume for a marker. - * \param[in] val_marker - Position where the vertex is stored. - * \return Index of the vertex. - */ - long GetVertex(unsigned short val_marker); - - /*! - * \brief Adds some area or volume of the CV. - * \param[in] val_Volume - Local volume to be added to the total one. - */ - void AddVolume(su2double val_Volume); - - /*! - * \brief Get area or volume of the control volume. - * \return Area or volume of the control volume. - */ - su2double GetVolume(void); - - /*! - * \brief Get information about the movement of the node. - * \return TRUE if the point is going to be moved; otherwise FALSE. - */ - bool GetMove(void); - - /*! - * \brief Set if a point belong to the boundary. - * \note It also create the structure to store the vertex. - * \param[in] val_nmarker - Max number of marker. - */ - void SetBoundary(unsigned short val_nmarker); - - /*! - * \brief Reset the boundary of a control volume. - */ - void ResetBoundary(void); - - /*! - * \overload - * \param[in] val_boundary - TRUE if the point belong to the boundary; otherwise FALSE. - */ - void SetBoundary(bool val_boundary); - - /*! - * \brief Provides information about if a point belong to the boundaries. - * \return TRUE if the point belong to the boundary; otherwise FALSE. - */ - bool GetBoundary(void); - - /*! - * \brief Set if a point belong to the boundary. - * \param[in] val_boundary - TRUE if the point belong to the physical boundary; otherwise FALSE. - */ - void SetPhysicalBoundary(bool val_boundary); - - /*! - * \brief Set if a point belong to the boundary. - * \param[in] val_boundary - TRUE if the point belong to the physical boundary; otherwise FALSE. - */ - void SetSolidBoundary(bool val_boundary); - - /*! - * \brief Provides information about if a point belong to the physical boundaries (without MPI). - * \return TRUE if the point belong to the boundary; otherwise FALSE. - */ - bool GetPhysicalBoundary(void); - - /*! - * \brief Provides information about if a point belong to the physical boundaries (without MPI). - * \return TRUE if the point belong to the boundary; otherwise FALSE. - */ - bool GetSolidBoundary(void); - - /*! - * \brief Set a color to the point that comes from the grid partitioning. - * \note Each domain has a different color. - * \param[in] val_color - Color of the point. - */ - void SetColor(unsigned short val_color); - - /*! - * \brief Set the number of neighbor (artificial dissipation). - * \param[in] val_nneighbor - Number of neighbors. - */ - void SetnNeighbor(unsigned short val_nneighbor); - - /*! - * \brief Get the number of neighbor of a point. - * \return Number of neighbors. - */ - unsigned short GetnNeighbor(void); - - /*! - * \brief Get the color of a point, the color indicates to which subdomain the point belong to. - * \return Color of the point. - */ - unsigned short GetColor(void); - - /*! - * \brief Get the global index in a parallel computation. - * \return Global index in a parallel computation. - */ - unsigned long GetGlobalIndex(void); - - /*! - * \brief Set the global index in a parallel computation. - * \return Global index in a parallel computation. - */ - void SetGlobalIndex(unsigned long val_globalindex); - - /*! - * \brief Get the volume of the control volume at time n. - * \return Volume of the control volume at time n - */ - su2double GetVolume_n(void); - - /*! - * \brief Get the volume of the control volume at time n+1. - * \return Volume of the control volume at time n+1 - */ - su2double GetVolume_nM1(void); - - /*! - * \brief Set the volume of the control volume at time n. - */ - void SetVolume_n(void); - - /*! - * \brief Set the volume of the control volume at time n+1. - */ - void SetVolume_nM1(void); - - /*! - * \brief Get the coordinates of the control volume at time n. - * \return Coordinates of the control volume at time n. - */ - su2double* GetCoord_n(void); - - /*! - * \brief Get the coordinates of the control volume at time n-1. - * \return Volume of the control volume at time n-1 - */ - su2double* GetCoord_n1(void); - - /*! - * \brief Get the coordinates of the control volume at time n+1. - * \return Volume of the control volume at time n+1 - */ - su2double* GetCoord_p1(void); - - /*! - * \brief Set the coordinates of the control volume at time n. - */ - void SetCoord_n(void); - - /*! - * \brief Set the coordinates of the control volume at time n-1. - */ - void SetCoord_n1(void); - - /*! - * \brief Set the coordinates of the control volume at time n+1. - * \param[in] val_coord - Value of the grid coordinates at time n+1. - */ - void SetCoord_p1(su2double *val_coord); - - /*! - * \brief Set the volume of the control volume. - * \param[in] val_Volume - Value of the volume. - */ - void SetVolume(su2double val_Volume); - - /*! - * \brief Set if a element is going to be moved on the deformation process. - * \param[in] val_move - true or false depending if the point will be moved. - */ - void SetMove(bool val_move); - - /*! - * \brief Set the parent control volume of an agglomerated control volume. - * \param[in] val_parent_CV - Index of the parent control volume. - */ - void SetParent_CV(unsigned long val_parent_CV); - - /*! - * \brief Set the children control volumes of an agglomerated control volume. - * \param[in] val_nchildren_CV - Number of children. - * \param[in] val_children_CV - Index of the children control volume. - */ - void SetChildren_CV(unsigned short val_nchildren_CV, unsigned long val_children_CV); - - /*! - * \brief Get the parent control volume of an agglomerated control volume. - * \return Index of the parent control volume. - */ - unsigned long GetParent_CV(void); - - /*! - * \brief Get the children control volume of an agglomerated control volume. - * \param[in] val_nchildren_CV - Number of the children. - * \return Index of the parent control volume. - */ - unsigned long GetChildren_CV(unsigned short val_nchildren_CV); - - /*! - * \brief Get information about if a control volume has been agglomerated. - * \return TRUE if the point has been agglomerated; otherwise FALSE. - */ - bool GetAgglomerate(void); - - /*! - * \brief Get information about if the indirect neighbors can be agglomerated. - * \return TRUE if the indirect neigbors can be agglomerated; otherwise FALSE. - */ - bool GetAgglomerate_Indirect(void); - - /*! - * \brief Set information about if the indirect neighbors can be agglomerated. - * \param[in] val_agglomerate - The indirect neigbors can be agglomerated. - */ - void SetAgglomerate_Indirect(bool val_agglomerate); - - /*! - * \brief Get the number of children of an agglomerated control volume. - * \return Number of children control volume. - */ - unsigned short GetnChildren_CV(void); - - /*! - * \brief Set the number of children of an agglomerated control volume. - * \param[in] val_nchildren_CV - Number of children of the control volume. - */ - void SetnChildren_CV(unsigned short val_nchildren_CV); - - /*! - * \brief Get the value of the summed coordinates for implicit smoothing. - * \return Sum of coordinates at a point. - */ - su2double *GetCoord_Sum(void); - - /*! - * \brief Get the value of the old coordinates for implicit smoothing. - * \return Old coordinates at a point. - */ - su2double *GetCoord_Old(void); - - /*! - * \brief Get the value of the grid velocity at the point. - * \return Grid velocity at the point. - */ - su2double *GetGridVel(void); - - /*! - * \brief Get the value of the grid velocity gradient at the point. - * \return Grid velocity gradient at the point. - */ - su2double **GetGridVel_Grad(void); - - /*! - * \brief Add the value of the coordinates to the Coord_Sum vector for implicit smoothing. - * \param[in] val_coord_sum - Value of the coordinates to add. - */ - void AddCoord_Sum(su2double *val_coord_sum); - - /*! - * \brief Initialize the vector Coord_Sum. - */ - void SetCoord_SumZero(void); - - /*! - * \brief Set the value of the vector Coord_Old for implicit smoothing. - * \param[in] val_coord_old - Value of the coordinates. - */ - void SetCoord_Old(su2double *val_coord_old); - - /*! - * \brief Set the value of the grid velocity at the point. - * \param[in] val_dim - Index of the coordinate. - * \param[in] val_gridvel - Value of the grid velocity. - */ - void SetGridVel(unsigned short val_dim, su2double val_gridvel); - - /*! - * \overload - * \param[in] val_gridvel - Value of the grid velocity. - */ - void SetGridVel(su2double *val_gridvel); - - /*! - * \brief Set the gradient of the grid velocity. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value of the gradient. - */ - void SetGridVel_Grad(unsigned short val_var, unsigned short val_dim, su2double val_value); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - void GetNormal(su2double *val_normal); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - su2double *GetNormal(void); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - void SetNormal(su2double *val_face_normal); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - unsigned short GetnNodes(void); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - void SetZeroValues(void); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - void AddNormal(su2double *val_face_normal); -}; - -/*! - * \class CEdge - * \brief Class for defining an edge. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CEdge : public CDualGrid { -private: - su2double *Coord_CG; /*!< \brief Center-of-gravity of the element. */ - unsigned long *Nodes; /*!< \brief Vector to store the global nodes of an element. */ - su2double *Normal; /*!< \brief Normal al elemento y coordenadas de su centro de gravedad. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_iPoint - First node of the edge. - * \param[in] val_jPoint - Second node of the edge. - * \param[in] val_nDim - Number of dimensions of the problem. - */ - CEdge(unsigned long val_iPoint, unsigned long val_jPoint, unsigned short val_nDim); - - /*! - * \brief Destructor of the class. - */ - ~CEdge(void); - - /*! - * \brief Set the center of gravity of the edge. - * \param[in] val_coord - Coordinates of all the nodes needed for computing the centre of gravity of an edge. - */ - void SetCoord_CG(su2double **val_coord); - - /*! - * \brief Obtain the centre of gravity of the edge. - * \param[in] val_dim - Position to read the coordinate. - * \return Coordinate val_dim of the centre of gravity. - */ - su2double GetCG(unsigned short val_dim); - - /*! - * \brief Get the nodes of the edge. - * \param[in] val_node - Position of the node that makes the edge. - * \return Index of the node that compose the edge. - */ - - unsigned long GetNode(unsigned short val_node); - - /*! - * \brief Get the number of nodes of an element. - * \return Number of nodes that set an edge (2). - */ - unsigned short GetnNodes(void); - - /*! - * \brief Compute Volume associated to each edge. - * \param[in] val_coord_Edge_CG - Coordinates of the centre of gravity of the edge. - * \param[in] val_coord_FaceElem_CG - Coordinates of the centre of gravity of the face of an element. - * \param[in] val_coord_Elem_CG - Coordinates of the centre of gravity of the element. - * \param[in] val_coord_Point - Coordinates of the point that form the control volume. - * \return Local volume associated to the edge. - */ - su2double GetVolume(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG, su2double *val_coord_Point); - - /*! - * \overload - * \param[in] val_coord_Edge_CG - Coordinates of the centre of gravity of the edge. - * \param[in] val_coord_Elem_CG - Coordinates of the centre of gravity of the element. - * \param[in] val_coord_Point - Coordinates of the point that form the control volume. - * \return Local volume associated to the edge. - */ - su2double GetVolume(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG, su2double *val_coord_Point); - - /*! - * \brief Set the face that correspond to an edge. - * \param[in] val_coord_Edge_CG - Coordinates of the centre of gravity of the edge. - * \param[in] val_coord_FaceElem_CG - Coordinates of the centre of gravity of the face of an element. - * \param[in] val_coord_Elem_CG - Coordinates of the centre of gravity of the element. - * \param[in] config - Definition of the particular problem. - * \return Compute the normal (dimensional) to the face that makes the control volume boundaries. - */ - void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG); - - /*! - * \overload - * \brief Set the face that correspond to an edge. - * \param[in] val_coord_Edge_CG - Coordinates of the centre of gravity of the edge. - * \param[in] val_coord_Elem_CG - Coordinates of the centre of gravity of the element. - * \param[in] config - Definition of the particular problem. - * \return Compute the normal (dimensional) to the face that makes the contorl volume boundaries. - */ - void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG); - - /*! - * \brief Copy the the normal vector of a face. - * \param[in] val_normal - Vector where the subroutine is goint to copy the normal (dimensional). - */ - void GetNormal(su2double *val_normal); - - /*! - * \brief Get the normal to a face of the control volume asociated with an edge. - * \return Dimensional normal vector, the modulus is the area of the face. - */ - su2double *GetNormal(void); - - /*! - * \brief Initialize normal vector. - */ - void SetZeroValues(void); - - /*! - * \brief Set the normal vector. - * \param[in] val_face_normal - Vector to initialize the normal vector. - * \return Value of the normal vector. - */ - void SetNormal(su2double *val_face_normal); - - /*! - * \brief Add a vector to the normal vector. - * \param[in] val_face_normal - Vector to add to the normal vector. - */ - void AddNormal(su2double *val_face_normal); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - su2double *GetCoord(void); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - void SetCoord(su2double *val_coord); - -}; - -/*! - * \class CVertex - * \brief Class for vertex definition (equivalent to edges, but for the boundaries). - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CVertex : public CDualGrid { -private: - unsigned long *Nodes; /*!< \brief Vector to store the global nodes of an element. */ - su2double *Normal; /*!< \brief Normal coordinates of the element and its center of gravity. */ - su2double Aux_Var; /*!< \brief Auxiliar variable defined only on the surface. */ - su2double CartCoord[3]; /*!< \brief Vertex cartesians coordinates. */ - su2double VarCoord[3]; /*!< \brief Used for storing the coordinate variation due to a surface modification. */ - long PeriodicPoint[2]; /*!< \brief Store the periodic point of a boundary (iProcessor, iPoint) */ - short Rotation_Type; /*!< \brief Type of rotation associated with the vertex (MPI and periodic) */ - unsigned long Normal_Neighbor; /*!< \brief Index of the closest neighbor. */ - unsigned long Donor_Elem; /*!< \brief Store the donor element for interpolation across zones/ */ - su2double Basis_Function[3]; /*!< \brief Basis function values for interpolation across zones. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_point - Node of the vertex. - * \param[in] val_nDim - Number of dimensions of the problem. - */ - CVertex(unsigned long val_point, unsigned short val_nDim); - - /*! - * \brief Destructor of the class. - */ - ~CVertex(void); - - /*! - * \brief Get the number of nodes of a vertex. - * \return Number of nodes that set a vertex (1). - */ - unsigned short GetnNodes(void); - - /*! - * \brief Get the node of the vertex. - * \return Index of the node that compose the vertex. - */ - unsigned long GetNode(void); - - /*! - * \brief Set the face that correspond to a vertex. - * \param[in] val_coord_Edge_CG - Coordinates of the centre of gravity of the edge. - * \param[in] val_coord_FaceElem_CG - Coordinates of the centre of gravity of the face of an element. - * \param[in] val_coord_Elem_CG - Coordinates of the centre of gravity of the element. - * \return Compute the normal (dimensional) to the face that makes the vertex. - */ - void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG); - - /*! - * \overload - * \param[in] val_coord_Edge_CG - Coordinates of the centre of gravity of the edge. - * \param[in] val_coord_Elem_CG - Coordinates of the centre of gravity of the element. - * \return Compute the normal (dimensional) to the face that makes the vertex. - */ - void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG); - - /*! - * \brief Copy the the normal vector of a face. - * \param[in] val_normal - Vector where the subroutine is goint to copy the normal (dimensional). - */ - void GetNormal(su2double *val_normal); - - /*! - * \brief Get the normal to a face of the control volume asociated with a vertex. - * \return Dimensional normal vector, the modulus is the area of the face. - */ - su2double *GetNormal(void); - - /*! - * \brief Initialize normal vector. - */ - void SetZeroValues(void); - - /*! - * \brief Set the value of an auxiliary variable for gradient computation. - * \param[in] val_auxvar - Value of the auxiliar variable. - */ - void SetAuxVar(su2double val_auxvar); - - /*! - * \brief Get the value of an auxiliary variable for gradient computation. - * \return Value of the auxiliar variable. - */ - su2double GetAuxVar(void); - - /*! - * \brief Add the value of an auxiliary variable for gradient computation. - * \param[in] val_auxvar - Value of the auxiliar variable. - */ - void AddAuxVar(su2double val_auxvar); - - /*! - * \brief Set the normal vector. - * \param[in] val_face_normal - Vector to initialize the normal vector. - * \return Value of the normal vector. - */ - void SetNormal(su2double *val_face_normal); - - /*! - * \brief Add a vector to the normal vector. - * \param[in] val_face_normal - Vector to add to the normal vector. - */ - void AddNormal(su2double *val_face_normal); - - /*! - * \brief Set the value of the coordinate variation due to a surface modification. - * \param[in] val_varcoord - Variation of the coordinate. - */ - void SetVarCoord(su2double *val_varcoord); - - /*! - * \brief Add the value of the coordinate variation due to a surface modification. - * \param[in] val_varcoord - Variation of the coordinate. - */ - void AddVarCoord(su2double *val_varcoord); - - /*! - * \brief Get the value of the coordinate variation due to a surface modification. - * \return Variation of the coordinate. - */ - su2double *GetVarCoord(void); - - /*! - * \brief Set the value of the cartesian coordinate for the vertex. - * \param[in] val_coord - Value of the cartesian coordinate. - */ - void SetCoord(su2double *val_coord); - - /*! - * \brief Get the value of the cartesian coordinate for the vertex. - * \return Value of the cartesian coordinate of the vertex. - */ - su2double *GetCoord(void); - - /*! - * \brief Get the value of the cartesian coordinate for the vertex. - * \param[in] val_dim - Variable of the dimension. - * \return Value of the cartesian coordinate of the vertex. - */ - su2double GetCoord(unsigned short val_dim); - - /*! - * \brief Set the type of rotation associated to the vertex. - * \param[in] val_rotation_type - Value of the rotation that will be applied to the solution at the vertex - */ - void SetRotation_Type(short val_rotation_type); - - /*! - * \brief Get the type of rotation associated to the vertex. - * \return Value of the rotation that must be applied to the solution of the vertex - */ - short GetRotation_Type(void); - - /*! - * \overload - * \param[in] val_periodicpoint - Value of periodic point of the vertex. - * \param[in] val_processor - Processor where the point belong. - */ - void SetDonorPoint(long val_periodicpoint, long val_processor); - - /*! - * \brief Get the value of the periodic point of a vertex. - * \return Value of the periodic point of a vertex. - */ - long GetDonorPoint(void); - - /*! - * \brief Get the value of the periodic point of a vertex. - * \return Value of the periodic point of a vertex. - */ - long GetDonorProcessor(void); - - /*! - * \brief Get the value of the periodic point of a vertex, and its somain - * \return Value of the periodic point of a vertex, and the domain. - */ - long *GetPeriodicPointDomain(void); - - /*! - * \brief Set the donor element of a vertex for interpolation across zones. - * \param[in] val_donorelem - donor element index. - */ - void SetDonorElem(long val_donorelem); - - /*! - * \brief Get the donor element of a vertex for interpolation across zones. - * \return Value of the donor element of a vertex. - */ - long GetDonorElem(void); - - /*! - * \brief Set the finite element basis functions needed for interpolation. - * \param[in] val_node - a node index of the owner element. - * \param[in] val_basis - basis function value for the node. - */ - void SetBasisFunction(unsigned short val_node, su2double val_basis); - - /*! - * \brief Get the finite element basis functions needed for interpolation. - * \param[in] val_node - a node index of the owner element. - * \return Value of the basis function for this node. - */ - su2double GetBasisFunction(unsigned short val_node); - - /*! - * \brief Set the index of the closest neighbor to a point on the boundaries. - * \param[in] val_Normal_Neighbor - Index of the closest neighbor. - */ - void SetNormal_Neighbor(unsigned long val_Normal_Neighbor); - - /*! - * \brief Get the value of the closest neighbor. - * \return Index of the closest neighbor. - */ - unsigned long GetNormal_Neighbor(void); - -}; - -#include "dual_grid_structure.inl" +/*! + * \file dual_grid_structure.hpp + * \brief Headers of the main subroutines for doing the complete dual grid structure. + * The subroutines and functions are in the dual_grid_structure.cpp file. + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +#include "./mpi_structure.hpp" + +#include +#include +#include +#include + +#include "config_structure.hpp" + +using namespace std; + +/*! + * \class CDualGrid + * \brief Class for controlling the dual volume definition. The dual volume is compose by + * three main elements: points, edges, and vertices. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CDualGrid{ +protected: + static unsigned short nDim; /*!< \brief Number of dimensions of the problem. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + */ + CDualGrid(unsigned short val_nDim); + + /*! + * \brief Destructor of the class. + */ + ~CDualGrid(void); + + /*! + * \brief A pure virtual member. + */ + virtual su2double *GetCoord(void) = 0; + + /*! + * \brief A pure virtual member. + * \param[in] val_coord - Coordinate of the point. + */ + virtual void SetCoord(su2double *val_coord) = 0; + + /*! + * \brief A pure virtual member. + * \param[in] val_coord_Edge_CG - Coordinates of the centre of gravity of the edge. + * \param[in] val_coord_FaceElem_CG - Coordinates of the centre of gravity of the face of an element. + * \param[in] val_coord_Elem_CG - Coordinates of the centre of gravity of the element. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG) = 0; + + /*! + * \overload + * \param[in] val_coord_Edge_CG - Coordinates of the centre of gravity of the edge. + * \param[in] val_coord_Elem_CG - Coordinates of the centre of gravity of the element. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG) = 0; + + /*! + * \brief A pure virtual member. + * \param[in] val_normal - Coordinates of the normal. + */ + virtual void GetNormal(su2double *val_normal) = 0; + + /*! + * \brief A pure virtual member. + */ + virtual su2double *GetNormal(void) = 0; + + /*! + * \brief A pure virtual member. + * \param[in] val_face_normal - Coordinates of the normal. + */ + virtual void SetNormal(su2double *val_face_normal) = 0; + + /*! + * \brief A pure virtual member. + */ + virtual unsigned short GetnNodes(void) = 0; + + /*! + * \brief A pure virtual member. + */ + virtual void SetZeroValues(void) = 0; + + /*! + * \brief A pure virtual member. + * \param[in] val_face_normal - Normal vector to be added. + */ + virtual void AddNormal(su2double *val_face_normal) = 0; +}; + +/*! + * \class CPoint + * \brief Class for point definition (including control volume definition). + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CPoint : public CDualGrid { +private: + unsigned short nElem, /*!< \brief Number of elements that set up the control volume. */ + nPoint; /*!< \brief Number of points that set up the control volume */ + vector Elem; /*!< \brief Elements that set up a control volume around a node. */ + vector Point; /*!< \brief Points surrounding the central node of the control volume. */ + vector Edge; /*!< \brief Edges that set up a control volume. */ + su2double *Volume; /*!< \brief Volume or Area of the control volume in 3D and 2D. */ + bool Domain, /*!< \brief Indicates if a point must be computed or belong to another boundary */ + Boundary, /*!< \brief To see if a point belong to the boundary (including MPI). */ + PhysicalBoundary, /*!< \brief To see if a point belong to the physical boundary (without includin MPI). */ + SolidBoundary; /*!< \brief To see if a point belong to the physical boundary (without includin MPI). */ + long *Vertex; /*!< \brief Index of the vertex that correspond which the control volume (we need one for each marker in the same node). */ + su2double *Coord, /*!< \brief vector with the coordinates of the node. */ + *Coord_Old, /*!< \brief Old coordinates vector for geometry smoothing. */ + *Coord_Sum, /*!< \brief Sum of coordinates vector for geometry smoothing. */ + *Coord_n, /*!< \brief Coordinates at time n for use with dynamic meshes. */ + *Coord_n1, /*!< \brief Coordinates at time n-1 for use with dynamic meshes. */ + *Coord_p1; /*!< \brief Coordinates at time n+1 for use with dynamic meshes. */ + su2double *GridVel; /*!< \brief Velocity of the grid for dynamic mesh cases. */ + su2double **GridVel_Grad; /*!< \brief Gradient of the grid velocity for dynamic meshes. */ + unsigned long Parent_CV; /*!< \brief Index of the parent control volume in the agglomeration process. */ + unsigned short nChildren_CV; /*!< \brief Number of children in the agglomeration process. */ + vector Children_CV; /*!< \brief Index of the children control volumes in the agglomeration process. */ + bool Agglomerate_Indirect, /*!< \brief This flag indicates if the indirect points can be agglomerated. */ + Agglomerate; /*!< \brief This flag indicates if the element has been agglomerated. */ + bool Move; /*!< \brief This flag indicates if the point is going to be move in the grid deformation process. */ + unsigned short color; /*!< \brief Color of the point in the partitioning strategy. */ + su2double Wall_Distance; /*!< \brief Distance to the nearest wall. */ + su2double SharpEdge_Distance; /*!< \brief Distance to a sharp edge. */ + su2double Curvature; /*!< \brief Value of the surface curvature (SU2_GEO). */ + unsigned long GlobalIndex; /*!< \brief Global index in the parallel simulation. */ + unsigned short nNeighbor; /*!< \brief Number of neighbors. */ + bool Flip_Orientation; /*!< \brief Flip the orientation of the normal. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_globalindex Global index in the parallel simulation. + * \param[in] config - Definition of the particular problem. + */ + CPoint(unsigned short val_nDim, unsigned long val_globalindex, CConfig *config); + + /*! + * \overload + * \param[in] val_coord_0 First coordinate of the point. + * \param[in] val_coord_1 Second coordinate of the point. + * \param[in] val_globalindex Global index in the parallel simulation. + * \param[in] config - Definition of the particular problem. + */ + CPoint(su2double val_coord_0, su2double val_coord_1, unsigned long val_globalindex, CConfig *config); + + /*! + * \overload + * \param[in] val_coord_0 First coordinate of the point. + * \param[in] val_coord_1 Second coordinate of the point. + * \param[in] val_coord_2 Third coordinate of the point. + * \param[in] val_globalindex Global index in the parallel simulation. + * \param[in] config - Definition of the particular problem. + */ + CPoint(su2double val_coord_0, su2double val_coord_1, su2double val_coord_2, unsigned long val_globalindex, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CPoint(void); + + /*! + * \brief For parallel computation, its indicates if a point must be computed or not. + * \param[in] val_domain - TRUE if the point belong to the domain; otherwise FALSE. + */ + void SetDomain(bool val_domain); + + /*! + * \brief For parallel computation, its indicates if a point must be computed or not. + * \return TRUE if the node belong to the physical domain; otherwise FALSE. + */ + bool GetDomain(void); + + /*! + * \brief Set the value of the distance to the nearest wall. + * \param[in] val_distance - Value of the distance. + */ + void SetWall_Distance(su2double val_distance); + + /*! + * \brief Set the value of the distance to a sharp edge. + * \param[in] val_distance - Value of the distance. + */ + void SetSharpEdge_Distance(su2double val_distance); + + /*! + * \brief Get the value of the distance to the nearest wall. + * \return Value of the distance to the nearest wall. + */ + su2double GetWall_Distance(void); + + /*! + * \brief Set the value of the curvature at a surface node. + * \param[in] val_curvature - Value of the curvature. + */ + void SetCurvature(su2double val_curvature); + + /*! + * \brief Get the value of the curvature at a surface node. + * \return Value of the curvature. + */ + su2double GetCurvature(void); + + /*! + * \brief Get the value of the distance to a sharp edge + * \return Value of the distance to the nearest wall. + */ + su2double GetSharpEdge_Distance(void); + + /*! + * \brief Set the number of elements that compose the control volume. + * \param[in] val_nElem - Number of elements that make the control volume around a node. + */ + void SetnElem(unsigned short val_nElem); + + /*! + * \brief Set the number of points that compose the control volume. + * \param[in] val_nPoint - Number of points that compose the control volume (points surrounding points). + */ + void SetnPoint(unsigned short val_nPoint); + + /*! + * \brief Get the coordinates dor the control volume. + * \param[in] val_dim - Number of dimensions of the problem. + * \return Coordinate that correspond with val_dim. + */ + su2double GetCoord(unsigned short val_dim); + + /*! + * \brief Get the coordinates of the control volume. + * \return pointer to the coordinate of the point. + */ + su2double *GetCoord(void); + + /*! + * \brief Set the coordinates for the control volume. + * \param[in] val_dim - Position to store the coordinate. + * \param[in] val_coord - Coordinate for val_dim. + */ + void SetCoord(unsigned short val_dim, su2double val_coord); + + /*! + * \brief Get the coordinates of the control volume. + * \return pointer to the coordinate of the point. + */ + bool GetFlip_Orientation(void); + + /*! + * \brief Set the coordinates for the control volume. + * \param[in] val_dim - Position to store the coordinate. + * \param[in] val_coord - Coordinate for val_dim. + */ + void SetFlip_Orientation(void); + + /*! + * \brief Set the coordinates for the control volume. + * \param[in] val_dim - Position to store the coordinate. + * \param[in] val_coord - Coordinate for val_dim. + */ + void AddCoord(unsigned short val_dim, su2double val_coord); + + /*! + * \overload + * \param[in] val_coord - Coordinate of the point. + */ + void SetCoord(su2double *val_coord); + + /*! + * \brief Get the number of elements that compose the control volume. + * \return Number of elements that compose the control volume. + */ + unsigned short GetnElem(void); + + /*! + * \brief Get the number of points that compose the control volume. + * \return Number of points that compose the control volume. + */ + unsigned short GetnPoint(void); + + /*! + * \brief Set the elements that set the control volume. + * \param[in] val_elem - Element to be added. + */ + void SetElem(unsigned long val_elem); + + /*! + * \brief Reset the elements of a control volume. + */ + void ResetElem(void); + + /*! + * \brief Reset the points that compose the control volume. + */ + void ResetPoint(void); + + /*! + * \brief Set the points that compose the control volume. + * \param[in] val_point - Point to be added. + */ + void SetPoint(unsigned long val_point); + + /*! + * \brief Set the edges that compose the control volume. + * \param[in] val_edge - Edge to be added. + * \param[in] val_nEdge - Position in which is going to be stored the edge for each control volume. + */ + void SetEdge(long val_edge, unsigned short val_nEdge); + + /*! + * \brief Set the boundary vertex that compose the control volume. + * \param[in] val_vertex - Vertex to be added. + * \param[in] val_nMarker - Marker of the vertex to be added (position where is going to be stored). + */ + void SetVertex(long val_vertex, unsigned short val_nMarker); + + /*! + * \brief Get all the elements that compose the control volume. + * \param[in] val_elem - Position where the element is stored. + * \return Index of the element. + */ + unsigned long GetElem(unsigned short val_elem); + + /*! + * \brief Get all the points that compose the control volume. + * \param[in] val_point - Position where the point is stored. + * \return Index of the point. + */ + unsigned long GetPoint(unsigned short val_point); + + /*! + * \brief Get all the edges that compose the control volume. + * \param[in] val_edge - Position where the edge is stored. + * \return Index of the edge. + */ + long GetEdge(unsigned short val_edge); + + /*! + * \brief Get the vertex that compose the control volume for a marker. + * \param[in] val_marker - Position where the vertex is stored. + * \return Index of the vertex. + */ + long GetVertex(unsigned short val_marker); + + /*! + * \brief Adds some area or volume of the CV. + * \param[in] val_Volume - Local volume to be added to the total one. + */ + void AddVolume(su2double val_Volume); + + /*! + * \brief Get area or volume of the control volume. + * \return Area or volume of the control volume. + */ + su2double GetVolume(void); + + /*! + * \brief Get information about the movement of the node. + * \return TRUE if the point is going to be moved; otherwise FALSE. + */ + bool GetMove(void); + + /*! + * \brief Set if a point belong to the boundary. + * \note It also create the structure to store the vertex. + * \param[in] val_nmarker - Max number of marker. + */ + void SetBoundary(unsigned short val_nmarker); + + /*! + * \brief Reset the boundary of a control volume. + */ + void ResetBoundary(void); + + /*! + * \overload + * \param[in] val_boundary - TRUE if the point belong to the boundary; otherwise FALSE. + */ + void SetBoundary(bool val_boundary); + + /*! + * \brief Provides information about if a point belong to the boundaries. + * \return TRUE if the point belong to the boundary; otherwise FALSE. + */ + bool GetBoundary(void); + + /*! + * \brief Set if a point belong to the boundary. + * \param[in] val_boundary - TRUE if the point belong to the physical boundary; otherwise FALSE. + */ + void SetPhysicalBoundary(bool val_boundary); + + /*! + * \brief Set if a point belong to the boundary. + * \param[in] val_boundary - TRUE if the point belong to the physical boundary; otherwise FALSE. + */ + void SetSolidBoundary(bool val_boundary); + + /*! + * \brief Provides information about if a point belong to the physical boundaries (without MPI). + * \return TRUE if the point belong to the boundary; otherwise FALSE. + */ + bool GetPhysicalBoundary(void); + + /*! + * \brief Provides information about if a point belong to the physical boundaries (without MPI). + * \return TRUE if the point belong to the boundary; otherwise FALSE. + */ + bool GetSolidBoundary(void); + + /*! + * \brief Set a color to the point that comes from the grid partitioning. + * \note Each domain has a different color. + * \param[in] val_color - Color of the point. + */ + void SetColor(unsigned short val_color); + + /*! + * \brief Set the number of neighbor (artificial dissipation). + * \param[in] val_nneighbor - Number of neighbors. + */ + void SetnNeighbor(unsigned short val_nneighbor); + + /*! + * \brief Get the number of neighbor of a point. + * \return Number of neighbors. + */ + unsigned short GetnNeighbor(void); + + /*! + * \brief Get the color of a point, the color indicates to which subdomain the point belong to. + * \return Color of the point. + */ + unsigned short GetColor(void); + + /*! + * \brief Get the global index in a parallel computation. + * \return Global index in a parallel computation. + */ + unsigned long GetGlobalIndex(void); + + /*! + * \brief Set the global index in a parallel computation. + * \return Global index in a parallel computation. + */ + void SetGlobalIndex(unsigned long val_globalindex); + + /*! + * \brief Get the volume of the control volume at time n. + * \return Volume of the control volume at time n + */ + su2double GetVolume_n(void); + + /*! + * \brief Get the volume of the control volume at time n+1. + * \return Volume of the control volume at time n+1 + */ + su2double GetVolume_nM1(void); + + /*! + * \brief Set the volume of the control volume at time n. + */ + void SetVolume_n(void); + + /*! + * \brief Set the volume of the control volume at time n+1. + */ + void SetVolume_nM1(void); + + /*! + * \brief Get the coordinates of the control volume at time n. + * \return Coordinates of the control volume at time n. + */ + su2double* GetCoord_n(void); + + /*! + * \brief Get the coordinates of the control volume at time n-1. + * \return Volume of the control volume at time n-1 + */ + su2double* GetCoord_n1(void); + + /*! + * \brief Get the coordinates of the control volume at time n+1. + * \return Volume of the control volume at time n+1 + */ + su2double* GetCoord_p1(void); + + /*! + * \brief Set the coordinates of the control volume at time n. + */ + void SetCoord_n(void); + + /*! + * \brief Set the coordinates of the control volume at time n-1. + */ + void SetCoord_n1(void); + + /*! + * \brief Set the coordinates of the control volume at time n+1. + * \param[in] val_coord - Value of the grid coordinates at time n+1. + */ + void SetCoord_p1(su2double *val_coord); + + /*! + * \brief Set the volume of the control volume. + * \param[in] val_Volume - Value of the volume. + */ + void SetVolume(su2double val_Volume); + + /*! + * \brief Set if a element is going to be moved on the deformation process. + * \param[in] val_move - true or false depending if the point will be moved. + */ + void SetMove(bool val_move); + + /*! + * \brief Set the parent control volume of an agglomerated control volume. + * \param[in] val_parent_CV - Index of the parent control volume. + */ + void SetParent_CV(unsigned long val_parent_CV); + + /*! + * \brief Set the children control volumes of an agglomerated control volume. + * \param[in] val_nchildren_CV - Number of children. + * \param[in] val_children_CV - Index of the children control volume. + */ + void SetChildren_CV(unsigned short val_nchildren_CV, unsigned long val_children_CV); + + /*! + * \brief Get the parent control volume of an agglomerated control volume. + * \return Index of the parent control volume. + */ + unsigned long GetParent_CV(void); + + /*! + * \brief Get the children control volume of an agglomerated control volume. + * \param[in] val_nchildren_CV - Number of the children. + * \return Index of the parent control volume. + */ + unsigned long GetChildren_CV(unsigned short val_nchildren_CV); + + /*! + * \brief Get information about if a control volume has been agglomerated. + * \return TRUE if the point has been agglomerated; otherwise FALSE. + */ + bool GetAgglomerate(void); + + /*! + * \brief Get information about if the indirect neighbors can be agglomerated. + * \return TRUE if the indirect neigbors can be agglomerated; otherwise FALSE. + */ + bool GetAgglomerate_Indirect(void); + + /*! + * \brief Set information about if the indirect neighbors can be agglomerated. + * \param[in] val_agglomerate - The indirect neigbors can be agglomerated. + */ + void SetAgglomerate_Indirect(bool val_agglomerate); + + /*! + * \brief Get the number of children of an agglomerated control volume. + * \return Number of children control volume. + */ + unsigned short GetnChildren_CV(void); + + /*! + * \brief Set the number of children of an agglomerated control volume. + * \param[in] val_nchildren_CV - Number of children of the control volume. + */ + void SetnChildren_CV(unsigned short val_nchildren_CV); + + /*! + * \brief Get the value of the summed coordinates for implicit smoothing. + * \return Sum of coordinates at a point. + */ + su2double *GetCoord_Sum(void); + + /*! + * \brief Get the value of the old coordinates for implicit smoothing. + * \return Old coordinates at a point. + */ + su2double *GetCoord_Old(void); + + /*! + * \brief Get the value of the grid velocity at the point. + * \return Grid velocity at the point. + */ + su2double *GetGridVel(void); + + /*! + * \brief Get the value of the grid velocity gradient at the point. + * \return Grid velocity gradient at the point. + */ + su2double **GetGridVel_Grad(void); + + /*! + * \brief Add the value of the coordinates to the Coord_Sum vector for implicit smoothing. + * \param[in] val_coord_sum - Value of the coordinates to add. + */ + void AddCoord_Sum(su2double *val_coord_sum); + + /*! + * \brief Initialize the vector Coord_Sum. + */ + void SetCoord_SumZero(void); + + /*! + * \brief Set the value of the vector Coord_Old for implicit smoothing. + * \param[in] val_coord_old - Value of the coordinates. + */ + void SetCoord_Old(su2double *val_coord_old); + + /*! + * \brief Set the value of the grid velocity at the point. + * \param[in] val_dim - Index of the coordinate. + * \param[in] val_gridvel - Value of the grid velocity. + */ + void SetGridVel(unsigned short val_dim, su2double val_gridvel); + + /*! + * \overload + * \param[in] val_gridvel - Value of the grid velocity. + */ + void SetGridVel(su2double *val_gridvel); + + /*! + * \brief Set the gradient of the grid velocity. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value of the gradient. + */ + void SetGridVel_Grad(unsigned short val_var, unsigned short val_dim, su2double val_value); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + void GetNormal(su2double *val_normal); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + su2double *GetNormal(void); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + void SetNormal(su2double *val_face_normal); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + unsigned short GetnNodes(void); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + void SetZeroValues(void); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + void AddNormal(su2double *val_face_normal); +}; + +/*! + * \class CEdge + * \brief Class for defining an edge. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CEdge : public CDualGrid { +private: + su2double *Coord_CG; /*!< \brief Center-of-gravity of the element. */ + unsigned long *Nodes; /*!< \brief Vector to store the global nodes of an element. */ + su2double *Normal; /*!< \brief Normal al elemento y coordenadas de su centro de gravedad. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_iPoint - First node of the edge. + * \param[in] val_jPoint - Second node of the edge. + * \param[in] val_nDim - Number of dimensions of the problem. + */ + CEdge(unsigned long val_iPoint, unsigned long val_jPoint, unsigned short val_nDim); + + /*! + * \brief Destructor of the class. + */ + ~CEdge(void); + + /*! + * \brief Set the center of gravity of the edge. + * \param[in] val_coord - Coordinates of all the nodes needed for computing the centre of gravity of an edge. + */ + void SetCoord_CG(su2double **val_coord); + + /*! + * \brief Obtain the centre of gravity of the edge. + * \param[in] val_dim - Position to read the coordinate. + * \return Coordinate val_dim of the centre of gravity. + */ + su2double GetCG(unsigned short val_dim); + + /*! + * \brief Get the nodes of the edge. + * \param[in] val_node - Position of the node that makes the edge. + * \return Index of the node that compose the edge. + */ + + unsigned long GetNode(unsigned short val_node); + + /*! + * \brief Get the number of nodes of an element. + * \return Number of nodes that set an edge (2). + */ + unsigned short GetnNodes(void); + + /*! + * \brief Compute Volume associated to each edge. + * \param[in] val_coord_Edge_CG - Coordinates of the centre of gravity of the edge. + * \param[in] val_coord_FaceElem_CG - Coordinates of the centre of gravity of the face of an element. + * \param[in] val_coord_Elem_CG - Coordinates of the centre of gravity of the element. + * \param[in] val_coord_Point - Coordinates of the point that form the control volume. + * \return Local volume associated to the edge. + */ + su2double GetVolume(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG, su2double *val_coord_Point); + + /*! + * \overload + * \param[in] val_coord_Edge_CG - Coordinates of the centre of gravity of the edge. + * \param[in] val_coord_Elem_CG - Coordinates of the centre of gravity of the element. + * \param[in] val_coord_Point - Coordinates of the point that form the control volume. + * \return Local volume associated to the edge. + */ + su2double GetVolume(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG, su2double *val_coord_Point); + + /*! + * \brief Set the face that correspond to an edge. + * \param[in] val_coord_Edge_CG - Coordinates of the centre of gravity of the edge. + * \param[in] val_coord_FaceElem_CG - Coordinates of the centre of gravity of the face of an element. + * \param[in] val_coord_Elem_CG - Coordinates of the centre of gravity of the element. + * \param[in] config - Definition of the particular problem. + * \return Compute the normal (dimensional) to the face that makes the control volume boundaries. + */ + void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG); + + /*! + * \overload + * \brief Set the face that correspond to an edge. + * \param[in] val_coord_Edge_CG - Coordinates of the centre of gravity of the edge. + * \param[in] val_coord_Elem_CG - Coordinates of the centre of gravity of the element. + * \param[in] config - Definition of the particular problem. + * \return Compute the normal (dimensional) to the face that makes the contorl volume boundaries. + */ + void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG); + + /*! + * \brief Copy the the normal vector of a face. + * \param[in] val_normal - Vector where the subroutine is goint to copy the normal (dimensional). + */ + void GetNormal(su2double *val_normal); + + /*! + * \brief Get the normal to a face of the control volume asociated with an edge. + * \return Dimensional normal vector, the modulus is the area of the face. + */ + su2double *GetNormal(void); + + /*! + * \brief Initialize normal vector. + */ + void SetZeroValues(void); + + /*! + * \brief Set the normal vector. + * \param[in] val_face_normal - Vector to initialize the normal vector. + * \return Value of the normal vector. + */ + void SetNormal(su2double *val_face_normal); + + /*! + * \brief Add a vector to the normal vector. + * \param[in] val_face_normal - Vector to add to the normal vector. + */ + void AddNormal(su2double *val_face_normal); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + su2double *GetCoord(void); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + void SetCoord(su2double *val_coord); + +}; + +/*! + * \class CVertex + * \brief Class for vertex definition (equivalent to edges, but for the boundaries). + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CVertex : public CDualGrid { +private: + unsigned long *Nodes; /*!< \brief Vector to store the global nodes of an element. */ + su2double *Normal; /*!< \brief Normal coordinates of the element and its center of gravity. */ + su2double Aux_Var; /*!< \brief Auxiliar variable defined only on the surface. */ + su2double CartCoord[3]; /*!< \brief Vertex cartesians coordinates. */ + su2double VarCoord[3]; /*!< \brief Used for storing the coordinate variation due to a surface modification. */ + long PeriodicPoint[2]; /*!< \brief Store the periodic point of a boundary (iProcessor, iPoint) */ + short Rotation_Type; /*!< \brief Type of rotation associated with the vertex (MPI and periodic) */ + unsigned long Normal_Neighbor; /*!< \brief Index of the closest neighbor. */ + unsigned long Donor_Elem; /*!< \brief Store the donor element for interpolation across zones/ */ + su2double Basis_Function[3]; /*!< \brief Basis function values for interpolation across zones. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_point - Node of the vertex. + * \param[in] val_nDim - Number of dimensions of the problem. + */ + CVertex(unsigned long val_point, unsigned short val_nDim); + + /*! + * \brief Destructor of the class. + */ + ~CVertex(void); + + /*! + * \brief Get the number of nodes of a vertex. + * \return Number of nodes that set a vertex (1). + */ + unsigned short GetnNodes(void); + + /*! + * \brief Get the node of the vertex. + * \return Index of the node that compose the vertex. + */ + unsigned long GetNode(void); + + /*! + * \brief Set the face that correspond to a vertex. + * \param[in] val_coord_Edge_CG - Coordinates of the centre of gravity of the edge. + * \param[in] val_coord_FaceElem_CG - Coordinates of the centre of gravity of the face of an element. + * \param[in] val_coord_Elem_CG - Coordinates of the centre of gravity of the element. + * \return Compute the normal (dimensional) to the face that makes the vertex. + */ + void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG); + + /*! + * \overload + * \param[in] val_coord_Edge_CG - Coordinates of the centre of gravity of the edge. + * \param[in] val_coord_Elem_CG - Coordinates of the centre of gravity of the element. + * \return Compute the normal (dimensional) to the face that makes the vertex. + */ + void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG); + + /*! + * \brief Copy the the normal vector of a face. + * \param[in] val_normal - Vector where the subroutine is goint to copy the normal (dimensional). + */ + void GetNormal(su2double *val_normal); + + /*! + * \brief Get the normal to a face of the control volume asociated with a vertex. + * \return Dimensional normal vector, the modulus is the area of the face. + */ + su2double *GetNormal(void); + + /*! + * \brief Initialize normal vector. + */ + void SetZeroValues(void); + + /*! + * \brief Set the value of an auxiliary variable for gradient computation. + * \param[in] val_auxvar - Value of the auxiliar variable. + */ + void SetAuxVar(su2double val_auxvar); + + /*! + * \brief Get the value of an auxiliary variable for gradient computation. + * \return Value of the auxiliar variable. + */ + su2double GetAuxVar(void); + + /*! + * \brief Add the value of an auxiliary variable for gradient computation. + * \param[in] val_auxvar - Value of the auxiliar variable. + */ + void AddAuxVar(su2double val_auxvar); + + /*! + * \brief Set the normal vector. + * \param[in] val_face_normal - Vector to initialize the normal vector. + * \return Value of the normal vector. + */ + void SetNormal(su2double *val_face_normal); + + /*! + * \brief Add a vector to the normal vector. + * \param[in] val_face_normal - Vector to add to the normal vector. + */ + void AddNormal(su2double *val_face_normal); + + /*! + * \brief Set the value of the coordinate variation due to a surface modification. + * \param[in] val_varcoord - Variation of the coordinate. + */ + void SetVarCoord(su2double *val_varcoord); + + /*! + * \brief Add the value of the coordinate variation due to a surface modification. + * \param[in] val_varcoord - Variation of the coordinate. + */ + void AddVarCoord(su2double *val_varcoord); + + /*! + * \brief Get the value of the coordinate variation due to a surface modification. + * \return Variation of the coordinate. + */ + su2double *GetVarCoord(void); + + /*! + * \brief Set the value of the cartesian coordinate for the vertex. + * \param[in] val_coord - Value of the cartesian coordinate. + */ + void SetCoord(su2double *val_coord); + + /*! + * \brief Get the value of the cartesian coordinate for the vertex. + * \return Value of the cartesian coordinate of the vertex. + */ + su2double *GetCoord(void); + + /*! + * \brief Get the value of the cartesian coordinate for the vertex. + * \param[in] val_dim - Variable of the dimension. + * \return Value of the cartesian coordinate of the vertex. + */ + su2double GetCoord(unsigned short val_dim); + + /*! + * \brief Set the type of rotation associated to the vertex. + * \param[in] val_rotation_type - Value of the rotation that will be applied to the solution at the vertex + */ + void SetRotation_Type(short val_rotation_type); + + /*! + * \brief Get the type of rotation associated to the vertex. + * \return Value of the rotation that must be applied to the solution of the vertex + */ + short GetRotation_Type(void); + + /*! + * \overload + * \param[in] val_periodicpoint - Value of periodic point of the vertex. + * \param[in] val_processor - Processor where the point belong. + */ + void SetDonorPoint(long val_periodicpoint, long val_processor); + + /*! + * \brief Get the value of the periodic point of a vertex. + * \return Value of the periodic point of a vertex. + */ + long GetDonorPoint(void); + + /*! + * \brief Get the value of the periodic point of a vertex. + * \return Value of the periodic point of a vertex. + */ + long GetDonorProcessor(void); + + /*! + * \brief Get the value of the periodic point of a vertex, and its somain + * \return Value of the periodic point of a vertex, and the domain. + */ + long *GetPeriodicPointDomain(void); + + /*! + * \brief Set the donor element of a vertex for interpolation across zones. + * \param[in] val_donorelem - donor element index. + */ + void SetDonorElem(long val_donorelem); + + /*! + * \brief Get the donor element of a vertex for interpolation across zones. + * \return Value of the donor element of a vertex. + */ + long GetDonorElem(void); + + /*! + * \brief Set the finite element basis functions needed for interpolation. + * \param[in] val_node - a node index of the owner element. + * \param[in] val_basis - basis function value for the node. + */ + void SetBasisFunction(unsigned short val_node, su2double val_basis); + + /*! + * \brief Get the finite element basis functions needed for interpolation. + * \param[in] val_node - a node index of the owner element. + * \return Value of the basis function for this node. + */ + su2double GetBasisFunction(unsigned short val_node); + + /*! + * \brief Set the index of the closest neighbor to a point on the boundaries. + * \param[in] val_Normal_Neighbor - Index of the closest neighbor. + */ + void SetNormal_Neighbor(unsigned long val_Normal_Neighbor); + + /*! + * \brief Get the value of the closest neighbor. + * \return Index of the closest neighbor. + */ + unsigned long GetNormal_Neighbor(void); + +}; + +#include "dual_grid_structure.inl" diff --git a/Common/include/dual_grid_structure.inl b/Common/include/dual_grid_structure.inl index c1d7786edbe..86f1e1c50af 100644 --- a/Common/include/dual_grid_structure.inl +++ b/Common/include/dual_grid_structure.inl @@ -1,339 +1,339 @@ -/*! - * \file dual_grid_structure.inl - * \brief In-Line subroutines of the dual_grid_structure.hpp file. - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -inline void CPoint::SetElem(unsigned long val_elem) { Elem.push_back(val_elem); nElem = Elem.size(); } - -inline void CPoint::ResetBoundary(void) { if (Vertex != NULL) delete [] Vertex; Boundary = false; } - -inline void CPoint::ResetElem(void) { Elem.clear(); nElem = 0; } - -inline void CPoint::ResetPoint(void) { Point.clear(); Edge.clear(); nPoint = 0; } - -inline su2double CPoint::GetCoord(unsigned short val_dim) { return Coord[val_dim]; } - -inline su2double *CPoint::GetCoord(void) { return Coord; } - -inline bool CPoint::GetFlip_Orientation(void) { return Flip_Orientation; } - -inline void CPoint::SetCoord(unsigned short val_dim, su2double val_coord) { Coord[val_dim] = val_coord; } - -inline void CPoint::SetFlip_Orientation(void) { Flip_Orientation = true; } - -inline void CPoint::AddCoord(unsigned short val_dim, su2double val_coord) { Coord[val_dim] += val_coord; } - -inline void CPoint::SetCoord(su2double *val_coord) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Coord[iDim]=val_coord[iDim]; -} - -inline void CPoint::SetnElem(unsigned short val_nElem) { nElem = val_nElem; } - -inline unsigned short CPoint::GetnElem(void) { return nElem; } - -inline void CPoint::SetEdge(long val_edge, unsigned short val_nedge) { Edge[val_nedge] = val_edge; } - -inline unsigned long CPoint::GetElem(unsigned short val_elem) { return Elem[val_elem]; } - -inline long CPoint::GetEdge(unsigned short val_edge) { return Edge[val_edge]; } - -inline void CPoint::SetnPoint(unsigned short val_nPoint) { nPoint = val_nPoint; } - -inline unsigned short CPoint::GetnPoint(void) { return nPoint; } - -inline unsigned long CPoint::GetPoint(unsigned short val_point) { return Point[val_point]; } - -inline su2double CPoint::GetVolume (void) { return Volume[0]; } - -inline bool CPoint::GetMove (void) { return Move; } - -inline bool CPoint::GetBoundary(void) { return Boundary; } - -inline void CPoint::SetBoundary(bool val_boundary) { Boundary = val_boundary; } - -inline void CPoint::SetPhysicalBoundary(bool val_boundary) { PhysicalBoundary = val_boundary; } - -inline bool CPoint::GetPhysicalBoundary(void) { return PhysicalBoundary; } - -inline void CPoint::SetSolidBoundary(bool val_boundary) { SolidBoundary = val_boundary; } - -inline bool CPoint::GetSolidBoundary(void) { return SolidBoundary; } - -inline void CPoint::AddVolume (su2double val_Volume) { Volume[0] += val_Volume; } - -inline void CPoint::SetVolume (su2double val_Volume) { Volume[0] = val_Volume; } - -inline void CPoint::SetMove(bool val_move) { Move = val_move; } - -inline su2double *CPoint::GetCoord_Old(void) { return Coord_Old; } - -inline su2double *CPoint::GetCoord_Sum(void) { return Coord_Sum; } - -inline su2double *CPoint::GetGridVel(void) { return GridVel; } - -inline su2double **CPoint::GetGridVel_Grad(void) { return GridVel_Grad; } - -inline void CPoint::SetCoord_Old(su2double *val_coord_old) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Coord_Old[iDim] = val_coord_old[iDim]; -} - -inline void CPoint::SetCoord_SumZero(void) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Coord_Sum[iDim] = 0.0; -} - -inline void CPoint::AddCoord_Sum(su2double *val_coord_sum) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Coord_Sum[iDim] += val_coord_sum[iDim]; -} - -inline void CPoint::SetGridVel(unsigned short val_dim, su2double val_gridvel) { GridVel[val_dim] = val_gridvel; } - -inline void CPoint::SetGridVel_Grad(unsigned short val_var, unsigned short val_dim, su2double val_value) { GridVel_Grad[val_var][val_dim] = val_value; } - -inline void CPoint::SetChildren_CV (unsigned short val_nchildren_CV, unsigned long val_children_CV) { - if (Children_CV.size() <= val_nchildren_CV) Children_CV.resize(val_nchildren_CV+1); - Children_CV[val_nchildren_CV] = val_children_CV; -} - -inline unsigned short CPoint::GetnNodes() { return 0; } - -inline unsigned long CPoint::GetParent_CV (void) { return Parent_CV; } - -inline unsigned long CPoint::GetChildren_CV (unsigned short val_nchildren_CV) { return Children_CV[val_nchildren_CV]; } - -inline bool CPoint::GetAgglomerate (void) { return Agglomerate; } - -inline bool CPoint::GetAgglomerate_Indirect (void) { return Agglomerate_Indirect; } - -inline void CPoint::SetAgglomerate_Indirect(bool val_agglomerate) { Agglomerate_Indirect = val_agglomerate; }; - -inline void CPoint::SetVertex(long val_vertex, unsigned short val_nmarker) { - if (Boundary) Vertex[val_nmarker] = val_vertex; -} - -inline unsigned short CPoint::GetnChildren_CV (void) { return nChildren_CV; } - -inline long CPoint::GetVertex(unsigned short val_marker) { - if (Boundary) return Vertex[val_marker]; - else return -1; -} - -inline void CPoint::SetnChildren_CV (unsigned short val_nchildren_CV) { nChildren_CV = val_nchildren_CV; } - -inline void CPoint::SetParent_CV (unsigned long val_parent_CV) { Parent_CV = val_parent_CV; Agglomerate = true; } - -inline void CPoint::SetGridVel(su2double *val_gridvel) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - GridVel[iDim] = val_gridvel[iDim]; -} - -inline void CPoint::SetVolume_n (void) { Volume[1] = Volume[0]; } - -inline void CPoint::SetVolume_nM1 (void) { Volume[2] = Volume[1]; } - -inline su2double CPoint::GetVolume_n (void) { return Volume[1]; } - -inline su2double CPoint::GetVolume_nM1 (void) { return Volume[2]; } - -inline void CPoint::SetCoord_n (void) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Coord_n[iDim] = Coord[iDim]; -} - -inline void CPoint::SetCoord_n1 (void) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Coord_n1[iDim] = Coord_n[iDim]; -} - -inline void CPoint::SetCoord_p1(su2double *val_coord) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Coord_p1[iDim] = val_coord[iDim]; -} - -inline su2double *CPoint::GetCoord_n (void) { return Coord_n; } - -inline su2double *CPoint::GetCoord_n1 (void) { return Coord_n1; } - -inline su2double *CPoint::GetCoord_p1 (void) { return Coord_p1; } - -inline void CPoint::SetColor(unsigned short val_color) { color = val_color; } - -inline void CPoint::SetnNeighbor(unsigned short val_nneighbor) { nNeighbor = val_nneighbor; } - -inline unsigned short CPoint::GetnNeighbor(void) { return nNeighbor; } - -inline unsigned short CPoint::GetColor(void) { return color; } - -inline unsigned long CPoint::GetGlobalIndex(void) { return GlobalIndex; } - -inline void CPoint::SetGlobalIndex(unsigned long val_globalindex) { GlobalIndex = val_globalindex; } - -inline void CPoint::SetDomain(bool val_domain) { Domain = val_domain; } - -inline bool CPoint::GetDomain(void) { return Domain; } - -inline void CPoint::SetWall_Distance(su2double val_distance) { Wall_Distance = val_distance; } - -inline void CPoint::SetCurvature(su2double val_curvature) { Curvature = val_curvature; } - -inline void CPoint::SetSharpEdge_Distance(su2double val_distance) { SharpEdge_Distance = val_distance; } - -inline su2double CPoint::GetWall_Distance(void) { return Wall_Distance; } - -inline su2double CPoint::GetCurvature(void) { return Curvature; } - -inline su2double CPoint::GetSharpEdge_Distance(void) { return SharpEdge_Distance; } - -inline void CPoint::SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG) { } - -inline void CPoint::SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG) { } - -inline void CPoint::GetNormal(su2double *val_normal) { } - -inline su2double *CPoint::GetNormal(void) { return 0; } - -inline void CPoint::SetNormal(su2double *val_face_normal) { } - -inline void CPoint::SetZeroValues(void) { } - -inline void CPoint::AddNormal(su2double *val_face_normal) { } - -inline unsigned short CEdge::GetnNodes() { return 2; } - -inline unsigned long CEdge::GetNode(unsigned short val_node) { return Nodes[val_node]; } - -inline su2double CEdge::GetCG(unsigned short val_dim) { return Coord_CG[val_dim]; } - -inline su2double *CEdge::GetNormal(void) { return Normal; } - -inline void CEdge::GetNormal(su2double *val_normal) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - val_normal[iDim] = Normal[iDim]; -} - -inline void CEdge::SetNormal(su2double *val_face_normal) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Normal[iDim]=val_face_normal[iDim]; -} - -inline void CEdge::AddNormal(su2double *val_face_normal) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Normal[iDim] += val_face_normal[iDim]; -} - -inline void CEdge::SetZeroValues(void) { - for (unsigned short iDim = 0; iDim < nDim; iDim ++) - Normal[iDim] = 0.0; -} - -inline su2double *CEdge::GetCoord(void) { return NULL; } - -inline void CEdge::SetCoord(su2double *val_coord) { } - -inline unsigned short CVertex::GetnNodes() { return 1; } - -inline unsigned long CVertex::GetNode() { return Nodes[0]; } - -inline su2double *CVertex::GetNormal(void) { return Normal; } - -inline su2double *CVertex::GetVarCoord(void) { return VarCoord; } - -inline su2double *CVertex::GetCoord(void) { return CartCoord; } - -inline su2double CVertex::GetCoord(unsigned short val_dim) { return CartCoord[val_dim]; } - -inline void CVertex::SetAuxVar(su2double val_auxvar) { Aux_Var = val_auxvar; } - -inline void CVertex::AddAuxVar(su2double val_auxvar) { Aux_Var += val_auxvar; } - -inline su2double CVertex::GetAuxVar(void) { return Aux_Var; } - -inline void CVertex::GetNormal(su2double *val_normal) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - val_normal[iDim] = Normal[iDim]; -} - -inline void CVertex::SetNormal(su2double *val_face_normal) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Normal[iDim]=val_face_normal[iDim]; -} - -inline void CVertex::SetVarCoord(su2double *val_varcoord) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - VarCoord[iDim] = val_varcoord[iDim]; -} - -inline void CVertex::AddVarCoord(su2double *val_varcoord) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - VarCoord[iDim] += val_varcoord[iDim]; -} - -inline void CVertex::SetCoord(su2double *val_coord) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - CartCoord[iDim] = val_coord[iDim]; -} - -inline void CVertex::SetRotation_Type(short val_rotation_type) { Rotation_Type = val_rotation_type; } - -inline short CVertex::GetRotation_Type(void) { return Rotation_Type; } - -inline void CVertex::SetDonorPoint(long val_periodicpoint, long val_processor) { - PeriodicPoint[0] = val_periodicpoint; - PeriodicPoint[1] = val_processor; -} - -inline void CVertex::SetDonorElem(long val_donorelem) { Donor_Elem = val_donorelem; } - -inline long CVertex::GetDonorElem(void) { return Donor_Elem; } - -inline long CVertex::GetDonorPoint(void) { return PeriodicPoint[0]; } - -inline long CVertex::GetDonorProcessor(void) { return PeriodicPoint[1]; } - -inline void CVertex::SetBasisFunction(unsigned short val_node, su2double val_basis) { Basis_Function[val_node] = val_basis; } - -inline su2double CVertex::GetBasisFunction(unsigned short val_node) { return Basis_Function[val_node]; } - -inline long *CVertex::GetPeriodicPointDomain(void) { return PeriodicPoint; } - -inline void CVertex::SetZeroValues(void) { - for (unsigned short iDim = 0; iDim < nDim; iDim ++) - Normal[iDim] = 0.0; -} - -inline unsigned long CVertex::GetNormal_Neighbor(void) { return Normal_Neighbor; } - -inline void CVertex::SetNormal_Neighbor(unsigned long val_Normal_Neighbor) { Normal_Neighbor = val_Normal_Neighbor; } - - +/*! + * \file dual_grid_structure.inl + * \brief In-Line subroutines of the dual_grid_structure.hpp file. + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +inline void CPoint::SetElem(unsigned long val_elem) { Elem.push_back(val_elem); nElem = Elem.size(); } + +inline void CPoint::ResetBoundary(void) { if (Vertex != NULL) delete [] Vertex; Boundary = false; } + +inline void CPoint::ResetElem(void) { Elem.clear(); nElem = 0; } + +inline void CPoint::ResetPoint(void) { Point.clear(); Edge.clear(); nPoint = 0; } + +inline su2double CPoint::GetCoord(unsigned short val_dim) { return Coord[val_dim]; } + +inline su2double *CPoint::GetCoord(void) { return Coord; } + +inline bool CPoint::GetFlip_Orientation(void) { return Flip_Orientation; } + +inline void CPoint::SetCoord(unsigned short val_dim, su2double val_coord) { Coord[val_dim] = val_coord; } + +inline void CPoint::SetFlip_Orientation(void) { Flip_Orientation = true; } + +inline void CPoint::AddCoord(unsigned short val_dim, su2double val_coord) { Coord[val_dim] += val_coord; } + +inline void CPoint::SetCoord(su2double *val_coord) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Coord[iDim]=val_coord[iDim]; +} + +inline void CPoint::SetnElem(unsigned short val_nElem) { nElem = val_nElem; } + +inline unsigned short CPoint::GetnElem(void) { return nElem; } + +inline void CPoint::SetEdge(long val_edge, unsigned short val_nedge) { Edge[val_nedge] = val_edge; } + +inline unsigned long CPoint::GetElem(unsigned short val_elem) { return Elem[val_elem]; } + +inline long CPoint::GetEdge(unsigned short val_edge) { return Edge[val_edge]; } + +inline void CPoint::SetnPoint(unsigned short val_nPoint) { nPoint = val_nPoint; } + +inline unsigned short CPoint::GetnPoint(void) { return nPoint; } + +inline unsigned long CPoint::GetPoint(unsigned short val_point) { return Point[val_point]; } + +inline su2double CPoint::GetVolume (void) { return Volume[0]; } + +inline bool CPoint::GetMove (void) { return Move; } + +inline bool CPoint::GetBoundary(void) { return Boundary; } + +inline void CPoint::SetBoundary(bool val_boundary) { Boundary = val_boundary; } + +inline void CPoint::SetPhysicalBoundary(bool val_boundary) { PhysicalBoundary = val_boundary; } + +inline bool CPoint::GetPhysicalBoundary(void) { return PhysicalBoundary; } + +inline void CPoint::SetSolidBoundary(bool val_boundary) { SolidBoundary = val_boundary; } + +inline bool CPoint::GetSolidBoundary(void) { return SolidBoundary; } + +inline void CPoint::AddVolume (su2double val_Volume) { Volume[0] += val_Volume; } + +inline void CPoint::SetVolume (su2double val_Volume) { Volume[0] = val_Volume; } + +inline void CPoint::SetMove(bool val_move) { Move = val_move; } + +inline su2double *CPoint::GetCoord_Old(void) { return Coord_Old; } + +inline su2double *CPoint::GetCoord_Sum(void) { return Coord_Sum; } + +inline su2double *CPoint::GetGridVel(void) { return GridVel; } + +inline su2double **CPoint::GetGridVel_Grad(void) { return GridVel_Grad; } + +inline void CPoint::SetCoord_Old(su2double *val_coord_old) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Coord_Old[iDim] = val_coord_old[iDim]; +} + +inline void CPoint::SetCoord_SumZero(void) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Coord_Sum[iDim] = 0.0; +} + +inline void CPoint::AddCoord_Sum(su2double *val_coord_sum) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Coord_Sum[iDim] += val_coord_sum[iDim]; +} + +inline void CPoint::SetGridVel(unsigned short val_dim, su2double val_gridvel) { GridVel[val_dim] = val_gridvel; } + +inline void CPoint::SetGridVel_Grad(unsigned short val_var, unsigned short val_dim, su2double val_value) { GridVel_Grad[val_var][val_dim] = val_value; } + +inline void CPoint::SetChildren_CV (unsigned short val_nchildren_CV, unsigned long val_children_CV) { + if (Children_CV.size() <= val_nchildren_CV) Children_CV.resize(val_nchildren_CV+1); + Children_CV[val_nchildren_CV] = val_children_CV; +} + +inline unsigned short CPoint::GetnNodes() { return 0; } + +inline unsigned long CPoint::GetParent_CV (void) { return Parent_CV; } + +inline unsigned long CPoint::GetChildren_CV (unsigned short val_nchildren_CV) { return Children_CV[val_nchildren_CV]; } + +inline bool CPoint::GetAgglomerate (void) { return Agglomerate; } + +inline bool CPoint::GetAgglomerate_Indirect (void) { return Agglomerate_Indirect; } + +inline void CPoint::SetAgglomerate_Indirect(bool val_agglomerate) { Agglomerate_Indirect = val_agglomerate; }; + +inline void CPoint::SetVertex(long val_vertex, unsigned short val_nmarker) { + if (Boundary) Vertex[val_nmarker] = val_vertex; +} + +inline unsigned short CPoint::GetnChildren_CV (void) { return nChildren_CV; } + +inline long CPoint::GetVertex(unsigned short val_marker) { + if (Boundary) return Vertex[val_marker]; + else return -1; +} + +inline void CPoint::SetnChildren_CV (unsigned short val_nchildren_CV) { nChildren_CV = val_nchildren_CV; } + +inline void CPoint::SetParent_CV (unsigned long val_parent_CV) { Parent_CV = val_parent_CV; Agglomerate = true; } + +inline void CPoint::SetGridVel(su2double *val_gridvel) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + GridVel[iDim] = val_gridvel[iDim]; +} + +inline void CPoint::SetVolume_n (void) { Volume[1] = Volume[0]; } + +inline void CPoint::SetVolume_nM1 (void) { Volume[2] = Volume[1]; } + +inline su2double CPoint::GetVolume_n (void) { return Volume[1]; } + +inline su2double CPoint::GetVolume_nM1 (void) { return Volume[2]; } + +inline void CPoint::SetCoord_n (void) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Coord_n[iDim] = Coord[iDim]; +} + +inline void CPoint::SetCoord_n1 (void) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Coord_n1[iDim] = Coord_n[iDim]; +} + +inline void CPoint::SetCoord_p1(su2double *val_coord) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Coord_p1[iDim] = val_coord[iDim]; +} + +inline su2double *CPoint::GetCoord_n (void) { return Coord_n; } + +inline su2double *CPoint::GetCoord_n1 (void) { return Coord_n1; } + +inline su2double *CPoint::GetCoord_p1 (void) { return Coord_p1; } + +inline void CPoint::SetColor(unsigned short val_color) { color = val_color; } + +inline void CPoint::SetnNeighbor(unsigned short val_nneighbor) { nNeighbor = val_nneighbor; } + +inline unsigned short CPoint::GetnNeighbor(void) { return nNeighbor; } + +inline unsigned short CPoint::GetColor(void) { return color; } + +inline unsigned long CPoint::GetGlobalIndex(void) { return GlobalIndex; } + +inline void CPoint::SetGlobalIndex(unsigned long val_globalindex) { GlobalIndex = val_globalindex; } + +inline void CPoint::SetDomain(bool val_domain) { Domain = val_domain; } + +inline bool CPoint::GetDomain(void) { return Domain; } + +inline void CPoint::SetWall_Distance(su2double val_distance) { Wall_Distance = val_distance; } + +inline void CPoint::SetCurvature(su2double val_curvature) { Curvature = val_curvature; } + +inline void CPoint::SetSharpEdge_Distance(su2double val_distance) { SharpEdge_Distance = val_distance; } + +inline su2double CPoint::GetWall_Distance(void) { return Wall_Distance; } + +inline su2double CPoint::GetCurvature(void) { return Curvature; } + +inline su2double CPoint::GetSharpEdge_Distance(void) { return SharpEdge_Distance; } + +inline void CPoint::SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG) { } + +inline void CPoint::SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG) { } + +inline void CPoint::GetNormal(su2double *val_normal) { } + +inline su2double *CPoint::GetNormal(void) { return 0; } + +inline void CPoint::SetNormal(su2double *val_face_normal) { } + +inline void CPoint::SetZeroValues(void) { } + +inline void CPoint::AddNormal(su2double *val_face_normal) { } + +inline unsigned short CEdge::GetnNodes() { return 2; } + +inline unsigned long CEdge::GetNode(unsigned short val_node) { return Nodes[val_node]; } + +inline su2double CEdge::GetCG(unsigned short val_dim) { return Coord_CG[val_dim]; } + +inline su2double *CEdge::GetNormal(void) { return Normal; } + +inline void CEdge::GetNormal(su2double *val_normal) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + val_normal[iDim] = Normal[iDim]; +} + +inline void CEdge::SetNormal(su2double *val_face_normal) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Normal[iDim]=val_face_normal[iDim]; +} + +inline void CEdge::AddNormal(su2double *val_face_normal) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Normal[iDim] += val_face_normal[iDim]; +} + +inline void CEdge::SetZeroValues(void) { + for (unsigned short iDim = 0; iDim < nDim; iDim ++) + Normal[iDim] = 0.0; +} + +inline su2double *CEdge::GetCoord(void) { return NULL; } + +inline void CEdge::SetCoord(su2double *val_coord) { } + +inline unsigned short CVertex::GetnNodes() { return 1; } + +inline unsigned long CVertex::GetNode() { return Nodes[0]; } + +inline su2double *CVertex::GetNormal(void) { return Normal; } + +inline su2double *CVertex::GetVarCoord(void) { return VarCoord; } + +inline su2double *CVertex::GetCoord(void) { return CartCoord; } + +inline su2double CVertex::GetCoord(unsigned short val_dim) { return CartCoord[val_dim]; } + +inline void CVertex::SetAuxVar(su2double val_auxvar) { Aux_Var = val_auxvar; } + +inline void CVertex::AddAuxVar(su2double val_auxvar) { Aux_Var += val_auxvar; } + +inline su2double CVertex::GetAuxVar(void) { return Aux_Var; } + +inline void CVertex::GetNormal(su2double *val_normal) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + val_normal[iDim] = Normal[iDim]; +} + +inline void CVertex::SetNormal(su2double *val_face_normal) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Normal[iDim]=val_face_normal[iDim]; +} + +inline void CVertex::SetVarCoord(su2double *val_varcoord) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + VarCoord[iDim] = val_varcoord[iDim]; +} + +inline void CVertex::AddVarCoord(su2double *val_varcoord) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + VarCoord[iDim] += val_varcoord[iDim]; +} + +inline void CVertex::SetCoord(su2double *val_coord) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + CartCoord[iDim] = val_coord[iDim]; +} + +inline void CVertex::SetRotation_Type(short val_rotation_type) { Rotation_Type = val_rotation_type; } + +inline short CVertex::GetRotation_Type(void) { return Rotation_Type; } + +inline void CVertex::SetDonorPoint(long val_periodicpoint, long val_processor) { + PeriodicPoint[0] = val_periodicpoint; + PeriodicPoint[1] = val_processor; +} + +inline void CVertex::SetDonorElem(long val_donorelem) { Donor_Elem = val_donorelem; } + +inline long CVertex::GetDonorElem(void) { return Donor_Elem; } + +inline long CVertex::GetDonorPoint(void) { return PeriodicPoint[0]; } + +inline long CVertex::GetDonorProcessor(void) { return PeriodicPoint[1]; } + +inline void CVertex::SetBasisFunction(unsigned short val_node, su2double val_basis) { Basis_Function[val_node] = val_basis; } + +inline su2double CVertex::GetBasisFunction(unsigned short val_node) { return Basis_Function[val_node]; } + +inline long *CVertex::GetPeriodicPointDomain(void) { return PeriodicPoint; } + +inline void CVertex::SetZeroValues(void) { + for (unsigned short iDim = 0; iDim < nDim; iDim ++) + Normal[iDim] = 0.0; +} + +inline unsigned long CVertex::GetNormal_Neighbor(void) { return Normal_Neighbor; } + +inline void CVertex::SetNormal_Neighbor(unsigned long val_Normal_Neighbor) { Normal_Neighbor = val_Normal_Neighbor; } + + diff --git a/Common/include/geometry_structure.inl b/Common/include/geometry_structure.inl index 026bf638c11..b17c48e909f 100644 --- a/Common/include/geometry_structure.inl +++ b/Common/include/geometry_structure.inl @@ -1,293 +1,293 @@ -/*! - * \file geometry_structure.inl - * \brief In-Line subroutines of the geometry_structure.hpp file. - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -inline long CGeometry::GetGlobal_to_Local_Point(long val_ipoint) { return 0; } - -inline unsigned short CGeometry::GetGlobal_to_Local_Marker(unsigned short val_imarker) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nPoint(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nPointDomain(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nElem(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nElemLine(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nElemTria(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nElemQuad(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nElemTetr(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nElemHexa(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nElemPris(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nElemPyra(void) { return 0; } - -inline unsigned long CGeometry::GetnElemLine(void) { return 0; } - -inline unsigned long CGeometry::GetnElemTria(void) { return 0; } - -inline unsigned long CGeometry::GetnElemQuad(void) { return 0; } - -inline unsigned long CGeometry::GetnElemTetr(void) { return 0; } - -inline unsigned long CGeometry::GetnElemHexa(void) { return 0; } - -inline unsigned long CGeometry::GetnElemPris(void) { return 0; } - -inline unsigned long CGeometry::GetnElemPyra(void) { return 0; } - -inline void CGeometry::Check_IntElem_Orientation(CConfig *config) { } - -inline void CGeometry::Check_BoundElem_Orientation(CConfig *config) { } - -inline void CGeometry::SetColorGrid(CConfig *config) { } - -inline void CGeometry::SetColorGrid_Parallel(CConfig *config) { } - -inline void CGeometry::DivideConnectivity(CConfig *config, unsigned short Elem_Type) { } - -inline void CGeometry::SetRotationalVelocity(CConfig *config, unsigned short val_iZone) { } - -inline void CGeometry::SetTranslationalVelocity(CConfig *config) { } - -inline void CGeometry::SetGridVelocity(CConfig *config, unsigned long iter) { } - -inline void CGeometry::SetRestricted_GridVelocity(CGeometry *fine_mesh, CConfig *config) { } - -inline void CGeometry::Set_MPI_Coord(CConfig *config) { } - -inline void CGeometry::Set_MPI_GridVel(CConfig *config) { } - -inline void CGeometry::SetPeriodicBoundary(CConfig *config) { } - -inline void CGeometry::SetPeriodicBoundary(CGeometry *geometry, CConfig *config) { } - -inline void CGeometry::SetSendReceive(CConfig *config) { } - -inline void CGeometry::SetBoundaries(CConfig *config) { } - -inline void CGeometry::ComputeWall_Distance(CConfig *config) { } - -inline void CGeometry::SetPositive_ZArea(CConfig *config) { } - -inline void CGeometry::SetPoint_Connectivity(void) { } - -inline void CGeometry::SetRCM_Ordering(CConfig *config) { } - -inline void CGeometry::SetCoord_Smoothing (unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config) { } - -inline void CGeometry::SetCoord(CGeometry *geometry) { } - -inline void CGeometry::SetPoint_Connectivity(CGeometry *fine_grid) { } - -inline void CGeometry::SetElement_Connectivity(void) { } - -inline unsigned long CGeometry::GetnPoint(void) { return nPoint; } - -inline unsigned long CGeometry::GetnPointDomain(void) { return nPointDomain; } - -inline unsigned long CGeometry::GetnElem(void) { return nElem; } - -inline unsigned short CGeometry::GetnDim(void) { return nDim; } - -inline unsigned short CGeometry::GetnZone(void) { return nZone; } - -inline unsigned short CGeometry::GetnMarker(void) { return nMarker; } - -inline string CGeometry::GetMarker_Tag(unsigned short val_marker) { return Tag_to_Marker[val_marker]; } - -inline unsigned long CGeometry::GetMax_GlobalPoint(void) { return Max_GlobalPoint; } - -inline void CGeometry::SetnMarker(unsigned short val_nmarker) { nMarker = val_nmarker; } - -inline void CGeometry::SetnElem_Bound(unsigned short val_marker, unsigned long val_nelem_bound) { nElem_Bound[val_marker]= val_nelem_bound; } - -inline unsigned long CGeometry::GetnElem_Bound(unsigned short val_marker) { return nElem_Bound[val_marker]; } - -inline void CGeometry::SetMarker_Tag(unsigned short val_marker, string val_index) { Tag_to_Marker[val_marker] = val_index; } - -inline void CGeometry::SetnPoint(unsigned long val_npoint) { nPoint = val_npoint; } - -inline void CGeometry::SetnPointDomain(unsigned long val_npoint) { nPointDomain = val_npoint; } - -inline void CGeometry::SetnElem(unsigned long val_nelem) { nElem = val_nelem; } - -inline void CGeometry::SetnDim(unsigned short val_nDim) { nDim = val_nDim; } - -inline unsigned long CGeometry::GetnVertex(unsigned short val_marker) { return nVertex[val_marker]; } - -inline unsigned long CGeometry::GetnEdge(void) { return nEdge; } - -inline bool CGeometry::FindFace(unsigned long first_elem, unsigned long second_elem, unsigned short &face_first_elem, unsigned short &face_second_elem) {return 0;} - -inline void CGeometry::SetBoundVolume(void) { } - -inline void CGeometry::SetVertex(void) { } - -inline void CGeometry::SetVertex(CConfig *config) { } - -inline void CGeometry::SetVertex(CGeometry *fine_grid, CConfig *config) { } - -inline void CGeometry::SetCoord_CG(void) { } - -inline void CGeometry::SetControlVolume(CConfig *config, unsigned short action) { } - -inline void CGeometry::SetControlVolume(CConfig *config, CGeometry *geometry, unsigned short action) { } - -inline void CGeometry::VisualizeControlVolume(CConfig *config, unsigned short action) { } - -inline void CGeometry::MatchNearField(CConfig *config) { } - -inline void CGeometry::MatchActuator_Disk(CConfig *config) { } - -inline void CGeometry::MatchInterface(CConfig *config) { } - -inline void CGeometry::MatchZone(CConfig *config, CGeometry *geometry_donor, CConfig *config_donor, unsigned short val_iZone, unsigned short val_nZone) { } - -inline void CGeometry::SetBoundControlVolume(CConfig *config, unsigned short action) { } - -inline void CGeometry::SetBoundControlVolume(CConfig *config, CGeometry *geometry, unsigned short action) { } - -inline void CGeometry::SetTecPlot(char config_filename[MAX_STRING_SIZE], bool new_file) { } - -inline void CGeometry::SetMeshFile(CConfig *config, string val_mesh_out_filename) { } - -inline void CGeometry::SetMeshFile(CGeometry *geometry, CConfig *config, string val_mesh_out_filename) { } - -inline void CGeometry::SetBoundTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file, CConfig *config) { } - -inline void CGeometry::SetBoundSTL(char mesh_filename[MAX_STRING_SIZE], bool new_file, CConfig *config) { } - -inline su2double CGeometry::Compute_MaxThickness(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { return 0; } - -inline su2double CGeometry::Compute_AoA(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { return 0; } - -inline su2double CGeometry::Compute_Chord(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { return 0; } - -inline su2double CGeometry::Compute_Thickness(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, su2double Location, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { return 0; } - -inline su2double CGeometry::Compute_Area(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { return 0; } - -inline su2double CGeometry::Compute_Volume(CConfig *config, bool original_surface) { return 0; } - -inline void CGeometry::FindNormal_Neighbor(CConfig *config) { } - -inline void CGeometry::SetBoundSensitivity(CConfig *config) { } - -inline void CPhysicalGeometry::SetPoint_Connectivity(CGeometry *geometry) { CGeometry::SetPoint_Connectivity(geometry); } - -inline void CMultiGridGeometry::SetPoint_Connectivity(void) { CGeometry::SetPoint_Connectivity(); } - -inline long CPhysicalGeometry::GetGlobal_to_Local_Point(long val_ipoint) { return Global_to_Local_Point[val_ipoint]; } - -inline unsigned short CPhysicalGeometry::GetGlobal_to_Local_Marker(unsigned short val_imarker) { return Global_to_Local_Marker[val_imarker]; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nPoint(void) { return Global_nPoint; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nPointDomain(void) { return Global_nPointDomain; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nElem(void) { return Global_nElem; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nElemLine(void) { return Global_nelem_edge; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nElemTria(void) { return Global_nelem_triangle; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nElemQuad(void) { return Global_nelem_quad; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nElemTetr(void) { return Global_nelem_tetra; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nElemHexa(void) { return Global_nelem_hexa; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nElemPris(void) { return Global_nelem_prism; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nElemPyra(void) { return Global_nelem_pyramid; } - -inline unsigned long CPhysicalGeometry::GetnElemLine(void) { return nelem_edge; } - -inline unsigned long CPhysicalGeometry::GetnElemTria(void) { return nelem_triangle; } - -inline unsigned long CPhysicalGeometry::GetnElemQuad(void) { return nelem_quad; } - -inline unsigned long CPhysicalGeometry::GetnElemTetr(void) { return nelem_tetra; } - -inline unsigned long CPhysicalGeometry::GetnElemHexa(void) { return nelem_hexa; } - -inline unsigned long CPhysicalGeometry::GetnElemPris(void) { return nelem_prism; } - -inline unsigned long CPhysicalGeometry::GetnElemPyra(void) { return nelem_pyramid; } - -inline void CGeometry::SetGeometryPlanes(CConfig *config) {} - -inline vector CGeometry::GetGeometryPlanes() { return XCoordList; } - -inline vector CPhysicalGeometry::GetGeometryPlanes() { return XCoordList; } - -inline vector CMultiGridGeometry::GetGeometryPlanes() { return XCoordList; } - -inline vector > CGeometry::GetXCoord() { return Xcoord_plane; } - -inline vector > CPhysicalGeometry::GetXCoord() { return Xcoord_plane; } - -inline vector > CMultiGridGeometry::GetXCoord() { return Xcoord_plane; } - -inline vector > CGeometry::GetYCoord() { return Ycoord_plane; } - -inline vector > CPhysicalGeometry::GetYCoord() { return Ycoord_plane; } - -inline vector > CMultiGridGeometry::GetYCoord() { return Ycoord_plane; } - -inline vector > CGeometry::GetZCoord() { return Zcoord_plane; } - -inline vector > CPhysicalGeometry::GetZCoord() { return Zcoord_plane; } - -inline vector > CMultiGridGeometry::GetZCoord() { return Zcoord_plane; } - - -inline vector > CGeometry::GetPlanarPoints() { return Plane_points; } - -inline vector > CPhysicalGeometry::GetPlanarPoints() { return Plane_points; } - -inline vector > CMultiGridGeometry::GetPlanarPoints() { return Plane_points; } - -inline void CGeometry::SetSensitivity(CConfig* config){} - -inline su2double CGeometry::GetSensitivity(unsigned long iPoint, unsigned short iDim){return 0.0;} - -inline su2double CPhysicalGeometry::GetSensitivity(unsigned long iPoint, unsigned short iDim){return Sensitivity[iPoint*nDim+iDim];} - -inline void CGeometry::SetSensitivity(unsigned long iPoint, unsigned short iDim, su2double val){} - -inline void CPhysicalGeometry::SetSensitivity(unsigned long iPoint, unsigned short iDim, su2double val){Sensitivity[iPoint*nDim+iDim] = val;} +/*! + * \file geometry_structure.inl + * \brief In-Line subroutines of the geometry_structure.hpp file. + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +inline long CGeometry::GetGlobal_to_Local_Point(long val_ipoint) { return 0; } + +inline unsigned short CGeometry::GetGlobal_to_Local_Marker(unsigned short val_imarker) { return 0; } + +inline unsigned long CGeometry::GetGlobal_nPoint(void) { return 0; } + +inline unsigned long CGeometry::GetGlobal_nPointDomain(void) { return 0; } + +inline unsigned long CGeometry::GetGlobal_nElem(void) { return 0; } + +inline unsigned long CGeometry::GetGlobal_nElemLine(void) { return 0; } + +inline unsigned long CGeometry::GetGlobal_nElemTria(void) { return 0; } + +inline unsigned long CGeometry::GetGlobal_nElemQuad(void) { return 0; } + +inline unsigned long CGeometry::GetGlobal_nElemTetr(void) { return 0; } + +inline unsigned long CGeometry::GetGlobal_nElemHexa(void) { return 0; } + +inline unsigned long CGeometry::GetGlobal_nElemPris(void) { return 0; } + +inline unsigned long CGeometry::GetGlobal_nElemPyra(void) { return 0; } + +inline unsigned long CGeometry::GetnElemLine(void) { return 0; } + +inline unsigned long CGeometry::GetnElemTria(void) { return 0; } + +inline unsigned long CGeometry::GetnElemQuad(void) { return 0; } + +inline unsigned long CGeometry::GetnElemTetr(void) { return 0; } + +inline unsigned long CGeometry::GetnElemHexa(void) { return 0; } + +inline unsigned long CGeometry::GetnElemPris(void) { return 0; } + +inline unsigned long CGeometry::GetnElemPyra(void) { return 0; } + +inline void CGeometry::Check_IntElem_Orientation(CConfig *config) { } + +inline void CGeometry::Check_BoundElem_Orientation(CConfig *config) { } + +inline void CGeometry::SetColorGrid(CConfig *config) { } + +inline void CGeometry::SetColorGrid_Parallel(CConfig *config) { } + +inline void CGeometry::DivideConnectivity(CConfig *config, unsigned short Elem_Type) { } + +inline void CGeometry::SetRotationalVelocity(CConfig *config, unsigned short val_iZone) { } + +inline void CGeometry::SetTranslationalVelocity(CConfig *config) { } + +inline void CGeometry::SetGridVelocity(CConfig *config, unsigned long iter) { } + +inline void CGeometry::SetRestricted_GridVelocity(CGeometry *fine_mesh, CConfig *config) { } + +inline void CGeometry::Set_MPI_Coord(CConfig *config) { } + +inline void CGeometry::Set_MPI_GridVel(CConfig *config) { } + +inline void CGeometry::SetPeriodicBoundary(CConfig *config) { } + +inline void CGeometry::SetPeriodicBoundary(CGeometry *geometry, CConfig *config) { } + +inline void CGeometry::SetSendReceive(CConfig *config) { } + +inline void CGeometry::SetBoundaries(CConfig *config) { } + +inline void CGeometry::ComputeWall_Distance(CConfig *config) { } + +inline void CGeometry::SetPositive_ZArea(CConfig *config) { } + +inline void CGeometry::SetPoint_Connectivity(void) { } + +inline void CGeometry::SetRCM_Ordering(CConfig *config) { } + +inline void CGeometry::SetCoord_Smoothing (unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config) { } + +inline void CGeometry::SetCoord(CGeometry *geometry) { } + +inline void CGeometry::SetPoint_Connectivity(CGeometry *fine_grid) { } + +inline void CGeometry::SetElement_Connectivity(void) { } + +inline unsigned long CGeometry::GetnPoint(void) { return nPoint; } + +inline unsigned long CGeometry::GetnPointDomain(void) { return nPointDomain; } + +inline unsigned long CGeometry::GetnElem(void) { return nElem; } + +inline unsigned short CGeometry::GetnDim(void) { return nDim; } + +inline unsigned short CGeometry::GetnZone(void) { return nZone; } + +inline unsigned short CGeometry::GetnMarker(void) { return nMarker; } + +inline string CGeometry::GetMarker_Tag(unsigned short val_marker) { return Tag_to_Marker[val_marker]; } + +inline unsigned long CGeometry::GetMax_GlobalPoint(void) { return Max_GlobalPoint; } + +inline void CGeometry::SetnMarker(unsigned short val_nmarker) { nMarker = val_nmarker; } + +inline void CGeometry::SetnElem_Bound(unsigned short val_marker, unsigned long val_nelem_bound) { nElem_Bound[val_marker]= val_nelem_bound; } + +inline unsigned long CGeometry::GetnElem_Bound(unsigned short val_marker) { return nElem_Bound[val_marker]; } + +inline void CGeometry::SetMarker_Tag(unsigned short val_marker, string val_index) { Tag_to_Marker[val_marker] = val_index; } + +inline void CGeometry::SetnPoint(unsigned long val_npoint) { nPoint = val_npoint; } + +inline void CGeometry::SetnPointDomain(unsigned long val_npoint) { nPointDomain = val_npoint; } + +inline void CGeometry::SetnElem(unsigned long val_nelem) { nElem = val_nelem; } + +inline void CGeometry::SetnDim(unsigned short val_nDim) { nDim = val_nDim; } + +inline unsigned long CGeometry::GetnVertex(unsigned short val_marker) { return nVertex[val_marker]; } + +inline unsigned long CGeometry::GetnEdge(void) { return nEdge; } + +inline bool CGeometry::FindFace(unsigned long first_elem, unsigned long second_elem, unsigned short &face_first_elem, unsigned short &face_second_elem) {return 0;} + +inline void CGeometry::SetBoundVolume(void) { } + +inline void CGeometry::SetVertex(void) { } + +inline void CGeometry::SetVertex(CConfig *config) { } + +inline void CGeometry::SetVertex(CGeometry *fine_grid, CConfig *config) { } + +inline void CGeometry::SetCoord_CG(void) { } + +inline void CGeometry::SetControlVolume(CConfig *config, unsigned short action) { } + +inline void CGeometry::SetControlVolume(CConfig *config, CGeometry *geometry, unsigned short action) { } + +inline void CGeometry::VisualizeControlVolume(CConfig *config, unsigned short action) { } + +inline void CGeometry::MatchNearField(CConfig *config) { } + +inline void CGeometry::MatchActuator_Disk(CConfig *config) { } + +inline void CGeometry::MatchInterface(CConfig *config) { } + +inline void CGeometry::MatchZone(CConfig *config, CGeometry *geometry_donor, CConfig *config_donor, unsigned short val_iZone, unsigned short val_nZone) { } + +inline void CGeometry::SetBoundControlVolume(CConfig *config, unsigned short action) { } + +inline void CGeometry::SetBoundControlVolume(CConfig *config, CGeometry *geometry, unsigned short action) { } + +inline void CGeometry::SetTecPlot(char config_filename[MAX_STRING_SIZE], bool new_file) { } + +inline void CGeometry::SetMeshFile(CConfig *config, string val_mesh_out_filename) { } + +inline void CGeometry::SetMeshFile(CGeometry *geometry, CConfig *config, string val_mesh_out_filename) { } + +inline void CGeometry::SetBoundTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file, CConfig *config) { } + +inline void CGeometry::SetBoundSTL(char mesh_filename[MAX_STRING_SIZE], bool new_file, CConfig *config) { } + +inline su2double CGeometry::Compute_MaxThickness(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { return 0; } + +inline su2double CGeometry::Compute_AoA(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { return 0; } + +inline su2double CGeometry::Compute_Chord(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { return 0; } + +inline su2double CGeometry::Compute_Thickness(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, su2double Location, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { return 0; } + +inline su2double CGeometry::Compute_Area(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { return 0; } + +inline su2double CGeometry::Compute_Volume(CConfig *config, bool original_surface) { return 0; } + +inline void CGeometry::FindNormal_Neighbor(CConfig *config) { } + +inline void CGeometry::SetBoundSensitivity(CConfig *config) { } + +inline void CPhysicalGeometry::SetPoint_Connectivity(CGeometry *geometry) { CGeometry::SetPoint_Connectivity(geometry); } + +inline void CMultiGridGeometry::SetPoint_Connectivity(void) { CGeometry::SetPoint_Connectivity(); } + +inline long CPhysicalGeometry::GetGlobal_to_Local_Point(long val_ipoint) { return Global_to_Local_Point[val_ipoint]; } + +inline unsigned short CPhysicalGeometry::GetGlobal_to_Local_Marker(unsigned short val_imarker) { return Global_to_Local_Marker[val_imarker]; } + +inline unsigned long CPhysicalGeometry::GetGlobal_nPoint(void) { return Global_nPoint; } + +inline unsigned long CPhysicalGeometry::GetGlobal_nPointDomain(void) { return Global_nPointDomain; } + +inline unsigned long CPhysicalGeometry::GetGlobal_nElem(void) { return Global_nElem; } + +inline unsigned long CPhysicalGeometry::GetGlobal_nElemLine(void) { return Global_nelem_edge; } + +inline unsigned long CPhysicalGeometry::GetGlobal_nElemTria(void) { return Global_nelem_triangle; } + +inline unsigned long CPhysicalGeometry::GetGlobal_nElemQuad(void) { return Global_nelem_quad; } + +inline unsigned long CPhysicalGeometry::GetGlobal_nElemTetr(void) { return Global_nelem_tetra; } + +inline unsigned long CPhysicalGeometry::GetGlobal_nElemHexa(void) { return Global_nelem_hexa; } + +inline unsigned long CPhysicalGeometry::GetGlobal_nElemPris(void) { return Global_nelem_prism; } + +inline unsigned long CPhysicalGeometry::GetGlobal_nElemPyra(void) { return Global_nelem_pyramid; } + +inline unsigned long CPhysicalGeometry::GetnElemLine(void) { return nelem_edge; } + +inline unsigned long CPhysicalGeometry::GetnElemTria(void) { return nelem_triangle; } + +inline unsigned long CPhysicalGeometry::GetnElemQuad(void) { return nelem_quad; } + +inline unsigned long CPhysicalGeometry::GetnElemTetr(void) { return nelem_tetra; } + +inline unsigned long CPhysicalGeometry::GetnElemHexa(void) { return nelem_hexa; } + +inline unsigned long CPhysicalGeometry::GetnElemPris(void) { return nelem_prism; } + +inline unsigned long CPhysicalGeometry::GetnElemPyra(void) { return nelem_pyramid; } + +inline void CGeometry::SetGeometryPlanes(CConfig *config) {} + +inline vector CGeometry::GetGeometryPlanes() { return XCoordList; } + +inline vector CPhysicalGeometry::GetGeometryPlanes() { return XCoordList; } + +inline vector CMultiGridGeometry::GetGeometryPlanes() { return XCoordList; } + +inline vector > CGeometry::GetXCoord() { return Xcoord_plane; } + +inline vector > CPhysicalGeometry::GetXCoord() { return Xcoord_plane; } + +inline vector > CMultiGridGeometry::GetXCoord() { return Xcoord_plane; } + +inline vector > CGeometry::GetYCoord() { return Ycoord_plane; } + +inline vector > CPhysicalGeometry::GetYCoord() { return Ycoord_plane; } + +inline vector > CMultiGridGeometry::GetYCoord() { return Ycoord_plane; } + +inline vector > CGeometry::GetZCoord() { return Zcoord_plane; } + +inline vector > CPhysicalGeometry::GetZCoord() { return Zcoord_plane; } + +inline vector > CMultiGridGeometry::GetZCoord() { return Zcoord_plane; } + + +inline vector > CGeometry::GetPlanarPoints() { return Plane_points; } + +inline vector > CPhysicalGeometry::GetPlanarPoints() { return Plane_points; } + +inline vector > CMultiGridGeometry::GetPlanarPoints() { return Plane_points; } + +inline void CGeometry::SetSensitivity(CConfig* config){} + +inline su2double CGeometry::GetSensitivity(unsigned long iPoint, unsigned short iDim){return 0.0;} + +inline su2double CPhysicalGeometry::GetSensitivity(unsigned long iPoint, unsigned short iDim){return Sensitivity[iPoint*nDim+iDim];} + +inline void CGeometry::SetSensitivity(unsigned long iPoint, unsigned short iDim, su2double val){} + +inline void CPhysicalGeometry::SetSensitivity(unsigned long iPoint, unsigned short iDim, su2double val){Sensitivity[iPoint*nDim+iDim] = val;} diff --git a/Common/include/grid_adaptation_structure.hpp b/Common/include/grid_adaptation_structure.hpp index 25eb788f4f5..aa91192ea38 100644 --- a/Common/include/grid_adaptation_structure.hpp +++ b/Common/include/grid_adaptation_structure.hpp @@ -1,345 +1,345 @@ -/*! - * \file grid_adaptation_structure.hpp - * \brief Headers of the main subroutines for doing the numerical grid - * adaptation. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -#include "./mpi_structure.hpp" - -#include -#include -#include -#include - -#include "geometry_structure.hpp" -#include "config_structure.hpp" - -using namespace std; - -/*! - * \class CGridAdaptation - * \brief Parent class for defining the grid adaptation. - * \author F. Palacios - * \version 2.0.7 - */ -class CGridAdaptation { -protected: - unsigned long nPoint_new, /*!< \brief Number of new points. */ - nElem_new; /*!< \brief Number of new elements. */ - unsigned short nDim, /*!< \brief Number of dimensions of the problem. */ - nVar; /*!< \brief Number of variables in the problem. */ - su2double **ConsVar_Sol, /*!< \brief Conservative variables (original solution). */ - **ConsVar_Res, /*!< \brief Conservative variables (residual). */ - **ConsVar_Adapt; /*!< \brief Conservative variables (adapted solution). */ - su2double **AdjVar_Sol, /*!< \brief Adjoint variables (original solution). */ - **AdjVar_Res, /*!< \brief Adjoint variables (residual). */ - **AdjVar_Adapt; /*!< \brief Adjoint variables (adapted solution). */ - su2double **LinVar_Sol, /*!< \brief Linear variables (original solution). */ - **LinVar_Res, /*!< \brief Linear variables (residual). */ - **LinVar_Adapt; /*!< \brief Linear variables (adapted solution). */ - su2double **Gradient, /*!< \brief Gradient value. */ - **Gradient_Flow, /*!< \brief Gradient of the flow variables. */ - **Gradient_Adj; /*!< \brief Fradient of the adjoint variables. */ - su2double *Index; /*!< \brief Adaptation index (indicates the value of the adaptation). */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - CGridAdaptation(CGeometry *geometry, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CGridAdaptation(void); - - /*! - * \brief Read the flow solution from the restart file. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void GetFlowSolution(CGeometry *geometry, CConfig *config); - - /*! - * \brief Read the flow solution from the restart file. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void GetFlowResidual(CGeometry *geometry, CConfig *config); - - /*! - * \brief Read the flow solution from the restart file. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void GetAdjSolution(CGeometry *geometry, CConfig *config); - - /*! - * \brief Read the flow solution from the restart file. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void GetAdjResidual(CGeometry *geometry, CConfig *config); - - /*! - * \brief Do a complete adaptation of the computational grid. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] strength - Adaptation Strength. - */ - void SetComplete_Refinement(CGeometry *geometry, unsigned short strength); - - /*! - * \brief Do not do any kind of adaptation. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] strength - Adaptation Strength. - */ - void SetNo_Refinement(CGeometry *geometry, unsigned short strength); - - /*! - * \brief Do an adaptation of the computational grid on the wake. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] strength - Adaptation Strength. - */ - void SetWake_Refinement(CGeometry *geometry, unsigned short strength); - - /*! - * \brief Do an adaptation of the computational grid on the supersonic shock region. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetSupShock_Refinement(CGeometry *geometry, CConfig *config); - - /*! - * \brief Do an adaptation of the computational grid on a near field boundary. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetNearField_Refinement(CGeometry *geometry, CConfig *config); - - /*! - * \brief Do a complete adaptation of the computational grid using a homothetic technique (2D). - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] geo_adapt - Geometrical definition of the adapted grid. - * \param[in] config - Definition of the particular problem. - */ - void SetHomothetic_Adaptation2D(CGeometry *geometry, CPhysicalGeometry *geo_adapt, CConfig *config); - - /*! - * \brief Do a complete adaptation of the computational grid using a homothetic technique (3D). - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] geo_adapt - Geometrical definition of the adapted grid. - * \param[in] config - Definition of the particular problem. - */ - void SetHomothetic_Adaptation3D(CGeometry *geometry, CPhysicalGeometry *geo_adapt, CConfig *config); - - /*! - * \brief Find the adaptation code for each element in the fine grid. - * \param[in] AdaptCode - Edge combination to stablish the right elemeent division. - * \return Adaptation code for the element. - */ - long CheckTriangleCode(bool *AdaptCode); - - /*! - * \brief Find the adaptation code for each element in the fine grid. - * \param[in] AdaptCode - Edge combination to stablish the right elemeent division. - * \return Adaptation code for the element. - */ - long CheckRectCode(bool *AdaptCode); - - /*! - * \brief Find the adaptation code for each element in the fine grid. - * \param[in] AdaptCode - Edge combination to stablish the right elemeent division. - * \return Adaptation code for the element. - */ - long CheckRectExtCode(bool *AdaptCode); - - /*! - * \brief Find the adaptation code for each element in the fine grid. - * \param[in] AdaptCode - Edge combination to stablish the right elemeent division. - * \return Adaptation code for the element. - */ - long CheckTetraCode(bool *AdaptCode); - - /*! - * \brief Find the adaptation code for each element in the fine grid. - * \param[in] AdaptCode - Edge combination to stablish the right elemeent division. - * \return Adaptation code for the element. - */ - long CheckHexaCode(bool *AdaptCode); - - /*! - * \brief Find the adaptation code for each element in the fine grid. - * \param[in] AdaptCode - Edge combination to stablish the right elemeent division. - * \return Adaptation code for the element. - */ - long CheckPyramCode(bool *AdaptCode); - - /*! - * \brief Division pattern of the element. - * \param[in] code - number that identify the division. - * \param[in] nodes - Nodes that compose the element, including new nodes. - * \param[in] edges - Edges that compose the element. - * \param[out] Division - Division pattern. - * \param[out] nPart - Number of new elements after the division. - */ - void TriangleDivision(long code, long *nodes, long *edges, long **Division, long *nPart); - - /*! - * \brief Division pattern of the element. - * \param[in] code - number that identify the division. - * \param[in] nodes - Nodes that compose the element, including new nodes. - * \param[in] edges - Edges that compose the element. - * \param[out] Division - Division pattern. - * \param[out] nPart - Number of new elements after the division. - */ - void RectDivision(long code, long *nodes, long **Division, long *nPart); - - /*! - * \brief Division pattern of the element. - * \param[in] code - number that identify the division. - * \param[in] nodes - Nodes that compose the element, including new nodes. - * \param[in] edges - Edges that compose the element. - * \param[out] Division - Division pattern. - * \param[out] nPart - Number of new elements after the division. - */ - void RectExtDivision(long code, long *nodes, long **Division, long *nPart); - - /*! - * \brief Division pattern of the element. - * \param[in] code - number that identify the division. - * \param[in] nodes - Nodes that compose the element, including new nodes. - * \param[in] edges - Edges that compose the element. - * \param[out] Division - Division pattern. - * \param[out] nPart - Number of new elements after the division. - */ - void TetraDivision(long code, long *nodes, long *edges, long **Division, long *nPart); - - /*! - * \brief Division pattern of the element. - * \param[in] code - number that identify the division. - * \param[in] nodes - Nodes that compose the element, including new nodes. - * \param[in] edges - Edges that compose the element. - * \param[out] Division - Division pattern. - * \param[out] nPart - Number of new elements after the division. - */ - void HexaDivision(long code, long *nodes, long **Division, long *nPart); - - /*! - * \brief Division pattern of the element. - * \param[in] code - number that identify the division. - * \param[in] nodes - Nodes that compose the element, including new nodes. - * \param[in] edges - Edges that compose the element. - * \param[out] Division - Division pattern. - * \param[out] nPart - Number of new elements after the division. - */ - void PyramDivision(long code, long *nodes, long **Division, long *nPart); - - /*! - * \brief Do a complete adaptation of the computational grid. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] strength _________________________. - */ - void SetIndicator_Flow(CGeometry *geometry, CConfig *config, unsigned short strength); - - /*! - * \brief Do a complete adaptation of the computational grid. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] strength _________________________. - */ - void SetIndicator_Adj(CGeometry *geometry, CConfig *config, unsigned short strength); - - /*! - * \brief Do a complete adaptation of the computational grid. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetIndicator_FlowAdj(CGeometry *geometry, CConfig *config); - - /*! - * \brief Read the flow solution from the restart file. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetIndicator_Robust(CGeometry *geometry, CConfig *config); - - /*! - * \brief Read the flow solution from the restart file. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetIndicator_Computable(CGeometry *geometry, CConfig *config); - - /*! - * \brief Read the flow solution from the restart file. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetIndicator_Computable_Robust(CGeometry *geometry, CConfig *config); - - /*! - * \brief Write the restart file with the adapted grid. - * \param[in] config - Definition of the particular problem. - * \param[in] mesh_flowfilename - _________________________. - */ - void SetRestart_FlowSolution(CConfig *config, CPhysicalGeometry *geo_adapt, string mesh_flowfilename); - - /*! - * \brief Write the restart file with the adapted grid. - * \param[in] config - Definition of the particular problem. - * \param[in] mesh_adjfilename - _________________________. - */ - void SetRestart_AdjSolution(CConfig *config, CPhysicalGeometry *geo_adapt, string mesh_adjfilename); - - /*! - * \brief Read the flow solution from the restart file. - * \param[in] config - Definition of the particular problem. - * \param[in] mesh_linfilename - _________________________. - */ - void SetRestart_LinSolution(CConfig *config, CPhysicalGeometry *geo_adapt, string mesh_linfilename); - - /*! - * \brief Read the flow solution from the restart file. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] max_elem - _________________________. - */ - void SetSensorElem(CGeometry *geometry, CConfig *config, unsigned long max_elem); - -}; - -#include "grid_adaptation_structure.inl" - - +/*! + * \file grid_adaptation_structure.hpp + * \brief Headers of the main subroutines for doing the numerical grid + * adaptation. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +#include "./mpi_structure.hpp" + +#include +#include +#include +#include + +#include "geometry_structure.hpp" +#include "config_structure.hpp" + +using namespace std; + +/*! + * \class CGridAdaptation + * \brief Parent class for defining the grid adaptation. + * \author F. Palacios + * \version 2.0.7 + */ +class CGridAdaptation { +protected: + unsigned long nPoint_new, /*!< \brief Number of new points. */ + nElem_new; /*!< \brief Number of new elements. */ + unsigned short nDim, /*!< \brief Number of dimensions of the problem. */ + nVar; /*!< \brief Number of variables in the problem. */ + su2double **ConsVar_Sol, /*!< \brief Conservative variables (original solution). */ + **ConsVar_Res, /*!< \brief Conservative variables (residual). */ + **ConsVar_Adapt; /*!< \brief Conservative variables (adapted solution). */ + su2double **AdjVar_Sol, /*!< \brief Adjoint variables (original solution). */ + **AdjVar_Res, /*!< \brief Adjoint variables (residual). */ + **AdjVar_Adapt; /*!< \brief Adjoint variables (adapted solution). */ + su2double **LinVar_Sol, /*!< \brief Linear variables (original solution). */ + **LinVar_Res, /*!< \brief Linear variables (residual). */ + **LinVar_Adapt; /*!< \brief Linear variables (adapted solution). */ + su2double **Gradient, /*!< \brief Gradient value. */ + **Gradient_Flow, /*!< \brief Gradient of the flow variables. */ + **Gradient_Adj; /*!< \brief Fradient of the adjoint variables. */ + su2double *Index; /*!< \brief Adaptation index (indicates the value of the adaptation). */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + CGridAdaptation(CGeometry *geometry, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CGridAdaptation(void); + + /*! + * \brief Read the flow solution from the restart file. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void GetFlowSolution(CGeometry *geometry, CConfig *config); + + /*! + * \brief Read the flow solution from the restart file. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void GetFlowResidual(CGeometry *geometry, CConfig *config); + + /*! + * \brief Read the flow solution from the restart file. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void GetAdjSolution(CGeometry *geometry, CConfig *config); + + /*! + * \brief Read the flow solution from the restart file. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void GetAdjResidual(CGeometry *geometry, CConfig *config); + + /*! + * \brief Do a complete adaptation of the computational grid. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] strength - Adaptation Strength. + */ + void SetComplete_Refinement(CGeometry *geometry, unsigned short strength); + + /*! + * \brief Do not do any kind of adaptation. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] strength - Adaptation Strength. + */ + void SetNo_Refinement(CGeometry *geometry, unsigned short strength); + + /*! + * \brief Do an adaptation of the computational grid on the wake. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] strength - Adaptation Strength. + */ + void SetWake_Refinement(CGeometry *geometry, unsigned short strength); + + /*! + * \brief Do an adaptation of the computational grid on the supersonic shock region. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetSupShock_Refinement(CGeometry *geometry, CConfig *config); + + /*! + * \brief Do an adaptation of the computational grid on a near field boundary. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetNearField_Refinement(CGeometry *geometry, CConfig *config); + + /*! + * \brief Do a complete adaptation of the computational grid using a homothetic technique (2D). + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] geo_adapt - Geometrical definition of the adapted grid. + * \param[in] config - Definition of the particular problem. + */ + void SetHomothetic_Adaptation2D(CGeometry *geometry, CPhysicalGeometry *geo_adapt, CConfig *config); + + /*! + * \brief Do a complete adaptation of the computational grid using a homothetic technique (3D). + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] geo_adapt - Geometrical definition of the adapted grid. + * \param[in] config - Definition of the particular problem. + */ + void SetHomothetic_Adaptation3D(CGeometry *geometry, CPhysicalGeometry *geo_adapt, CConfig *config); + + /*! + * \brief Find the adaptation code for each element in the fine grid. + * \param[in] AdaptCode - Edge combination to stablish the right elemeent division. + * \return Adaptation code for the element. + */ + long CheckTriangleCode(bool *AdaptCode); + + /*! + * \brief Find the adaptation code for each element in the fine grid. + * \param[in] AdaptCode - Edge combination to stablish the right elemeent division. + * \return Adaptation code for the element. + */ + long CheckRectCode(bool *AdaptCode); + + /*! + * \brief Find the adaptation code for each element in the fine grid. + * \param[in] AdaptCode - Edge combination to stablish the right elemeent division. + * \return Adaptation code for the element. + */ + long CheckRectExtCode(bool *AdaptCode); + + /*! + * \brief Find the adaptation code for each element in the fine grid. + * \param[in] AdaptCode - Edge combination to stablish the right elemeent division. + * \return Adaptation code for the element. + */ + long CheckTetraCode(bool *AdaptCode); + + /*! + * \brief Find the adaptation code for each element in the fine grid. + * \param[in] AdaptCode - Edge combination to stablish the right elemeent division. + * \return Adaptation code for the element. + */ + long CheckHexaCode(bool *AdaptCode); + + /*! + * \brief Find the adaptation code for each element in the fine grid. + * \param[in] AdaptCode - Edge combination to stablish the right elemeent division. + * \return Adaptation code for the element. + */ + long CheckPyramCode(bool *AdaptCode); + + /*! + * \brief Division pattern of the element. + * \param[in] code - number that identify the division. + * \param[in] nodes - Nodes that compose the element, including new nodes. + * \param[in] edges - Edges that compose the element. + * \param[out] Division - Division pattern. + * \param[out] nPart - Number of new elements after the division. + */ + void TriangleDivision(long code, long *nodes, long *edges, long **Division, long *nPart); + + /*! + * \brief Division pattern of the element. + * \param[in] code - number that identify the division. + * \param[in] nodes - Nodes that compose the element, including new nodes. + * \param[in] edges - Edges that compose the element. + * \param[out] Division - Division pattern. + * \param[out] nPart - Number of new elements after the division. + */ + void RectDivision(long code, long *nodes, long **Division, long *nPart); + + /*! + * \brief Division pattern of the element. + * \param[in] code - number that identify the division. + * \param[in] nodes - Nodes that compose the element, including new nodes. + * \param[in] edges - Edges that compose the element. + * \param[out] Division - Division pattern. + * \param[out] nPart - Number of new elements after the division. + */ + void RectExtDivision(long code, long *nodes, long **Division, long *nPart); + + /*! + * \brief Division pattern of the element. + * \param[in] code - number that identify the division. + * \param[in] nodes - Nodes that compose the element, including new nodes. + * \param[in] edges - Edges that compose the element. + * \param[out] Division - Division pattern. + * \param[out] nPart - Number of new elements after the division. + */ + void TetraDivision(long code, long *nodes, long *edges, long **Division, long *nPart); + + /*! + * \brief Division pattern of the element. + * \param[in] code - number that identify the division. + * \param[in] nodes - Nodes that compose the element, including new nodes. + * \param[in] edges - Edges that compose the element. + * \param[out] Division - Division pattern. + * \param[out] nPart - Number of new elements after the division. + */ + void HexaDivision(long code, long *nodes, long **Division, long *nPart); + + /*! + * \brief Division pattern of the element. + * \param[in] code - number that identify the division. + * \param[in] nodes - Nodes that compose the element, including new nodes. + * \param[in] edges - Edges that compose the element. + * \param[out] Division - Division pattern. + * \param[out] nPart - Number of new elements after the division. + */ + void PyramDivision(long code, long *nodes, long **Division, long *nPart); + + /*! + * \brief Do a complete adaptation of the computational grid. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] strength _________________________. + */ + void SetIndicator_Flow(CGeometry *geometry, CConfig *config, unsigned short strength); + + /*! + * \brief Do a complete adaptation of the computational grid. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] strength _________________________. + */ + void SetIndicator_Adj(CGeometry *geometry, CConfig *config, unsigned short strength); + + /*! + * \brief Do a complete adaptation of the computational grid. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetIndicator_FlowAdj(CGeometry *geometry, CConfig *config); + + /*! + * \brief Read the flow solution from the restart file. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetIndicator_Robust(CGeometry *geometry, CConfig *config); + + /*! + * \brief Read the flow solution from the restart file. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetIndicator_Computable(CGeometry *geometry, CConfig *config); + + /*! + * \brief Read the flow solution from the restart file. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetIndicator_Computable_Robust(CGeometry *geometry, CConfig *config); + + /*! + * \brief Write the restart file with the adapted grid. + * \param[in] config - Definition of the particular problem. + * \param[in] mesh_flowfilename - _________________________. + */ + void SetRestart_FlowSolution(CConfig *config, CPhysicalGeometry *geo_adapt, string mesh_flowfilename); + + /*! + * \brief Write the restart file with the adapted grid. + * \param[in] config - Definition of the particular problem. + * \param[in] mesh_adjfilename - _________________________. + */ + void SetRestart_AdjSolution(CConfig *config, CPhysicalGeometry *geo_adapt, string mesh_adjfilename); + + /*! + * \brief Read the flow solution from the restart file. + * \param[in] config - Definition of the particular problem. + * \param[in] mesh_linfilename - _________________________. + */ + void SetRestart_LinSolution(CConfig *config, CPhysicalGeometry *geo_adapt, string mesh_linfilename); + + /*! + * \brief Read the flow solution from the restart file. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] max_elem - _________________________. + */ + void SetSensorElem(CGeometry *geometry, CConfig *config, unsigned long max_elem); + +}; + +#include "grid_adaptation_structure.inl" + + diff --git a/Common/include/grid_adaptation_structure.inl b/Common/include/grid_adaptation_structure.inl index bd565929885..8840d09a7f4 100644 --- a/Common/include/grid_adaptation_structure.inl +++ b/Common/include/grid_adaptation_structure.inl @@ -1,33 +1,33 @@ -/*! - * \file grid_adaptation_structure.inl - * \brief In-Line subroutines of the grid_adaptation_structure.hpp file. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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 - +/*! + * \file grid_adaptation_structure.inl + * \brief In-Line subroutines of the grid_adaptation_structure.hpp file. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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 + diff --git a/Common/include/grid_movement_structure.hpp b/Common/include/grid_movement_structure.hpp index 1bdce81ee1f..8f3774dc35c 100644 --- a/Common/include/grid_movement_structure.hpp +++ b/Common/include/grid_movement_structure.hpp @@ -1,1448 +1,1448 @@ -/*! - * \file grid_movement_structure.hpp - * \brief Headers of the main subroutines for doing the numerical grid - * movement (including volumetric movement, surface movement and Free From - * technique definition). The subroutines and functions are in - * the grid_movement_structure.cpp file. - * \author F. Palacios, T. Economon, S. Padron - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -#include "./mpi_structure.hpp" - -#include -#include -#include -#include -#include - -#include "geometry_structure.hpp" -#include "config_structure.hpp" -#include "matrix_structure.hpp" -#include "vector_structure.hpp" -#include "linear_solvers_structure.hpp" - -using namespace std; - -/*! - * \class CGridMovement - * \brief Class for moving the surface and volumetric - * numerical grid (2D and 3D problems). - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CGridMovement { -public: - - /*! - * \brief Constructor of the class. - */ - CGridMovement(void); - - /*! - * \brief Destructor of the class. - */ - ~CGridMovement(void); - - /*! - * \brief A pure virtual member. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetSurface_Deformation(CGeometry *geometry, CConfig *config); - -}; - -/*! - * \class CFreeFormDefBox - * \brief Class for defining the free form FFDBox structure. - * \author F. Palacios & A. Galdran. - * \version 4.0.1 "Cardinal" - */ -class CFreeFormDefBox : public CGridMovement { -public: - unsigned short nDim; /*!< \brief Number of dimensions of the problem. */ - unsigned short nCornerPoints, /*!< \brief Number of corner points of the FFDBox. */ - nControlPoints, nControlPoints_Copy; /*!< \brief Number of control points of the FFDBox. */ - su2double **Coord_Corner_Points, /*!< \brief Coordinates of the corner points. */ - ****Coord_Control_Points, /*!< \brief Coordinates of the control points. */ - ****ParCoord_Control_Points, /*!< \brief Coordinates of the control points. */ - ****Coord_Control_Points_Copy, /*!< \brief Coordinates of the control points (copy). */ - ****Coord_SupportCP; /*!< \brief Coordinates of the support control points. */ - unsigned short lOrder, lOrder_Copy, /*!< \brief Order of the FFDBox in the i direction. */ - mOrder, mOrder_Copy, /*!< \brief Order of the FFDBox in the j direction. */ - nOrder, nOrder_Copy; /*!< \brief Order of the FFDBox in the k direction. */ - unsigned short lDegree, lDegree_Copy, /*!< \brief Degree of the FFDBox in the i direction. (lOrder - 1)*/ - mDegree, mDegree_Copy, /*!< \brief Degree of the FFDBox in the j direction. (mOrder - 1)*/ - nDegree, nDegree_Copy; /*!< \brief Degree of the FFDBox in the k direction. (nOrder - 1)*/ - su2double *ParamCoord, *ParamCoord_, /*!< \brief Parametric coordinates of a point. */ - *cart_coord, *cart_coord_; /*!< \brief Cartesian coordinates of a point. */ - su2double ObjFunc; /*!< \brief Objective function of the point inversion process. */ - su2double *Gradient; /*!< \brief Gradient of the point inversion process. */ - su2double **Hessian; /*!< \brief Hessian of the point inversion process. */ - su2double MaxCoord[3]; /*!< \brief Maximum coordinates of the FFDBox. */ - su2double MinCoord[3]; /*!< \brief Minimum coordinates of the FFDBox. */ - string Tag; /*!< \brief Tag to identify the FFDBox. */ - unsigned short Level; /*!< \brief Nested level of the FFD box. */ - vector CartesianCoord[3]; /*!< \brief Vector with all the cartesian coordinates in the FFD FFDBox. */ - vector ParametricCoord[3]; /*!< \brief Vector with all the parametrics coordinates in the FFD FFDBox. */ - vector MarkerIndex; /*!< \brief Vector with all markers in the FFD FFDBox. */ - vector VertexIndex; /*!< \brief Vector with all vertex index in the FFD FFDBox. */ - vector PointIndex; /*!< \brief Vector with all points index in the FFD FFDBox. */ - unsigned long nSurfacePoint; /*!< \brief Number of surfaces in the FFD FFDBox. */ - vector ParentFFDBox; /*!< \brief Vector with all the parent FFD FFDBox. */ - vector ChildFFDBox; /*!< \brief Vector with all the child FFD FFDBox. */ - vector Fix_IPlane; /*!< \brief Fix FFD I plane. */ - vector Fix_JPlane; /*!< \brief Fix FFD J plane. */ - vector Fix_KPlane; /*!< \brief Fix FFD K plane. */ - -public: - - /*! - * \brief Constructor of the class. - */ - CFreeFormDefBox(void); - - /*! - * \overload - * \param[in] val_lDegree - Degree of the FFDBox in the i direction. - * \param[in] val_mDegree - Degree of the FFDBox in the j direction. - * \param[in] val_nDegree - Degree of the FFDBox in the k direction. - */ - CFreeFormDefBox(unsigned short val_lDegree, unsigned short val_mDegree, unsigned short val_nDegree); - - /*! - * \brief Destructor of the class. - */ - ~CFreeFormDefBox(void); - - /*! - * \brief Define the I planes to to fix in a FFD box. - * \param[in] val_plane - Index of the plane to fix. - */ - void Set_Fix_IPlane(unsigned short val_plane); - - /*! - * \brief Define the I planes to to fix in a FFD box. - * \param[in] val_plane - Index of the plane to fix. - */ - void Set_Fix_JPlane(unsigned short val_plane); - - /*! - * \brief Define the I planes to to fix in a FFD box. - * \param[in] val_plane - Index of the plane to fix. - */ - void Set_Fix_KPlane(unsigned short val_plane); - - /*! - * \brief Define the I planes to to fix in a FFD box. - * \param[in] val_plane - Index of the plane to fix. - */ - unsigned short Get_Fix_IPlane(unsigned short val_index); - - /*! - * \brief Define the I planes to to fix in a FFD box. - * \param[in] val_plane - Index of the plane to fix. - */ - unsigned short Get_Fix_JPlane(unsigned short val_index); - - /*! - * \brief Define the I planes to to fix in a FFD box. - * \param[in] val_plane - Index of the plane to fix. - */ - unsigned short Get_Fix_KPlane(unsigned short val_index); - - /*! - * \brief Define the I planes to to fix in a FFD box. - * \param[in] val_plane - Index of the plane to fix. - */ - unsigned short Get_nFix_IPlane(void); - - /*! - * \brief Define the I planes to to fix in a FFD box. - * \param[in] val_plane - Index of the plane to fix. - */ - unsigned short Get_nFix_JPlane(void); - - /*! - * \brief Define the I planes to to fix in a FFD box. - * \param[in] val_plane - Index of the plane to fix. - */ - unsigned short Get_nFix_KPlane(void); - - /*! - * \brief Add to the vector of markers a new marker. - * \param[in] val_iMarker - New marker inside the FFD box. - */ - void Set_MarkerIndex(unsigned short val_iMarker); - - /*! - * \brief Add to the vector of vertices a new vertex. - * \param[in] val_iVertex - New vertex inside the FFD box. - */ - void Set_VertexIndex(unsigned long val_iVertex); - - /*! - * \brief Add to the vector of points a new point. - * \param[in] val_iPoint - New point inside the FFD box. - */ - void Set_PointIndex(unsigned long val_iPoint); - - /*! - * \brief Add to the vector of cartesian coordinates a new coordinate. - * \param[in] val_coord - New coordinate inside the FFD box. - */ - void Set_CartesianCoord(su2double *val_coord); - - /*! - * \brief Add to the vector of parametric coordinates a new coordinate. - * \param[in] val_coord - New coordinate inside the FFD box. - */ - void Set_ParametricCoord(su2double *val_coord); - - /*! - * \brief Add to the vector of parent FFDBoxes a new FFD FFDBox. - * \param[in] val_iParentFFDBox - New parent FFDBox in the vector. - */ - void SetParentFFDBox(string val_iParentFFDBox); - - /*! - * \brief Add to the vector of child FFDBoxes a new FFD FFDBox. - * \param[in] val_iChildFFDBox - New child FFDBox in the vector. - */ - void SetChildFFDBox(string val_iChildFFDBox); - - /*! - * \brief _______________. - * \param[in] val_coord - _______________. - * \param[in] val_iSurfacePoints - _______________. - */ - void Set_CartesianCoord(su2double *val_coord, unsigned long val_iSurfacePoints); - - /*! - * \brief _______________. - * \param[in] val_coord - _______________. - * \param[in] val_iSurfacePoints - _______________. - */ - void Set_ParametricCoord(su2double *val_coord, unsigned long val_iSurfacePoints); - - /*! - * \brief _______________. - * \param[in] Get_MarkerIndex - _______________. - * \return _______________. - */ - unsigned short Get_MarkerIndex(unsigned long val_iSurfacePoints); - - /*! - * \brief _______________. - * \param[in] Get_VertexIndex - _______________. - * \return _______________. - */ - unsigned long Get_VertexIndex(unsigned long val_iSurfacePoints); - - /*! - * \brief _______________. - * \param[in] Get_PointIndex - _______________. - * \return _______________. - */ - unsigned long Get_PointIndex(unsigned long val_iSurfacePoints); - - /*! - * \brief _______________. - * \param[in] Get_CartesianCoord - _______________. - * \return _______________. - */ - su2double *Get_CartesianCoord(unsigned long val_iSurfacePoints); - - /*! - * \brief _______________. - * \param[in] Get_ParametricCoord - _______________. - * \return _______________. - */ - su2double *Get_ParametricCoord(unsigned long val_iSurfacePoints); - - /*! - * \brief _______________. - * \param[in] GetnSurfacePoint - _______________. - * \return _______________. - */ - unsigned long GetnSurfacePoint(void); - - /*! - * \brief _______________. - * \param[in] GetnParentFFDBox - _______________. - * \return _______________. - */ - unsigned short GetnParentFFDBox(void); - - /*! - * \brief _______________. - * \param[in] GetnChildFFDBox - _______________. - * \return _______________. - */ - unsigned short GetnChildFFDBox(void); - - /*! - * \brief _______________. - * \param[in] val_ParentFFDBox - _______________. - * \return _______________. - */ - string GetParentFFDBoxTag(unsigned short val_ParentFFDBox); - - /*! - * \brief _______________. - * \param[in] val_ChildFFDBox - _______________. - * \return _______________. - */ - string GetChildFFDBoxTag(unsigned short val_ChildFFDBox); - - /*! - * \brief Change the the position of the corners of the unitary FFDBox, - * and find the position of the control points for the FFDBox - * \param[in] FFDBox - Original FFDBox where we want to compute the control points. - */ - void SetSupportCPChange(CFreeFormDefBox *FFDBox); - - /*! - * \brief Set the number of corner points. - * \param[in] val_ncornerpoints - Number of corner points. - */ - void SetnCornerPoints(unsigned short val_ncornerpoints); - - /*! - * \brief Get the number of corner points. - * \return Number of corner points. - */ - unsigned short GetnCornerPoints(void); - - /*! - * \brief Get the number of control points. - * \return Number of control points. - */ - unsigned short GetnControlPoints(void); - - /*! - * \brief Get the number of control points. - * \return Number of control points. - */ - void SetnControlPoints(void); - - /*! - * \brief Get the number of numerical points on the surface. - * \return Number of numerical points on the surface. - */ - unsigned long GetnSurfacePoints(void); - - /*! - * \brief Set the corner point for the unitary FFDBox. - */ - void SetUnitCornerPoints(void); - - /*! - * \brief Set the coordinates of the corner points. - * \param[in] val_coord - Coordinates of the corner point with index val_icornerpoints. - * \param[in] val_icornerpoints - Index of the corner point. - */ - void SetCoordCornerPoints(su2double *val_coord, unsigned short val_icornerpoints); - - /*! - * \overload - * \param[in] val_xcoord - X coordinate of the corner point with index val_icornerpoints. - * \param[in] val_ycoord - Y coordinate of the corner point with index val_icornerpoints. - * \param[in] val_zcoord - Z coordinate of the corner point with index val_icornerpoints. - * \param[in] val_icornerpoints - Index of the corner point. - */ - void SetCoordCornerPoints(su2double val_xcoord, su2double val_ycoord, su2double val_zcoord, unsigned short val_icornerpoints); - - /*! - * \brief Set the coordinates of the control points. - * \param[in] val_coord - Coordinates of the control point. - * \param[in] iDegree - Index of the FFDBox, i direction. - * \param[in] jDegree - Index of the FFDBox, j direction. - * \param[in] kDegree - Index of the FFDBox, k direction. - */ - void SetCoordControlPoints(su2double *val_coord, unsigned short iDegree, unsigned short jDegree, unsigned short kDegree); - - /*! - * \brief Set the coordinates of the control points. - * \param[in] val_coord - Coordinates of the control point. - * \param[in] iDegree - Index of the FFDBox, i direction. - * \param[in] jDegree - Index of the FFDBox, j direction. - * \param[in] kDegree - Index of the FFDBox, k direction. - */ - void SetCoordControlPoints_Copy(su2double *val_coord, unsigned short iDegree, unsigned short jDegree, unsigned short kDegree); - - /*! - * \brief Set the coordinates of the control points. - * \param[in] val_coord - Coordinates of the control point. - * \param[in] iDegree - Index of the FFDBox, i direction. - * \param[in] jDegree - Index of the FFDBox, j direction. - * \param[in] kDegree - Index of the FFDBox, k direction. - */ - void SetParCoordControlPoints(su2double *val_coord, unsigned short iDegree, unsigned short jDegree, unsigned short kDegree); - - /*! - * \brief Get the coordinates of the corner points. - * \param[in] val_dim - Index of the coordinate (x, y, z). - * \param[in] val_icornerpoints - Index of the corner point. - * \return Coordinate val_dim of the corner point val_icornerpoints. - */ - su2double GetCoordCornerPoints(unsigned short val_dim, unsigned short val_icornerpoints); - - /*! - * \brief Get the coordinates of the corner points. - * \param[in] val_icornerpoints - Index of the corner point. - * \return Pointer to the coordinate vector of the corner point val_icornerpoints. - */ - su2double *GetCoordCornerPoints(unsigned short val_icornerpoints); - - /*! - * \brief Get the coordinates of the control point. - * \param[in] val_iindex - Value of the local i index of the control point. - * \param[in] val_jindex - Value of the local j index of the control point. - * \param[in] val_kindex - Value of the local k index of the control point. - * \return Pointer to the coordinate vector of the control point with local index (i, j, k). - */ - su2double *GetCoordControlPoints(unsigned short val_iindex, unsigned short val_jindex, unsigned short val_kindex); - - /*! - * \brief Get the parametric coordinates of the control point. - * \param[in] val_iindex - Value of the local i index of the control point. - * \param[in] val_jindex - Value of the local j index of the control point. - * \param[in] val_kindex - Value of the local k index of the control point. - * \return Pointer to the coordinate vector of the control point with local index (i, j, k). - */ - su2double *GetParCoordControlPoints(unsigned short val_iindex, unsigned short val_jindex, unsigned short val_kindex); - - /*! - * \brief Set the control points in a parallelepiped (hexahedron). - */ - void SetControlPoints_Parallelepiped(void); - - /*! - * \brief Set the control points of the final chuck in a unitary hexahedron free form. - * \param[in] FFDBox - Original FFDBox where we want to compute the control points. - */ - void SetSupportCP(CFreeFormDefBox *FFDBox); - - /*! - * \brief Set the new value of the coordinates of the control points. - * \param[in] val_index - Local index (i, j, k) of the control point. - * \param[in] movement - Movement of the control point. - */ - void SetControlPoints(unsigned short *val_index, su2double *movement); - - /*! - * \brief Set the original value of the control points. - */ - void SetOriginalControlPoints(void); - - /*! - * \brief Set the tecplot file of the FFD chuck structure. - * \param[in] iFFDBox - Index of the FFD box. - * \param[in] original - Original box (before deformation). - */ - void SetTecplot(CGeometry *geometry, unsigned short iFFDBox, bool original); - - /*! - * \brief Set the cartesian coords of a point in R^3 and convert them to the parametric coords of - * our parametrization of a paralellepiped. - * \param[in] cart_coord - Cartesian coordinates of a point. - * \return Pointer to the parametric coordinates of a point. - */ - su2double *GetParametricCoord_Analytical(su2double *cart_coord); - - /*! - * \brief Iterative strategy for computing the parametric coordinates. - * \param[in] xyz - Cartesians coordinates of the target point. - * \param[in] guess - Initial guess for doing the parametric coordinates search. - * \param[in] tol - Level of convergence of the iterative method. - * \param[in] it_max - Maximal number of iterations. - * \return Parametric coordinates of the point. - */ - su2double *GetParametricCoord_Iterative(unsigned long iPoint, su2double *xyz, su2double *guess, CConfig *config); - - /*! - * \brief Compute the cross product. - * \param[in] v1 - First input vector. - * \param[in] v2 - Second input vector. - * \param[out] v3 - Output vector wuth the cross product. - */ - void CrossProduct(su2double *v1, su2double *v2, su2double *v3); - - /*! - * \brief Compute the doc product. - * \param[in] v1 - First input vector. - * \param[in] v2 - Sencond input vector. - * \return Dot product between v1, and v2. - */ - su2double DotProduct(su2double *v1, su2double *v2); - - /*! - * \brief Here we take the parametric coords of a point in the box and we convert them to the - * physical cartesian coords by plugging the ParamCoords on the Bezier parameterization of our box. - * \param[in] ParamCoord - Parametric coordinates of a point. - * \return Pointer to the cartesian coordinates of a point. - */ - su2double *EvalCartesianCoord(su2double *ParamCoord); - - /*! - * \brief Set the Bernstein polynomial, defined as B_i^n(t) = Binomial(n, i)*t^i*(1-t)^(n-i). - * \param[in] val_n - Degree of the Bernstein polynomial. - * \param[in] val_i - Order of the Bernstein polynomial. - * \param[in] val_t - Value of the parameter where the polynomial is evaluated. - * \return Value of the Bernstein polynomial. - */ - su2double GetBernstein(short val_n, short val_i, su2double val_t); - - /*! - * \brief Get the binomial coefficient n over i, defined as n!/(m!(n-m)!) - * \note If the denominator is 0, the value is 1. - * \param[in] n - Upper coefficient. - * \param[in] m - Lower coefficient. - * \return Value of the binomial coefficient n over m. - */ - unsigned long Binomial(unsigned short n, unsigned short m); - - /*! - * \brief Get the order in the l direction of the FFD FFDBox. - * \return Order in the l direction of the FFD FFDBox. - */ - unsigned short GetlOrder(void); - - /*! - * \brief Get the order in the m direction of the FFD FFDBox. - * \return Order in the m direction of the FFD FFDBox. - */ - unsigned short GetmOrder(void); - - /*! - * \brief Get the order in the n direction of the FFD FFDBox. - * \return Order in the n direction of the FFD FFDBox. - */ - unsigned short GetnOrder(void); - - /*! - * \brief Get the order in the l direction of the FFD FFDBox. - * \return Order in the l direction of the FFD FFDBox. - */ - void SetlOrder(unsigned short val_lOrder); - - /*! - * \brief Get the order in the m direction of the FFD FFDBox. - * \return Order in the m direction of the FFD FFDBox. - */ - void SetmOrder(unsigned short val_mOrder); - - /*! - * \brief Get the order in the n direction of the FFD FFDBox. - * \return Order in the n direction of the FFD FFDBox. - */ - void SetnOrder(unsigned short val_nOrder); - - /*! - * \brief Set, at each vertex, the index of the free form FFDBox that contains the vertex. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iFFDBox - Index of the FFDBox. - */ - bool GetPointFFD(CGeometry *geometry, CConfig *config, unsigned long iPoint); - - /*! - * \brief Set the zone of the computational domain that is going to be deformed. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iFFDBox - Index of the FFDBox. - */ - void SetDeformationZone(CGeometry *geometry, CConfig *config, unsigned short iFFDBox); - - /*! - * \brief The "order" derivative of the i-th Bernstein polynomial of degree n, evaluated at t, - * is calculated as (B_i^n(t))^{order}(t) = n*(GetBernstein(n-1, i-1, t)-GetBernstein(n-1, i, t)), - * having in account that if i=0, GetBernstein(n-1,-1, t) = 0. - * \param[in] val_n - Degree of the Bernstein polynomial. - * \param[in] val_i - Order of the Bernstein polynomial. - * \param[in] val_t - Value of the parameter where the polynomial is evaluated. - * \param[in] val_order - Order of the derivative. - * \return Value of the Derivative of the Bernstein polynomial. - */ - su2double GetBernsteinDerivative(short val_n, short val_i, su2double val_t, short val_order); - - /*! - * \brief The routine computes the gradient of F(u, v, w) = ||X(u, v, w)-(x, y, z)||^2 evaluated at (u, v, w). - * \param[in] val_coord - Parametric coordiates of the target point. - * \param[in] xyz - Cartesians coordinates of the point. - * \param[in] analytical - Compute the analytical gradient. - * \return Value of the analytical gradient. - */ - su2double *GetFFDGradient(su2double *val_coord, su2double *xyz); - - /*! - * \brief The routine that computes the Hessian of F(u, v, w) = ||X(u, v, w)-(x, y, z)||^2 evaluated at (u, v, w) - * Input: (u, v, w), (x, y, z) - * Output: Hessian F (u, v, w). - * \param[in] uvw - Current value of the parametrics coordinates. - * \param[in] xyz - Cartesians coordinates of the target point to compose the functional. - * \param[in] val_Hessian - Value of the hessian. - */ - void GetFFDHessian(su2double *uvw, su2double *xyz, su2double **val_Hessian); - - /*! - * \brief An auxiliary routine to help us compute the gradient of F(u, v, w) = ||X(u, v, w)-(x, y, z)||^2 = - * (Sum_ijk^lmn P1_ijk Bi Bj Bk -x)^2+(Sum_ijk^lmn P2_ijk Bi Bj Bk -y)^2+(Sum_ijk^lmn P3_ijk Bi Bj Bk -z)^2 - * Input: val_t, val_diff (to identify the index of the Bernstein polynomail we differentiate), the i, j, k , l, m, n - * E.G.: val_diff=2 => we differentiate w.r.t. w (val_diff=0,1, or 2) Output: d [B_i^l*B_j^m *B_k^n] / d val_diff - * (val_u, val_v, val_w). - * \param[in] uvw - __________. - * \param[in] val_diff - __________. - * \param[in] ijk - __________. - * \param[in] lmn - Degree of the FFD box. - * \return __________. - */ - su2double GetDerivative1(su2double *uvw, unsigned short val_diff, unsigned short *ijk, unsigned short *lmn); - - /*! - * \brief An auxiliary routine to help us compute the gradient of F(u, v, w) = ||X(u, v, w)-(x, y, z)||^2 = - * (Sum_ijk^lmn P1_ijk Bi Bj Bk -x)^2+(Sum_ijk^lmn P2_ijk Bi Bj Bk -y)^2+(Sum_ijk^lmn P3_ijk Bi Bj Bk -z)^2 - * Input: (u, v, w), dim , xyz=(x, y, z), l, m, n E.G.: dim=2 => we use the third coordinate of the control points, - * and the z-coordinate of xyz (0<=dim<=2) Output: 2* ( (Sum_{i, j, k}^l, m, n P_{ijk}[dim] B_i^l[u] B_j^m[v] B_k^n[w]) - - * xyz[dim]). - * \param[in] uvw - __________. - * \param[in] dim - __________. - * \param[in] xyz - __________. - * \param[in] lmn - Degree of the FFD box. - * \return __________. - */ - su2double GetDerivative2(su2double *uvw, unsigned short dim, su2double *xyz, unsigned short *lmn); - - /*! - * \brief An auxiliary routine to help us compute the gradient of F(u, v, w) = ||X(u, v, w)-(x, y, z)||^2 = - * (Sum_ijk^lmn P1_ijk Bi Bj Bk -x)^2+(Sum_ijk^lmn P2_ijk Bi Bj Bk -y)+(Sum_ijk^lmn P3_ijk Bi Bj Bk -z) - * \param[in] uvw - Parametric coordiates of the point. - * \param[in] dim - Value of the coordinate to be differentiate. - * \param[in] diff_this - Diferentiation with respect this coordinate. - * \param[in] lmn - Degree of the FFD box. - * \return Sum_{i, j, k}^{l, m, n} [one of them with -1, - * depending on diff_this=0,1 or 2] P_{ijk}[dim] * (B_i^l[u] B_j^m[v] B_k^n[w])--one of them diffrentiated; - * which? diff_thiss will tell us ; E.G.: dim=2, diff_this=1 => we use the third coordinate of the control - * points, and derivate de v-Bersntein polynomial (use m-1 when summing!!). - */ - su2double GetDerivative3(su2double *uvw, unsigned short dim, unsigned short diff_this, - unsigned short *lmn); - - /*! - * \brief An auxiliary routine to help us compute the Hessian of F(u, v, w) = ||X(u, v, w)-(x, y, z)||^2 = - * (Sum_ijk^lmn P1_ijk Bi Bj Bk -x)^2+(Sum_ijk^lmn P2_ijk Bi Bj Bk -y)+(Sum_ijk^lmn P3_ijk Bi Bj Bk -z) - * Input: val_t, val_diff, val_diff2 (to identify the index of the Bernstein polynomials we differentiate), the i, j, k , l, m, n - * E.G.: val_diff=1, val_diff2=2 => we differentiate w.r.t. v and w (val_diff=0,1, or 2) - * E.G.: val_diff=0, val_diff2=0 => we differentiate w.r.t. u two times - * Output: [d [B_i^l*B_j^m *B_k^n]/d val_diff *d [B_i^l*B_j^m *B_k^n]/d val_diff2] (val_u, val_v, val_w) . - * \param[in] uvw - __________. - * \param[in] val_diff - __________. - * \param[in] val_diff2 - __________. - * \param[in] ijk - __________. - * \param[in] lmn - Degree of the FFD box. - * \return __________. - */ - su2double GetDerivative4(su2double *uvw, unsigned short val_diff, unsigned short val_diff2, - unsigned short *ijk, unsigned short *lmn); - - /*! - * \brief An auxiliary routine to help us compute the Hessian of F(u, v, w) = ||X(u, v, w)-(x, y, z)||^2 = - * (Sum_ijk^lmn P1_ijk Bi Bj Bk -x)^2+(Sum_ijk^lmn P2_ijk Bi Bj Bk -y)+(Sum_ijk^lmn P3_ijk Bi Bj Bk -z) - * Input: (u, v, w), dim , diff_this, diff_this_also, xyz=(x, y, z), l, m, n - * Output: - * Sum_{i, j, k}^{l, m, n} [two of them with -1, depending on diff_this, diff_this_also=0,1 or 2] - * P_{ijk}[dim] * (B_i^l[u] B_j^m[v] B_k^n[w])--one of them diffrentiated; which? diff_thiss will tell us ; - * E.G.: dim=2, diff_this=1 => we use the third coordinate of the control points, and derivate de v-Bersntein - * polynomial (use m-1 when summing!!). - * \param[in] uvw - __________. - * \param[in] dim - __________. - * \param[in] diff_this - __________. - * \param[in] diff_this_also - __________. - * \param[in] lmn - Degree of the FFD box. - * \return __________. - */ - su2double GetDerivative5(su2double *uvw, unsigned short dim, unsigned short diff_this, unsigned short diff_this_also, - unsigned short *lmn); - - /*! - * \brief Euclidean norm of a vector. - * \param[in] a - _______. - * \return __________. - */ - su2double GetNorm(su2double *a); - - /*! - * \brief Set the tag that identify a FFDBox. - * \param[in] val_tag - value of the tag. - */ - void SetTag(string val_tag); - - /*! - * \brief Get the tag that identify a FFDBox. - * \return Value of the tag that identigy the FFDBox. - */ - string GetTag(void); - - /*! - * \brief Set the nested level of the FFDBox. - * \param[in] val_level - value of the level. - */ - void SetLevel(unsigned short val_level); - - /*! - * \brief Get the nested level of the FFDBox. - * \return Value of the nested level of the the FFDBox. - */ - unsigned short GetLevel(void); - - /*! - * \brief Compute the determinant of a 3 by 3 matrix. - * \param[in] val_matrix 3 by 3 matrix. - * \result Determinant of the matrix - */ - su2double Determinant_3x3(su2double A00, su2double A01, su2double A02, su2double A10, su2double A11, - su2double A12, su2double A20, su2double A21, su2double A22); - -}; - -/*! - * \class CVolumetricMovement - * \brief Class for moving the volumetric numerical grid. - * \author F. Palacios, A. Bueno, T. Economon, S. Padron. - * \version 4.0.1 "Cardinal" - */ -class CVolumetricMovement : public CGridMovement { -protected: - - unsigned short nDim; /*!< \brief Number of dimensions. */ - unsigned short nVar; /*!< \brief Number of variables. */ - - unsigned long nPoint; /*!< \brief Number of points. */ - unsigned long nPointDomain; /*!< \brief Number of points in the domain. */ - - CSysMatrix StiffMatrix; /*!< \brief Matrix to store the point-to-point stiffness. */ - CSysVector LinSysSol; - CSysVector LinSysRes; - -public: - - /*! - * \brief Constructor of the class. - */ - CVolumetricMovement(CGeometry *geometry, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CVolumetricMovement(void); - - /*! - * \brief Update the value of the coordinates after the grid movement. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void UpdateGridCoord(CGeometry *geometry, CConfig *config); - - /*! - * \brief Update the dual grid after the grid movement (edges and control volumes). - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void UpdateDualGrid(CGeometry *geometry, 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); - - /*! - * \brief Compute the stiffness matrix for grid deformation using spring analogy. - * \param[in] geometry - Geometrical definition of the problem. - * \return Value of the length of the smallest edge of the grid. - */ - su2double SetFEAMethodContributions_Elem(CGeometry *geometry, CConfig *config); - - /*! - * \brief Build the stiffness matrix for a 3-D hexahedron element. The result will be placed in StiffMatrix_Elem. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] StiffMatrix_Elem - Element stiffness matrix to be filled. - * \param[in] CoordCorners - Index value for Node 1 of the current hexahedron. - */ - void SetFEA_StiffMatrix3D(CGeometry *geometry, CConfig *config, su2double **StiffMatrix_Elem, unsigned long PointCorners[8], su2double CoordCorners[8][3], unsigned short nNodes, su2double scale); - - /*! - * \brief Build the stiffness matrix for a 3-D hexahedron element. The result will be placed in StiffMatrix_Elem. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] StiffMatrix_Elem - Element stiffness matrix to be filled. - * \param[in] CoordCorners - Index value for Node 1 of the current hexahedron. - */ - void SetFEA_StiffMatrix2D(CGeometry *geometry, CConfig *config, su2double **StiffMatrix_Elem, unsigned long PointCorners[8], su2double CoordCorners[8][3], unsigned short nNodes, su2double scale); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] Mu - Local coordinates. - * \param[in] CoordCorners - Coordiantes of the corners. - * \param[in] DShapeFunction - Shape function information - */ - su2double ShapeFunc_Hexa(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] Mu - Local coordinates. - * \param[in] CoordCorners - Coordiantes of the corners. - * \param[in] DShapeFunction - Shape function information - */ - su2double ShapeFunc_Tetra(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] Mu - Local coordinates. - * \param[in] CoordCorners - Coordiantes of the corners. - * \param[in] DShapeFunction - Shape function information - */ - su2double ShapeFunc_Pyram(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] Mu - Local coordinates. - * \param[in] CoordCorners - Coordiantes of the corners. - * \param[in] DShapeFunction - Shape function information - */ - su2double ShapeFunc_Prism(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] CoordCorners - Coordiantes of the corners. - * \param[in] DShapeFunction - Shape function information - */ - su2double ShapeFunc_Triangle(su2double Xi, su2double Eta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] CoordCorners - Coordiantes of the corners. - * \param[in] DShapeFunction - Shape function information - */ - su2double ShapeFunc_Quadrilateral(su2double Xi, su2double Eta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); - - /*! - * \brief Compute the shape functions for hexahedron - * \param[in] CoordCorners - coordinates of the cornes of the hexahedron. - */ - su2double GetHexa_Volume(su2double CoordCorners[8][3]); - - /*! - * \brief Compute the shape functions for hexahedron - * \param[in] CoordCorners - coordinates of the cornes of the hexahedron. - */ - su2double GetTetra_Volume(su2double CoordCorners[8][3]); - - /*! - * \brief Compute the shape functions for hexahedron - * \param[in] CoordCorners - coordinates of the cornes of the hexahedron. - */ - su2double GetPrism_Volume(su2double CoordCorners[8][3]); - - /*! - * \brief Compute the shape functions for hexahedron - * \param[in] CoordCorners - coordinates of the cornes of the hexahedron. - */ - su2double GetPyram_Volume(su2double CoordCorners[8][3]); - - /*! - * \brief Compute the shape functions for hexahedron - * \param[in] CoordCorners - coordinates of the cornes of the hexahedron. - */ - su2double GetTriangle_Area(su2double CoordCorners[8][3]); - - /*! - * \brief Compute the shape functions for hexahedron - * \param[in] CoordCorners - coordinates of the cornes of the hexahedron. - */ - su2double GetQuadrilateral_Area(su2double CoordCorners[8][3]); - - /*! - * \brief Add the stiffness matrix for a 2-D triangular element to the global stiffness matrix for the entire mesh (node-based). - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] StiffMatrix_Elem - Element stiffness matrix to be filled. - * \param[in] PointCorners - * \param[in] nNodes - */ - void AddFEA_StiffMatrix(CGeometry *geometry, su2double **StiffMatrix_Elem, unsigned long PointCorners[8], unsigned short nNodes); - - /*! - * \brief Check for negative volumes (all elements) after performing grid deformation. - * \param[in] geometry - Geometrical definition of the problem. - */ - su2double Check_Grid(CGeometry *geometry); - - /*! - * \brief Compute the minimum distance to the nearest deforming surface. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void ComputeDeforming_Wall_Distance(CGeometry *geometry, CConfig *config); - - /*! - * \brief Check the boundary vertex that are going to be moved. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetBoundaryDisplacements(CGeometry *geometry, CConfig *config); - - /*! - * \brief Check the domain points vertex that are going to be moved. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetDomainDisplacements(CGeometry *geometry, CConfig *config); - - /*! - * \brief Unsteady grid movement using rigid mesh rotation. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iZone - Zone number in the mesh. - * \param[in] iter - Physical time iteration number. - */ - void Rigid_Rotation(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter); - - /*! - * \brief Unsteady pitching grid movement using rigid mesh motion. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iZone - Zone number in the mesh. - * \param[in] iter - Physical time iteration number. - */ - void Rigid_Pitching(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter); - - /*! - * \brief Unsteady plunging grid movement using rigid mesh motion. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iZone - Zone number in the mesh. - * \param[in] iter - Physical time iteration number. - */ - void Rigid_Plunging(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter); - - /*! - * \brief Unsteady translational grid movement using rigid mesh motion. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iZone - Zone number in the mesh. - * \param[in] iter - Physical time iteration number. - */ - void Rigid_Translation(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter); - - /*! - * \brief Scale the volume grid by a multiplicative factor. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] UpdateGeo - Update geometry. - */ - void SetVolume_Scaling(CGeometry *geometry, CConfig *config, bool UpdateGeo); - - /*! - * \brief Translate the volume grid by a specified displacement vector. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] UpdateGeo - Update geometry. - */ - void SetVolume_Translation(CGeometry *geometry, CConfig *config, bool UpdateGeo); - - /*! - * \brief Rotate the volume grid around a specified axis and angle. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] UpdateGeo - Update geometry. - */ - void SetVolume_Rotation(CGeometry *geometry, CConfig *config, bool UpdateGeo); - - /*! - * \brief Grid deformation using the spring analogy method. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] UpdateGeo - Update geometry. - * \param[in] Derivative - Compute the derivative (disabled by default). Does not actually deform the grid if enabled. - */ - void SetVolume_Deformation(CGeometry *geometry, CConfig *config, bool UpdateGeo, bool Derivative = false); - - /*! - * \brief Set the derivatives of the boundary nodes. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetBoundaryDerivatives(CGeometry *geometry, CConfig *config); - - /*! - * \brief Update the derivatives of the coordinates after the grid movement. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void UpdateGridCoord_Derivatives(CGeometry *geometry, CConfig *config); - - /*! - * \brief Compute the determinant of a 3 by 3 matrix. - * 3 by 3 matrix elements - * \param[in] A00 - * \param[in] A01 - * \param[in] A02 - * \param[in] A10 - * \param[in] A11 - * \param[in] A12 - * \param[in] A20 - * \param[in] A21 - * \param[in] A22 - * \result Determinant of the matrix - */ - su2double Determinant_3x3(su2double A00, su2double A01, su2double A02, su2double A10, su2double A11, su2double A12, su2double A20, su2double A21, su2double A22); - -}; - -/*! - * \class CSurfaceMovement - * \brief Class for moving the surface numerical grid. - * \author F. Palacios, T. Economon. - * \version 4.0.1 "Cardinal" - */ -class CSurfaceMovement : public CGridMovement { -protected: - CFreeFormDefBox** FFDBox; /*!< \brief Definition of the Free Form Deformation Box. */ - unsigned short nFFDBox; /*!< \brief Number of FFD FFDBoxes. */ - unsigned short nLevel; /*!< \brief Level of the FFD FFDBoxes (parent/child). */ - bool FFDBoxDefinition; /*!< \brief If the FFD FFDBox has been defined in the input file. */ - vector GlobalCoordX[MAX_NUMBER_FFD]; - vector GlobalCoordY[MAX_NUMBER_FFD]; - vector GlobalCoordZ[MAX_NUMBER_FFD]; - vector GlobalTag[MAX_NUMBER_FFD]; - vector GlobalPoint[MAX_NUMBER_FFD]; - -public: - - /*! - * \brief Constructor of the class. - */ - CSurfaceMovement(void); - - /*! - * \brief Destructor of the class. - */ - ~CSurfaceMovement(void); - - /*! - * \brief Set a Hicks-Henne deformation bump functions on an airfoil. - * \param[in] boundary - Geometry of the boundary. - * \param[in] config - Definition of the particular problem. - * \param[in] iDV - Index of the design variable. - * \param[in] ResetDef - Reset the deformation before starting a new one. - */ - void SetHicksHenne(CGeometry *boundary, CConfig *config, unsigned short iDV, bool ResetDef); - - /*! - * \brief Set a NACA 4 digits airfoil family for airfoil deformation. - * \param[in] boundary - Geometry of the boundary. - * \param[in] config - Definition of the particular problem. - */ - void SetNACA_4Digits(CGeometry *boundary, CConfig *config); - - /*! - * \brief Set a parabolic family for airfoil deformation. - * \param[in] boundary - Geometry of the boundary. - * \param[in] config - Definition of the particular problem. - */ - void SetParabolic(CGeometry *boundary, CConfig *config); - - /*! - * \brief Set a obstacle in a channel. - * \param[in] boundary - Geometry of the boundary. - * \param[in] config - Definition of the particular problem. - */ - void SetAirfoil(CGeometry *boundary, CConfig *config); - - /*! - * \brief Set a rotation for surface movement. - * \param[in] boundary - Geometry of the boundary. - * \param[in] config - Definition of the particular problem. - * \param[in] iDV - Index of the design variable. - * \param[in] ResetDef - Reset the deformation before starting a new one. - */ - void SetRotation(CGeometry *boundary, CConfig *config, unsigned short iDV, bool ResetDef); - - /*! - * \brief Set the translational/rotational velocity for a moving wall. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iZone - Zone number in the mesh. - * \param[in] iter - Physical time iteration number. - */ - void Moving_Walls(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter); - - /*! - * \brief Computes the displacement of a translating surface for a dynamic mesh simulation. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iter - Current physical time iteration. - * \param[in] iZone - Zone number in the mesh. - */ - void Surface_Translating(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone); - - /*! - * \brief Computes the displacement of a plunging surface for a dynamic mesh simulation. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iter - Current physical time iteration. - * \param[in] iZone - Zone number in the mesh. - */ - void Surface_Plunging(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone); - - /*! - * \brief Computes the displacement of a pitching surface for a dynamic mesh simulation. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iter - Current physical time iteration. - * \param[in] iZone - Zone number in the mesh. - */ - void Surface_Pitching(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone); - - /*! - * \brief Computes the displacement of a rotating surface for a dynamic mesh simulation. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iter - Current physical time iteration. - * \param[in] iZone - Zone number in the mesh. - */ - void Surface_Rotating(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone); - - /*! - * \brief Unsteady aeroelastic grid movement by deforming the mesh. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] ExtIter - Physical iteration number. - * \param[in] iMarker - Marker to deform. - * \param[in] iMarker_Monitoring - Marker we are monitoring. - * \param[in] displacements - solution of typical section wing model. - */ - void AeroelasticDeform(CGeometry *geometry, CConfig *config, unsigned long ExtIter, unsigned short iMarker, unsigned short iMarker_Monitoring, vector& displacements); - - /*! - * \brief Deforms a 3-D flutter/pitching surface during an unsteady simulation. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iter - Current physical time iteration. - * \param[in] iZone - Zone number in the mesh. - */ - void SetBoundary_Flutter3D(CGeometry *geometry, CConfig *config, - CFreeFormDefBox **FFDBox, unsigned long iter, unsigned short iZone); - - /*! - * \brief Set the collective pitch for a blade surface movement. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetCollective_Pitch(CGeometry *geometry, CConfig *config); - - /*! - * \brief Set any surface deformationsbased on an input file. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iZone - Zone number in the mesh. - * \param[in] iter - Current physical time iteration. - */ - void SetExternal_Deformation(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter); - - /*! - * \brief Set a displacement for surface movement. - * \param[in] boundary - Geometry of the boundary. - * \param[in] config - Definition of the particular problem. - * \param[in] iDV - Index of the design variable. - * \param[in] ResetDef - Reset the deformation before starting a new one. - */ - void SetTranslation(CGeometry *boundary, CConfig *config, unsigned short iDV, bool ResetDef); - - /*! - * \brief Set a displacement for surface movement. - * \param[in] boundary - Geometry of the boundary. - * \param[in] config - Definition of the particular problem. - * \param[in] iDV - Index of the design variable. - * \param[in] ResetDef - Reset the deformation before starting a new one. - */ - void SetScale(CGeometry *boundary, CConfig *config, unsigned short iDV, bool ResetDef); - - /*! - * \brief Copy the boundary coordinates to each vertex. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void CopyBoundary(CGeometry *geometry, CConfig *config); - - /*! - * \brief Set the surface/boundary deformation. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetSurface_Deformation(CGeometry *geometry, CConfig *config); - - /*! - * \brief Compute the parametric coordinates of a grid point using a point inversion strategy - * in the free form FFDBox. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. - */ - void SetParametricCoord(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iFFDBox); - - /*! - * \brief Update the parametric coordinates of a grid point using a point inversion strategy - * in the free form FFDBox. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. - * \param[in] iFFDBox - _____________________. - */ - void UpdateParametricCoord(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iFFDBox); - - /*! - * \brief Check the intersections of the FFD with the surface - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. - * \param[in] iFFDBox - _____________________. - */ - void CheckFFDIntersections(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iFFDBox); - - /*! - * \brief _____________________. - * \param[in] geometry - _____________________. - * \param[in] config - _____________________. - * \param[in] FFDBoxParent - _____________________. - * \param[in] FFDBoxChild - _____________________. - */ - void SetParametricCoordCP(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBoxParent, CFreeFormDefBox *FFDBoxChild); - - /*! - * \brief _____________________. - * \param[in] geometry - _____________________. - * \param[in] config - _____________________. - * \param[in] FFDBoxParent - _____________________. - * \param[in] FFDBoxChild - _____________________. - */ - void GetCartesianCoordCP(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBoxParent, CFreeFormDefBox *FFDBoxChild); - - /*! - * \brief Recompute the cartesian coordinates using the control points position. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. - * \param[in] iFFDBox - _____________________. - */ - void SetCartesianCoord(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iFFDBox); - - /*! - * \brief Set the deformation of the Free From box using the control point position. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. - * \param[in] iDV - Index of the design variable. - * \param[in] ResetDef - Reset the deformation before starting a new one. - */ - void SetFFDCPChange_2D(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); - - /*! - * \brief Set the deformation of the Free From box using the control point position. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. - * \param[in] iDV - Index of the design variable. - * \param[in] ResetDef - Reset the deformation before starting a new one. - */ - void SetFFDCPChange(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); - - /*! - * \brief Set a camber deformation of the Free From box using the control point position. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. - * \param[in] iDV - Index of the design variable. - * \param[in] ResetDef - Reset the deformation before starting a new one. - */ - void SetFFDCamber_2D(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); - - /*! - * \brief Set a thickness deformation of the Free From box using the control point position. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. - * \param[in] iDV - Index of the design variable. - * \param[in] ResetDef - Reset the deformation before starting a new one. - */ - void SetFFDThickness_2D(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); - - /*! - * \brief Set a camber deformation of the Free From box using the control point position. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. - * \param[in] iDV - Index of the design variable. - * \param[in] ResetDef - Reset the deformation before starting a new one. - */ - void SetFFDCamber(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); - - /*! - * \brief Set a thickness deformation of the Free From box using the control point position. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. - * \param[in] iDV - Index of the design variable. - * \param[in] ResetDef - Reset the deformation before starting a new one. - */ - void SetFFDThickness(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); - - /*! - * \brief Set a dihedral angle deformation of the Free From box using the control point position. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. - * \param[in] iDV - Index of the design variable. - * \param[in] ResetDef - Reset the deformation before starting a new one. - */ - void SetFFDDihedralAngle(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); - - /*! - * \brief Set a twist angle deformation of the Free From box using the control point position. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. - * \param[in] iDV - Index of the design variable. - * \param[in] ResetDef - Reset the deformation before starting a new one. - */ - void SetFFDTwistAngle(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); - - /*! - * \brief Set a rotation angle deformation of the Free From box using the control point position. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. - * \param[in] iDV - Index of the design variable. - * \param[in] ResetDef - Reset the deformation before starting a new one. - */ - void SetFFDRotation(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); - - /*! - * \brief Set a rotation angle deformation in a control surface of the Free From box using the control point position. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. - * \param[in] iDV - Index of the design variable. - * \param[in] ResetDef - Reset the deformation before starting a new one. - */ - void SetFFDControl_Surface(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); - - /*! - * \brief Read the free form information from the grid input file. - * \note If there is no control point information, and no parametric - * coordinates information, the code will compute that information. - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. - * \param[in] val_mesh_filename - Name of the grid input file. - */ - void ReadFFDInfo(CGeometry *geometry, CConfig *config, CFreeFormDefBox **FFDBox, string val_mesh_filename); - - /*! - * \brief Read the free form information from the grid input file. - * \note If there is no control point information, and no parametric - * coordinates information, the code will compute that information. - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. - */ - void ReadFFDInfo(CGeometry *geometry, CConfig *config, CFreeFormDefBox **FFDBox); - - /*! - * \brief Merge the Free Form information in the SU2 file. - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] val_mesh_filename - Name of the grid output file. - */ - void MergeFFDInfo(CGeometry *geometry, CConfig *config); - - /*! - * \brief Write the Free Form information in the SU2 file. - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] val_mesh_filename - Name of the grid output file. - */ - void WriteFFDInfo(CGeometry *geometry, CConfig *config); - - /*! - * \brief Get information about if there is a complete FFDBox definition, or it is necessary to - * compute the parametric coordinates. - * \return TRUE if the input grid file has a complete information; otherwise FALSE. - */ - bool GetFFDBoxDefinition(void); - - /*! - * \brief Obtain the number of FFDBoxes. - * \return Number of FFD FFDBoxes. - */ - unsigned short GetnFFDBox(void); - - /*! - * \brief Obtain the number of levels. - * \return Number of FFD levels. - */ - unsigned short GetnLevel(void); - - /*! - * \brief Set derivatives of the surface/boundary deformation. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetSurface_Derivative(CGeometry *geometry, CConfig *config); -}; - -#include "grid_movement_structure.inl" +/*! + * \file grid_movement_structure.hpp + * \brief Headers of the main subroutines for doing the numerical grid + * movement (including volumetric movement, surface movement and Free From + * technique definition). The subroutines and functions are in + * the grid_movement_structure.cpp file. + * \author F. Palacios, T. Economon, S. Padron + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +#include "./mpi_structure.hpp" + +#include +#include +#include +#include +#include + +#include "geometry_structure.hpp" +#include "config_structure.hpp" +#include "matrix_structure.hpp" +#include "vector_structure.hpp" +#include "linear_solvers_structure.hpp" + +using namespace std; + +/*! + * \class CGridMovement + * \brief Class for moving the surface and volumetric + * numerical grid (2D and 3D problems). + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CGridMovement { +public: + + /*! + * \brief Constructor of the class. + */ + CGridMovement(void); + + /*! + * \brief Destructor of the class. + */ + ~CGridMovement(void); + + /*! + * \brief A pure virtual member. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetSurface_Deformation(CGeometry *geometry, CConfig *config); + +}; + +/*! + * \class CFreeFormDefBox + * \brief Class for defining the free form FFDBox structure. + * \author F. Palacios & A. Galdran. + * \version 4.0.1 "Cardinal" + */ +class CFreeFormDefBox : public CGridMovement { +public: + unsigned short nDim; /*!< \brief Number of dimensions of the problem. */ + unsigned short nCornerPoints, /*!< \brief Number of corner points of the FFDBox. */ + nControlPoints, nControlPoints_Copy; /*!< \brief Number of control points of the FFDBox. */ + su2double **Coord_Corner_Points, /*!< \brief Coordinates of the corner points. */ + ****Coord_Control_Points, /*!< \brief Coordinates of the control points. */ + ****ParCoord_Control_Points, /*!< \brief Coordinates of the control points. */ + ****Coord_Control_Points_Copy, /*!< \brief Coordinates of the control points (copy). */ + ****Coord_SupportCP; /*!< \brief Coordinates of the support control points. */ + unsigned short lOrder, lOrder_Copy, /*!< \brief Order of the FFDBox in the i direction. */ + mOrder, mOrder_Copy, /*!< \brief Order of the FFDBox in the j direction. */ + nOrder, nOrder_Copy; /*!< \brief Order of the FFDBox in the k direction. */ + unsigned short lDegree, lDegree_Copy, /*!< \brief Degree of the FFDBox in the i direction. (lOrder - 1)*/ + mDegree, mDegree_Copy, /*!< \brief Degree of the FFDBox in the j direction. (mOrder - 1)*/ + nDegree, nDegree_Copy; /*!< \brief Degree of the FFDBox in the k direction. (nOrder - 1)*/ + su2double *ParamCoord, *ParamCoord_, /*!< \brief Parametric coordinates of a point. */ + *cart_coord, *cart_coord_; /*!< \brief Cartesian coordinates of a point. */ + su2double ObjFunc; /*!< \brief Objective function of the point inversion process. */ + su2double *Gradient; /*!< \brief Gradient of the point inversion process. */ + su2double **Hessian; /*!< \brief Hessian of the point inversion process. */ + su2double MaxCoord[3]; /*!< \brief Maximum coordinates of the FFDBox. */ + su2double MinCoord[3]; /*!< \brief Minimum coordinates of the FFDBox. */ + string Tag; /*!< \brief Tag to identify the FFDBox. */ + unsigned short Level; /*!< \brief Nested level of the FFD box. */ + vector CartesianCoord[3]; /*!< \brief Vector with all the cartesian coordinates in the FFD FFDBox. */ + vector ParametricCoord[3]; /*!< \brief Vector with all the parametrics coordinates in the FFD FFDBox. */ + vector MarkerIndex; /*!< \brief Vector with all markers in the FFD FFDBox. */ + vector VertexIndex; /*!< \brief Vector with all vertex index in the FFD FFDBox. */ + vector PointIndex; /*!< \brief Vector with all points index in the FFD FFDBox. */ + unsigned long nSurfacePoint; /*!< \brief Number of surfaces in the FFD FFDBox. */ + vector ParentFFDBox; /*!< \brief Vector with all the parent FFD FFDBox. */ + vector ChildFFDBox; /*!< \brief Vector with all the child FFD FFDBox. */ + vector Fix_IPlane; /*!< \brief Fix FFD I plane. */ + vector Fix_JPlane; /*!< \brief Fix FFD J plane. */ + vector Fix_KPlane; /*!< \brief Fix FFD K plane. */ + +public: + + /*! + * \brief Constructor of the class. + */ + CFreeFormDefBox(void); + + /*! + * \overload + * \param[in] val_lDegree - Degree of the FFDBox in the i direction. + * \param[in] val_mDegree - Degree of the FFDBox in the j direction. + * \param[in] val_nDegree - Degree of the FFDBox in the k direction. + */ + CFreeFormDefBox(unsigned short val_lDegree, unsigned short val_mDegree, unsigned short val_nDegree); + + /*! + * \brief Destructor of the class. + */ + ~CFreeFormDefBox(void); + + /*! + * \brief Define the I planes to to fix in a FFD box. + * \param[in] val_plane - Index of the plane to fix. + */ + void Set_Fix_IPlane(unsigned short val_plane); + + /*! + * \brief Define the I planes to to fix in a FFD box. + * \param[in] val_plane - Index of the plane to fix. + */ + void Set_Fix_JPlane(unsigned short val_plane); + + /*! + * \brief Define the I planes to to fix in a FFD box. + * \param[in] val_plane - Index of the plane to fix. + */ + void Set_Fix_KPlane(unsigned short val_plane); + + /*! + * \brief Define the I planes to to fix in a FFD box. + * \param[in] val_plane - Index of the plane to fix. + */ + unsigned short Get_Fix_IPlane(unsigned short val_index); + + /*! + * \brief Define the I planes to to fix in a FFD box. + * \param[in] val_plane - Index of the plane to fix. + */ + unsigned short Get_Fix_JPlane(unsigned short val_index); + + /*! + * \brief Define the I planes to to fix in a FFD box. + * \param[in] val_plane - Index of the plane to fix. + */ + unsigned short Get_Fix_KPlane(unsigned short val_index); + + /*! + * \brief Define the I planes to to fix in a FFD box. + * \param[in] val_plane - Index of the plane to fix. + */ + unsigned short Get_nFix_IPlane(void); + + /*! + * \brief Define the I planes to to fix in a FFD box. + * \param[in] val_plane - Index of the plane to fix. + */ + unsigned short Get_nFix_JPlane(void); + + /*! + * \brief Define the I planes to to fix in a FFD box. + * \param[in] val_plane - Index of the plane to fix. + */ + unsigned short Get_nFix_KPlane(void); + + /*! + * \brief Add to the vector of markers a new marker. + * \param[in] val_iMarker - New marker inside the FFD box. + */ + void Set_MarkerIndex(unsigned short val_iMarker); + + /*! + * \brief Add to the vector of vertices a new vertex. + * \param[in] val_iVertex - New vertex inside the FFD box. + */ + void Set_VertexIndex(unsigned long val_iVertex); + + /*! + * \brief Add to the vector of points a new point. + * \param[in] val_iPoint - New point inside the FFD box. + */ + void Set_PointIndex(unsigned long val_iPoint); + + /*! + * \brief Add to the vector of cartesian coordinates a new coordinate. + * \param[in] val_coord - New coordinate inside the FFD box. + */ + void Set_CartesianCoord(su2double *val_coord); + + /*! + * \brief Add to the vector of parametric coordinates a new coordinate. + * \param[in] val_coord - New coordinate inside the FFD box. + */ + void Set_ParametricCoord(su2double *val_coord); + + /*! + * \brief Add to the vector of parent FFDBoxes a new FFD FFDBox. + * \param[in] val_iParentFFDBox - New parent FFDBox in the vector. + */ + void SetParentFFDBox(string val_iParentFFDBox); + + /*! + * \brief Add to the vector of child FFDBoxes a new FFD FFDBox. + * \param[in] val_iChildFFDBox - New child FFDBox in the vector. + */ + void SetChildFFDBox(string val_iChildFFDBox); + + /*! + * \brief _______________. + * \param[in] val_coord - _______________. + * \param[in] val_iSurfacePoints - _______________. + */ + void Set_CartesianCoord(su2double *val_coord, unsigned long val_iSurfacePoints); + + /*! + * \brief _______________. + * \param[in] val_coord - _______________. + * \param[in] val_iSurfacePoints - _______________. + */ + void Set_ParametricCoord(su2double *val_coord, unsigned long val_iSurfacePoints); + + /*! + * \brief _______________. + * \param[in] Get_MarkerIndex - _______________. + * \return _______________. + */ + unsigned short Get_MarkerIndex(unsigned long val_iSurfacePoints); + + /*! + * \brief _______________. + * \param[in] Get_VertexIndex - _______________. + * \return _______________. + */ + unsigned long Get_VertexIndex(unsigned long val_iSurfacePoints); + + /*! + * \brief _______________. + * \param[in] Get_PointIndex - _______________. + * \return _______________. + */ + unsigned long Get_PointIndex(unsigned long val_iSurfacePoints); + + /*! + * \brief _______________. + * \param[in] Get_CartesianCoord - _______________. + * \return _______________. + */ + su2double *Get_CartesianCoord(unsigned long val_iSurfacePoints); + + /*! + * \brief _______________. + * \param[in] Get_ParametricCoord - _______________. + * \return _______________. + */ + su2double *Get_ParametricCoord(unsigned long val_iSurfacePoints); + + /*! + * \brief _______________. + * \param[in] GetnSurfacePoint - _______________. + * \return _______________. + */ + unsigned long GetnSurfacePoint(void); + + /*! + * \brief _______________. + * \param[in] GetnParentFFDBox - _______________. + * \return _______________. + */ + unsigned short GetnParentFFDBox(void); + + /*! + * \brief _______________. + * \param[in] GetnChildFFDBox - _______________. + * \return _______________. + */ + unsigned short GetnChildFFDBox(void); + + /*! + * \brief _______________. + * \param[in] val_ParentFFDBox - _______________. + * \return _______________. + */ + string GetParentFFDBoxTag(unsigned short val_ParentFFDBox); + + /*! + * \brief _______________. + * \param[in] val_ChildFFDBox - _______________. + * \return _______________. + */ + string GetChildFFDBoxTag(unsigned short val_ChildFFDBox); + + /*! + * \brief Change the the position of the corners of the unitary FFDBox, + * and find the position of the control points for the FFDBox + * \param[in] FFDBox - Original FFDBox where we want to compute the control points. + */ + void SetSupportCPChange(CFreeFormDefBox *FFDBox); + + /*! + * \brief Set the number of corner points. + * \param[in] val_ncornerpoints - Number of corner points. + */ + void SetnCornerPoints(unsigned short val_ncornerpoints); + + /*! + * \brief Get the number of corner points. + * \return Number of corner points. + */ + unsigned short GetnCornerPoints(void); + + /*! + * \brief Get the number of control points. + * \return Number of control points. + */ + unsigned short GetnControlPoints(void); + + /*! + * \brief Get the number of control points. + * \return Number of control points. + */ + void SetnControlPoints(void); + + /*! + * \brief Get the number of numerical points on the surface. + * \return Number of numerical points on the surface. + */ + unsigned long GetnSurfacePoints(void); + + /*! + * \brief Set the corner point for the unitary FFDBox. + */ + void SetUnitCornerPoints(void); + + /*! + * \brief Set the coordinates of the corner points. + * \param[in] val_coord - Coordinates of the corner point with index val_icornerpoints. + * \param[in] val_icornerpoints - Index of the corner point. + */ + void SetCoordCornerPoints(su2double *val_coord, unsigned short val_icornerpoints); + + /*! + * \overload + * \param[in] val_xcoord - X coordinate of the corner point with index val_icornerpoints. + * \param[in] val_ycoord - Y coordinate of the corner point with index val_icornerpoints. + * \param[in] val_zcoord - Z coordinate of the corner point with index val_icornerpoints. + * \param[in] val_icornerpoints - Index of the corner point. + */ + void SetCoordCornerPoints(su2double val_xcoord, su2double val_ycoord, su2double val_zcoord, unsigned short val_icornerpoints); + + /*! + * \brief Set the coordinates of the control points. + * \param[in] val_coord - Coordinates of the control point. + * \param[in] iDegree - Index of the FFDBox, i direction. + * \param[in] jDegree - Index of the FFDBox, j direction. + * \param[in] kDegree - Index of the FFDBox, k direction. + */ + void SetCoordControlPoints(su2double *val_coord, unsigned short iDegree, unsigned short jDegree, unsigned short kDegree); + + /*! + * \brief Set the coordinates of the control points. + * \param[in] val_coord - Coordinates of the control point. + * \param[in] iDegree - Index of the FFDBox, i direction. + * \param[in] jDegree - Index of the FFDBox, j direction. + * \param[in] kDegree - Index of the FFDBox, k direction. + */ + void SetCoordControlPoints_Copy(su2double *val_coord, unsigned short iDegree, unsigned short jDegree, unsigned short kDegree); + + /*! + * \brief Set the coordinates of the control points. + * \param[in] val_coord - Coordinates of the control point. + * \param[in] iDegree - Index of the FFDBox, i direction. + * \param[in] jDegree - Index of the FFDBox, j direction. + * \param[in] kDegree - Index of the FFDBox, k direction. + */ + void SetParCoordControlPoints(su2double *val_coord, unsigned short iDegree, unsigned short jDegree, unsigned short kDegree); + + /*! + * \brief Get the coordinates of the corner points. + * \param[in] val_dim - Index of the coordinate (x, y, z). + * \param[in] val_icornerpoints - Index of the corner point. + * \return Coordinate val_dim of the corner point val_icornerpoints. + */ + su2double GetCoordCornerPoints(unsigned short val_dim, unsigned short val_icornerpoints); + + /*! + * \brief Get the coordinates of the corner points. + * \param[in] val_icornerpoints - Index of the corner point. + * \return Pointer to the coordinate vector of the corner point val_icornerpoints. + */ + su2double *GetCoordCornerPoints(unsigned short val_icornerpoints); + + /*! + * \brief Get the coordinates of the control point. + * \param[in] val_iindex - Value of the local i index of the control point. + * \param[in] val_jindex - Value of the local j index of the control point. + * \param[in] val_kindex - Value of the local k index of the control point. + * \return Pointer to the coordinate vector of the control point with local index (i, j, k). + */ + su2double *GetCoordControlPoints(unsigned short val_iindex, unsigned short val_jindex, unsigned short val_kindex); + + /*! + * \brief Get the parametric coordinates of the control point. + * \param[in] val_iindex - Value of the local i index of the control point. + * \param[in] val_jindex - Value of the local j index of the control point. + * \param[in] val_kindex - Value of the local k index of the control point. + * \return Pointer to the coordinate vector of the control point with local index (i, j, k). + */ + su2double *GetParCoordControlPoints(unsigned short val_iindex, unsigned short val_jindex, unsigned short val_kindex); + + /*! + * \brief Set the control points in a parallelepiped (hexahedron). + */ + void SetControlPoints_Parallelepiped(void); + + /*! + * \brief Set the control points of the final chuck in a unitary hexahedron free form. + * \param[in] FFDBox - Original FFDBox where we want to compute the control points. + */ + void SetSupportCP(CFreeFormDefBox *FFDBox); + + /*! + * \brief Set the new value of the coordinates of the control points. + * \param[in] val_index - Local index (i, j, k) of the control point. + * \param[in] movement - Movement of the control point. + */ + void SetControlPoints(unsigned short *val_index, su2double *movement); + + /*! + * \brief Set the original value of the control points. + */ + void SetOriginalControlPoints(void); + + /*! + * \brief Set the tecplot file of the FFD chuck structure. + * \param[in] iFFDBox - Index of the FFD box. + * \param[in] original - Original box (before deformation). + */ + void SetTecplot(CGeometry *geometry, unsigned short iFFDBox, bool original); + + /*! + * \brief Set the cartesian coords of a point in R^3 and convert them to the parametric coords of + * our parametrization of a paralellepiped. + * \param[in] cart_coord - Cartesian coordinates of a point. + * \return Pointer to the parametric coordinates of a point. + */ + su2double *GetParametricCoord_Analytical(su2double *cart_coord); + + /*! + * \brief Iterative strategy for computing the parametric coordinates. + * \param[in] xyz - Cartesians coordinates of the target point. + * \param[in] guess - Initial guess for doing the parametric coordinates search. + * \param[in] tol - Level of convergence of the iterative method. + * \param[in] it_max - Maximal number of iterations. + * \return Parametric coordinates of the point. + */ + su2double *GetParametricCoord_Iterative(unsigned long iPoint, su2double *xyz, su2double *guess, CConfig *config); + + /*! + * \brief Compute the cross product. + * \param[in] v1 - First input vector. + * \param[in] v2 - Second input vector. + * \param[out] v3 - Output vector wuth the cross product. + */ + void CrossProduct(su2double *v1, su2double *v2, su2double *v3); + + /*! + * \brief Compute the doc product. + * \param[in] v1 - First input vector. + * \param[in] v2 - Sencond input vector. + * \return Dot product between v1, and v2. + */ + su2double DotProduct(su2double *v1, su2double *v2); + + /*! + * \brief Here we take the parametric coords of a point in the box and we convert them to the + * physical cartesian coords by plugging the ParamCoords on the Bezier parameterization of our box. + * \param[in] ParamCoord - Parametric coordinates of a point. + * \return Pointer to the cartesian coordinates of a point. + */ + su2double *EvalCartesianCoord(su2double *ParamCoord); + + /*! + * \brief Set the Bernstein polynomial, defined as B_i^n(t) = Binomial(n, i)*t^i*(1-t)^(n-i). + * \param[in] val_n - Degree of the Bernstein polynomial. + * \param[in] val_i - Order of the Bernstein polynomial. + * \param[in] val_t - Value of the parameter where the polynomial is evaluated. + * \return Value of the Bernstein polynomial. + */ + su2double GetBernstein(short val_n, short val_i, su2double val_t); + + /*! + * \brief Get the binomial coefficient n over i, defined as n!/(m!(n-m)!) + * \note If the denominator is 0, the value is 1. + * \param[in] n - Upper coefficient. + * \param[in] m - Lower coefficient. + * \return Value of the binomial coefficient n over m. + */ + unsigned long Binomial(unsigned short n, unsigned short m); + + /*! + * \brief Get the order in the l direction of the FFD FFDBox. + * \return Order in the l direction of the FFD FFDBox. + */ + unsigned short GetlOrder(void); + + /*! + * \brief Get the order in the m direction of the FFD FFDBox. + * \return Order in the m direction of the FFD FFDBox. + */ + unsigned short GetmOrder(void); + + /*! + * \brief Get the order in the n direction of the FFD FFDBox. + * \return Order in the n direction of the FFD FFDBox. + */ + unsigned short GetnOrder(void); + + /*! + * \brief Get the order in the l direction of the FFD FFDBox. + * \return Order in the l direction of the FFD FFDBox. + */ + void SetlOrder(unsigned short val_lOrder); + + /*! + * \brief Get the order in the m direction of the FFD FFDBox. + * \return Order in the m direction of the FFD FFDBox. + */ + void SetmOrder(unsigned short val_mOrder); + + /*! + * \brief Get the order in the n direction of the FFD FFDBox. + * \return Order in the n direction of the FFD FFDBox. + */ + void SetnOrder(unsigned short val_nOrder); + + /*! + * \brief Set, at each vertex, the index of the free form FFDBox that contains the vertex. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iFFDBox - Index of the FFDBox. + */ + bool GetPointFFD(CGeometry *geometry, CConfig *config, unsigned long iPoint); + + /*! + * \brief Set the zone of the computational domain that is going to be deformed. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iFFDBox - Index of the FFDBox. + */ + void SetDeformationZone(CGeometry *geometry, CConfig *config, unsigned short iFFDBox); + + /*! + * \brief The "order" derivative of the i-th Bernstein polynomial of degree n, evaluated at t, + * is calculated as (B_i^n(t))^{order}(t) = n*(GetBernstein(n-1, i-1, t)-GetBernstein(n-1, i, t)), + * having in account that if i=0, GetBernstein(n-1,-1, t) = 0. + * \param[in] val_n - Degree of the Bernstein polynomial. + * \param[in] val_i - Order of the Bernstein polynomial. + * \param[in] val_t - Value of the parameter where the polynomial is evaluated. + * \param[in] val_order - Order of the derivative. + * \return Value of the Derivative of the Bernstein polynomial. + */ + su2double GetBernsteinDerivative(short val_n, short val_i, su2double val_t, short val_order); + + /*! + * \brief The routine computes the gradient of F(u, v, w) = ||X(u, v, w)-(x, y, z)||^2 evaluated at (u, v, w). + * \param[in] val_coord - Parametric coordiates of the target point. + * \param[in] xyz - Cartesians coordinates of the point. + * \param[in] analytical - Compute the analytical gradient. + * \return Value of the analytical gradient. + */ + su2double *GetFFDGradient(su2double *val_coord, su2double *xyz); + + /*! + * \brief The routine that computes the Hessian of F(u, v, w) = ||X(u, v, w)-(x, y, z)||^2 evaluated at (u, v, w) + * Input: (u, v, w), (x, y, z) + * Output: Hessian F (u, v, w). + * \param[in] uvw - Current value of the parametrics coordinates. + * \param[in] xyz - Cartesians coordinates of the target point to compose the functional. + * \param[in] val_Hessian - Value of the hessian. + */ + void GetFFDHessian(su2double *uvw, su2double *xyz, su2double **val_Hessian); + + /*! + * \brief An auxiliary routine to help us compute the gradient of F(u, v, w) = ||X(u, v, w)-(x, y, z)||^2 = + * (Sum_ijk^lmn P1_ijk Bi Bj Bk -x)^2+(Sum_ijk^lmn P2_ijk Bi Bj Bk -y)^2+(Sum_ijk^lmn P3_ijk Bi Bj Bk -z)^2 + * Input: val_t, val_diff (to identify the index of the Bernstein polynomail we differentiate), the i, j, k , l, m, n + * E.G.: val_diff=2 => we differentiate w.r.t. w (val_diff=0,1, or 2) Output: d [B_i^l*B_j^m *B_k^n] / d val_diff + * (val_u, val_v, val_w). + * \param[in] uvw - __________. + * \param[in] val_diff - __________. + * \param[in] ijk - __________. + * \param[in] lmn - Degree of the FFD box. + * \return __________. + */ + su2double GetDerivative1(su2double *uvw, unsigned short val_diff, unsigned short *ijk, unsigned short *lmn); + + /*! + * \brief An auxiliary routine to help us compute the gradient of F(u, v, w) = ||X(u, v, w)-(x, y, z)||^2 = + * (Sum_ijk^lmn P1_ijk Bi Bj Bk -x)^2+(Sum_ijk^lmn P2_ijk Bi Bj Bk -y)^2+(Sum_ijk^lmn P3_ijk Bi Bj Bk -z)^2 + * Input: (u, v, w), dim , xyz=(x, y, z), l, m, n E.G.: dim=2 => we use the third coordinate of the control points, + * and the z-coordinate of xyz (0<=dim<=2) Output: 2* ( (Sum_{i, j, k}^l, m, n P_{ijk}[dim] B_i^l[u] B_j^m[v] B_k^n[w]) - + * xyz[dim]). + * \param[in] uvw - __________. + * \param[in] dim - __________. + * \param[in] xyz - __________. + * \param[in] lmn - Degree of the FFD box. + * \return __________. + */ + su2double GetDerivative2(su2double *uvw, unsigned short dim, su2double *xyz, unsigned short *lmn); + + /*! + * \brief An auxiliary routine to help us compute the gradient of F(u, v, w) = ||X(u, v, w)-(x, y, z)||^2 = + * (Sum_ijk^lmn P1_ijk Bi Bj Bk -x)^2+(Sum_ijk^lmn P2_ijk Bi Bj Bk -y)+(Sum_ijk^lmn P3_ijk Bi Bj Bk -z) + * \param[in] uvw - Parametric coordiates of the point. + * \param[in] dim - Value of the coordinate to be differentiate. + * \param[in] diff_this - Diferentiation with respect this coordinate. + * \param[in] lmn - Degree of the FFD box. + * \return Sum_{i, j, k}^{l, m, n} [one of them with -1, + * depending on diff_this=0,1 or 2] P_{ijk}[dim] * (B_i^l[u] B_j^m[v] B_k^n[w])--one of them diffrentiated; + * which? diff_thiss will tell us ; E.G.: dim=2, diff_this=1 => we use the third coordinate of the control + * points, and derivate de v-Bersntein polynomial (use m-1 when summing!!). + */ + su2double GetDerivative3(su2double *uvw, unsigned short dim, unsigned short diff_this, + unsigned short *lmn); + + /*! + * \brief An auxiliary routine to help us compute the Hessian of F(u, v, w) = ||X(u, v, w)-(x, y, z)||^2 = + * (Sum_ijk^lmn P1_ijk Bi Bj Bk -x)^2+(Sum_ijk^lmn P2_ijk Bi Bj Bk -y)+(Sum_ijk^lmn P3_ijk Bi Bj Bk -z) + * Input: val_t, val_diff, val_diff2 (to identify the index of the Bernstein polynomials we differentiate), the i, j, k , l, m, n + * E.G.: val_diff=1, val_diff2=2 => we differentiate w.r.t. v and w (val_diff=0,1, or 2) + * E.G.: val_diff=0, val_diff2=0 => we differentiate w.r.t. u two times + * Output: [d [B_i^l*B_j^m *B_k^n]/d val_diff *d [B_i^l*B_j^m *B_k^n]/d val_diff2] (val_u, val_v, val_w) . + * \param[in] uvw - __________. + * \param[in] val_diff - __________. + * \param[in] val_diff2 - __________. + * \param[in] ijk - __________. + * \param[in] lmn - Degree of the FFD box. + * \return __________. + */ + su2double GetDerivative4(su2double *uvw, unsigned short val_diff, unsigned short val_diff2, + unsigned short *ijk, unsigned short *lmn); + + /*! + * \brief An auxiliary routine to help us compute the Hessian of F(u, v, w) = ||X(u, v, w)-(x, y, z)||^2 = + * (Sum_ijk^lmn P1_ijk Bi Bj Bk -x)^2+(Sum_ijk^lmn P2_ijk Bi Bj Bk -y)+(Sum_ijk^lmn P3_ijk Bi Bj Bk -z) + * Input: (u, v, w), dim , diff_this, diff_this_also, xyz=(x, y, z), l, m, n + * Output: + * Sum_{i, j, k}^{l, m, n} [two of them with -1, depending on diff_this, diff_this_also=0,1 or 2] + * P_{ijk}[dim] * (B_i^l[u] B_j^m[v] B_k^n[w])--one of them diffrentiated; which? diff_thiss will tell us ; + * E.G.: dim=2, diff_this=1 => we use the third coordinate of the control points, and derivate de v-Bersntein + * polynomial (use m-1 when summing!!). + * \param[in] uvw - __________. + * \param[in] dim - __________. + * \param[in] diff_this - __________. + * \param[in] diff_this_also - __________. + * \param[in] lmn - Degree of the FFD box. + * \return __________. + */ + su2double GetDerivative5(su2double *uvw, unsigned short dim, unsigned short diff_this, unsigned short diff_this_also, + unsigned short *lmn); + + /*! + * \brief Euclidean norm of a vector. + * \param[in] a - _______. + * \return __________. + */ + su2double GetNorm(su2double *a); + + /*! + * \brief Set the tag that identify a FFDBox. + * \param[in] val_tag - value of the tag. + */ + void SetTag(string val_tag); + + /*! + * \brief Get the tag that identify a FFDBox. + * \return Value of the tag that identigy the FFDBox. + */ + string GetTag(void); + + /*! + * \brief Set the nested level of the FFDBox. + * \param[in] val_level - value of the level. + */ + void SetLevel(unsigned short val_level); + + /*! + * \brief Get the nested level of the FFDBox. + * \return Value of the nested level of the the FFDBox. + */ + unsigned short GetLevel(void); + + /*! + * \brief Compute the determinant of a 3 by 3 matrix. + * \param[in] val_matrix 3 by 3 matrix. + * \result Determinant of the matrix + */ + su2double Determinant_3x3(su2double A00, su2double A01, su2double A02, su2double A10, su2double A11, + su2double A12, su2double A20, su2double A21, su2double A22); + +}; + +/*! + * \class CVolumetricMovement + * \brief Class for moving the volumetric numerical grid. + * \author F. Palacios, A. Bueno, T. Economon, S. Padron. + * \version 4.0.1 "Cardinal" + */ +class CVolumetricMovement : public CGridMovement { +protected: + + unsigned short nDim; /*!< \brief Number of dimensions. */ + unsigned short nVar; /*!< \brief Number of variables. */ + + unsigned long nPoint; /*!< \brief Number of points. */ + unsigned long nPointDomain; /*!< \brief Number of points in the domain. */ + + CSysMatrix StiffMatrix; /*!< \brief Matrix to store the point-to-point stiffness. */ + CSysVector LinSysSol; + CSysVector LinSysRes; + +public: + + /*! + * \brief Constructor of the class. + */ + CVolumetricMovement(CGeometry *geometry, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CVolumetricMovement(void); + + /*! + * \brief Update the value of the coordinates after the grid movement. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void UpdateGridCoord(CGeometry *geometry, CConfig *config); + + /*! + * \brief Update the dual grid after the grid movement (edges and control volumes). + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void UpdateDualGrid(CGeometry *geometry, 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); + + /*! + * \brief Compute the stiffness matrix for grid deformation using spring analogy. + * \param[in] geometry - Geometrical definition of the problem. + * \return Value of the length of the smallest edge of the grid. + */ + su2double SetFEAMethodContributions_Elem(CGeometry *geometry, CConfig *config); + + /*! + * \brief Build the stiffness matrix for a 3-D hexahedron element. The result will be placed in StiffMatrix_Elem. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] StiffMatrix_Elem - Element stiffness matrix to be filled. + * \param[in] CoordCorners - Index value for Node 1 of the current hexahedron. + */ + void SetFEA_StiffMatrix3D(CGeometry *geometry, CConfig *config, su2double **StiffMatrix_Elem, unsigned long PointCorners[8], su2double CoordCorners[8][3], unsigned short nNodes, su2double scale); + + /*! + * \brief Build the stiffness matrix for a 3-D hexahedron element. The result will be placed in StiffMatrix_Elem. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] StiffMatrix_Elem - Element stiffness matrix to be filled. + * \param[in] CoordCorners - Index value for Node 1 of the current hexahedron. + */ + void SetFEA_StiffMatrix2D(CGeometry *geometry, CConfig *config, su2double **StiffMatrix_Elem, unsigned long PointCorners[8], su2double CoordCorners[8][3], unsigned short nNodes, su2double scale); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] Mu - Local coordinates. + * \param[in] CoordCorners - Coordiantes of the corners. + * \param[in] DShapeFunction - Shape function information + */ + su2double ShapeFunc_Hexa(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] Mu - Local coordinates. + * \param[in] CoordCorners - Coordiantes of the corners. + * \param[in] DShapeFunction - Shape function information + */ + su2double ShapeFunc_Tetra(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] Mu - Local coordinates. + * \param[in] CoordCorners - Coordiantes of the corners. + * \param[in] DShapeFunction - Shape function information + */ + su2double ShapeFunc_Pyram(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] Mu - Local coordinates. + * \param[in] CoordCorners - Coordiantes of the corners. + * \param[in] DShapeFunction - Shape function information + */ + su2double ShapeFunc_Prism(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] CoordCorners - Coordiantes of the corners. + * \param[in] DShapeFunction - Shape function information + */ + su2double ShapeFunc_Triangle(su2double Xi, su2double Eta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] CoordCorners - Coordiantes of the corners. + * \param[in] DShapeFunction - Shape function information + */ + su2double ShapeFunc_Quadrilateral(su2double Xi, su2double Eta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); + + /*! + * \brief Compute the shape functions for hexahedron + * \param[in] CoordCorners - coordinates of the cornes of the hexahedron. + */ + su2double GetHexa_Volume(su2double CoordCorners[8][3]); + + /*! + * \brief Compute the shape functions for hexahedron + * \param[in] CoordCorners - coordinates of the cornes of the hexahedron. + */ + su2double GetTetra_Volume(su2double CoordCorners[8][3]); + + /*! + * \brief Compute the shape functions for hexahedron + * \param[in] CoordCorners - coordinates of the cornes of the hexahedron. + */ + su2double GetPrism_Volume(su2double CoordCorners[8][3]); + + /*! + * \brief Compute the shape functions for hexahedron + * \param[in] CoordCorners - coordinates of the cornes of the hexahedron. + */ + su2double GetPyram_Volume(su2double CoordCorners[8][3]); + + /*! + * \brief Compute the shape functions for hexahedron + * \param[in] CoordCorners - coordinates of the cornes of the hexahedron. + */ + su2double GetTriangle_Area(su2double CoordCorners[8][3]); + + /*! + * \brief Compute the shape functions for hexahedron + * \param[in] CoordCorners - coordinates of the cornes of the hexahedron. + */ + su2double GetQuadrilateral_Area(su2double CoordCorners[8][3]); + + /*! + * \brief Add the stiffness matrix for a 2-D triangular element to the global stiffness matrix for the entire mesh (node-based). + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] StiffMatrix_Elem - Element stiffness matrix to be filled. + * \param[in] PointCorners + * \param[in] nNodes + */ + void AddFEA_StiffMatrix(CGeometry *geometry, su2double **StiffMatrix_Elem, unsigned long PointCorners[8], unsigned short nNodes); + + /*! + * \brief Check for negative volumes (all elements) after performing grid deformation. + * \param[in] geometry - Geometrical definition of the problem. + */ + su2double Check_Grid(CGeometry *geometry); + + /*! + * \brief Compute the minimum distance to the nearest deforming surface. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void ComputeDeforming_Wall_Distance(CGeometry *geometry, CConfig *config); + + /*! + * \brief Check the boundary vertex that are going to be moved. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetBoundaryDisplacements(CGeometry *geometry, CConfig *config); + + /*! + * \brief Check the domain points vertex that are going to be moved. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetDomainDisplacements(CGeometry *geometry, CConfig *config); + + /*! + * \brief Unsteady grid movement using rigid mesh rotation. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Zone number in the mesh. + * \param[in] iter - Physical time iteration number. + */ + void Rigid_Rotation(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter); + + /*! + * \brief Unsteady pitching grid movement using rigid mesh motion. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Zone number in the mesh. + * \param[in] iter - Physical time iteration number. + */ + void Rigid_Pitching(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter); + + /*! + * \brief Unsteady plunging grid movement using rigid mesh motion. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Zone number in the mesh. + * \param[in] iter - Physical time iteration number. + */ + void Rigid_Plunging(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter); + + /*! + * \brief Unsteady translational grid movement using rigid mesh motion. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Zone number in the mesh. + * \param[in] iter - Physical time iteration number. + */ + void Rigid_Translation(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter); + + /*! + * \brief Scale the volume grid by a multiplicative factor. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] UpdateGeo - Update geometry. + */ + void SetVolume_Scaling(CGeometry *geometry, CConfig *config, bool UpdateGeo); + + /*! + * \brief Translate the volume grid by a specified displacement vector. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] UpdateGeo - Update geometry. + */ + void SetVolume_Translation(CGeometry *geometry, CConfig *config, bool UpdateGeo); + + /*! + * \brief Rotate the volume grid around a specified axis and angle. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] UpdateGeo - Update geometry. + */ + void SetVolume_Rotation(CGeometry *geometry, CConfig *config, bool UpdateGeo); + + /*! + * \brief Grid deformation using the spring analogy method. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] UpdateGeo - Update geometry. + * \param[in] Derivative - Compute the derivative (disabled by default). Does not actually deform the grid if enabled. + */ + void SetVolume_Deformation(CGeometry *geometry, CConfig *config, bool UpdateGeo, bool Derivative = false); + + /*! + * \brief Set the derivatives of the boundary nodes. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetBoundaryDerivatives(CGeometry *geometry, CConfig *config); + + /*! + * \brief Update the derivatives of the coordinates after the grid movement. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void UpdateGridCoord_Derivatives(CGeometry *geometry, CConfig *config); + + /*! + * \brief Compute the determinant of a 3 by 3 matrix. + * 3 by 3 matrix elements + * \param[in] A00 + * \param[in] A01 + * \param[in] A02 + * \param[in] A10 + * \param[in] A11 + * \param[in] A12 + * \param[in] A20 + * \param[in] A21 + * \param[in] A22 + * \result Determinant of the matrix + */ + su2double Determinant_3x3(su2double A00, su2double A01, su2double A02, su2double A10, su2double A11, su2double A12, su2double A20, su2double A21, su2double A22); + +}; + +/*! + * \class CSurfaceMovement + * \brief Class for moving the surface numerical grid. + * \author F. Palacios, T. Economon. + * \version 4.0.1 "Cardinal" + */ +class CSurfaceMovement : public CGridMovement { +protected: + CFreeFormDefBox** FFDBox; /*!< \brief Definition of the Free Form Deformation Box. */ + unsigned short nFFDBox; /*!< \brief Number of FFD FFDBoxes. */ + unsigned short nLevel; /*!< \brief Level of the FFD FFDBoxes (parent/child). */ + bool FFDBoxDefinition; /*!< \brief If the FFD FFDBox has been defined in the input file. */ + vector GlobalCoordX[MAX_NUMBER_FFD]; + vector GlobalCoordY[MAX_NUMBER_FFD]; + vector GlobalCoordZ[MAX_NUMBER_FFD]; + vector GlobalTag[MAX_NUMBER_FFD]; + vector GlobalPoint[MAX_NUMBER_FFD]; + +public: + + /*! + * \brief Constructor of the class. + */ + CSurfaceMovement(void); + + /*! + * \brief Destructor of the class. + */ + ~CSurfaceMovement(void); + + /*! + * \brief Set a Hicks-Henne deformation bump functions on an airfoil. + * \param[in] boundary - Geometry of the boundary. + * \param[in] config - Definition of the particular problem. + * \param[in] iDV - Index of the design variable. + * \param[in] ResetDef - Reset the deformation before starting a new one. + */ + void SetHicksHenne(CGeometry *boundary, CConfig *config, unsigned short iDV, bool ResetDef); + + /*! + * \brief Set a NACA 4 digits airfoil family for airfoil deformation. + * \param[in] boundary - Geometry of the boundary. + * \param[in] config - Definition of the particular problem. + */ + void SetNACA_4Digits(CGeometry *boundary, CConfig *config); + + /*! + * \brief Set a parabolic family for airfoil deformation. + * \param[in] boundary - Geometry of the boundary. + * \param[in] config - Definition of the particular problem. + */ + void SetParabolic(CGeometry *boundary, CConfig *config); + + /*! + * \brief Set a obstacle in a channel. + * \param[in] boundary - Geometry of the boundary. + * \param[in] config - Definition of the particular problem. + */ + void SetAirfoil(CGeometry *boundary, CConfig *config); + + /*! + * \brief Set a rotation for surface movement. + * \param[in] boundary - Geometry of the boundary. + * \param[in] config - Definition of the particular problem. + * \param[in] iDV - Index of the design variable. + * \param[in] ResetDef - Reset the deformation before starting a new one. + */ + void SetRotation(CGeometry *boundary, CConfig *config, unsigned short iDV, bool ResetDef); + + /*! + * \brief Set the translational/rotational velocity for a moving wall. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Zone number in the mesh. + * \param[in] iter - Physical time iteration number. + */ + void Moving_Walls(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter); + + /*! + * \brief Computes the displacement of a translating surface for a dynamic mesh simulation. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iter - Current physical time iteration. + * \param[in] iZone - Zone number in the mesh. + */ + void Surface_Translating(CGeometry *geometry, CConfig *config, + unsigned long iter, unsigned short iZone); + + /*! + * \brief Computes the displacement of a plunging surface for a dynamic mesh simulation. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iter - Current physical time iteration. + * \param[in] iZone - Zone number in the mesh. + */ + void Surface_Plunging(CGeometry *geometry, CConfig *config, + unsigned long iter, unsigned short iZone); + + /*! + * \brief Computes the displacement of a pitching surface for a dynamic mesh simulation. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iter - Current physical time iteration. + * \param[in] iZone - Zone number in the mesh. + */ + void Surface_Pitching(CGeometry *geometry, CConfig *config, + unsigned long iter, unsigned short iZone); + + /*! + * \brief Computes the displacement of a rotating surface for a dynamic mesh simulation. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iter - Current physical time iteration. + * \param[in] iZone - Zone number in the mesh. + */ + void Surface_Rotating(CGeometry *geometry, CConfig *config, + unsigned long iter, unsigned short iZone); + + /*! + * \brief Unsteady aeroelastic grid movement by deforming the mesh. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] ExtIter - Physical iteration number. + * \param[in] iMarker - Marker to deform. + * \param[in] iMarker_Monitoring - Marker we are monitoring. + * \param[in] displacements - solution of typical section wing model. + */ + void AeroelasticDeform(CGeometry *geometry, CConfig *config, unsigned long ExtIter, unsigned short iMarker, unsigned short iMarker_Monitoring, vector& displacements); + + /*! + * \brief Deforms a 3-D flutter/pitching surface during an unsteady simulation. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iter - Current physical time iteration. + * \param[in] iZone - Zone number in the mesh. + */ + void SetBoundary_Flutter3D(CGeometry *geometry, CConfig *config, + CFreeFormDefBox **FFDBox, unsigned long iter, unsigned short iZone); + + /*! + * \brief Set the collective pitch for a blade surface movement. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetCollective_Pitch(CGeometry *geometry, CConfig *config); + + /*! + * \brief Set any surface deformationsbased on an input file. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Zone number in the mesh. + * \param[in] iter - Current physical time iteration. + */ + void SetExternal_Deformation(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter); + + /*! + * \brief Set a displacement for surface movement. + * \param[in] boundary - Geometry of the boundary. + * \param[in] config - Definition of the particular problem. + * \param[in] iDV - Index of the design variable. + * \param[in] ResetDef - Reset the deformation before starting a new one. + */ + void SetTranslation(CGeometry *boundary, CConfig *config, unsigned short iDV, bool ResetDef); + + /*! + * \brief Set a displacement for surface movement. + * \param[in] boundary - Geometry of the boundary. + * \param[in] config - Definition of the particular problem. + * \param[in] iDV - Index of the design variable. + * \param[in] ResetDef - Reset the deformation before starting a new one. + */ + void SetScale(CGeometry *boundary, CConfig *config, unsigned short iDV, bool ResetDef); + + /*! + * \brief Copy the boundary coordinates to each vertex. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void CopyBoundary(CGeometry *geometry, CConfig *config); + + /*! + * \brief Set the surface/boundary deformation. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetSurface_Deformation(CGeometry *geometry, CConfig *config); + + /*! + * \brief Compute the parametric coordinates of a grid point using a point inversion strategy + * in the free form FFDBox. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. + */ + void SetParametricCoord(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iFFDBox); + + /*! + * \brief Update the parametric coordinates of a grid point using a point inversion strategy + * in the free form FFDBox. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. + * \param[in] iFFDBox - _____________________. + */ + void UpdateParametricCoord(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iFFDBox); + + /*! + * \brief Check the intersections of the FFD with the surface + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. + * \param[in] iFFDBox - _____________________. + */ + void CheckFFDIntersections(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iFFDBox); + + /*! + * \brief _____________________. + * \param[in] geometry - _____________________. + * \param[in] config - _____________________. + * \param[in] FFDBoxParent - _____________________. + * \param[in] FFDBoxChild - _____________________. + */ + void SetParametricCoordCP(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBoxParent, CFreeFormDefBox *FFDBoxChild); + + /*! + * \brief _____________________. + * \param[in] geometry - _____________________. + * \param[in] config - _____________________. + * \param[in] FFDBoxParent - _____________________. + * \param[in] FFDBoxChild - _____________________. + */ + void GetCartesianCoordCP(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBoxParent, CFreeFormDefBox *FFDBoxChild); + + /*! + * \brief Recompute the cartesian coordinates using the control points position. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. + * \param[in] iFFDBox - _____________________. + */ + void SetCartesianCoord(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iFFDBox); + + /*! + * \brief Set the deformation of the Free From box using the control point position. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. + * \param[in] iDV - Index of the design variable. + * \param[in] ResetDef - Reset the deformation before starting a new one. + */ + void SetFFDCPChange_2D(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); + + /*! + * \brief Set the deformation of the Free From box using the control point position. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. + * \param[in] iDV - Index of the design variable. + * \param[in] ResetDef - Reset the deformation before starting a new one. + */ + void SetFFDCPChange(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); + + /*! + * \brief Set a camber deformation of the Free From box using the control point position. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. + * \param[in] iDV - Index of the design variable. + * \param[in] ResetDef - Reset the deformation before starting a new one. + */ + void SetFFDCamber_2D(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); + + /*! + * \brief Set a thickness deformation of the Free From box using the control point position. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. + * \param[in] iDV - Index of the design variable. + * \param[in] ResetDef - Reset the deformation before starting a new one. + */ + void SetFFDThickness_2D(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); + + /*! + * \brief Set a camber deformation of the Free From box using the control point position. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. + * \param[in] iDV - Index of the design variable. + * \param[in] ResetDef - Reset the deformation before starting a new one. + */ + void SetFFDCamber(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); + + /*! + * \brief Set a thickness deformation of the Free From box using the control point position. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. + * \param[in] iDV - Index of the design variable. + * \param[in] ResetDef - Reset the deformation before starting a new one. + */ + void SetFFDThickness(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); + + /*! + * \brief Set a dihedral angle deformation of the Free From box using the control point position. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. + * \param[in] iDV - Index of the design variable. + * \param[in] ResetDef - Reset the deformation before starting a new one. + */ + void SetFFDDihedralAngle(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); + + /*! + * \brief Set a twist angle deformation of the Free From box using the control point position. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. + * \param[in] iDV - Index of the design variable. + * \param[in] ResetDef - Reset the deformation before starting a new one. + */ + void SetFFDTwistAngle(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); + + /*! + * \brief Set a rotation angle deformation of the Free From box using the control point position. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. + * \param[in] iDV - Index of the design variable. + * \param[in] ResetDef - Reset the deformation before starting a new one. + */ + void SetFFDRotation(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); + + /*! + * \brief Set a rotation angle deformation in a control surface of the Free From box using the control point position. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. + * \param[in] iDV - Index of the design variable. + * \param[in] ResetDef - Reset the deformation before starting a new one. + */ + void SetFFDControl_Surface(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iDV, bool ResetDef); + + /*! + * \brief Read the free form information from the grid input file. + * \note If there is no control point information, and no parametric + * coordinates information, the code will compute that information. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. + * \param[in] val_mesh_filename - Name of the grid input file. + */ + void ReadFFDInfo(CGeometry *geometry, CConfig *config, CFreeFormDefBox **FFDBox, string val_mesh_filename); + + /*! + * \brief Read the free form information from the grid input file. + * \note If there is no control point information, and no parametric + * coordinates information, the code will compute that information. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] FFDBox - Array with all the free forms FFDBoxes of the computation. + */ + void ReadFFDInfo(CGeometry *geometry, CConfig *config, CFreeFormDefBox **FFDBox); + + /*! + * \brief Merge the Free Form information in the SU2 file. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] val_mesh_filename - Name of the grid output file. + */ + void MergeFFDInfo(CGeometry *geometry, CConfig *config); + + /*! + * \brief Write the Free Form information in the SU2 file. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] val_mesh_filename - Name of the grid output file. + */ + void WriteFFDInfo(CGeometry *geometry, CConfig *config); + + /*! + * \brief Get information about if there is a complete FFDBox definition, or it is necessary to + * compute the parametric coordinates. + * \return TRUE if the input grid file has a complete information; otherwise FALSE. + */ + bool GetFFDBoxDefinition(void); + + /*! + * \brief Obtain the number of FFDBoxes. + * \return Number of FFD FFDBoxes. + */ + unsigned short GetnFFDBox(void); + + /*! + * \brief Obtain the number of levels. + * \return Number of FFD levels. + */ + unsigned short GetnLevel(void); + + /*! + * \brief Set derivatives of the surface/boundary deformation. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetSurface_Derivative(CGeometry *geometry, CConfig *config); +}; + +#include "grid_movement_structure.inl" diff --git a/Common/include/grid_movement_structure.inl b/Common/include/grid_movement_structure.inl index 3608d63fd96..7510585acb8 100644 --- a/Common/include/grid_movement_structure.inl +++ b/Common/include/grid_movement_structure.inl @@ -1,213 +1,213 @@ -/*! - * \file grid_movement_structure.inl - * \brief In-Line subroutines of the grid_movement_structure.hpp file. - * \author F. Palacios, T. Economon, S. Padron - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -inline void CGridMovement::SetSurface_Deformation(CGeometry *geometry, CConfig *config) { } - -inline unsigned short CSurfaceMovement::GetnLevel(void) { return nLevel; } - -inline unsigned short CSurfaceMovement::GetnFFDBox(void) { return nFFDBox; } - -inline bool CSurfaceMovement::GetFFDBoxDefinition(void) { return FFDBoxDefinition; } - -inline void CFreeFormDefBox::Set_Fix_IPlane(unsigned short val_plane) { Fix_IPlane.push_back(val_plane); } - -inline void CFreeFormDefBox::Set_Fix_JPlane(unsigned short val_plane) { Fix_JPlane.push_back(val_plane); } - -inline void CFreeFormDefBox::Set_Fix_KPlane(unsigned short val_plane) { Fix_KPlane.push_back(val_plane); } - -inline unsigned short CFreeFormDefBox::Get_Fix_IPlane(unsigned short val_index) { return Fix_IPlane[val_index]; } - -inline unsigned short CFreeFormDefBox::Get_Fix_JPlane(unsigned short val_index) { return Fix_JPlane[val_index]; } - -inline unsigned short CFreeFormDefBox::Get_Fix_KPlane(unsigned short val_index) { return Fix_KPlane[val_index]; } - -inline unsigned short CFreeFormDefBox::Get_nFix_IPlane(void) { return Fix_IPlane.size(); } - -inline unsigned short CFreeFormDefBox::Get_nFix_JPlane(void) { return Fix_JPlane.size(); } - -inline unsigned short CFreeFormDefBox::Get_nFix_KPlane(void) { return Fix_KPlane.size(); } - -inline void CFreeFormDefBox::Set_MarkerIndex(unsigned short val_iMarker) { MarkerIndex.push_back(val_iMarker); } - -inline void CFreeFormDefBox::SetParentFFDBox(string val_iParentFFDBox) { ParentFFDBox.push_back(val_iParentFFDBox); } - -inline void CFreeFormDefBox::SetChildFFDBox(string val_iChildFFDBox) { ChildFFDBox.push_back(val_iChildFFDBox); } - -inline void CFreeFormDefBox::Set_VertexIndex(unsigned long val_iVertex) { VertexIndex.push_back(val_iVertex); } - -inline void CFreeFormDefBox::Set_PointIndex(unsigned long val_iPoint) { PointIndex.push_back(val_iPoint); } - -inline void CFreeFormDefBox::Set_CartesianCoord(su2double *val_coord) { CartesianCoord[0].push_back(val_coord[0]); - CartesianCoord[1].push_back(val_coord[1]); - CartesianCoord[2].push_back(val_coord[2]); } - -inline void CFreeFormDefBox::Set_CartesianCoord(su2double *val_coord, unsigned long val_iSurfacePoints) { CartesianCoord[0][val_iSurfacePoints] = val_coord[0]; - CartesianCoord[1][val_iSurfacePoints] = val_coord[1]; - CartesianCoord[2][val_iSurfacePoints] = val_coord[2]; } - -inline void CFreeFormDefBox::Set_ParametricCoord(su2double *val_coord) { ParametricCoord[0].push_back(val_coord[0]); - ParametricCoord[1].push_back(val_coord[1]); - ParametricCoord[2].push_back(val_coord[2]); } - -inline void CFreeFormDefBox::Set_ParametricCoord(su2double *val_coord, unsigned long val_iSurfacePoints) { ParametricCoord[0][val_iSurfacePoints] = val_coord[0]; - ParametricCoord[1][val_iSurfacePoints] = val_coord[1]; - ParametricCoord[2][val_iSurfacePoints] = val_coord[2]; } - -inline unsigned short CFreeFormDefBox::Get_MarkerIndex(unsigned long val_iSurfacePoints) { return MarkerIndex[val_iSurfacePoints]; } - -inline unsigned short CFreeFormDefBox::GetnParentFFDBox(void) { return ParentFFDBox.size(); } - -inline unsigned short CFreeFormDefBox::GetnChildFFDBox(void) { return ChildFFDBox.size(); } - -inline string CFreeFormDefBox::GetParentFFDBoxTag(unsigned short val_ParentFFDBox) { return ParentFFDBox[val_ParentFFDBox]; } - -inline string CFreeFormDefBox::GetChildFFDBoxTag(unsigned short val_ChildFFDBox) { return ChildFFDBox[val_ChildFFDBox]; } - -inline unsigned long CFreeFormDefBox::Get_VertexIndex(unsigned long val_iSurfacePoints) { return VertexIndex[val_iSurfacePoints]; } - -inline unsigned long CFreeFormDefBox::Get_PointIndex(unsigned long val_iSurfacePoints) { return PointIndex[val_iSurfacePoints]; } - -inline su2double *CFreeFormDefBox::Get_CartesianCoord(unsigned long val_iSurfacePoints) { - cart_coord_[0] = CartesianCoord[0][val_iSurfacePoints]; - cart_coord_[1] = CartesianCoord[1][val_iSurfacePoints]; - cart_coord_[2] = CartesianCoord[2][val_iSurfacePoints]; - return cart_coord_; } - -inline su2double *CFreeFormDefBox::Get_ParametricCoord(unsigned long val_iSurfacePoints) { - ParamCoord_[0] = ParametricCoord[0][val_iSurfacePoints]; - ParamCoord_[1] = ParametricCoord[1][val_iSurfacePoints]; - ParamCoord_[2] = ParametricCoord[2][val_iSurfacePoints]; - return ParamCoord_; } - -inline unsigned long CFreeFormDefBox::GetnSurfacePoint(void) { return PointIndex.size(); } - -inline void CFreeFormDefBox::SetnCornerPoints(unsigned short val_ncornerpoints) { nCornerPoints = val_ncornerpoints; } - -inline unsigned short CFreeFormDefBox::GetnCornerPoints(void) { return nCornerPoints; } - -inline unsigned short CFreeFormDefBox::GetnControlPoints(void) { return nControlPoints; } - -inline void CFreeFormDefBox::SetnControlPoints(void) { nControlPoints = lOrder*mOrder*nOrder; } - -inline unsigned long CFreeFormDefBox::GetnSurfacePoints(void) { return 0; } - -inline su2double *CFreeFormDefBox::GetCoordCornerPoints(unsigned short val_icornerpoints) { return Coord_Corner_Points[val_icornerpoints]; } - -inline su2double *CFreeFormDefBox::GetCoordControlPoints(unsigned short val_iindex, unsigned short val_jindex, unsigned short val_kindex) { return Coord_Control_Points[val_iindex][val_jindex][val_kindex]; } - -inline su2double *CFreeFormDefBox::GetParCoordControlPoints(unsigned short val_iindex, unsigned short val_jindex, unsigned short val_kindex) { return ParCoord_Control_Points[val_iindex][val_jindex][val_kindex]; } - -inline su2double CFreeFormDefBox::GetCoordCornerPoints(unsigned short val_dim, unsigned short val_icornerpoints) { return Coord_Corner_Points[val_icornerpoints][val_dim]; } - -inline unsigned short CFreeFormDefBox::GetlOrder(void) { return lOrder; } - -inline unsigned short CFreeFormDefBox::GetmOrder(void) { return mOrder; } - -inline unsigned short CFreeFormDefBox::GetnOrder(void) { return nOrder; } - -inline void CFreeFormDefBox::SetlOrder(unsigned short val_lOrder) { lOrder = val_lOrder; lDegree = lOrder-1; } - -inline void CFreeFormDefBox::SetmOrder(unsigned short val_mOrder) { mOrder = val_mOrder; mDegree = mOrder-1; } - -inline void CFreeFormDefBox::SetnOrder(unsigned short val_nOrder) { nOrder = val_nOrder; nDegree = nOrder-1;} - -inline void CFreeFormDefBox::SetCoordCornerPoints(su2double *val_coord, unsigned short val_icornerpoints) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Coord_Corner_Points[val_icornerpoints][iDim] = val_coord[iDim]; -} - -inline void CFreeFormDefBox::SetCoordControlPoints(su2double *val_coord, unsigned short iDegree, unsigned short jDegree, unsigned short kDegree) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) { - Coord_Control_Points[iDegree][jDegree][kDegree][iDim] = val_coord[iDim]; - } -} - -inline void CFreeFormDefBox::SetCoordControlPoints_Copy(su2double *val_coord, unsigned short iDegree, unsigned short jDegree, unsigned short kDegree) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) { - Coord_Control_Points_Copy[iDegree][jDegree][kDegree][iDim] = val_coord[iDim]; - } -} - -inline void CFreeFormDefBox::SetParCoordControlPoints(su2double *val_coord, unsigned short iDegree, unsigned short jDegree, unsigned short kDegree) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - ParCoord_Control_Points[iDegree][jDegree][kDegree][iDim] = val_coord[iDim]; -} - -inline void CFreeFormDefBox::SetCoordCornerPoints(su2double val_xcoord, su2double val_ycoord, su2double val_zcoord, unsigned short val_icornerpoints) { - Coord_Corner_Points[val_icornerpoints][0] = val_xcoord; - Coord_Corner_Points[val_icornerpoints][1] = val_ycoord; - Coord_Corner_Points[val_icornerpoints][2] = val_zcoord; -} - -inline void CFreeFormDefBox::SetControlPoints(unsigned short *val_index, su2double *movement) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Coord_Control_Points[val_index[0]][val_index[1]][val_index[2]][iDim] += movement[iDim]; -} - -inline void CFreeFormDefBox::SetOriginalControlPoints() { - for (unsigned short iDegree = 0; iDegree <= lDegree_Copy; iDegree++) - for (unsigned short jDegree = 0; jDegree <= mDegree_Copy; jDegree++) - for (unsigned short kDegree = 0; kDegree <= nDegree_Copy; kDegree++) - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Coord_Control_Points[iDegree][jDegree][kDegree][iDim] = Coord_Control_Points_Copy[iDegree][jDegree][kDegree][iDim]; - - lDegree = lDegree_Copy; mDegree = mDegree_Copy; nDegree = nDegree_Copy; - lOrder = lOrder_Copy; mOrder = mOrder_Copy; nOrder = nOrder_Copy; - nControlPoints = nControlPoints_Copy; -} - -inline void CFreeFormDefBox::CrossProduct (su2double *v1, su2double *v2, su2double *v3) { - v3[0] = v1[1]*v2[2]-v1[2]*v2[1]; - v3[1] = v1[2]*v2[0]-v1[0]*v2[2]; - v3[2] = v1[0]*v2[1]-v1[1]*v2[0]; -} - -inline su2double CFreeFormDefBox::DotProduct (su2double *v1, su2double *v2) { su2double scalar = v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]; return scalar; } - -inline su2double CFreeFormDefBox::GetNorm(su2double *a) { su2double norm = sqrt(a[0]*a[0] + a[1]*a[1]+ a[2]*a[2]); return norm; } - -inline void CFreeFormDefBox::SetTag(string val_tag) { Tag = val_tag; } - -inline string CFreeFormDefBox::GetTag() { return Tag; } - -inline void CFreeFormDefBox::SetLevel(unsigned short val_level) { Level = val_level; } - -inline unsigned short CFreeFormDefBox::GetLevel() { return Level; } - -inline su2double CFreeFormDefBox::Determinant_3x3(su2double A00, su2double A01, su2double A02, su2double A10, su2double A11, su2double A12, su2double A20, su2double A21, su2double A22) { - return A00*(A11*A22-A12*A21) - A01*(A10*A22-A12*A20) + A02*(A10*A21-A11*A20); -} - -inline su2double CVolumetricMovement::Determinant_3x3(su2double A00, su2double A01, su2double A02, su2double A10, su2double A11, su2double A12, su2double A20, su2double A21, su2double A22) { - return A00*(A11*A22-A12*A21) - A01*(A10*A22-A12*A20) + A02*(A10*A21-A11*A20); -} +/*! + * \file grid_movement_structure.inl + * \brief In-Line subroutines of the grid_movement_structure.hpp file. + * \author F. Palacios, T. Economon, S. Padron + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +inline void CGridMovement::SetSurface_Deformation(CGeometry *geometry, CConfig *config) { } + +inline unsigned short CSurfaceMovement::GetnLevel(void) { return nLevel; } + +inline unsigned short CSurfaceMovement::GetnFFDBox(void) { return nFFDBox; } + +inline bool CSurfaceMovement::GetFFDBoxDefinition(void) { return FFDBoxDefinition; } + +inline void CFreeFormDefBox::Set_Fix_IPlane(unsigned short val_plane) { Fix_IPlane.push_back(val_plane); } + +inline void CFreeFormDefBox::Set_Fix_JPlane(unsigned short val_plane) { Fix_JPlane.push_back(val_plane); } + +inline void CFreeFormDefBox::Set_Fix_KPlane(unsigned short val_plane) { Fix_KPlane.push_back(val_plane); } + +inline unsigned short CFreeFormDefBox::Get_Fix_IPlane(unsigned short val_index) { return Fix_IPlane[val_index]; } + +inline unsigned short CFreeFormDefBox::Get_Fix_JPlane(unsigned short val_index) { return Fix_JPlane[val_index]; } + +inline unsigned short CFreeFormDefBox::Get_Fix_KPlane(unsigned short val_index) { return Fix_KPlane[val_index]; } + +inline unsigned short CFreeFormDefBox::Get_nFix_IPlane(void) { return Fix_IPlane.size(); } + +inline unsigned short CFreeFormDefBox::Get_nFix_JPlane(void) { return Fix_JPlane.size(); } + +inline unsigned short CFreeFormDefBox::Get_nFix_KPlane(void) { return Fix_KPlane.size(); } + +inline void CFreeFormDefBox::Set_MarkerIndex(unsigned short val_iMarker) { MarkerIndex.push_back(val_iMarker); } + +inline void CFreeFormDefBox::SetParentFFDBox(string val_iParentFFDBox) { ParentFFDBox.push_back(val_iParentFFDBox); } + +inline void CFreeFormDefBox::SetChildFFDBox(string val_iChildFFDBox) { ChildFFDBox.push_back(val_iChildFFDBox); } + +inline void CFreeFormDefBox::Set_VertexIndex(unsigned long val_iVertex) { VertexIndex.push_back(val_iVertex); } + +inline void CFreeFormDefBox::Set_PointIndex(unsigned long val_iPoint) { PointIndex.push_back(val_iPoint); } + +inline void CFreeFormDefBox::Set_CartesianCoord(su2double *val_coord) { CartesianCoord[0].push_back(val_coord[0]); + CartesianCoord[1].push_back(val_coord[1]); + CartesianCoord[2].push_back(val_coord[2]); } + +inline void CFreeFormDefBox::Set_CartesianCoord(su2double *val_coord, unsigned long val_iSurfacePoints) { CartesianCoord[0][val_iSurfacePoints] = val_coord[0]; + CartesianCoord[1][val_iSurfacePoints] = val_coord[1]; + CartesianCoord[2][val_iSurfacePoints] = val_coord[2]; } + +inline void CFreeFormDefBox::Set_ParametricCoord(su2double *val_coord) { ParametricCoord[0].push_back(val_coord[0]); + ParametricCoord[1].push_back(val_coord[1]); + ParametricCoord[2].push_back(val_coord[2]); } + +inline void CFreeFormDefBox::Set_ParametricCoord(su2double *val_coord, unsigned long val_iSurfacePoints) { ParametricCoord[0][val_iSurfacePoints] = val_coord[0]; + ParametricCoord[1][val_iSurfacePoints] = val_coord[1]; + ParametricCoord[2][val_iSurfacePoints] = val_coord[2]; } + +inline unsigned short CFreeFormDefBox::Get_MarkerIndex(unsigned long val_iSurfacePoints) { return MarkerIndex[val_iSurfacePoints]; } + +inline unsigned short CFreeFormDefBox::GetnParentFFDBox(void) { return ParentFFDBox.size(); } + +inline unsigned short CFreeFormDefBox::GetnChildFFDBox(void) { return ChildFFDBox.size(); } + +inline string CFreeFormDefBox::GetParentFFDBoxTag(unsigned short val_ParentFFDBox) { return ParentFFDBox[val_ParentFFDBox]; } + +inline string CFreeFormDefBox::GetChildFFDBoxTag(unsigned short val_ChildFFDBox) { return ChildFFDBox[val_ChildFFDBox]; } + +inline unsigned long CFreeFormDefBox::Get_VertexIndex(unsigned long val_iSurfacePoints) { return VertexIndex[val_iSurfacePoints]; } + +inline unsigned long CFreeFormDefBox::Get_PointIndex(unsigned long val_iSurfacePoints) { return PointIndex[val_iSurfacePoints]; } + +inline su2double *CFreeFormDefBox::Get_CartesianCoord(unsigned long val_iSurfacePoints) { + cart_coord_[0] = CartesianCoord[0][val_iSurfacePoints]; + cart_coord_[1] = CartesianCoord[1][val_iSurfacePoints]; + cart_coord_[2] = CartesianCoord[2][val_iSurfacePoints]; + return cart_coord_; } + +inline su2double *CFreeFormDefBox::Get_ParametricCoord(unsigned long val_iSurfacePoints) { + ParamCoord_[0] = ParametricCoord[0][val_iSurfacePoints]; + ParamCoord_[1] = ParametricCoord[1][val_iSurfacePoints]; + ParamCoord_[2] = ParametricCoord[2][val_iSurfacePoints]; + return ParamCoord_; } + +inline unsigned long CFreeFormDefBox::GetnSurfacePoint(void) { return PointIndex.size(); } + +inline void CFreeFormDefBox::SetnCornerPoints(unsigned short val_ncornerpoints) { nCornerPoints = val_ncornerpoints; } + +inline unsigned short CFreeFormDefBox::GetnCornerPoints(void) { return nCornerPoints; } + +inline unsigned short CFreeFormDefBox::GetnControlPoints(void) { return nControlPoints; } + +inline void CFreeFormDefBox::SetnControlPoints(void) { nControlPoints = lOrder*mOrder*nOrder; } + +inline unsigned long CFreeFormDefBox::GetnSurfacePoints(void) { return 0; } + +inline su2double *CFreeFormDefBox::GetCoordCornerPoints(unsigned short val_icornerpoints) { return Coord_Corner_Points[val_icornerpoints]; } + +inline su2double *CFreeFormDefBox::GetCoordControlPoints(unsigned short val_iindex, unsigned short val_jindex, unsigned short val_kindex) { return Coord_Control_Points[val_iindex][val_jindex][val_kindex]; } + +inline su2double *CFreeFormDefBox::GetParCoordControlPoints(unsigned short val_iindex, unsigned short val_jindex, unsigned short val_kindex) { return ParCoord_Control_Points[val_iindex][val_jindex][val_kindex]; } + +inline su2double CFreeFormDefBox::GetCoordCornerPoints(unsigned short val_dim, unsigned short val_icornerpoints) { return Coord_Corner_Points[val_icornerpoints][val_dim]; } + +inline unsigned short CFreeFormDefBox::GetlOrder(void) { return lOrder; } + +inline unsigned short CFreeFormDefBox::GetmOrder(void) { return mOrder; } + +inline unsigned short CFreeFormDefBox::GetnOrder(void) { return nOrder; } + +inline void CFreeFormDefBox::SetlOrder(unsigned short val_lOrder) { lOrder = val_lOrder; lDegree = lOrder-1; } + +inline void CFreeFormDefBox::SetmOrder(unsigned short val_mOrder) { mOrder = val_mOrder; mDegree = mOrder-1; } + +inline void CFreeFormDefBox::SetnOrder(unsigned short val_nOrder) { nOrder = val_nOrder; nDegree = nOrder-1;} + +inline void CFreeFormDefBox::SetCoordCornerPoints(su2double *val_coord, unsigned short val_icornerpoints) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Coord_Corner_Points[val_icornerpoints][iDim] = val_coord[iDim]; +} + +inline void CFreeFormDefBox::SetCoordControlPoints(su2double *val_coord, unsigned short iDegree, unsigned short jDegree, unsigned short kDegree) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) { + Coord_Control_Points[iDegree][jDegree][kDegree][iDim] = val_coord[iDim]; + } +} + +inline void CFreeFormDefBox::SetCoordControlPoints_Copy(su2double *val_coord, unsigned short iDegree, unsigned short jDegree, unsigned short kDegree) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) { + Coord_Control_Points_Copy[iDegree][jDegree][kDegree][iDim] = val_coord[iDim]; + } +} + +inline void CFreeFormDefBox::SetParCoordControlPoints(su2double *val_coord, unsigned short iDegree, unsigned short jDegree, unsigned short kDegree) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + ParCoord_Control_Points[iDegree][jDegree][kDegree][iDim] = val_coord[iDim]; +} + +inline void CFreeFormDefBox::SetCoordCornerPoints(su2double val_xcoord, su2double val_ycoord, su2double val_zcoord, unsigned short val_icornerpoints) { + Coord_Corner_Points[val_icornerpoints][0] = val_xcoord; + Coord_Corner_Points[val_icornerpoints][1] = val_ycoord; + Coord_Corner_Points[val_icornerpoints][2] = val_zcoord; +} + +inline void CFreeFormDefBox::SetControlPoints(unsigned short *val_index, su2double *movement) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Coord_Control_Points[val_index[0]][val_index[1]][val_index[2]][iDim] += movement[iDim]; +} + +inline void CFreeFormDefBox::SetOriginalControlPoints() { + for (unsigned short iDegree = 0; iDegree <= lDegree_Copy; iDegree++) + for (unsigned short jDegree = 0; jDegree <= mDegree_Copy; jDegree++) + for (unsigned short kDegree = 0; kDegree <= nDegree_Copy; kDegree++) + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Coord_Control_Points[iDegree][jDegree][kDegree][iDim] = Coord_Control_Points_Copy[iDegree][jDegree][kDegree][iDim]; + + lDegree = lDegree_Copy; mDegree = mDegree_Copy; nDegree = nDegree_Copy; + lOrder = lOrder_Copy; mOrder = mOrder_Copy; nOrder = nOrder_Copy; + nControlPoints = nControlPoints_Copy; +} + +inline void CFreeFormDefBox::CrossProduct (su2double *v1, su2double *v2, su2double *v3) { + v3[0] = v1[1]*v2[2]-v1[2]*v2[1]; + v3[1] = v1[2]*v2[0]-v1[0]*v2[2]; + v3[2] = v1[0]*v2[1]-v1[1]*v2[0]; +} + +inline su2double CFreeFormDefBox::DotProduct (su2double *v1, su2double *v2) { su2double scalar = v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]; return scalar; } + +inline su2double CFreeFormDefBox::GetNorm(su2double *a) { su2double norm = sqrt(a[0]*a[0] + a[1]*a[1]+ a[2]*a[2]); return norm; } + +inline void CFreeFormDefBox::SetTag(string val_tag) { Tag = val_tag; } + +inline string CFreeFormDefBox::GetTag() { return Tag; } + +inline void CFreeFormDefBox::SetLevel(unsigned short val_level) { Level = val_level; } + +inline unsigned short CFreeFormDefBox::GetLevel() { return Level; } + +inline su2double CFreeFormDefBox::Determinant_3x3(su2double A00, su2double A01, su2double A02, su2double A10, su2double A11, su2double A12, su2double A20, su2double A21, su2double A22) { + return A00*(A11*A22-A12*A21) - A01*(A10*A22-A12*A20) + A02*(A10*A21-A11*A20); +} + +inline su2double CVolumetricMovement::Determinant_3x3(su2double A00, su2double A01, su2double A02, su2double A10, su2double A11, su2double A12, su2double A20, su2double A21, su2double A22) { + return A00*(A11*A22-A12*A21) - A01*(A10*A22-A12*A20) + A02*(A10*A21-A11*A20); +} diff --git a/Common/include/matrix_structure.hpp b/Common/include/matrix_structure.hpp index 41a309adef4..639a1c33e77 100644 --- a/Common/include/matrix_structure.hpp +++ b/Common/include/matrix_structure.hpp @@ -1,695 +1,695 @@ -/*! - * \file matrix_structure.hpp - * \brief Headers of the main subroutines for creating the sparse matrices-by-blocks. - * The subroutines and functions are in the matrix_structure.cpp file. - * \author F. Palacios, A. Bueno, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -#include "./mpi_structure.hpp" -#include -#include -#include -#include - -#include "config_structure.hpp" -#include "geometry_structure.hpp" -#include "vector_structure.hpp" - -using namespace std; - -const su2double eps = numeric_limits::epsilon(); /*!< \brief machine epsilon */ - - -/*! - * \class CSysMatrix - * \brief Main class for defining sparse matrices-by-blocks - with compressed row format. - * \author A. Bueno, F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CSysMatrix { -private: - unsigned long nPoint, /*!< \brief Number of points in the grid. */ - nPointDomain, /*!< \brief Number of points in the grid. */ - nVar, /*!< \brief Number of variables. */ - nEqn; /*!< \brief Number of equations. */ - su2double *matrix; /*!< \brief Entries of the sparse matrix. */ - su2double *ILU_matrix; /*!< \brief Entries of the ILU sparse matrix. */ - unsigned long *row_ptr; /*!< \brief Pointers to the first element in each row. */ - unsigned long *col_ind; /*!< \brief Column index for each of the elements in val(). */ - unsigned long nnz; /*!< \brief Number of possible nonzero entries in the matrix. */ - su2double *block; /*!< \brief Internal array to store a subblock of the matrix. */ - su2double *block_inverse; /*!< \brief Internal array to store a subblock of the matrix. */ - su2double *block_weight; /*!< \brief Internal array to store a subblock of the matrix. */ - su2double *prod_block_vector; /*!< \brief Internal array to store the product of a subblock with a vector. */ - su2double *prod_row_vector; /*!< \brief Internal array to store the product of a matrix-by-blocks "row" with a vector. */ - su2double *aux_vector; /*!< \brief Auxiliary array to store intermediate results. */ - su2double *sum_vector; /*!< \brief Auxiliary array to store intermediate results. */ - su2double *invM; /*!< \brief Inverse of (Jacobi) preconditioner. */ - - bool *LineletBool; /*!< \brief Identify if a point belong to a linelet. */ - vector *LineletPoint; /*!< \brief Linelet structure. */ - unsigned long nLinelet; /*!< \brief Number of Linelets in the system. */ - su2double **UBlock, **invUBlock, **LBlock, - **yVector, **zVector, **rVector, *LFBlock, - *LyVector, *FzVector; /*!< \brief Arrays of the Linelet preconditioner methodology. */ - unsigned long max_nElem; - -public: - - /*! - * \brief Constructor of the class. - */ - CSysMatrix(void); - - /*! - * \brief Destructor of the class. - */ - ~CSysMatrix(void); - - /*! - * \brief Initializes space matrix system. - * \param[in] nVar - Number of variables. - * \param[in] nEqn - Number of equations. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void Initialize(unsigned long nPoint, unsigned long nPointDomain, unsigned short nVar, unsigned short nEqn, - bool EdgeConnect, CGeometry *geometry, CConfig *config); - - /*! - * \brief Assigns values to the sparse-matrix structure. - * \param[in] val_nPoint - Number of points in the nPoint x nPoint block structure - * \param[in] val_nVar - Number of nVar x nVar variables in each subblock of the matrix-by-block structure. - * \param[in] val_nEq - Number of nEqn x nVar variables in each subblock of the matrix-by-block structure. - * \param[in] val_row_ptr - Pointers to the first element in each row. - * \param[in] val_col_ind - Column index for each of the elements in val(). - * \param[in] val_nnz - Number of possible nonzero entries in the matrix. - * \param[in] config - Definition of the particular problem. - */ - void SetIndexes(unsigned long val_nPoint, unsigned long val_nPointDomain, unsigned short val_nVar, unsigned short val_nEq, unsigned long* val_row_ptr, unsigned long* val_col_ind, unsigned long val_nnz, CConfig *config); - - /*! - * \brief Sets to zero all the entries of the sparse matrix. - */ - void SetValZero(void); - - /*! - * \brief Copies the block (i, j) of the matrix-by-blocks structure in the internal variable *block. - * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. - * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. - */ - su2double *GetBlock(unsigned long block_i, unsigned long block_j); - - /*! - * \brief Copies the block (i, j) of the matrix-by-blocks structure in the internal variable *block. - * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. - * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. - */ - su2double GetBlock(unsigned long block_i, unsigned long block_j, unsigned short iVar, unsigned short jVar); - - /*! - * \brief Set the value of a block in the sparse matrix. - * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. - * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. - * \param[in] **val_block - Block to set to A(i, j). - */ - void SetBlock(unsigned long block_i, unsigned long block_j, su2double **val_block); - - /*! - * \brief Set the value of a block in the sparse matrix. - * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. - * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. - * \param[in] **val_block - Block to set to A(i, j). - */ - void SetBlock(unsigned long block_i, unsigned long block_j, su2double *val_block); - - /*! - * \brief Adds the specified block to the sparse matrix. - * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. - * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. - * \param[in] **val_block - Block to add to A(i, j). - */ - void AddBlock(unsigned long block_i, unsigned long block_j, su2double **val_block); - - /*! - * \brief Subtracts the specified block to the sparse matrix. - * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. - * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. - * \param[in] **val_block - Block to subtract to A(i, j). - */ - void SubtractBlock(unsigned long block_i, unsigned long block_j, su2double **val_block); - - /*! - * \brief Copies the block (i, j) of the matrix-by-blocks structure in the internal variable *block. - * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. - * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. - */ - su2double *GetBlock_ILUMatrix(unsigned long block_i, unsigned long block_j); - - /*! - * \brief Set the value of a block in the sparse matrix. - * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. - * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. - * \param[in] **val_block - Block to set to A(i, j). - */ - void SetBlock_ILUMatrix(unsigned long block_i, unsigned long block_j, su2double *val_block); - - - /*! - * \brief Set the transposed value of a block in the sparse matrix. - * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. - * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. - * \param[in] **val_block - Block to set to A(i, j). - */ - void SetBlockTransposed_ILUMatrix(unsigned long block_i, unsigned long block_j, su2double *val_block); - - /*! - * \brief Subtracts the specified block to the sparse matrix. - * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. - * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. - * \param[in] **val_block - Block to subtract to A(i, j). - */ - void SubtractBlock_ILUMatrix(unsigned long block_i, unsigned long block_j, su2double *val_block); - - /*! - * \brief Adds the specified value to the diagonal of the (i, i) subblock - * of the matrix-by-blocks structure. - * \param[in] block_i - Index of the block in the matrix-by-blocks structure. - * \param[in] val_matrix - Value to add to the diagonal elements of A(i, i). - */ - void AddVal2Diag(unsigned long block_i, su2double val_matrix); - - /*! - * \brief Sets the specified value to the diagonal of the (i, i) subblock - * of the matrix-by-blocks structure. - * \param[in] block_i - Index of the block in the matrix-by-blocks structure. - * \param[in] val_matrix - Value to add to the diagonal elements of A(i, i). - */ - void SetVal2Diag(unsigned long block_i, su2double val_matrix); - - /*! - * \brief Calculates the matrix-vector product - * \param[in] matrix - * \param[in] vector - * \param[out] product - */ - void MatrixVectorProduct(su2double *matrix, su2double *vector, su2double *product); - - /*! - * \brief Calculates the matrix-matrix product - * \param[in] matrix_a - * \param[in] matrix_b - * \param[out] product - */ - void MatrixMatrixProduct(su2double *matrix_a, su2double *matrix_b, su2double *product); - - /*! - * \brief Deletes the values of the row i of the sparse matrix. - * \param[in] i - Index of the row. - */ - void DeleteValsRowi(unsigned long i); - - /*! - * \brief Performs the Gauss Elimination algorithm to solve the linear subsystem of the (i, i) subblock and rhs. - * \param[in] block_i - Index of the (i, i) subblock in the matrix-by-blocks structure. - * \param[in] rhs - Right-hand-side of the linear system. - * \param[in] transposed - If true the transposed of the block is used (default = false). - * \return Solution of the linear system (overwritten on rhs). - */ - void Gauss_Elimination(unsigned long block_i, su2double* rhs, bool transposed = false); - - /*! - * \brief Performs the Gauss Elimination algorithm to solve the linear subsystem of the (i, i) subblock and rhs. - * \param[in] Block - matrix-by-blocks structure. - * \param[in] rhs - Right-hand-side of the linear system. - * \return Solution of the linear system (overwritten on rhs). - */ - void Gauss_Elimination(su2double* Block, su2double* rhs); - - /*! - * \brief Performs the Gauss Elimination algorithm to solve the linear subsystem of the (i, i) subblock and rhs. - * \param[in] block_i - Index of the (i, i) subblock in the matrix-by-blocks structure. - * \param[in] rhs - Right-hand-side of the linear system. - * \return Solution of the linear system (overwritten on rhs). - */ - void Gauss_Elimination_ILUMatrix(unsigned long block_i, su2double* rhs); - - /*! - * \fn void CSysMatrix::ProdBlockVector(unsigned long block_i, unsigned long block_j, su2double* vec); - * \brief Performs the product of the block (i, j) by vector vec. - * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. - * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. - * \param[in] vec - Vector to be multiplied by the block (i, j) of the sparse matrix A. - * \return Product of A(i, j) by vector *vec (stored at *prod_block_vector). - */ - void ProdBlockVector(unsigned long block_i, unsigned long block_j, const CSysVector & vec); - - /*! - * \brief Performs the product of i-th row of the upper part of a sparse matrix by a vector. - * \param[in] vec - Vector to be multiplied by the upper part of the sparse matrix A. - * \param[in] row_i - Row of the matrix to be multiplied by vector vec. - * \return prod Result of the product U(A)*vec (stored at *prod_row_vector). - */ - void UpperProduct(CSysVector & vec, unsigned long row_i); - - /*! - * \brief Performs the product of i-th row of the lower part of a sparse matrix by a vector. - * \param[in] vec - Vector to be multiplied by the lower part of the sparse matrix A. - * \param[in] row_i - Row of the matrix to be multiplied by vector vec. - * \return prod Result of the product L(A)*vec (stored at *prod_row_vector). - */ - void LowerProduct(CSysVector & vec, unsigned long row_i); - - /*! - * \brief Performs the product of i-th row of the diagonal part of a sparse matrix by a vector. - * \param[in] vec - Vector to be multiplied by the diagonal part of the sparse matrix A. - * \param[in] row_i - Row of the matrix to be multiplied by vector vec. - * \return prod Result of the product D(A)*vec (stored at *prod_row_vector). - */ - void DiagonalProduct(CSysVector & vec, unsigned long row_i); - - /*! - * \brief Send receive the solution using MPI. - * \param[in] x - Solution.. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SendReceive_Solution(CSysVector & x, CGeometry *geometry, CConfig *config); - - /*! - * \brief Send receive the solution using MPI and the transposed structure of the matrix. - * \param[in] x - Solution.. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SendReceive_SolutionTransposed(CSysVector & x, CGeometry *geometry, CConfig *config); - - /*! - * \brief Performs the product of i-th row of a sparse matrix by a vector. - * \param[in] vec - Vector to be multiplied by the row of the sparse matrix A. - * \param[in] row_i - Row of the matrix to be multiplied by vector vec. - * \return Result of the product (stored at *prod_row_vector). - */ - void RowProduct(const CSysVector & vec, unsigned long row_i); - - /*! - * \brief Performs the product of a sparse matrix by a vector. - * \param[in] vec - Vector to be multiplied by the sparse matrix A. - * \param[out] prod - Result of the product. - * \return Result of the product A*vec. - */ - void MatrixVectorProduct(const CSysVector & vec, CSysVector & prod); - - /*! - * \brief Performs the product of a sparse matrix by a CSysVector. - * \param[in] vec - CSysVector to be multiplied by the sparse matrix A. - * \param[out] prod - Result of the product. - */ - void MatrixVectorProduct(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config); - - /*! - * \brief Performs the product of a sparse matrix by a CSysVector. - * \param[in] vec - CSysVector to be multiplied by the sparse matrix A. - * \param[out] prod - Result of the product. - */ - void MatrixVectorProductTransposed(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config); - - /*! - * \brief Performs the product of two block matrices. - */ - void GetMultBlockBlock(su2double *c, su2double *a, su2double *b); - - /*! - * \brief Performs the product of a block matrices by a vector. - */ - void GetMultBlockVector(su2double *c, su2double *a, su2double *b); - - /*! - * \brief Performs the subtraction of two matrices. - */ - void GetSubsBlock(su2double *c, su2double *a, su2double *b); - - /*! - * \brief Performs the subtraction of two vectors. - */ - void GetSubsVector(su2double *c, su2double *a, su2double *b); - - /*! - * \brief Inverse diagonal block. - * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. - * \param[out] invBlock - Inverse block. - */ - void InverseDiagonalBlock(unsigned long block_i, su2double *invBlock, bool transpose = false); - - /*! - * \brief Inverse diagonal block. - * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. - * \param[out] invBlock - Inverse block. - */ - void InverseDiagonalBlock_ILUMatrix(unsigned long block_i, su2double *invBlock); - - /*! - * \brief Inverse a block. - * \param[in] Block - block matrix. - * \param[out] invBlock - Inverse block. - */ - void InverseBlock(su2double *Block, su2double *invBlock); - - /*! - * \brief Build the Jacobi preconditioner. - */ - void BuildJacobiPreconditioner(bool transpose = false); - - /*! - * \brief Multiply CSysVector by the preconditioner - * \param[in] vec - CSysVector to be multiplied by the preconditioner. - * \param[out] prod - Result of the product A*vec. - */ - void ComputeJacobiPreconditioner(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config); - - /*! - * \brief Apply Jacobi as a classical iterative smoother - * \param[in] b - CSysVector containing the residual (b) - * \param[in] x - CSysVector containing the solution (x^k) - * \param[in] mat_vec - object that defines matrix-vector product - * \param[in] tol - tolerance with which to solve the system - * \param[in] m - maximum size of the search subspace - * \param[in] monitoring - turn on priting residuals from solver to screen. - * \param[out] x - CSysVector containing the result of the smoothing (x^k+1 = x^k + M^-1*(b - A*x^k). - */ - unsigned long Jacobi_Smoother(const CSysVector & b, CSysVector & x, CMatrixVectorProduct & mat_vec, su2double tol, unsigned long m, su2double *residual, bool monitoring, CGeometry *geometry, CConfig *config); - - /*! - * \brief Build the ILU0 preconditioner. - * \param[in] transposed - Flag to use the transposed matrix to construct the preconditioner. - */ - void BuildILUPreconditioner(bool transposed = false); - - /*! - * \brief Multiply CSysVector by the preconditioner - * \param[in] vec - CSysVector to be multiplied by the preconditioner. - * \param[out] prod - Result of the product A*vec. - */ - void ComputeILUPreconditioner(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config); - - /*! - * \brief Apply ILU0 as a classical iterative smoother - * \param[in] b - CSysVector containing the residual (b) - * \param[in] x - CSysVector containing the solution (x^k) - * \param[in] mat_vec - object that defines matrix-vector product - * \param[in] tol - tolerance with which to solve the system - * \param[in] m - maximum size of the search subspace - * \param[in] monitoring - turn on priting residuals from solver to screen. - * \param[out] x - CSysVector containing the result of the smoothing (x^k+1 = x^k + M^-1*(b - A*x^k). - */ - unsigned long ILU0_Smoother(const CSysVector & b, CSysVector & x, CMatrixVectorProduct & mat_vec, su2double tol, unsigned long m, su2double *residual, bool monitoring, CGeometry *geometry, CConfig *config); - - /*! - * \brief Multiply CSysVector by the preconditioner - * \param[in] vec - CSysVector to be multiplied by the preconditioner. - * \param[out] prod - Result of the product A*vec. - */ - void ComputeLU_SGSPreconditioner(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config); - -/*! - * \brief Apply LU_SGS as a classical iterative smoother - * \param[in] b - CSysVector containing the residual (b) - * \param[in] x - CSysVector containing the solution (x^k) - * \param[in] mat_vec - object that defines matrix-vector product - * \param[in] tol - tolerance with which to solve the system - * \param[in] m - maximum size of the search subspace - * \param[in] monitoring - turn on priting residuals from solver to screen. - * \param[out] x - CSysVector containing the result of the smoothing (x^k+1 = x^k + M^-1*(b - A*x^k). - */ - unsigned long LU_SGS_Smoother(const CSysVector & b, CSysVector & x, CMatrixVectorProduct & mat_vec, su2double tol, unsigned long m, su2double *residual, bool monitoring, CGeometry *geometry, CConfig *config); - - /*! - * \brief Build the Linelet preconditioner. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - unsigned short BuildLineletPreconditioner(CGeometry *geometry, CConfig *config); - - /*! - * \brief Multiply CSysVector by the preconditioner - * \param[in] vec - CSysVector to be multiplied by the preconditioner. - * \param[out] prod - Result of the product A*vec. - */ - void ComputeLineletPreconditioner(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config); - - /*! - * \brief Compute the residual Ax-b - * \param[in] sol - CSysVector to be multiplied by the preconditioner. - * \param[in] f - Result of the product A*vec. - * \param[out] res - Result of the product A*vec. - */ - void ComputeResidual(const CSysVector & sol, const CSysVector & f, CSysVector & res); - -}; - -/*! - * \class CSysMatrixVectorProduct - * \brief specialization of matrix-vector product that uses CSysMatrix class - */ -class CSysMatrixVectorProduct : public CMatrixVectorProduct { -private: - CSysMatrix* sparse_matrix; /*!< \brief pointer to matrix that defines the product. */ - CGeometry* geometry; /*!< \brief pointer to matrix that defines the geometry. */ - CConfig* config; /*!< \brief pointer to matrix that defines the config. */ - -public: - - /*! - * \brief constructor of the class - * \param[in] matrix_ref - matrix reference that will be used to define the products - */ - CSysMatrixVectorProduct(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref); - - /*! - * \brief destructor of the class - */ - ~CSysMatrixVectorProduct() {} - - /*! - * \brief operator that defines the CSysMatrix-CSysVector product - * \param[in] u - CSysVector that is being multiplied by the sparse matrix - * \param[out] v - CSysVector that is the result of the product - */ - void operator()(const CSysVector & u, CSysVector & v) const; -}; - -/*! - * \class CSysMatrixVectorProduct - * \brief specialization of matrix-vector product that uses CSysMatrix class - */ -class CSysMatrixVectorProductTransposed : public CMatrixVectorProduct { -private: - CSysMatrix* sparse_matrix; /*!< \brief pointer to matrix that defines the product. */ - CGeometry* geometry; /*!< \brief pointer to matrix that defines the geometry. */ - CConfig* config; /*!< \brief pointer to matrix that defines the config. */ - -public: - - /*! - * \brief constructor of the class - * \param[in] matrix_ref - matrix reference that will be used to define the products - */ - CSysMatrixVectorProductTransposed(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref); - - /*! - * \brief destructor of the class - */ - ~CSysMatrixVectorProductTransposed() {} - - /*! - * \brief operator that defines the CSysMatrix-CSysVector product - * \param[in] u - CSysVector that is being multiplied by the sparse matrix - * \param[out] v - CSysVector that is the result of the product - */ - void operator()(const CSysVector & u, CSysVector & v) const; -}; - -/*! - * \class CJacobiPreconditioner - * \brief specialization of preconditioner that uses CSysMatrix class - */ -class CJacobiPreconditioner : public CPreconditioner { -private: - CSysMatrix* sparse_matrix; /*!< \brief pointer to matrix that defines the preconditioner. */ - CGeometry* geometry; /*!< \brief pointer to matrix that defines the geometry. */ - CConfig* config; /*!< \brief pointer to matrix that defines the config. */ - -public: - - /*! - * \brief constructor of the class - * \param[in] matrix_ref - matrix reference that will be used to define the preconditioner - */ - CJacobiPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref); - - /*! - * \brief destructor of the class - */ - ~CJacobiPreconditioner() {} - - /*! - * \brief operator that defines the preconditioner operation - * \param[in] u - CSysVector that is being preconditioned - * \param[out] v - CSysVector that is the result of the preconditioning - */ - void operator()(const CSysVector & u, CSysVector & v) const; -}; - -/*! - * \class CJacobiTransposedPreconditioner - * \brief specialization of preconditioner that uses CSysMatrix class - */ -class CJacobiTransposedPreconditioner : public CPreconditioner { -private: - CSysMatrix* sparse_matrix; /*!< \brief pointer to matrix that defines the preconditioner. */ - CGeometry* geometry; /*!< \brief pointer to matrix that defines the geometry. */ - CConfig* config; /*!< \brief pointer to matrix that defines the config. */ - -public: - - /*! - * \brief constructor of the class - * \param[in] matrix_ref - matrix reference that will be used to define the preconditioner - */ - CJacobiTransposedPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref); - - /*! - * \brief destructor of the class - */ - ~CJacobiTransposedPreconditioner() {} - - /*! - * \brief operator that defines the preconditioner operation - * \param[in] u - CSysVector that is being preconditioned - * \param[out] v - CSysVector that is the result of the preconditioning - */ - void operator()(const CSysVector & u, CSysVector & v) const; -}; - -/*! - * \class CILUPreconditioner - * \brief specialization of preconditioner that uses CSysMatrix class - */ -class CILUPreconditioner : public CPreconditioner { -private: - CSysMatrix* sparse_matrix; /*!< \brief pointer to matrix that defines the preconditioner. */ - CGeometry* geometry; /*!< \brief pointer to matrix that defines the geometry. */ - CConfig* config; /*!< \brief pointer to matrix that defines the config. */ - -public: - - /*! - * \brief constructor of the class - * \param[in] matrix_ref - matrix reference that will be used to define the preconditioner - */ - CILUPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref); - - /*! - * \brief destructor of the class - */ - ~CILUPreconditioner() {} - - /*! - * \brief operator that defines the preconditioner operation - * \param[in] u - CSysVector that is being preconditioned - * \param[out] v - CSysVector that is the result of the preconditioning - */ - void operator()(const CSysVector & u, CSysVector & v) const; -}; - -/*! - * \class CLU_SGSPreconditioner - * \brief specialization of preconditioner that uses CSysMatrix class - */ -class CLU_SGSPreconditioner : public CPreconditioner { -private: - CSysMatrix* sparse_matrix; /*!< \brief pointer to matrix that defines the preconditioner. */ - CGeometry* geometry; /*!< \brief pointer to matrix that defines the geometry. */ - CConfig* config; /*!< \brief pointer to matrix that defines the config. */ - -public: - - /*! - * \brief constructor of the class - * \param[in] matrix_ref - matrix reference that will be used to define the preconditioner - */ - CLU_SGSPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref); - - /*! - * \brief destructor of the class - */ - ~CLU_SGSPreconditioner() {} - - /*! - * \brief operator that defines the preconditioner operation - * \param[in] u - CSysVector that is being preconditioned - * \param[out] v - CSysVector that is the result of the preconditioning - */ - void operator()(const CSysVector & u, CSysVector & v) const; -}; - -/*! - * \class CLineletPreconditioner - * \brief specialization of preconditioner that uses CSysMatrix class - */ -class CLineletPreconditioner : public CPreconditioner { -private: - CSysMatrix* sparse_matrix; /*!< \brief pointer to matrix that defines the preconditioner. */ - CGeometry* geometry; /*!< \brief pointer to matrix that defines the geometry. */ - CConfig* config; /*!< \brief pointer to matrix that defines the config. */ - -public: - - /*! - * \brief constructor of the class - * \param[in] matrix_ref - matrix reference that will be used to define the preconditioner - */ - CLineletPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref); - - /*! - * \brief destructor of the class - */ - ~CLineletPreconditioner() {} - - /*! - * \brief operator that defines the preconditioner operation - * \param[in] u - CSysVector that is being preconditioned - * \param[out] v - CSysVector that is the result of the preconditioning - */ - void operator()(const CSysVector & u, CSysVector & v) const; -}; - -#include "matrix_structure.inl" +/*! + * \file matrix_structure.hpp + * \brief Headers of the main subroutines for creating the sparse matrices-by-blocks. + * The subroutines and functions are in the matrix_structure.cpp file. + * \author F. Palacios, A. Bueno, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +#include "./mpi_structure.hpp" +#include +#include +#include +#include + +#include "config_structure.hpp" +#include "geometry_structure.hpp" +#include "vector_structure.hpp" + +using namespace std; + +const su2double eps = numeric_limits::epsilon(); /*!< \brief machine epsilon */ + + +/*! + * \class CSysMatrix + * \brief Main class for defining sparse matrices-by-blocks + with compressed row format. + * \author A. Bueno, F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CSysMatrix { +private: + unsigned long nPoint, /*!< \brief Number of points in the grid. */ + nPointDomain, /*!< \brief Number of points in the grid. */ + nVar, /*!< \brief Number of variables. */ + nEqn; /*!< \brief Number of equations. */ + su2double *matrix; /*!< \brief Entries of the sparse matrix. */ + su2double *ILU_matrix; /*!< \brief Entries of the ILU sparse matrix. */ + unsigned long *row_ptr; /*!< \brief Pointers to the first element in each row. */ + unsigned long *col_ind; /*!< \brief Column index for each of the elements in val(). */ + unsigned long nnz; /*!< \brief Number of possible nonzero entries in the matrix. */ + su2double *block; /*!< \brief Internal array to store a subblock of the matrix. */ + su2double *block_inverse; /*!< \brief Internal array to store a subblock of the matrix. */ + su2double *block_weight; /*!< \brief Internal array to store a subblock of the matrix. */ + su2double *prod_block_vector; /*!< \brief Internal array to store the product of a subblock with a vector. */ + su2double *prod_row_vector; /*!< \brief Internal array to store the product of a matrix-by-blocks "row" with a vector. */ + su2double *aux_vector; /*!< \brief Auxiliary array to store intermediate results. */ + su2double *sum_vector; /*!< \brief Auxiliary array to store intermediate results. */ + su2double *invM; /*!< \brief Inverse of (Jacobi) preconditioner. */ + + bool *LineletBool; /*!< \brief Identify if a point belong to a linelet. */ + vector *LineletPoint; /*!< \brief Linelet structure. */ + unsigned long nLinelet; /*!< \brief Number of Linelets in the system. */ + su2double **UBlock, **invUBlock, **LBlock, + **yVector, **zVector, **rVector, *LFBlock, + *LyVector, *FzVector; /*!< \brief Arrays of the Linelet preconditioner methodology. */ + unsigned long max_nElem; + +public: + + /*! + * \brief Constructor of the class. + */ + CSysMatrix(void); + + /*! + * \brief Destructor of the class. + */ + ~CSysMatrix(void); + + /*! + * \brief Initializes space matrix system. + * \param[in] nVar - Number of variables. + * \param[in] nEqn - Number of equations. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void Initialize(unsigned long nPoint, unsigned long nPointDomain, unsigned short nVar, unsigned short nEqn, + bool EdgeConnect, CGeometry *geometry, CConfig *config); + + /*! + * \brief Assigns values to the sparse-matrix structure. + * \param[in] val_nPoint - Number of points in the nPoint x nPoint block structure + * \param[in] val_nVar - Number of nVar x nVar variables in each subblock of the matrix-by-block structure. + * \param[in] val_nEq - Number of nEqn x nVar variables in each subblock of the matrix-by-block structure. + * \param[in] val_row_ptr - Pointers to the first element in each row. + * \param[in] val_col_ind - Column index for each of the elements in val(). + * \param[in] val_nnz - Number of possible nonzero entries in the matrix. + * \param[in] config - Definition of the particular problem. + */ + void SetIndexes(unsigned long val_nPoint, unsigned long val_nPointDomain, unsigned short val_nVar, unsigned short val_nEq, unsigned long* val_row_ptr, unsigned long* val_col_ind, unsigned long val_nnz, CConfig *config); + + /*! + * \brief Sets to zero all the entries of the sparse matrix. + */ + void SetValZero(void); + + /*! + * \brief Copies the block (i, j) of the matrix-by-blocks structure in the internal variable *block. + * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. + * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. + */ + su2double *GetBlock(unsigned long block_i, unsigned long block_j); + + /*! + * \brief Copies the block (i, j) of the matrix-by-blocks structure in the internal variable *block. + * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. + * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. + */ + su2double GetBlock(unsigned long block_i, unsigned long block_j, unsigned short iVar, unsigned short jVar); + + /*! + * \brief Set the value of a block in the sparse matrix. + * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. + * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. + * \param[in] **val_block - Block to set to A(i, j). + */ + void SetBlock(unsigned long block_i, unsigned long block_j, su2double **val_block); + + /*! + * \brief Set the value of a block in the sparse matrix. + * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. + * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. + * \param[in] **val_block - Block to set to A(i, j). + */ + void SetBlock(unsigned long block_i, unsigned long block_j, su2double *val_block); + + /*! + * \brief Adds the specified block to the sparse matrix. + * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. + * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. + * \param[in] **val_block - Block to add to A(i, j). + */ + void AddBlock(unsigned long block_i, unsigned long block_j, su2double **val_block); + + /*! + * \brief Subtracts the specified block to the sparse matrix. + * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. + * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. + * \param[in] **val_block - Block to subtract to A(i, j). + */ + void SubtractBlock(unsigned long block_i, unsigned long block_j, su2double **val_block); + + /*! + * \brief Copies the block (i, j) of the matrix-by-blocks structure in the internal variable *block. + * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. + * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. + */ + su2double *GetBlock_ILUMatrix(unsigned long block_i, unsigned long block_j); + + /*! + * \brief Set the value of a block in the sparse matrix. + * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. + * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. + * \param[in] **val_block - Block to set to A(i, j). + */ + void SetBlock_ILUMatrix(unsigned long block_i, unsigned long block_j, su2double *val_block); + + + /*! + * \brief Set the transposed value of a block in the sparse matrix. + * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. + * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. + * \param[in] **val_block - Block to set to A(i, j). + */ + void SetBlockTransposed_ILUMatrix(unsigned long block_i, unsigned long block_j, su2double *val_block); + + /*! + * \brief Subtracts the specified block to the sparse matrix. + * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. + * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. + * \param[in] **val_block - Block to subtract to A(i, j). + */ + void SubtractBlock_ILUMatrix(unsigned long block_i, unsigned long block_j, su2double *val_block); + + /*! + * \brief Adds the specified value to the diagonal of the (i, i) subblock + * of the matrix-by-blocks structure. + * \param[in] block_i - Index of the block in the matrix-by-blocks structure. + * \param[in] val_matrix - Value to add to the diagonal elements of A(i, i). + */ + void AddVal2Diag(unsigned long block_i, su2double val_matrix); + + /*! + * \brief Sets the specified value to the diagonal of the (i, i) subblock + * of the matrix-by-blocks structure. + * \param[in] block_i - Index of the block in the matrix-by-blocks structure. + * \param[in] val_matrix - Value to add to the diagonal elements of A(i, i). + */ + void SetVal2Diag(unsigned long block_i, su2double val_matrix); + + /*! + * \brief Calculates the matrix-vector product + * \param[in] matrix + * \param[in] vector + * \param[out] product + */ + void MatrixVectorProduct(su2double *matrix, su2double *vector, su2double *product); + + /*! + * \brief Calculates the matrix-matrix product + * \param[in] matrix_a + * \param[in] matrix_b + * \param[out] product + */ + void MatrixMatrixProduct(su2double *matrix_a, su2double *matrix_b, su2double *product); + + /*! + * \brief Deletes the values of the row i of the sparse matrix. + * \param[in] i - Index of the row. + */ + void DeleteValsRowi(unsigned long i); + + /*! + * \brief Performs the Gauss Elimination algorithm to solve the linear subsystem of the (i, i) subblock and rhs. + * \param[in] block_i - Index of the (i, i) subblock in the matrix-by-blocks structure. + * \param[in] rhs - Right-hand-side of the linear system. + * \param[in] transposed - If true the transposed of the block is used (default = false). + * \return Solution of the linear system (overwritten on rhs). + */ + void Gauss_Elimination(unsigned long block_i, su2double* rhs, bool transposed = false); + + /*! + * \brief Performs the Gauss Elimination algorithm to solve the linear subsystem of the (i, i) subblock and rhs. + * \param[in] Block - matrix-by-blocks structure. + * \param[in] rhs - Right-hand-side of the linear system. + * \return Solution of the linear system (overwritten on rhs). + */ + void Gauss_Elimination(su2double* Block, su2double* rhs); + + /*! + * \brief Performs the Gauss Elimination algorithm to solve the linear subsystem of the (i, i) subblock and rhs. + * \param[in] block_i - Index of the (i, i) subblock in the matrix-by-blocks structure. + * \param[in] rhs - Right-hand-side of the linear system. + * \return Solution of the linear system (overwritten on rhs). + */ + void Gauss_Elimination_ILUMatrix(unsigned long block_i, su2double* rhs); + + /*! + * \fn void CSysMatrix::ProdBlockVector(unsigned long block_i, unsigned long block_j, su2double* vec); + * \brief Performs the product of the block (i, j) by vector vec. + * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. + * \param[in] block_j - Indexes of the block in the matrix-by-blocks structure. + * \param[in] vec - Vector to be multiplied by the block (i, j) of the sparse matrix A. + * \return Product of A(i, j) by vector *vec (stored at *prod_block_vector). + */ + void ProdBlockVector(unsigned long block_i, unsigned long block_j, const CSysVector & vec); + + /*! + * \brief Performs the product of i-th row of the upper part of a sparse matrix by a vector. + * \param[in] vec - Vector to be multiplied by the upper part of the sparse matrix A. + * \param[in] row_i - Row of the matrix to be multiplied by vector vec. + * \return prod Result of the product U(A)*vec (stored at *prod_row_vector). + */ + void UpperProduct(CSysVector & vec, unsigned long row_i); + + /*! + * \brief Performs the product of i-th row of the lower part of a sparse matrix by a vector. + * \param[in] vec - Vector to be multiplied by the lower part of the sparse matrix A. + * \param[in] row_i - Row of the matrix to be multiplied by vector vec. + * \return prod Result of the product L(A)*vec (stored at *prod_row_vector). + */ + void LowerProduct(CSysVector & vec, unsigned long row_i); + + /*! + * \brief Performs the product of i-th row of the diagonal part of a sparse matrix by a vector. + * \param[in] vec - Vector to be multiplied by the diagonal part of the sparse matrix A. + * \param[in] row_i - Row of the matrix to be multiplied by vector vec. + * \return prod Result of the product D(A)*vec (stored at *prod_row_vector). + */ + void DiagonalProduct(CSysVector & vec, unsigned long row_i); + + /*! + * \brief Send receive the solution using MPI. + * \param[in] x - Solution.. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SendReceive_Solution(CSysVector & x, CGeometry *geometry, CConfig *config); + + /*! + * \brief Send receive the solution using MPI and the transposed structure of the matrix. + * \param[in] x - Solution.. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SendReceive_SolutionTransposed(CSysVector & x, CGeometry *geometry, CConfig *config); + + /*! + * \brief Performs the product of i-th row of a sparse matrix by a vector. + * \param[in] vec - Vector to be multiplied by the row of the sparse matrix A. + * \param[in] row_i - Row of the matrix to be multiplied by vector vec. + * \return Result of the product (stored at *prod_row_vector). + */ + void RowProduct(const CSysVector & vec, unsigned long row_i); + + /*! + * \brief Performs the product of a sparse matrix by a vector. + * \param[in] vec - Vector to be multiplied by the sparse matrix A. + * \param[out] prod - Result of the product. + * \return Result of the product A*vec. + */ + void MatrixVectorProduct(const CSysVector & vec, CSysVector & prod); + + /*! + * \brief Performs the product of a sparse matrix by a CSysVector. + * \param[in] vec - CSysVector to be multiplied by the sparse matrix A. + * \param[out] prod - Result of the product. + */ + void MatrixVectorProduct(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config); + + /*! + * \brief Performs the product of a sparse matrix by a CSysVector. + * \param[in] vec - CSysVector to be multiplied by the sparse matrix A. + * \param[out] prod - Result of the product. + */ + void MatrixVectorProductTransposed(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config); + + /*! + * \brief Performs the product of two block matrices. + */ + void GetMultBlockBlock(su2double *c, su2double *a, su2double *b); + + /*! + * \brief Performs the product of a block matrices by a vector. + */ + void GetMultBlockVector(su2double *c, su2double *a, su2double *b); + + /*! + * \brief Performs the subtraction of two matrices. + */ + void GetSubsBlock(su2double *c, su2double *a, su2double *b); + + /*! + * \brief Performs the subtraction of two vectors. + */ + void GetSubsVector(su2double *c, su2double *a, su2double *b); + + /*! + * \brief Inverse diagonal block. + * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. + * \param[out] invBlock - Inverse block. + */ + void InverseDiagonalBlock(unsigned long block_i, su2double *invBlock, bool transpose = false); + + /*! + * \brief Inverse diagonal block. + * \param[in] block_i - Indexes of the block in the matrix-by-blocks structure. + * \param[out] invBlock - Inverse block. + */ + void InverseDiagonalBlock_ILUMatrix(unsigned long block_i, su2double *invBlock); + + /*! + * \brief Inverse a block. + * \param[in] Block - block matrix. + * \param[out] invBlock - Inverse block. + */ + void InverseBlock(su2double *Block, su2double *invBlock); + + /*! + * \brief Build the Jacobi preconditioner. + */ + void BuildJacobiPreconditioner(bool transpose = false); + + /*! + * \brief Multiply CSysVector by the preconditioner + * \param[in] vec - CSysVector to be multiplied by the preconditioner. + * \param[out] prod - Result of the product A*vec. + */ + void ComputeJacobiPreconditioner(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config); + + /*! + * \brief Apply Jacobi as a classical iterative smoother + * \param[in] b - CSysVector containing the residual (b) + * \param[in] x - CSysVector containing the solution (x^k) + * \param[in] mat_vec - object that defines matrix-vector product + * \param[in] tol - tolerance with which to solve the system + * \param[in] m - maximum size of the search subspace + * \param[in] monitoring - turn on priting residuals from solver to screen. + * \param[out] x - CSysVector containing the result of the smoothing (x^k+1 = x^k + M^-1*(b - A*x^k). + */ + unsigned long Jacobi_Smoother(const CSysVector & b, CSysVector & x, CMatrixVectorProduct & mat_vec, su2double tol, unsigned long m, su2double *residual, bool monitoring, CGeometry *geometry, CConfig *config); + + /*! + * \brief Build the ILU0 preconditioner. + * \param[in] transposed - Flag to use the transposed matrix to construct the preconditioner. + */ + void BuildILUPreconditioner(bool transposed = false); + + /*! + * \brief Multiply CSysVector by the preconditioner + * \param[in] vec - CSysVector to be multiplied by the preconditioner. + * \param[out] prod - Result of the product A*vec. + */ + void ComputeILUPreconditioner(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config); + + /*! + * \brief Apply ILU0 as a classical iterative smoother + * \param[in] b - CSysVector containing the residual (b) + * \param[in] x - CSysVector containing the solution (x^k) + * \param[in] mat_vec - object that defines matrix-vector product + * \param[in] tol - tolerance with which to solve the system + * \param[in] m - maximum size of the search subspace + * \param[in] monitoring - turn on priting residuals from solver to screen. + * \param[out] x - CSysVector containing the result of the smoothing (x^k+1 = x^k + M^-1*(b - A*x^k). + */ + unsigned long ILU0_Smoother(const CSysVector & b, CSysVector & x, CMatrixVectorProduct & mat_vec, su2double tol, unsigned long m, su2double *residual, bool monitoring, CGeometry *geometry, CConfig *config); + + /*! + * \brief Multiply CSysVector by the preconditioner + * \param[in] vec - CSysVector to be multiplied by the preconditioner. + * \param[out] prod - Result of the product A*vec. + */ + void ComputeLU_SGSPreconditioner(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config); + +/*! + * \brief Apply LU_SGS as a classical iterative smoother + * \param[in] b - CSysVector containing the residual (b) + * \param[in] x - CSysVector containing the solution (x^k) + * \param[in] mat_vec - object that defines matrix-vector product + * \param[in] tol - tolerance with which to solve the system + * \param[in] m - maximum size of the search subspace + * \param[in] monitoring - turn on priting residuals from solver to screen. + * \param[out] x - CSysVector containing the result of the smoothing (x^k+1 = x^k + M^-1*(b - A*x^k). + */ + unsigned long LU_SGS_Smoother(const CSysVector & b, CSysVector & x, CMatrixVectorProduct & mat_vec, su2double tol, unsigned long m, su2double *residual, bool monitoring, CGeometry *geometry, CConfig *config); + + /*! + * \brief Build the Linelet preconditioner. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + unsigned short BuildLineletPreconditioner(CGeometry *geometry, CConfig *config); + + /*! + * \brief Multiply CSysVector by the preconditioner + * \param[in] vec - CSysVector to be multiplied by the preconditioner. + * \param[out] prod - Result of the product A*vec. + */ + void ComputeLineletPreconditioner(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config); + + /*! + * \brief Compute the residual Ax-b + * \param[in] sol - CSysVector to be multiplied by the preconditioner. + * \param[in] f - Result of the product A*vec. + * \param[out] res - Result of the product A*vec. + */ + void ComputeResidual(const CSysVector & sol, const CSysVector & f, CSysVector & res); + +}; + +/*! + * \class CSysMatrixVectorProduct + * \brief specialization of matrix-vector product that uses CSysMatrix class + */ +class CSysMatrixVectorProduct : public CMatrixVectorProduct { +private: + CSysMatrix* sparse_matrix; /*!< \brief pointer to matrix that defines the product. */ + CGeometry* geometry; /*!< \brief pointer to matrix that defines the geometry. */ + CConfig* config; /*!< \brief pointer to matrix that defines the config. */ + +public: + + /*! + * \brief constructor of the class + * \param[in] matrix_ref - matrix reference that will be used to define the products + */ + CSysMatrixVectorProduct(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref); + + /*! + * \brief destructor of the class + */ + ~CSysMatrixVectorProduct() {} + + /*! + * \brief operator that defines the CSysMatrix-CSysVector product + * \param[in] u - CSysVector that is being multiplied by the sparse matrix + * \param[out] v - CSysVector that is the result of the product + */ + void operator()(const CSysVector & u, CSysVector & v) const; +}; + +/*! + * \class CSysMatrixVectorProduct + * \brief specialization of matrix-vector product that uses CSysMatrix class + */ +class CSysMatrixVectorProductTransposed : public CMatrixVectorProduct { +private: + CSysMatrix* sparse_matrix; /*!< \brief pointer to matrix that defines the product. */ + CGeometry* geometry; /*!< \brief pointer to matrix that defines the geometry. */ + CConfig* config; /*!< \brief pointer to matrix that defines the config. */ + +public: + + /*! + * \brief constructor of the class + * \param[in] matrix_ref - matrix reference that will be used to define the products + */ + CSysMatrixVectorProductTransposed(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref); + + /*! + * \brief destructor of the class + */ + ~CSysMatrixVectorProductTransposed() {} + + /*! + * \brief operator that defines the CSysMatrix-CSysVector product + * \param[in] u - CSysVector that is being multiplied by the sparse matrix + * \param[out] v - CSysVector that is the result of the product + */ + void operator()(const CSysVector & u, CSysVector & v) const; +}; + +/*! + * \class CJacobiPreconditioner + * \brief specialization of preconditioner that uses CSysMatrix class + */ +class CJacobiPreconditioner : public CPreconditioner { +private: + CSysMatrix* sparse_matrix; /*!< \brief pointer to matrix that defines the preconditioner. */ + CGeometry* geometry; /*!< \brief pointer to matrix that defines the geometry. */ + CConfig* config; /*!< \brief pointer to matrix that defines the config. */ + +public: + + /*! + * \brief constructor of the class + * \param[in] matrix_ref - matrix reference that will be used to define the preconditioner + */ + CJacobiPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref); + + /*! + * \brief destructor of the class + */ + ~CJacobiPreconditioner() {} + + /*! + * \brief operator that defines the preconditioner operation + * \param[in] u - CSysVector that is being preconditioned + * \param[out] v - CSysVector that is the result of the preconditioning + */ + void operator()(const CSysVector & u, CSysVector & v) const; +}; + +/*! + * \class CJacobiTransposedPreconditioner + * \brief specialization of preconditioner that uses CSysMatrix class + */ +class CJacobiTransposedPreconditioner : public CPreconditioner { +private: + CSysMatrix* sparse_matrix; /*!< \brief pointer to matrix that defines the preconditioner. */ + CGeometry* geometry; /*!< \brief pointer to matrix that defines the geometry. */ + CConfig* config; /*!< \brief pointer to matrix that defines the config. */ + +public: + + /*! + * \brief constructor of the class + * \param[in] matrix_ref - matrix reference that will be used to define the preconditioner + */ + CJacobiTransposedPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref); + + /*! + * \brief destructor of the class + */ + ~CJacobiTransposedPreconditioner() {} + + /*! + * \brief operator that defines the preconditioner operation + * \param[in] u - CSysVector that is being preconditioned + * \param[out] v - CSysVector that is the result of the preconditioning + */ + void operator()(const CSysVector & u, CSysVector & v) const; +}; + +/*! + * \class CILUPreconditioner + * \brief specialization of preconditioner that uses CSysMatrix class + */ +class CILUPreconditioner : public CPreconditioner { +private: + CSysMatrix* sparse_matrix; /*!< \brief pointer to matrix that defines the preconditioner. */ + CGeometry* geometry; /*!< \brief pointer to matrix that defines the geometry. */ + CConfig* config; /*!< \brief pointer to matrix that defines the config. */ + +public: + + /*! + * \brief constructor of the class + * \param[in] matrix_ref - matrix reference that will be used to define the preconditioner + */ + CILUPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref); + + /*! + * \brief destructor of the class + */ + ~CILUPreconditioner() {} + + /*! + * \brief operator that defines the preconditioner operation + * \param[in] u - CSysVector that is being preconditioned + * \param[out] v - CSysVector that is the result of the preconditioning + */ + void operator()(const CSysVector & u, CSysVector & v) const; +}; + +/*! + * \class CLU_SGSPreconditioner + * \brief specialization of preconditioner that uses CSysMatrix class + */ +class CLU_SGSPreconditioner : public CPreconditioner { +private: + CSysMatrix* sparse_matrix; /*!< \brief pointer to matrix that defines the preconditioner. */ + CGeometry* geometry; /*!< \brief pointer to matrix that defines the geometry. */ + CConfig* config; /*!< \brief pointer to matrix that defines the config. */ + +public: + + /*! + * \brief constructor of the class + * \param[in] matrix_ref - matrix reference that will be used to define the preconditioner + */ + CLU_SGSPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref); + + /*! + * \brief destructor of the class + */ + ~CLU_SGSPreconditioner() {} + + /*! + * \brief operator that defines the preconditioner operation + * \param[in] u - CSysVector that is being preconditioned + * \param[out] v - CSysVector that is the result of the preconditioning + */ + void operator()(const CSysVector & u, CSysVector & v) const; +}; + +/*! + * \class CLineletPreconditioner + * \brief specialization of preconditioner that uses CSysMatrix class + */ +class CLineletPreconditioner : public CPreconditioner { +private: + CSysMatrix* sparse_matrix; /*!< \brief pointer to matrix that defines the preconditioner. */ + CGeometry* geometry; /*!< \brief pointer to matrix that defines the geometry. */ + CConfig* config; /*!< \brief pointer to matrix that defines the config. */ + +public: + + /*! + * \brief constructor of the class + * \param[in] matrix_ref - matrix reference that will be used to define the preconditioner + */ + CLineletPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref); + + /*! + * \brief destructor of the class + */ + ~CLineletPreconditioner() {} + + /*! + * \brief operator that defines the preconditioner operation + * \param[in] u - CSysVector that is being preconditioned + * \param[out] v - CSysVector that is the result of the preconditioning + */ + void operator()(const CSysVector & u, CSysVector & v) const; +}; + +#include "matrix_structure.inl" diff --git a/Common/include/matrix_structure.inl b/Common/include/matrix_structure.inl index 37a8f317f07..4a9c426ef4a 100644 --- a/Common/include/matrix_structure.inl +++ b/Common/include/matrix_structure.inl @@ -1,128 +1,128 @@ -/*! - * \file matrix_structure.inl - * \brief In-Line subroutines of the matrix_structure.hpp file. - * \author F. Palacios, A. Bueno, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -inline void CSysMatrix::SetValZero(void) { - for (unsigned long index = 0; index < nnz*nVar*nEqn; index++) - matrix[index] = 0.0; -} - -inline CSysMatrixVectorProduct::CSysMatrixVectorProduct(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref) { - sparse_matrix = &matrix_ref; - geometry = geometry_ref; - config = config_ref; -} - -inline void CSysMatrixVectorProduct::operator()(const CSysVector & u, CSysVector & v) const { - if (sparse_matrix == NULL) { - cerr << "CSysMatrixVectorProduct::operator()(const CSysVector &, CSysVector &): " << endl; - cerr << "pointer to sparse matrix is NULL." << endl; - throw(-1); - } - sparse_matrix->MatrixVectorProduct(u, v, geometry, config); -} - -inline CSysMatrixVectorProductTransposed::CSysMatrixVectorProductTransposed(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref) { - sparse_matrix = &matrix_ref; - geometry = geometry_ref; - config = config_ref; -} - -inline void CSysMatrixVectorProductTransposed::operator()(const CSysVector & u, CSysVector & v) const { - if (sparse_matrix == NULL) { - cerr << "CSysMatrixVectorProduct::operator()(const CSysVector &, CSysVector &): " << endl; - cerr << "pointer to sparse matrix is NULL." << endl; - throw(-1); - } - sparse_matrix->MatrixVectorProductTransposed(u, v, geometry, config); -} - - -inline CJacobiPreconditioner::CJacobiPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref) { - sparse_matrix = &matrix_ref; - geometry = geometry_ref; - config = config_ref; -} - -inline void CJacobiPreconditioner::operator()(const CSysVector & u, CSysVector & v) const { - if (sparse_matrix == NULL) { - cerr << "CJacobiPreconditioner::operator()(const CSysVector &, CSysVector &): " << endl; - cerr << "pointer to sparse matrix is NULL." << endl; - throw(-1); - } - sparse_matrix->ComputeJacobiPreconditioner(u, v, geometry, config); -} - -inline CILUPreconditioner::CILUPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref) { - sparse_matrix = &matrix_ref; - geometry = geometry_ref; - config = config_ref; -} - -inline void CILUPreconditioner::operator()(const CSysVector & u, CSysVector & v) const { - if (sparse_matrix == NULL) { - cerr << "CILUPreconditioner::operator()(const CSysVector &, CSysVector &): " << endl; - cerr << "pointer to sparse matrix is NULL." << endl; - throw(-1); - } - sparse_matrix->ComputeILUPreconditioner(u, v, geometry, config); -} - -inline CLU_SGSPreconditioner::CLU_SGSPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref) { - sparse_matrix = &matrix_ref; - geometry = geometry_ref; - config = config_ref; -} - -inline void CLU_SGSPreconditioner::operator()(const CSysVector & u, CSysVector & v) const { - if (sparse_matrix == NULL) { - cerr << "CLU_SGSPreconditioner::operator()(const CSysVector &, CSysVector &): " << endl; - cerr << "pointer to sparse matrix is NULL." << endl; - throw(-1); - } - sparse_matrix->ComputeLU_SGSPreconditioner(u, v, geometry, config); -} - -inline CLineletPreconditioner::CLineletPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref) { - sparse_matrix = &matrix_ref; - geometry = geometry_ref; - config = config_ref; -} - -inline void CLineletPreconditioner::operator()(const CSysVector & u, CSysVector & v) const { - if (sparse_matrix == NULL) { - cerr << "CLineletPreconditioner::operator()(const CSysVector &, CSysVector &): " << endl; - cerr << "pointer to sparse matrix is NULL." << endl; - throw(-1); - } - sparse_matrix->ComputeLineletPreconditioner(u, v, geometry, config); -} +/*! + * \file matrix_structure.inl + * \brief In-Line subroutines of the matrix_structure.hpp file. + * \author F. Palacios, A. Bueno, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +inline void CSysMatrix::SetValZero(void) { + for (unsigned long index = 0; index < nnz*nVar*nEqn; index++) + matrix[index] = 0.0; +} + +inline CSysMatrixVectorProduct::CSysMatrixVectorProduct(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref) { + sparse_matrix = &matrix_ref; + geometry = geometry_ref; + config = config_ref; +} + +inline void CSysMatrixVectorProduct::operator()(const CSysVector & u, CSysVector & v) const { + if (sparse_matrix == NULL) { + cerr << "CSysMatrixVectorProduct::operator()(const CSysVector &, CSysVector &): " << endl; + cerr << "pointer to sparse matrix is NULL." << endl; + throw(-1); + } + sparse_matrix->MatrixVectorProduct(u, v, geometry, config); +} + +inline CSysMatrixVectorProductTransposed::CSysMatrixVectorProductTransposed(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref) { + sparse_matrix = &matrix_ref; + geometry = geometry_ref; + config = config_ref; +} + +inline void CSysMatrixVectorProductTransposed::operator()(const CSysVector & u, CSysVector & v) const { + if (sparse_matrix == NULL) { + cerr << "CSysMatrixVectorProduct::operator()(const CSysVector &, CSysVector &): " << endl; + cerr << "pointer to sparse matrix is NULL." << endl; + throw(-1); + } + sparse_matrix->MatrixVectorProductTransposed(u, v, geometry, config); +} + + +inline CJacobiPreconditioner::CJacobiPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref) { + sparse_matrix = &matrix_ref; + geometry = geometry_ref; + config = config_ref; +} + +inline void CJacobiPreconditioner::operator()(const CSysVector & u, CSysVector & v) const { + if (sparse_matrix == NULL) { + cerr << "CJacobiPreconditioner::operator()(const CSysVector &, CSysVector &): " << endl; + cerr << "pointer to sparse matrix is NULL." << endl; + throw(-1); + } + sparse_matrix->ComputeJacobiPreconditioner(u, v, geometry, config); +} + +inline CILUPreconditioner::CILUPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref) { + sparse_matrix = &matrix_ref; + geometry = geometry_ref; + config = config_ref; +} + +inline void CILUPreconditioner::operator()(const CSysVector & u, CSysVector & v) const { + if (sparse_matrix == NULL) { + cerr << "CILUPreconditioner::operator()(const CSysVector &, CSysVector &): " << endl; + cerr << "pointer to sparse matrix is NULL." << endl; + throw(-1); + } + sparse_matrix->ComputeILUPreconditioner(u, v, geometry, config); +} + +inline CLU_SGSPreconditioner::CLU_SGSPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref) { + sparse_matrix = &matrix_ref; + geometry = geometry_ref; + config = config_ref; +} + +inline void CLU_SGSPreconditioner::operator()(const CSysVector & u, CSysVector & v) const { + if (sparse_matrix == NULL) { + cerr << "CLU_SGSPreconditioner::operator()(const CSysVector &, CSysVector &): " << endl; + cerr << "pointer to sparse matrix is NULL." << endl; + throw(-1); + } + sparse_matrix->ComputeLU_SGSPreconditioner(u, v, geometry, config); +} + +inline CLineletPreconditioner::CLineletPreconditioner(CSysMatrix & matrix_ref, CGeometry *geometry_ref, CConfig *config_ref) { + sparse_matrix = &matrix_ref; + geometry = geometry_ref; + config = config_ref; +} + +inline void CLineletPreconditioner::operator()(const CSysVector & u, CSysVector & v) const { + if (sparse_matrix == NULL) { + cerr << "CLineletPreconditioner::operator()(const CSysVector &, CSysVector &): " << endl; + cerr << "pointer to sparse matrix is NULL." << endl; + throw(-1); + } + sparse_matrix->ComputeLineletPreconditioner(u, v, geometry, config); +} diff --git a/Common/include/option_structure.hpp b/Common/include/option_structure.hpp index 9901cf29496..7ddb00c50a1 100644 --- a/Common/include/option_structure.hpp +++ b/Common/include/option_structure.hpp @@ -1,3079 +1,3079 @@ -/*! - * \file option_structure.hpp - * \brief Defines classes for referencing options for easy input in CConfig - * \author J. Hicken, B. Tracey - * \version 4.0.1 "Cardinal" - * - * Many of the classes in this file are templated, and therefore must - * be declared and defined here; to keep all elements together, there - * is no corresponding .cpp file at this time. - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -#include "./mpi_structure.hpp" - -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -/*! - * \class CCreateMap - * \brief creates a map from a list by overloading operator() - * \tparam T - the key type in the map - * \tparam U - the mapped value type in the map - * \author Boost.Assign and anonymous person on stackoverflow - * - * We need this to create static const maps that map strings to enum - * types. The implementation is based on the Boost.Assign library. This - * particular version is taken from - * http://stackoverflow.com/questions/138600/initializing-a-static-stdmapint-int-in-c - */ -template -class CCreateMap { -private: - std::map m_map; -public: - CCreateMap(const T& key, const U& val) { - m_map[key] = val; - } - CCreateMap& operator()(const T& key, const U& val) { - m_map[key] = val; - return *this; - } - operator std::map() { - return m_map; - } -}; - -/*! - * \brief utility function for converting strings to uppercase - * \param[in, out] str - string we want to convert - */ -inline void StringToUpperCase(string & str) { - std::transform(str.begin(), str.end(), str.begin(), ::toupper); -} - -/*! - * \brief utility function for converting strings to uppercase - * \param[in] str - string we want a copy of converted to uppercase - * \returns a copy of str in uppercase - */ -inline string StringToUpperCase(const string & str) { - string upp_str(str); - std::transform(upp_str.begin(), upp_str.end(), upp_str.begin(), ::toupper); - return upp_str; -} - -/*! - * \brief different software components of SU2 - */ -enum SU2_COMPONENT { - SU2_CFD = 1, /*!< \brief Running the SU2_CFD software. */ - SU2_DEF = 2, /*!< \brief Running the SU2_DEF software. */ - SU2_DOT = 3, /*!< \brief Running the SU2_DOT software. */ - SU2_MSH = 4, /*!< \brief Running the SU2_MSH software. */ - SU2_GEO = 5, /*!< \brief Running the SU2_GEO software. */ - SU2_SOL = 6 /*!< \brief Running the SU2_SOL software. */ -}; - -const unsigned int EXIT_DIVERGENCE = 2; /*!< \brief Exit code (divergence). */ - -const unsigned int BUFSIZE = 3000000; /*!< \brief MPI buffer. */ -const unsigned int MAX_PARAMETERS = 10; /*!< \brief Maximum number of parameters for a design variable definition. */ -const unsigned int MAX_NUMBER_PERIODIC = 10; /*!< \brief Maximum number of periodic boundary conditions. */ -const unsigned int MAX_STRING_SIZE = 200; /*!< \brief Maximum number of domains. */ -const unsigned int MAX_NUMBER_FFD = 10; /*!< \brief Maximum number of FFDBoxes for the FFD. */ -const unsigned int MAX_SOLS = 6; /*!< \brief Maximum number of solutions at the same time (dimension of solution container array). */ -const unsigned int MAX_TERMS = 6; /*!< \brief Maximum number of terms in the numerical equations (dimension of solver container array). */ -const unsigned int MAX_ZONES = 3; /*!< \brief Maximum number of zones. */ -const unsigned int NO_RK_ITER = 0; /*!< \brief No Runge-Kutta iteration. */ - -const unsigned int MESH_0 = 0; /*!< \brief Definition of the finest grid level. */ -const unsigned int MESH_1 = 1; /*!< \brief Definition of the finest grid level. */ -const unsigned int ZONE_0 = 0; /*!< \brief Definition of the first grid domain. */ -const unsigned int ZONE_1 = 1; /*!< \brief Definition of the first grid domain. */ - -const su2double STANDART_GRAVITY = 9.80665; /*!< \brief Acceleration due to gravity at surface of earth. */ - -const su2double EPS = 1.0E-16; /*!< \brief Error scale. */ -const su2double TURB_EPS = 1.0E-16; /*!< \brief Turbulent Error scale. */ - -const su2double ONE2 = 0.5; /*!< \brief One divided by two. */ -const su2double TWO3 = 2.0 / 3.0; /*!< \brief Two divided by three. */ -const su2double FOUR3 = 4.0 / 3.0; /*!< \brief Four divided by three. */ - -const su2double PI_NUMBER = 4.0 * atan(1.0); /*!< \brief Pi number. */ - -const int MASTER_NODE = 0; /*!< \brief Master node for MPI parallelization. */ -const int SINGLE_NODE = 1; /*!< \brief There is only a node in the MPI parallelization. */ -const int SINGLE_ZONE = 1; /*!< \brief There is only a zone. */ - -const int N_ELEM_TYPES = 7; /*!< \brief General output & CGNS defines. */ -const int N_POINTS_LINE = 2; /*!< \brief General output & CGNS defines. */ -const int N_POINTS_TRIANGLE = 3; /*!< \brief General output & CGNS defines. */ -const int N_POINTS_QUADRILATERAL = 4; /*!< \brief General output & CGNS defines. */ -const int N_POINTS_TETRAHEDRON = 4; /*!< \brief General output & CGNS defines. */ -const int N_POINTS_HEXAHEDRON = 8; /*!< \brief General output & CGNS defines. */ -const int N_POINTS_PYRAMID = 5; /*!< \brief General output & CGNS defines. */ -const int N_POINTS_PRISM = 6; /*!< \brief General output & CGNS defines. */ - -/*! - * \brief Boolean answers - */ -enum ANSWER { - NONE = 0, - NO = 0, /*!< \brief Boolean definition of no. */ - YES = 1 /*!< \brief Boolean definition of yes. */ -}; - -/*! - * \brief Verbosity level - */ -enum VERB_LEVEL { - VERB_NONE = 0, /*!< \brief No verbosity. */ - VERB_MEDIUM = 1, /*!< \brief Medium level of verbosity. */ - VERB_HIGH = 2 /*!< \brief High level of verbosity. */ -}; -static const map Verb_Map = CCreateMap -("NONE", VERB_NONE) -("MEDIUM", VERB_MEDIUM) -("HIGH", VERB_HIGH); - -/*! - * \brief different solver types for the CFD component - */ -enum ENUM_SOLVER { - NO_SOLVER = 0, /*!< \brief Definition of no solver. */ - EULER = 1, /*!< \brief Definition of the Euler's solver. */ - NAVIER_STOKES = 2, /*!< \brief Definition of the Navier-Stokes' solver. */ - RANS = 3, /*!< \brief Definition of the Reynolds-averaged Navier-Stokes' (RANS) solver. */ - POISSON_EQUATION = 4, /*!< \brief Definition of the poisson potential solver. */ - WAVE_EQUATION = 10, /*!< \brief Definition of the wave solver. */ - HEAT_EQUATION = 29, /*!< \brief Definition of the heat solver. */ - LINEAR_ELASTICITY = 11, /*!< \brief Definition of the FEA solver. */ - FLUID_STRUCTURE_INTERACTION = 12, /*!< \brief Definition of a FSI solver. */ - ADJ_EULER = 18, /*!< \brief Definition of the continuous adjoint Euler's solver. */ - ADJ_NAVIER_STOKES = 19, /*!< \brief Definition of the continuous adjoint Navier-Stokes' solver. */ - ADJ_RANS = 20, /*!< \brief Definition of the continuous adjoint Reynolds-averaged Navier-Stokes' (RANS) solver. */ - TEMPLATE_SOLVER = 30, /*!< \brief Definition of template solver. */ - DISC_ADJ_EULER = 35, - DISC_ADJ_RANS = 36, - DISC_ADJ_NAVIER_STOKES = 37 -}; -/* BEGIN_CONFIG_ENUMS */ -static const map Solver_Map = CCreateMap -("NONE", NO_SOLVER) -("EULER", EULER) -("NAVIER_STOKES", NAVIER_STOKES) -("RANS", RANS) -("POISSON_EQUATION", POISSON_EQUATION) -("ADJ_EULER", ADJ_EULER) -("ADJ_NAVIER_STOKES", ADJ_NAVIER_STOKES) -("ADJ_RANS", ADJ_RANS ) -("WAVE_EQUATION", WAVE_EQUATION) -("HEAT_EQUATION", HEAT_EQUATION) -("LINEAR_ELASTICITY", LINEAR_ELASTICITY) -("DISC_ADJ_EULER", DISC_ADJ_EULER) -("DISC_ADJ_RANS", DISC_ADJ_RANS) -("DISC_ADJ_NAVIERSTOKES", DISC_ADJ_EULER) -("FLUID_STRUCTURE_INTERACTION", FLUID_STRUCTURE_INTERACTION) - -("TEMPLATE_SOLVER", TEMPLATE_SOLVER); - - -/*! - * \brief types of fluid solvers - */ -enum ENUM_FSI_FLUID_PROBLEM { - NO_SOLVER_FFSI = 0, /*!< \brief Definition of no solver. */ - EULER_FFSI = 1, /*!< \brief Euler equations for the FSI problem */ - NAVIER_STOKES_FFSI = 2, /*!< \brief NS equations for the FSI problem */ - RANS_FFSI = 3 /*!< \brief RANS equations for the FSI problem */ -}; -static const map FSI_Fluid_Solver_Map = CCreateMap -("NONE", NO_SOLVER_FFSI) -("EULER", EULER_FFSI) -("NAVIER_STOKES", NAVIER_STOKES_FFSI) -("RANS", RANS_FFSI); - -/*! - * \brief types of structural solvers - */ -enum ENUM_FSI_STRUC_PROBLEM { - NO_SOLVER_SFSI = 0, /*!< \brief Definition of no solver. */ - LINEAR_ELASTICITY_SFSI = 11, /*!< \brief Linear elasticity equations for the FSI problem */ - NONLINEAR_ELASTICITY_SFSI = 2 /*!< \brief Nonlinear elasticity equations for the FSI problem */ -}; -static const map FSI_Struc_Solver_Map = CCreateMap -("NONE", NO_SOLVER_SFSI) -("LINEAR_ELASTICITY", LINEAR_ELASTICITY_SFSI) -("NONLINEAR_ELASTICITY", NONLINEAR_ELASTICITY_SFSI); - -/*! - * \brief different regime modes - */ -enum ENUM_REGIME { - COMPRESSIBLE = 0, /*!< \brief Definition of compressible solver. */ - INCOMPRESSIBLE = 1, /*!< \brief Definition of incompressible solver. */ - FREESURFACE = 2 /*!< \brief Definition of freesurface solver (incompressible). */ -}; -static const map Regime_Map = CCreateMap -("COMPRESSIBLE", COMPRESSIBLE) -("INCOMPRESSIBLE", INCOMPRESSIBLE) -("FREESURFACE", FREESURFACE); - -/*! - * \brief different non-dimensional modes - */ -enum ENUM_KIND_NONDIM { - DIMENSIONAL = 0, /*!< \brief Dimensional simulation. */ - FREESTREAM_PRESS_EQ_ONE = 1, /*!< \brief Non-dimensional simulation. */ - FREESTREAM_VEL_EQ_MACH = 2, /*!< \brief Non-dimensional simulation. */ - FREESTREAM_VEL_EQ_ONE = 3 /*!< \brief Non-dimensional simulation. */ -}; -static const map NonDim_Map = CCreateMap -("DIMENSIONAL", DIMENSIONAL) -("FREESTREAM_PRESS_EQ_ONE", FREESTREAM_PRESS_EQ_ONE) -("FREESTREAM_VEL_EQ_MACH", FREESTREAM_VEL_EQ_MACH) -("FREESTREAM_VEL_EQ_ONE", FREESTREAM_VEL_EQ_ONE); - -/*! - * \brief different system of measurements - */ -enum ENUM_MEASUREMENTS { - SI = 0, /*!< \brief Definition of compressible solver. */ - US = 1 /*!< \brief Definition of incompressible solver. */ -}; -static const map Measurements_Map = CCreateMap -("SI", SI) -("US", US); - -/*! - * \brief different types of systems - */ -enum RUNTIME_TYPE { - RUNTIME_FLOW_SYS = 2, /*!< \brief One-physics case, the code is solving the flow equations(Euler and Navier-Stokes). */ - RUNTIME_TURB_SYS = 3, /*!< \brief One-physics case, the code is solving the turbulence model. */ - RUNTIME_POISSON_SYS = 4, /*!< \brief One-physics case, the code is solving the poissonal potential equation. */ - RUNTIME_ADJPOT_SYS = 5, /*!< \brief One-physics case, the code is solving the adjoint potential flow equation. */ - RUNTIME_ADJFLOW_SYS = 6, /*!< \brief One-physics case, the code is solving the adjoint equations is being solved (Euler and Navier-Stokes). */ - RUNTIME_ADJTURB_SYS = 7, /*!< \brief One-physics case, the code is solving the adjoint turbulence model. */ - RUNTIME_WAVE_SYS = 8, /*!< \brief One-physics case, the code is solving the wave equation. */ - RUNTIME_MULTIGRID_SYS = 14, /*!< \brief Full Approximation Storage Multigrid system of equations. */ - RUNTIME_FEA_SYS = 20, /*!< \brief One-physics case, the code is solving the FEA equation. */ - RUNTIME_HEAT_SYS = 21, /*!< \brief One-physics case, the code is solving the heat equation. */ - RUNTIME_TRANS_SYS = 22, /*!< \brief One-physics case, the code is solving the turbulence model. */ -}; - -const int FLOW_SOL = 0; /*!< \brief Position of the mean flow solution in the solver container array. */ -const int ADJFLOW_SOL = 1; /*!< \brief Position of the continuous adjoint flow solution in the solver container array. */ - -const int TURB_SOL = 2; /*!< \brief Position of the turbulence model solution in the solver container array. */ -const int ADJTURB_SOL = 3; /*!< \brief Position of the continuous adjoint turbulence solution in the solver container array. */ - -const int TRANS_SOL = 4; /*!< \brief Position of the transition model solution in the solver container array. */ -const int POISSON_SOL = 2; /*!< \brief Position of the electronic potential solution in the solver container array. */ -const int WAVE_SOL = 1; /*!< \brief Position of the wave equation in the solution solver array. */ -const int HEAT_SOL = 2; /*!< \brief Position of the heat equation in the solution solver array. */ -const int FEA_SOL = 1; /*!< \brief Position of the FEA equation in the solution solver array. */ - -const int TEMPLATE_SOL = 0; /*!< \brief Position of the template solution. */ - -const int CONV_TERM = 0; /*!< \brief Position of the convective terms in the numerics container array. */ -const int VISC_TERM = 1; /*!< \brief Position of the viscous terms in the numerics container array. */ -const int SOURCE_FIRST_TERM = 2; /*!< \brief Position of the first source term in the numerics container array. */ -const int SOURCE_SECOND_TERM = 3; /*!< \brief Position of the second source term in the numerics container array. */ -const int CONV_BOUND_TERM = 4; /*!< \brief Position of the convective boundary terms in the numerics container array. */ -const int VISC_BOUND_TERM = 5; /*!< \brief Position of the viscous boundary terms in the numerics container array. */ - -/*! - * \brief types of mathematical problem to solve - */ -enum ENUM_MATH_PROBLEM { - DIRECT = 0, /*!< \brief Direct problem */ - CONTINUOUS_ADJOINT = 1, /*!< \brief Continuous adjoint problem */ - DISCRETE_ADJOINT = 2 /*< \brief AD-based discrete adjoint problem. */ -}; -static const map Math_Problem_Map = CCreateMap -("DIRECT", DIRECT) -("CONTINUOUS_ADJOINT", CONTINUOUS_ADJOINT) -("DISCRETE_ADJOINT", DISCRETE_ADJOINT); - -/*! - * \brief types of spatial discretizations - */ -enum ENUM_SPACE { - NO_CONVECTIVE = 0, /*!< \brief No convective scheme is used. */ - SPACE_CENTERED = 1, /*!< \brief Space centered convective numerical method. */ - SPACE_UPWIND = 2 /*!< \brief Upwind convective numerical method. */ -}; -static const map Space_Map = CCreateMap -("NONE", NO_CONVECTIVE) -("SPACE_CENTERED", SPACE_CENTERED) -("SPACE_UPWIND", SPACE_UPWIND); - -/*! - * \brief types of fluid model - */ -enum ENUM_FLUIDMODEL { - STANDARD_AIR = 0, - IDEAL_GAS = 1, /*!< \brief _____. */ - VW_GAS = 2, - PR_GAS = 3 -}; - -static const map FluidModel_Map = CCreateMap -("STANDARD_AIR", STANDARD_AIR) -("IDEAL_GAS", IDEAL_GAS) -("VW_GAS", VW_GAS) -("PR_GAS", PR_GAS); - -/*! - * \brief types of initialization option - */ - -enum ENUM_INIT_OPTION { - REYNOLDS = 0, /*!< \brief _____. */ - TD_CONDITIONS = 1 - -}; - -static const map InitOption_Map = CCreateMap -("REYNOLDS", REYNOLDS) -("TD_CONDITIONS", TD_CONDITIONS); - -/*! - * \brief types of initialization option - */ - -enum ENUM_FREESTREAM_OPTION { - TEMPERATURE_FS = 0, /*!< \brief _____. */ - DENSITY_FS = 1 - -}; - -static const map FreeStreamOption_Map = CCreateMap -("TEMPERATURE_FS", TEMPERATURE_FS) -("DENSITY_FS", DENSITY_FS); - -/*! - * \brief types of viscosity model - */ -enum ENUM_VISCOSITYMODEL { - CONSTANT_VISCOSITY = 0, /*!< \brief _____. */ - SUTHERLAND = 1 -}; - -static const map ViscosityModel_Map = CCreateMap -("CONSTANT_VISCOSITY", CONSTANT_VISCOSITY) -("SUTHERLAND", SUTHERLAND); - -/*! - * \brief types of thermal conductivity model - */ -enum ENUM_CONDUCTIVITYMODEL { - CONSTANT_CONDUCTIVITY = 0, /*!< \brief _____. */ - CONSTANT_PRANDTL = 1 -}; - -static const map ConductivityModel_Map = CCreateMap -("CONSTANT_CONDUCTIVITY", CONSTANT_CONDUCTIVITY) -("CONSTANT_PRANDTL", CONSTANT_PRANDTL); - -/*! - * \brief types of unsteady mesh motion - */ -enum ENUM_GRIDMOVEMENT { - NO_MOVEMENT = 0, /*!< \brief Simulation on a static mesh. */ - DEFORMING = 1, /*!< \brief Simulation with dynamically deforming meshes (plunging/pitching/rotation). */ - RIGID_MOTION = 2, /*!< \brief Simulation with rigid mesh motion (plunging/pitching/rotation). */ - FLUID_STRUCTURE = 3, /*!< \brief Fluid structure defromation. */ - EXTERNAL = 4, /*!< \brief Arbitrary grid motion specified by external files at each time step. */ - EXTERNAL_ROTATION = 5, /*!< \brief Arbitrary grid motion specified by external files at each time step with rigid rotation. */ - AEROELASTIC = 6, /*!< \brief Simulation with aeroelastic motion. */ - MOVING_WALL = 7, /*!< \brief Simulation with moving walls (translation/rotation). */ - ROTATING_FRAME = 8, /*!< \brief Simulation in a rotating frame. */ - ELASTICITY = 9, /*!< \brief Linear Elasticity. */ - AEROELASTIC_RIGID_MOTION = 10, /*!< \brief Simulation with rotation and aeroelastic motion. */ - STEADY_TRANSLATION = 11, /*!< \brief Simulation in a steadily translating frame. */ - GUST = 12 /*!< \brief Simulation on a static mesh with a gust. */ - -}; - -static const map GridMovement_Map = CCreateMap -("NONE", NO_MOVEMENT) -("DEFORMING", DEFORMING) -("RIGID_MOTION", RIGID_MOTION) -("FLUID_STRUCTURE", FLUID_STRUCTURE) -("EXTERNAL", EXTERNAL) -("EXTERNAL_ROTATION", EXTERNAL_ROTATION) -("AEROELASTIC", AEROELASTIC) -("ROTATING_FRAME", ROTATING_FRAME) -("ELASTICITY", ELASTICITY) -("MOVING_WALL", MOVING_WALL) -("AEROELASTIC_RIGID_MOTION", AEROELASTIC_RIGID_MOTION) -("STEADY_TRANSLATION", STEADY_TRANSLATION) -("GUST", GUST); - -/*! - * \brief type of wind gusts - */ -enum ENUM_GUST_TYPE { - NO_GUST = 0, /*!< \brief _______. */ - TOP_HAT = 1, /*!< \brief Top-hat function shaped gust */ - SINE = 2, /*!< \brief Sine shaped gust */ - ONE_M_COSINE = 3, /*!< \brief 1-cosine shaped gust */ - VORTEX = 4, /*!< \brief A gust made from vortices */ - EOG = 5 /*!< \brief An extreme operating gust */ -}; -static const map Gust_Type_Map = CCreateMap -("NONE", NO_GUST) -("TOP_HAT", TOP_HAT) -("SINE", SINE) -("ONE_M_COSINE", ONE_M_COSINE) -("VORTEX", VORTEX) -("EOG", EOG); - -/*! - * \brief type of wind direction - */ -enum ENUM_GUST_DIR { - X_DIR = 0, /*!< \brief _______. */ - Y_DIR = 1 /*!< \brief _______. */ -}; -static const map Gust_Dir_Map = CCreateMap -("X_DIR", X_DIR) -("Y_DIR", Y_DIR); - -// If you add to ENUM_CENTERED, you must also add the option to ENUM_CONVECTIVE -/*! - * \brief types of centered spatial discretizations - */ -enum ENUM_CENTERED { - NO_CENTERED = 0, /*!< \brief No centered scheme is used. */ - JST = 1, /*!< \brief Jameson-Smith-Turkel centered numerical method. */ - LAX = 2, /*!< \brief Lax-Friedrich centered numerical method. */ - JST_KE = 4 /*!< \brief Kinetic Energy preserving Jameson-Smith-Turkel centered numerical method. */ -}; -static const map Centered_Map = CCreateMap -("NONE", NO_CENTERED) -("JST", JST) -("JST_KE", JST_KE) -("LAX-FRIEDRICH", LAX); - - -// If you add to ENUM_UPWIND, you must also add the option to ENUM_CONVECTIVE -/*! - * \brief types of upwind spatial discretizations - */ -enum ENUM_UPWIND { - NO_UPWIND = 0, /*!< \brief No upwind scheme is used. */ - ROE = 1, /*!< \brief Roe's upwind numerical method. */ - SCALAR_UPWIND = 2, /*!< \brief Scalar upwind numerical method. */ - AUSM = 3, /*!< \brief AUSM numerical method. */ - HLLC = 4, /*!< \brief HLLC numerical method. */ - SW = 5, /*!< \brief Steger-Warming method. */ - MSW = 6, /*!< \brief Modified Steger-Warming method. */ - TURKEL = 7, /*!< \brief Roe-Turkel's upwind numerical method. */ - AUSMPWPLUS = 8, /*!< \brief AUSMPW+ numerical method. */ - CUSP = 9, /*!< \brief Convective upwind and split pressure numerical method. */ - CONVECTIVE_TEMPLATE = 10 /*!< \brief Template for new numerical method . */ -}; -static const map Upwind_Map = CCreateMap -("NONE", NO_UPWIND) -("ROE", ROE) -("TURKEL_PREC", TURKEL) -("AUSM", AUSM) -("AUSMPW+", AUSMPWPLUS) -("HLLC", HLLC) -("SW", SW) -("MSW", MSW) -("CUSP", CUSP) -("SCALAR_UPWIND", SCALAR_UPWIND) -("CONVECTIVE_TEMPLATE", CONVECTIVE_TEMPLATE); - -/*! - * \brief Spatial numerical order integration - */ -enum ENUM_SPATIAL_ORDER { - FIRST_ORDER = 0, /*!< \brief First order */ - SECOND_ORDER = 1, /*!< \brief Second order. */ - SECOND_ORDER_LIMITER = 2 /*!< \brief Second order with limiter. */ -}; -static const map SpatialOrder_Map = CCreateMap -("1ST_ORDER", FIRST_ORDER) -("2ND_ORDER", SECOND_ORDER) -("2ND_ORDER_LIMITER", SECOND_ORDER_LIMITER); - -/*! - * \brief types of slope limiters - */ -enum ENUM_LIMITER { - VENKATAKRISHNAN = 0, /*!< \brief Slope limiter using Venkatakrisnan method. */ - BARTH_JESPERSEN = 1, /*!< \brief Slope limiter using Barth-Jespersen method. */ - SHARP_EDGES = 2, /*!< \brief Slope limiter using sharp edges. */ - SOLID_WALL_DISTANCE = 3 /*!< \brief Slope limiter using wall distance. */ -}; -static const map Limiter_Map = CCreateMap -("VENKATAKRISHNAN", VENKATAKRISHNAN) -("BARTH_JESPERSEN", BARTH_JESPERSEN) -("SHARP_EDGES", SHARP_EDGES) -("WALL_DISTANCE", SOLID_WALL_DISTANCE); - -/*! - * \brief types of turbulent models - */ -enum ENUM_TURB_MODEL { - NO_TURB_MODEL = 0, /*!< \brief No turbulence model. */ - SA = 1, /*!< \brief Kind of Turbulent model (Spalart-Allmaras). */ - SA_NEG = 2, /*!< \brief Kind of Turbulent model (Spalart-Allmaras). */ - SST = 3, /*!< \brief Kind of Turbulence model (Menter SST). */ -}; -static const map Turb_Model_Map = CCreateMap -("NONE", NO_TURB_MODEL) -("SA", SA) -("SA_NEG", SA_NEG) -("SST", SST); - -/*! - * \brief types of transition models - */ -enum ENUM_TRANS_MODEL { - NO_TRANS_MODEL = 0, /*!< \brief No transition model. */ - LM = 1 /*!< \brief Kind of transition model (LM for Spalart-Allmaras). */ -}; -static const map Trans_Model_Map = CCreateMap -("NONE", NO_TRANS_MODEL) -("LM", LM); - -/*! - * \brief type of time integration schemes - */ -enum ENUM_TIME_INT { - RUNGE_KUTTA_EXPLICIT = 1, /*!< \brief Explicit Runge-Kutta time integration definition. */ - EULER_EXPLICIT = 2, /*!< \brief Explicit Euler time integration definition. */ - EULER_IMPLICIT = 3 /*!< \brief Implicit Euler time integration definition. */ -}; -static const map Time_Int_Map = CCreateMap -("RUNGE-KUTTA_EXPLICIT", RUNGE_KUTTA_EXPLICIT) -("EULER_EXPLICIT", EULER_EXPLICIT) -("EULER_IMPLICIT", EULER_IMPLICIT); - -/*! - * \brief type of time integration schemes - */ -enum ENUM_TIME_INT_FEA { - CD_EXPLICIT = 1, /*!< \brief Support for implementing an explicit method. */ - NEWMARK_IMPLICIT = 2, /*!< \brief Implicit Newmark integration definition. */ - GA_IMPLICIT = 3 /*!< \brief Support for implementing another implicit method. */ -}; -static const map Time_Int_Map_FEA = CCreateMap -("CD_EXPLICIT", CD_EXPLICIT) -("NEWMARK_IMPLICIT", NEWMARK_IMPLICIT) -("GA_IMPLICIT", GA_IMPLICIT); - -/*! - * \brief types of schemes to compute the flow gradient - */ -enum ENUM_FLOW_GRADIENT { - GREEN_GAUSS = 1, /*!< \brief Gradients computation using Green Gauss theorem. */ - WEIGHTED_LEAST_SQUARES = 2 /*!< \brief Gradients computation using Weighted Least Squares. */ -}; -static const map Gradient_Map = CCreateMap -("GREEN_GAUSS", GREEN_GAUSS) -("WEIGHTED_LEAST_SQUARES", WEIGHTED_LEAST_SQUARES); - -/*! - * \brief types of action to take on a geometry structure - */ -enum GEOMETRY_ACTION { - ALLOCATE = 0, /*!< \brief Allocate geometry structure. */ - UPDATE = 1 /*!< \brief Update geometry structure (grid moving, adaptation, etc.). */ -}; - -/*! - * \brief types of action to perform when doing the geometry evaluation - */ -enum GEOMETRY_MODE { - FUNCTION = 0, /*!< \brief Geometrical analysis. */ - GRADIENT = 1 /*!< \brief Geometrical analysis and gradient using finite differences. */ -}; -static const map GeometryMode_Map = CCreateMap -("FUNCTION", FUNCTION) -("GRADIENT", GRADIENT); - -/*! - * \brief types of boundary conditions - */ -enum BC_TYPE { - EULER_WALL = 1, /*!< \brief Boundary Euler wall definition. */ - FAR_FIELD = 2, /*!< \brief Boundary far-field definition. */ - SYMMETRY_PLANE = 3, /*!< \brief Boundary symmetry plane definition. */ - INLET_FLOW = 4, /*!< \brief Boundary inlet flow definition. */ - OUTLET_FLOW = 5, /*!< \brief Boundary outlet flow definition. */ - PERIODIC_BOUNDARY = 6, /*!< \brief Periodic boundary definition. */ - NEARFIELD_BOUNDARY = 7, /*!< \brief Near-Field boundary definition. */ - ELECTRODE_BOUNDARY = 8, /*!< \brief Electrode boundary definition. */ - DIELEC_BOUNDARY = 9, /*!< \brief Dipoisson boundary definition. */ - CUSTOM_BOUNDARY = 10, /*!< \brief custom boundary definition. */ - INTERFACE_BOUNDARY = 11, /*!< \brief Domain interface boundary definition. */ - DIRICHLET = 12, /*!< \brief Boundary Euler wall definition. */ - NEUMANN = 13, /*!< \brief Boundary Neumann definition. */ - DISPLACEMENT_BOUNDARY = 14, /*!< \brief Boundary displacement definition. */ - LOAD_BOUNDARY = 15, /*!< \brief Boundary Load definition. */ - FLOWLOAD_BOUNDARY = 16, /*!< \brief Boundary Load definition. */ - SUPERSONIC_INLET = 19, /*!< \brief Boundary supersonic inlet definition. */ - SUPERSONIC_OUTLET = 20, /*!< \brief Boundary supersonic inlet definition. */ - ENGINE_INFLOW = 21, /*!< \brief Boundary nacelle inflow. */ - ENGINE_EXHAUST = 22, /*!< \brief Boundary nacelle exhaust. */ - ENGINE_BLEED = 23, /*!< \brief Boundary engine bleed. */ - RIEMANN_BOUNDARY= 24, /*!< \brief Riemann Boundary definition. */ - ISOTHERMAL = 25, /*!< \brief No slip isothermal wall boundary condition. */ - HEAT_FLUX = 26, /*!< \brief No slip constant heat flux wall boundary condition. */ - PRESSURE_BOUNDARY = 27, /*!< \brief Pressure boundary condition. */ - ACTDISK_INLET = 32, /*!< \brief Actuator disk inlet boundary definition. */ - ACTDISK_OUTLET = 33, /*!< \brief Actuator disk outlet boundary definition. */ - CLAMPED_BOUNDARY = 34, /*!< \brief Clamped Boundary definition. */ - LOAD_DIR_BOUNDARY = 35, /*!< \brief Boundary Load definition. */ +/*! + * \file option_structure.hpp + * \brief Defines classes for referencing options for easy input in CConfig + * \author J. Hicken, B. Tracey + * \version 4.0.1 "Cardinal" + * + * Many of the classes in this file are templated, and therefore must + * be declared and defined here; to keep all elements together, there + * is no corresponding .cpp file at this time. + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +#include "./mpi_structure.hpp" + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +/*! + * \class CCreateMap + * \brief creates a map from a list by overloading operator() + * \tparam T - the key type in the map + * \tparam U - the mapped value type in the map + * \author Boost.Assign and anonymous person on stackoverflow + * + * We need this to create static const maps that map strings to enum + * types. The implementation is based on the Boost.Assign library. This + * particular version is taken from + * http://stackoverflow.com/questions/138600/initializing-a-static-stdmapint-int-in-c + */ +template +class CCreateMap { +private: + std::map m_map; +public: + CCreateMap(const T& key, const U& val) { + m_map[key] = val; + } + CCreateMap& operator()(const T& key, const U& val) { + m_map[key] = val; + return *this; + } + operator std::map() { + return m_map; + } +}; + +/*! + * \brief utility function for converting strings to uppercase + * \param[in, out] str - string we want to convert + */ +inline void StringToUpperCase(string & str) { + std::transform(str.begin(), str.end(), str.begin(), ::toupper); +} + +/*! + * \brief utility function for converting strings to uppercase + * \param[in] str - string we want a copy of converted to uppercase + * \returns a copy of str in uppercase + */ +inline string StringToUpperCase(const string & str) { + string upp_str(str); + std::transform(upp_str.begin(), upp_str.end(), upp_str.begin(), ::toupper); + return upp_str; +} + +/*! + * \brief different software components of SU2 + */ +enum SU2_COMPONENT { + SU2_CFD = 1, /*!< \brief Running the SU2_CFD software. */ + SU2_DEF = 2, /*!< \brief Running the SU2_DEF software. */ + SU2_DOT = 3, /*!< \brief Running the SU2_DOT software. */ + SU2_MSH = 4, /*!< \brief Running the SU2_MSH software. */ + SU2_GEO = 5, /*!< \brief Running the SU2_GEO software. */ + SU2_SOL = 6 /*!< \brief Running the SU2_SOL software. */ +}; + +const unsigned int EXIT_DIVERGENCE = 2; /*!< \brief Exit code (divergence). */ + +const unsigned int BUFSIZE = 3000000; /*!< \brief MPI buffer. */ +const unsigned int MAX_PARAMETERS = 10; /*!< \brief Maximum number of parameters for a design variable definition. */ +const unsigned int MAX_NUMBER_PERIODIC = 10; /*!< \brief Maximum number of periodic boundary conditions. */ +const unsigned int MAX_STRING_SIZE = 200; /*!< \brief Maximum number of domains. */ +const unsigned int MAX_NUMBER_FFD = 10; /*!< \brief Maximum number of FFDBoxes for the FFD. */ +const unsigned int MAX_SOLS = 6; /*!< \brief Maximum number of solutions at the same time (dimension of solution container array). */ +const unsigned int MAX_TERMS = 6; /*!< \brief Maximum number of terms in the numerical equations (dimension of solver container array). */ +const unsigned int MAX_ZONES = 3; /*!< \brief Maximum number of zones. */ +const unsigned int NO_RK_ITER = 0; /*!< \brief No Runge-Kutta iteration. */ + +const unsigned int MESH_0 = 0; /*!< \brief Definition of the finest grid level. */ +const unsigned int MESH_1 = 1; /*!< \brief Definition of the finest grid level. */ +const unsigned int ZONE_0 = 0; /*!< \brief Definition of the first grid domain. */ +const unsigned int ZONE_1 = 1; /*!< \brief Definition of the first grid domain. */ + +const su2double STANDART_GRAVITY = 9.80665; /*!< \brief Acceleration due to gravity at surface of earth. */ + +const su2double EPS = 1.0E-16; /*!< \brief Error scale. */ +const su2double TURB_EPS = 1.0E-16; /*!< \brief Turbulent Error scale. */ + +const su2double ONE2 = 0.5; /*!< \brief One divided by two. */ +const su2double TWO3 = 2.0 / 3.0; /*!< \brief Two divided by three. */ +const su2double FOUR3 = 4.0 / 3.0; /*!< \brief Four divided by three. */ + +const su2double PI_NUMBER = 4.0 * atan(1.0); /*!< \brief Pi number. */ + +const int MASTER_NODE = 0; /*!< \brief Master node for MPI parallelization. */ +const int SINGLE_NODE = 1; /*!< \brief There is only a node in the MPI parallelization. */ +const int SINGLE_ZONE = 1; /*!< \brief There is only a zone. */ + +const int N_ELEM_TYPES = 7; /*!< \brief General output & CGNS defines. */ +const int N_POINTS_LINE = 2; /*!< \brief General output & CGNS defines. */ +const int N_POINTS_TRIANGLE = 3; /*!< \brief General output & CGNS defines. */ +const int N_POINTS_QUADRILATERAL = 4; /*!< \brief General output & CGNS defines. */ +const int N_POINTS_TETRAHEDRON = 4; /*!< \brief General output & CGNS defines. */ +const int N_POINTS_HEXAHEDRON = 8; /*!< \brief General output & CGNS defines. */ +const int N_POINTS_PYRAMID = 5; /*!< \brief General output & CGNS defines. */ +const int N_POINTS_PRISM = 6; /*!< \brief General output & CGNS defines. */ + +/*! + * \brief Boolean answers + */ +enum ANSWER { + NONE = 0, + NO = 0, /*!< \brief Boolean definition of no. */ + YES = 1 /*!< \brief Boolean definition of yes. */ +}; + +/*! + * \brief Verbosity level + */ +enum VERB_LEVEL { + VERB_NONE = 0, /*!< \brief No verbosity. */ + VERB_MEDIUM = 1, /*!< \brief Medium level of verbosity. */ + VERB_HIGH = 2 /*!< \brief High level of verbosity. */ +}; +static const map Verb_Map = CCreateMap +("NONE", VERB_NONE) +("MEDIUM", VERB_MEDIUM) +("HIGH", VERB_HIGH); + +/*! + * \brief different solver types for the CFD component + */ +enum ENUM_SOLVER { + NO_SOLVER = 0, /*!< \brief Definition of no solver. */ + EULER = 1, /*!< \brief Definition of the Euler's solver. */ + NAVIER_STOKES = 2, /*!< \brief Definition of the Navier-Stokes' solver. */ + RANS = 3, /*!< \brief Definition of the Reynolds-averaged Navier-Stokes' (RANS) solver. */ + POISSON_EQUATION = 4, /*!< \brief Definition of the poisson potential solver. */ + WAVE_EQUATION = 10, /*!< \brief Definition of the wave solver. */ + HEAT_EQUATION = 29, /*!< \brief Definition of the heat solver. */ + LINEAR_ELASTICITY = 11, /*!< \brief Definition of the FEA solver. */ + FLUID_STRUCTURE_INTERACTION = 12, /*!< \brief Definition of a FSI solver. */ + ADJ_EULER = 18, /*!< \brief Definition of the continuous adjoint Euler's solver. */ + ADJ_NAVIER_STOKES = 19, /*!< \brief Definition of the continuous adjoint Navier-Stokes' solver. */ + ADJ_RANS = 20, /*!< \brief Definition of the continuous adjoint Reynolds-averaged Navier-Stokes' (RANS) solver. */ + TEMPLATE_SOLVER = 30, /*!< \brief Definition of template solver. */ + DISC_ADJ_EULER = 35, + DISC_ADJ_RANS = 36, + DISC_ADJ_NAVIER_STOKES = 37 +}; +/* BEGIN_CONFIG_ENUMS */ +static const map Solver_Map = CCreateMap +("NONE", NO_SOLVER) +("EULER", EULER) +("NAVIER_STOKES", NAVIER_STOKES) +("RANS", RANS) +("POISSON_EQUATION", POISSON_EQUATION) +("ADJ_EULER", ADJ_EULER) +("ADJ_NAVIER_STOKES", ADJ_NAVIER_STOKES) +("ADJ_RANS", ADJ_RANS ) +("WAVE_EQUATION", WAVE_EQUATION) +("HEAT_EQUATION", HEAT_EQUATION) +("LINEAR_ELASTICITY", LINEAR_ELASTICITY) +("DISC_ADJ_EULER", DISC_ADJ_EULER) +("DISC_ADJ_RANS", DISC_ADJ_RANS) +("DISC_ADJ_NAVIERSTOKES", DISC_ADJ_EULER) +("FLUID_STRUCTURE_INTERACTION", FLUID_STRUCTURE_INTERACTION) + +("TEMPLATE_SOLVER", TEMPLATE_SOLVER); + + +/*! + * \brief types of fluid solvers + */ +enum ENUM_FSI_FLUID_PROBLEM { + NO_SOLVER_FFSI = 0, /*!< \brief Definition of no solver. */ + EULER_FFSI = 1, /*!< \brief Euler equations for the FSI problem */ + NAVIER_STOKES_FFSI = 2, /*!< \brief NS equations for the FSI problem */ + RANS_FFSI = 3 /*!< \brief RANS equations for the FSI problem */ +}; +static const map FSI_Fluid_Solver_Map = CCreateMap +("NONE", NO_SOLVER_FFSI) +("EULER", EULER_FFSI) +("NAVIER_STOKES", NAVIER_STOKES_FFSI) +("RANS", RANS_FFSI); + +/*! + * \brief types of structural solvers + */ +enum ENUM_FSI_STRUC_PROBLEM { + NO_SOLVER_SFSI = 0, /*!< \brief Definition of no solver. */ + LINEAR_ELASTICITY_SFSI = 11, /*!< \brief Linear elasticity equations for the FSI problem */ + NONLINEAR_ELASTICITY_SFSI = 2 /*!< \brief Nonlinear elasticity equations for the FSI problem */ +}; +static const map FSI_Struc_Solver_Map = CCreateMap +("NONE", NO_SOLVER_SFSI) +("LINEAR_ELASTICITY", LINEAR_ELASTICITY_SFSI) +("NONLINEAR_ELASTICITY", NONLINEAR_ELASTICITY_SFSI); + +/*! + * \brief different regime modes + */ +enum ENUM_REGIME { + COMPRESSIBLE = 0, /*!< \brief Definition of compressible solver. */ + INCOMPRESSIBLE = 1, /*!< \brief Definition of incompressible solver. */ + FREESURFACE = 2 /*!< \brief Definition of freesurface solver (incompressible). */ +}; +static const map Regime_Map = CCreateMap +("COMPRESSIBLE", COMPRESSIBLE) +("INCOMPRESSIBLE", INCOMPRESSIBLE) +("FREESURFACE", FREESURFACE); + +/*! + * \brief different non-dimensional modes + */ +enum ENUM_KIND_NONDIM { + DIMENSIONAL = 0, /*!< \brief Dimensional simulation. */ + FREESTREAM_PRESS_EQ_ONE = 1, /*!< \brief Non-dimensional simulation. */ + FREESTREAM_VEL_EQ_MACH = 2, /*!< \brief Non-dimensional simulation. */ + FREESTREAM_VEL_EQ_ONE = 3 /*!< \brief Non-dimensional simulation. */ +}; +static const map NonDim_Map = CCreateMap +("DIMENSIONAL", DIMENSIONAL) +("FREESTREAM_PRESS_EQ_ONE", FREESTREAM_PRESS_EQ_ONE) +("FREESTREAM_VEL_EQ_MACH", FREESTREAM_VEL_EQ_MACH) +("FREESTREAM_VEL_EQ_ONE", FREESTREAM_VEL_EQ_ONE); + +/*! + * \brief different system of measurements + */ +enum ENUM_MEASUREMENTS { + SI = 0, /*!< \brief Definition of compressible solver. */ + US = 1 /*!< \brief Definition of incompressible solver. */ +}; +static const map Measurements_Map = CCreateMap +("SI", SI) +("US", US); + +/*! + * \brief different types of systems + */ +enum RUNTIME_TYPE { + RUNTIME_FLOW_SYS = 2, /*!< \brief One-physics case, the code is solving the flow equations(Euler and Navier-Stokes). */ + RUNTIME_TURB_SYS = 3, /*!< \brief One-physics case, the code is solving the turbulence model. */ + RUNTIME_POISSON_SYS = 4, /*!< \brief One-physics case, the code is solving the poissonal potential equation. */ + RUNTIME_ADJPOT_SYS = 5, /*!< \brief One-physics case, the code is solving the adjoint potential flow equation. */ + RUNTIME_ADJFLOW_SYS = 6, /*!< \brief One-physics case, the code is solving the adjoint equations is being solved (Euler and Navier-Stokes). */ + RUNTIME_ADJTURB_SYS = 7, /*!< \brief One-physics case, the code is solving the adjoint turbulence model. */ + RUNTIME_WAVE_SYS = 8, /*!< \brief One-physics case, the code is solving the wave equation. */ + RUNTIME_MULTIGRID_SYS = 14, /*!< \brief Full Approximation Storage Multigrid system of equations. */ + RUNTIME_FEA_SYS = 20, /*!< \brief One-physics case, the code is solving the FEA equation. */ + RUNTIME_HEAT_SYS = 21, /*!< \brief One-physics case, the code is solving the heat equation. */ + RUNTIME_TRANS_SYS = 22, /*!< \brief One-physics case, the code is solving the turbulence model. */ +}; + +const int FLOW_SOL = 0; /*!< \brief Position of the mean flow solution in the solver container array. */ +const int ADJFLOW_SOL = 1; /*!< \brief Position of the continuous adjoint flow solution in the solver container array. */ + +const int TURB_SOL = 2; /*!< \brief Position of the turbulence model solution in the solver container array. */ +const int ADJTURB_SOL = 3; /*!< \brief Position of the continuous adjoint turbulence solution in the solver container array. */ + +const int TRANS_SOL = 4; /*!< \brief Position of the transition model solution in the solver container array. */ +const int POISSON_SOL = 2; /*!< \brief Position of the electronic potential solution in the solver container array. */ +const int WAVE_SOL = 1; /*!< \brief Position of the wave equation in the solution solver array. */ +const int HEAT_SOL = 2; /*!< \brief Position of the heat equation in the solution solver array. */ +const int FEA_SOL = 1; /*!< \brief Position of the FEA equation in the solution solver array. */ + +const int TEMPLATE_SOL = 0; /*!< \brief Position of the template solution. */ + +const int CONV_TERM = 0; /*!< \brief Position of the convective terms in the numerics container array. */ +const int VISC_TERM = 1; /*!< \brief Position of the viscous terms in the numerics container array. */ +const int SOURCE_FIRST_TERM = 2; /*!< \brief Position of the first source term in the numerics container array. */ +const int SOURCE_SECOND_TERM = 3; /*!< \brief Position of the second source term in the numerics container array. */ +const int CONV_BOUND_TERM = 4; /*!< \brief Position of the convective boundary terms in the numerics container array. */ +const int VISC_BOUND_TERM = 5; /*!< \brief Position of the viscous boundary terms in the numerics container array. */ + +/*! + * \brief types of mathematical problem to solve + */ +enum ENUM_MATH_PROBLEM { + DIRECT = 0, /*!< \brief Direct problem */ + CONTINUOUS_ADJOINT = 1, /*!< \brief Continuous adjoint problem */ + DISCRETE_ADJOINT = 2 /*< \brief AD-based discrete adjoint problem. */ +}; +static const map Math_Problem_Map = CCreateMap +("DIRECT", DIRECT) +("CONTINUOUS_ADJOINT", CONTINUOUS_ADJOINT) +("DISCRETE_ADJOINT", DISCRETE_ADJOINT); + +/*! + * \brief types of spatial discretizations + */ +enum ENUM_SPACE { + NO_CONVECTIVE = 0, /*!< \brief No convective scheme is used. */ + SPACE_CENTERED = 1, /*!< \brief Space centered convective numerical method. */ + SPACE_UPWIND = 2 /*!< \brief Upwind convective numerical method. */ +}; +static const map Space_Map = CCreateMap +("NONE", NO_CONVECTIVE) +("SPACE_CENTERED", SPACE_CENTERED) +("SPACE_UPWIND", SPACE_UPWIND); + +/*! + * \brief types of fluid model + */ +enum ENUM_FLUIDMODEL { + STANDARD_AIR = 0, + IDEAL_GAS = 1, /*!< \brief _____. */ + VW_GAS = 2, + PR_GAS = 3 +}; + +static const map FluidModel_Map = CCreateMap +("STANDARD_AIR", STANDARD_AIR) +("IDEAL_GAS", IDEAL_GAS) +("VW_GAS", VW_GAS) +("PR_GAS", PR_GAS); + +/*! + * \brief types of initialization option + */ + +enum ENUM_INIT_OPTION { + REYNOLDS = 0, /*!< \brief _____. */ + TD_CONDITIONS = 1 + +}; + +static const map InitOption_Map = CCreateMap +("REYNOLDS", REYNOLDS) +("TD_CONDITIONS", TD_CONDITIONS); + +/*! + * \brief types of initialization option + */ + +enum ENUM_FREESTREAM_OPTION { + TEMPERATURE_FS = 0, /*!< \brief _____. */ + DENSITY_FS = 1 + +}; + +static const map FreeStreamOption_Map = CCreateMap +("TEMPERATURE_FS", TEMPERATURE_FS) +("DENSITY_FS", DENSITY_FS); + +/*! + * \brief types of viscosity model + */ +enum ENUM_VISCOSITYMODEL { + CONSTANT_VISCOSITY = 0, /*!< \brief _____. */ + SUTHERLAND = 1 +}; + +static const map ViscosityModel_Map = CCreateMap +("CONSTANT_VISCOSITY", CONSTANT_VISCOSITY) +("SUTHERLAND", SUTHERLAND); + +/*! + * \brief types of thermal conductivity model + */ +enum ENUM_CONDUCTIVITYMODEL { + CONSTANT_CONDUCTIVITY = 0, /*!< \brief _____. */ + CONSTANT_PRANDTL = 1 +}; + +static const map ConductivityModel_Map = CCreateMap +("CONSTANT_CONDUCTIVITY", CONSTANT_CONDUCTIVITY) +("CONSTANT_PRANDTL", CONSTANT_PRANDTL); + +/*! + * \brief types of unsteady mesh motion + */ +enum ENUM_GRIDMOVEMENT { + NO_MOVEMENT = 0, /*!< \brief Simulation on a static mesh. */ + DEFORMING = 1, /*!< \brief Simulation with dynamically deforming meshes (plunging/pitching/rotation). */ + RIGID_MOTION = 2, /*!< \brief Simulation with rigid mesh motion (plunging/pitching/rotation). */ + FLUID_STRUCTURE = 3, /*!< \brief Fluid structure defromation. */ + EXTERNAL = 4, /*!< \brief Arbitrary grid motion specified by external files at each time step. */ + EXTERNAL_ROTATION = 5, /*!< \brief Arbitrary grid motion specified by external files at each time step with rigid rotation. */ + AEROELASTIC = 6, /*!< \brief Simulation with aeroelastic motion. */ + MOVING_WALL = 7, /*!< \brief Simulation with moving walls (translation/rotation). */ + ROTATING_FRAME = 8, /*!< \brief Simulation in a rotating frame. */ + ELASTICITY = 9, /*!< \brief Linear Elasticity. */ + AEROELASTIC_RIGID_MOTION = 10, /*!< \brief Simulation with rotation and aeroelastic motion. */ + STEADY_TRANSLATION = 11, /*!< \brief Simulation in a steadily translating frame. */ + GUST = 12 /*!< \brief Simulation on a static mesh with a gust. */ + +}; + +static const map GridMovement_Map = CCreateMap +("NONE", NO_MOVEMENT) +("DEFORMING", DEFORMING) +("RIGID_MOTION", RIGID_MOTION) +("FLUID_STRUCTURE", FLUID_STRUCTURE) +("EXTERNAL", EXTERNAL) +("EXTERNAL_ROTATION", EXTERNAL_ROTATION) +("AEROELASTIC", AEROELASTIC) +("ROTATING_FRAME", ROTATING_FRAME) +("ELASTICITY", ELASTICITY) +("MOVING_WALL", MOVING_WALL) +("AEROELASTIC_RIGID_MOTION", AEROELASTIC_RIGID_MOTION) +("STEADY_TRANSLATION", STEADY_TRANSLATION) +("GUST", GUST); + +/*! + * \brief type of wind gusts + */ +enum ENUM_GUST_TYPE { + NO_GUST = 0, /*!< \brief _______. */ + TOP_HAT = 1, /*!< \brief Top-hat function shaped gust */ + SINE = 2, /*!< \brief Sine shaped gust */ + ONE_M_COSINE = 3, /*!< \brief 1-cosine shaped gust */ + VORTEX = 4, /*!< \brief A gust made from vortices */ + EOG = 5 /*!< \brief An extreme operating gust */ +}; +static const map Gust_Type_Map = CCreateMap +("NONE", NO_GUST) +("TOP_HAT", TOP_HAT) +("SINE", SINE) +("ONE_M_COSINE", ONE_M_COSINE) +("VORTEX", VORTEX) +("EOG", EOG); + +/*! + * \brief type of wind direction + */ +enum ENUM_GUST_DIR { + X_DIR = 0, /*!< \brief _______. */ + Y_DIR = 1 /*!< \brief _______. */ +}; +static const map Gust_Dir_Map = CCreateMap +("X_DIR", X_DIR) +("Y_DIR", Y_DIR); + +// If you add to ENUM_CENTERED, you must also add the option to ENUM_CONVECTIVE +/*! + * \brief types of centered spatial discretizations + */ +enum ENUM_CENTERED { + NO_CENTERED = 0, /*!< \brief No centered scheme is used. */ + JST = 1, /*!< \brief Jameson-Smith-Turkel centered numerical method. */ + LAX = 2, /*!< \brief Lax-Friedrich centered numerical method. */ + JST_KE = 4 /*!< \brief Kinetic Energy preserving Jameson-Smith-Turkel centered numerical method. */ +}; +static const map Centered_Map = CCreateMap +("NONE", NO_CENTERED) +("JST", JST) +("JST_KE", JST_KE) +("LAX-FRIEDRICH", LAX); + + +// If you add to ENUM_UPWIND, you must also add the option to ENUM_CONVECTIVE +/*! + * \brief types of upwind spatial discretizations + */ +enum ENUM_UPWIND { + NO_UPWIND = 0, /*!< \brief No upwind scheme is used. */ + ROE = 1, /*!< \brief Roe's upwind numerical method. */ + SCALAR_UPWIND = 2, /*!< \brief Scalar upwind numerical method. */ + AUSM = 3, /*!< \brief AUSM numerical method. */ + HLLC = 4, /*!< \brief HLLC numerical method. */ + SW = 5, /*!< \brief Steger-Warming method. */ + MSW = 6, /*!< \brief Modified Steger-Warming method. */ + TURKEL = 7, /*!< \brief Roe-Turkel's upwind numerical method. */ + AUSMPWPLUS = 8, /*!< \brief AUSMPW+ numerical method. */ + CUSP = 9, /*!< \brief Convective upwind and split pressure numerical method. */ + CONVECTIVE_TEMPLATE = 10 /*!< \brief Template for new numerical method . */ +}; +static const map Upwind_Map = CCreateMap +("NONE", NO_UPWIND) +("ROE", ROE) +("TURKEL_PREC", TURKEL) +("AUSM", AUSM) +("AUSMPW+", AUSMPWPLUS) +("HLLC", HLLC) +("SW", SW) +("MSW", MSW) +("CUSP", CUSP) +("SCALAR_UPWIND", SCALAR_UPWIND) +("CONVECTIVE_TEMPLATE", CONVECTIVE_TEMPLATE); + +/*! + * \brief Spatial numerical order integration + */ +enum ENUM_SPATIAL_ORDER { + FIRST_ORDER = 0, /*!< \brief First order */ + SECOND_ORDER = 1, /*!< \brief Second order. */ + SECOND_ORDER_LIMITER = 2 /*!< \brief Second order with limiter. */ +}; +static const map SpatialOrder_Map = CCreateMap +("1ST_ORDER", FIRST_ORDER) +("2ND_ORDER", SECOND_ORDER) +("2ND_ORDER_LIMITER", SECOND_ORDER_LIMITER); + +/*! + * \brief types of slope limiters + */ +enum ENUM_LIMITER { + VENKATAKRISHNAN = 0, /*!< \brief Slope limiter using Venkatakrisnan method. */ + BARTH_JESPERSEN = 1, /*!< \brief Slope limiter using Barth-Jespersen method. */ + SHARP_EDGES = 2, /*!< \brief Slope limiter using sharp edges. */ + SOLID_WALL_DISTANCE = 3 /*!< \brief Slope limiter using wall distance. */ +}; +static const map Limiter_Map = CCreateMap +("VENKATAKRISHNAN", VENKATAKRISHNAN) +("BARTH_JESPERSEN", BARTH_JESPERSEN) +("SHARP_EDGES", SHARP_EDGES) +("WALL_DISTANCE", SOLID_WALL_DISTANCE); + +/*! + * \brief types of turbulent models + */ +enum ENUM_TURB_MODEL { + NO_TURB_MODEL = 0, /*!< \brief No turbulence model. */ + SA = 1, /*!< \brief Kind of Turbulent model (Spalart-Allmaras). */ + SA_NEG = 2, /*!< \brief Kind of Turbulent model (Spalart-Allmaras). */ + SST = 3, /*!< \brief Kind of Turbulence model (Menter SST). */ +}; +static const map Turb_Model_Map = CCreateMap +("NONE", NO_TURB_MODEL) +("SA", SA) +("SA_NEG", SA_NEG) +("SST", SST); + +/*! + * \brief types of transition models + */ +enum ENUM_TRANS_MODEL { + NO_TRANS_MODEL = 0, /*!< \brief No transition model. */ + LM = 1 /*!< \brief Kind of transition model (LM for Spalart-Allmaras). */ +}; +static const map Trans_Model_Map = CCreateMap +("NONE", NO_TRANS_MODEL) +("LM", LM); + +/*! + * \brief type of time integration schemes + */ +enum ENUM_TIME_INT { + RUNGE_KUTTA_EXPLICIT = 1, /*!< \brief Explicit Runge-Kutta time integration definition. */ + EULER_EXPLICIT = 2, /*!< \brief Explicit Euler time integration definition. */ + EULER_IMPLICIT = 3 /*!< \brief Implicit Euler time integration definition. */ +}; +static const map Time_Int_Map = CCreateMap +("RUNGE-KUTTA_EXPLICIT", RUNGE_KUTTA_EXPLICIT) +("EULER_EXPLICIT", EULER_EXPLICIT) +("EULER_IMPLICIT", EULER_IMPLICIT); + +/*! + * \brief type of time integration schemes + */ +enum ENUM_TIME_INT_FEA { + CD_EXPLICIT = 1, /*!< \brief Support for implementing an explicit method. */ + NEWMARK_IMPLICIT = 2, /*!< \brief Implicit Newmark integration definition. */ + GA_IMPLICIT = 3 /*!< \brief Support for implementing another implicit method. */ +}; +static const map Time_Int_Map_FEA = CCreateMap +("CD_EXPLICIT", CD_EXPLICIT) +("NEWMARK_IMPLICIT", NEWMARK_IMPLICIT) +("GA_IMPLICIT", GA_IMPLICIT); + +/*! + * \brief types of schemes to compute the flow gradient + */ +enum ENUM_FLOW_GRADIENT { + GREEN_GAUSS = 1, /*!< \brief Gradients computation using Green Gauss theorem. */ + WEIGHTED_LEAST_SQUARES = 2 /*!< \brief Gradients computation using Weighted Least Squares. */ +}; +static const map Gradient_Map = CCreateMap +("GREEN_GAUSS", GREEN_GAUSS) +("WEIGHTED_LEAST_SQUARES", WEIGHTED_LEAST_SQUARES); + +/*! + * \brief types of action to take on a geometry structure + */ +enum GEOMETRY_ACTION { + ALLOCATE = 0, /*!< \brief Allocate geometry structure. */ + UPDATE = 1 /*!< \brief Update geometry structure (grid moving, adaptation, etc.). */ +}; + +/*! + * \brief types of action to perform when doing the geometry evaluation + */ +enum GEOMETRY_MODE { + FUNCTION = 0, /*!< \brief Geometrical analysis. */ + GRADIENT = 1 /*!< \brief Geometrical analysis and gradient using finite differences. */ +}; +static const map GeometryMode_Map = CCreateMap +("FUNCTION", FUNCTION) +("GRADIENT", GRADIENT); + +/*! + * \brief types of boundary conditions + */ +enum BC_TYPE { + EULER_WALL = 1, /*!< \brief Boundary Euler wall definition. */ + FAR_FIELD = 2, /*!< \brief Boundary far-field definition. */ + SYMMETRY_PLANE = 3, /*!< \brief Boundary symmetry plane definition. */ + INLET_FLOW = 4, /*!< \brief Boundary inlet flow definition. */ + OUTLET_FLOW = 5, /*!< \brief Boundary outlet flow definition. */ + PERIODIC_BOUNDARY = 6, /*!< \brief Periodic boundary definition. */ + NEARFIELD_BOUNDARY = 7, /*!< \brief Near-Field boundary definition. */ + ELECTRODE_BOUNDARY = 8, /*!< \brief Electrode boundary definition. */ + DIELEC_BOUNDARY = 9, /*!< \brief Dipoisson boundary definition. */ + CUSTOM_BOUNDARY = 10, /*!< \brief custom boundary definition. */ + INTERFACE_BOUNDARY = 11, /*!< \brief Domain interface boundary definition. */ + DIRICHLET = 12, /*!< \brief Boundary Euler wall definition. */ + NEUMANN = 13, /*!< \brief Boundary Neumann definition. */ + DISPLACEMENT_BOUNDARY = 14, /*!< \brief Boundary displacement definition. */ + LOAD_BOUNDARY = 15, /*!< \brief Boundary Load definition. */ + FLOWLOAD_BOUNDARY = 16, /*!< \brief Boundary Load definition. */ + SUPERSONIC_INLET = 19, /*!< \brief Boundary supersonic inlet definition. */ + SUPERSONIC_OUTLET = 20, /*!< \brief Boundary supersonic inlet definition. */ + ENGINE_INFLOW = 21, /*!< \brief Boundary nacelle inflow. */ + ENGINE_EXHAUST = 22, /*!< \brief Boundary nacelle exhaust. */ + ENGINE_BLEED = 23, /*!< \brief Boundary engine bleed. */ + RIEMANN_BOUNDARY= 24, /*!< \brief Riemann Boundary definition. */ + ISOTHERMAL = 25, /*!< \brief No slip isothermal wall boundary condition. */ + HEAT_FLUX = 26, /*!< \brief No slip constant heat flux wall boundary condition. */ + PRESSURE_BOUNDARY = 27, /*!< \brief Pressure boundary condition. */ + ACTDISK_INLET = 32, /*!< \brief Actuator disk inlet boundary definition. */ + ACTDISK_OUTLET = 33, /*!< \brief Actuator disk outlet boundary definition. */ + CLAMPED_BOUNDARY = 34, /*!< \brief Clamped Boundary definition. */ + LOAD_DIR_BOUNDARY = 35, /*!< \brief Boundary Load definition. */ LOAD_SINE_BOUNDARY = 36, /*!< \brief Sine-waveBoundary Load definition. */ - NRBC_BOUNDARY= 37, /*!< \brief NRBC Boundary definition. */ + NRBC_BOUNDARY= 37, /*!< \brief NRBC Boundary definition. */ SEND_RECEIVE = 99, /*!< \brief Boundary send-receive definition. */ -}; - - -/*! - * \brief different regime modes - */ -enum ENUM_2DFORM { - PLANE_STRESS = 0, /*!< \brief Definition of plane stress solver. */ - PLANE_STRAIN = 1 /*!< \brief Definition of plane strain solver. */ -}; -static const map ElasForm_2D = CCreateMap -("PLANE_STRESS", PLANE_STRESS) -("PLANE_STRAIN", PLANE_STRAIN); - - -/*! - * \brief different regime modes - */ -enum ENUM_AITKEN { - NO_RELAXATION = 0, /*!< \brief No relaxation in the strongly coupled approach. */ - FIXED_PARAMETER = 1, /*!< \brief Relaxation with a fixed parameter. */ - AITKEN_DYNAMIC = 2 /*!< \brief Relaxation using Aitken's dynamic parameter. */ -}; -static const map AitkenForm_Map = CCreateMap -("NONE", NO_RELAXATION) -("FIXED_PARAMETER", FIXED_PARAMETER) -("AITKEN_DYNAMIC", AITKEN_DYNAMIC); - - - -/*! - * \brief types Riemann boundary treatments - */ -enum RIEMANN_TYPE { - TOTAL_CONDITIONS_PT = 1, /*!< \brief User specifies total pressure, total temperature, and flow direction. */ - DENSITY_VELOCITY = 2, /*!< \brief User specifies density and velocity, and flow direction. */ - STATIC_PRESSURE = 3, /*!< \brief User specifies static pressure. */ - TOTAL_SUPERSONIC_INFLOW = 4, /*!< \brief User specifies total pressure, total temperature and Velocity components. */ - STATIC_SUPERSONIC_INFLOW_PT = 5, /*!< \brief User specifies static pressure, static temperature, and Mach components. */ - STATIC_SUPERSONIC_INFLOW_PD = 6, /*!< \brief User specifies static pressure, static temperature, and Mach components. */ - MIXING_IN = 7, /*!< \brief User does not specify anything information are retrieved from the other domain */ - MIXING_OUT = 8 /*!< \brief User does not specify anything information are retrieved from the other domain */ -}; - -static const map Riemann_Map = CCreateMap -("TOTAL_CONDITIONS_PT", TOTAL_CONDITIONS_PT) -("DENSITY_VELOCITY", DENSITY_VELOCITY) -("STATIC_PRESSURE", STATIC_PRESSURE) -("TOTAL_SUPERSONIC_INFLOW", TOTAL_SUPERSONIC_INFLOW) -("STATIC_SUPERSONIC_INFLOW_PT", STATIC_SUPERSONIC_INFLOW_PT) -("STATIC_SUPERSONIC_INFLOW_PD", STATIC_SUPERSONIC_INFLOW_PD) -("MIXING_IN", MIXING_IN) -("MIXING_OUT", MIXING_OUT); - - -static const map NRBC_Map = CCreateMap -("TOTAL_CONDITIONS_PT", TOTAL_CONDITIONS_PT) -("DENSITY_VELOCITY", DENSITY_VELOCITY) -("STATIC_PRESSURE", STATIC_PRESSURE) -("TOTAL_SUPERSONIC_INFLOW", TOTAL_SUPERSONIC_INFLOW) -("STATIC_SUPERSONIC_INFLOW_PT", STATIC_SUPERSONIC_INFLOW_PT) -("STATIC_SUPERSONIC_INFLOW_PD", STATIC_SUPERSONIC_INFLOW_PD) -("MIXING_IN", MIXING_IN) -("MIXING_OUT", MIXING_OUT); - - -/*! - * \brief types of mixing process for averaging quantities at the boundaries. - */ -enum MIXINGPROCESS_TYPE { - ALGEBRAIC_AVERAGE = 1, /*!< \brief an algebraic average is computed at the boundary of interest. */ - AREA_AVERAGE = 2, /*!< \brief an area average is computed at the boundary of interest. */ - MIXEDOUT_AVERAGE = 3 /*!< \brief an mixed-out average is computed at the boundary of interest. */ -}; - -static const map MixingProcess_Map = CCreateMap -("ALGEBRAIC_AVERAGE", ALGEBRAIC_AVERAGE) -("AREA_AVERAGE", AREA_AVERAGE) -("MIXEDOUT_AVERAGE", MIXEDOUT_AVERAGE); - -/*! - * \brief types of Turbomachinery performance indicators. - */ -enum TURBO_PERFORMANCE_TYPE { - BLADE = 1, /*!< \brief Turbomachinery blade performances. */ - STAGE = 2, /*!< \brief Turbomachinery blade stage performances. */ - TURBINE = 3 /*!< \brief Turbomachinery turbine performances. */ -}; - -static const map TurboPerformance_Map = CCreateMap -("BLADE", BLADE) -("STAGE", STAGE) -("TURBINE", TURBINE); - -/*! - * \brief types inlet boundary treatments - */ -enum INLET_TYPE { - TOTAL_CONDITIONS = 1, /*!< \brief User specifies total pressure, total temperature, and flow direction. */ - MASS_FLOW = 2 /*!< \brief User specifies density and velocity (mass flow). */ -}; -static const map Inlet_Map = CCreateMap -("TOTAL_CONDITIONS", TOTAL_CONDITIONS) -("MASS_FLOW", MASS_FLOW); - - -/*! - * \brief types of geometric entities based on VTK nomenclature - */ -enum GEO_TYPE { - VERTEX = 1, /*!< \brief VTK nomenclature for defining a vertex element. */ - LINE = 3, /*!< \brief VTK nomenclature for defining a line element. */ - TRIANGLE = 5, /*!< \brief VTK nomenclature for defining a triangle element. */ - QUADRILATERAL = 9, /*!< \brief VTK nomenclature for defining a quadrilateral element. */ - TETRAHEDRON = 10, /*!< \brief VTK nomenclature for defining a tetrahedron element. */ - HEXAHEDRON = 12, /*!< \brief VTK nomenclature for defining a hexahedron element. */ - PRISM = 13, /*!< \brief VTK nomenclature for defining a prism element. */ - PYRAMID = 14 /*!< \brief VTK nomenclature for defining a pyramid element. */ -}; - -/*! - * \brief types of objective functions - */ -enum ENUM_OBJECTIVE { - DRAG_COEFFICIENT = 1, /*!< \brief Drag objective function definition. */ - LIFT_COEFFICIENT = 2, /*!< \brief Lift objective function definition. */ - SIDEFORCE_COEFFICIENT = 3, /*!< \brief Side force objective function definition. */ - EFFICIENCY = 4, /*!< \brief Efficiency objective function definition. */ - INVERSE_DESIGN_PRESSURE = 5, /*!< \brief Pressure objective function definition (inverse design). */ - INVERSE_DESIGN_HEATFLUX = 6, /*!< \brief Heat flux objective function definition (inverse design). */ - TOTAL_HEATFLUX = 7, /*!< \brief Total heat flux. */ - MAXIMUM_HEATFLUX = 8, /*!< \brief Maximum heat flux. */ - MOMENT_X_COEFFICIENT = 9, /*!< \brief Pitching moment objective function definition. */ - MOMENT_Y_COEFFICIENT = 10, /*!< \brief Rolling moment objective function definition. */ - MOMENT_Z_COEFFICIENT = 11, /*!< \brief Yawing objective function definition. */ - EQUIVALENT_AREA = 12, /*!< \brief Equivalent area objective function definition. */ - NEARFIELD_PRESSURE = 13, /*!< \brief NearField Pressure objective function definition. */ - FORCE_X_COEFFICIENT = 14, /*!< \brief X-direction force objective function definition. */ - FORCE_Y_COEFFICIENT = 15, /*!< \brief Y-direction force objective function definition. */ - FORCE_Z_COEFFICIENT = 16, /*!< \brief Z-direction force objective function definition. */ - THRUST_COEFFICIENT = 17, /*!< \brief Thrust objective function definition. */ - TORQUE_COEFFICIENT = 18, /*!< \brief Torque objective function definition. */ - FIGURE_OF_MERIT = 19, /*!< \brief Rotor Figure of Merit objective function definition. */ - FREE_SURFACE = 20, /*!< \brief Free Surface objective function definition. */ - MAX_THICKNESS = 21, /*!< \brief Maximum thickness. */ - MIN_THICKNESS = 22, /*!< \brief Minimum thickness. */ - MAX_THICK_SEC1 = 23, /*!< \brief Maximum thickness in section 1. */ - MAX_THICK_SEC2 = 24, /*!< \brief Maximum thickness in section 2. */ - MAX_THICK_SEC3 = 25, /*!< \brief Maximum thickness in section 3. */ - MAX_THICK_SEC4 = 26, /*!< \brief Maximum thickness in section 4. */ - MAX_THICK_SEC5 = 27, /*!< \brief Maximum thickness in section 5. */ - AVG_TOTAL_PRESSURE = 28, /*!< \brief Total Pressure objective function definition. */ - AVG_OUTLET_PRESSURE = 29, /*!< \brief Static Pressure objective function definition. */ - MASS_FLOW_RATE = 30, /*!< \brief Mass Flow Rate objective function definition. */ - OUTLET_CHAIN_RULE=31 /*!<\brief Objective function defined via chain rule on primitive variable gradients. */ -}; - -static const map Objective_Map = CCreateMap -("DRAG", DRAG_COEFFICIENT) -("LIFT", LIFT_COEFFICIENT) -("SIDEFORCE", SIDEFORCE_COEFFICIENT) -("EFFICIENCY", EFFICIENCY) -("INVERSE_DESIGN_PRESSURE", INVERSE_DESIGN_PRESSURE) -("INVERSE_DESIGN_HEATFLUX", INVERSE_DESIGN_HEATFLUX) -("MOMENT_X", MOMENT_X_COEFFICIENT) -("MOMENT_Y", MOMENT_Y_COEFFICIENT) -("MOMENT_Z", MOMENT_Z_COEFFICIENT) -("EQUIVALENT_AREA", EQUIVALENT_AREA) -("NEARFIELD_PRESSURE", NEARFIELD_PRESSURE) -("FORCE_X", FORCE_X_COEFFICIENT) -("FORCE_Y", FORCE_Y_COEFFICIENT) -("FORCE_Z", FORCE_Z_COEFFICIENT) -("THRUST", THRUST_COEFFICIENT) -("TORQUE", TORQUE_COEFFICIENT) -("TOTAL_HEATFLUX", TOTAL_HEATFLUX) -("MAXIMUM_HEATFLUX", MAXIMUM_HEATFLUX) -("FIGURE_OF_MERIT", FIGURE_OF_MERIT) -("FREE_SURFACE", FREE_SURFACE) -("MAX_THICKNESS", MAX_THICKNESS) -("MIN_THICKNESS", MIN_THICKNESS) -("MAX_THICK_SEC1", MAX_THICK_SEC1) -("MAX_THICK_SEC2", MAX_THICK_SEC2) -("MAX_THICK_SEC3", MAX_THICK_SEC3) -("MAX_THICK_SEC4", MAX_THICK_SEC4) -("MAX_THICK_SEC5", MAX_THICK_SEC5) -("AVG_TOTAL_PRESSURE", AVG_TOTAL_PRESSURE) -("AVG_OUTLET_PRESSURE", AVG_OUTLET_PRESSURE) -("MASS_FLOW_RATE", MASS_FLOW_RATE) -("OUTLET_CHAIN_RULE", OUTLET_CHAIN_RULE); - -/*! - * \brief types of residual criteria equations - */ - -enum ENUM_RESIDUAL { - RHO_RESIDUAL = 1, /*!< \brief Rho equation residual criteria equation. */ - RHO_ENERGY_RESIDUAL = 2 /*!< \brief RhoE equation residual criteria equation. */ -}; - -static const map Residual_Map = CCreateMap -("RHO", RHO_RESIDUAL) -("RHO_ENERGY", RHO_ENERGY_RESIDUAL); - -/*! - * \brief types of sensitivities to compute - */ -enum ENUM_SENS { - SENS_GEOMETRY = 1, /*!< \brief Geometrical sensitivity. */ - SENS_MACH = 2, /*!< \brief Mach number sensitivity. */ - SENS_AOA = 3, /*!< \brief Angle of attack sensitivity. */ - SENS_AOS = 4 /*!< \brief Angle of Sideslip sensitivity. */ -}; -static const map Sens_Map = CCreateMap -("SENS_GEOMETRY", SENS_GEOMETRY) -("SENS_MACH", SENS_MACH) -("SENS_AOA", SENS_AOA) -("SENS_AOS", SENS_AOS); - -/*! - * \brief types of grid adaptation/refinement - */ -enum ENUM_ADAPT { - NO_ADAPT = 0, /*!< \brief No grid adaptation. */ - FULL = 1, /*!< \brief Do a complete grid refinement of all the computational grids. */ - FULL_FLOW = 2, /*!< \brief Do a complete grid refinement of the flow grid. */ - FULL_ADJOINT = 3, /*!< \brief Do a complete grid refinement of the adjoint grid. */ - GRAD_FLOW = 5, /*!< \brief Do a gradient based grid adaptation of the flow grid. */ - GRAD_ADJOINT = 6, /*!< \brief Do a gradient based grid adaptation of the adjoint grid. */ - GRAD_FLOW_ADJ = 7, /*!< \brief Do a gradient based grid adaptation of the flow and adjoint grid. */ - COMPUTABLE = 9, /*!< \brief Apply a computable error grid adaptation. */ - REMAINING = 10, /*!< \brief Apply a remaining error grid adaptation. */ - WAKE = 12, /*!< \brief Do a grid refinement on the wake. */ - SMOOTHING = 14, /*!< \brief Do a grid smoothing of the geometry. */ - SUPERSONIC_SHOCK = 15, /*!< \brief Do a grid smoothing. */ - PERIODIC = 17 /*!< \brief Add the periodic halo cells. */ -}; -static const map Adapt_Map = CCreateMap -("NONE", NO_ADAPT) -("FULL", FULL) -("FULL_FLOW", FULL_FLOW) -("FULL_ADJOINT", FULL_ADJOINT) -("GRAD_FLOW", GRAD_FLOW) -("GRAD_ADJOINT", GRAD_ADJOINT) -("GRAD_FLOW_ADJ", GRAD_FLOW_ADJ) -("COMPUTABLE", COMPUTABLE) -("REMAINING", REMAINING) -("WAKE", WAKE) -("SMOOTHING", SMOOTHING) -("SUPERSONIC_SHOCK", SUPERSONIC_SHOCK) -("PERIODIC", PERIODIC); - -/*! - * \brief types of input file formats - */ -enum ENUM_INPUT { - SU2 = 1, /*!< \brief SU2 input format. */ - CGNS = 2 /*!< \brief CGNS input format for the computational grid. */ -}; -static const map Input_Map = CCreateMap -("SU2", SU2) -("CGNS", CGNS); - -const int CGNS_STRING_SIZE = 33;/*!< \brief Length of strings used in the CGNS format. */ - -/*! - * \brief type of solution output file formats - */ -enum ENUM_OUTPUT { - TECPLOT = 1, /*!< \brief Tecplot format for the solution output. */ - TECPLOT_BINARY = 2, /*!< \brief Tecplot binary format for the solution output. */ - FIELDVIEW = 3, /*!< \brief FieldView format for the solution output. */ - FIELDVIEW_BINARY = 4, /*!< \brief FieldView binary format for the solution output. */ - CSV = 5, /*!< \brief Comma-separated values format for the solution output. */ - CGNS_SOL = 6, /*!< \brief CGNS format for the solution output. */ - PARAVIEW = 7 /*!< \brief Paraview format for the solution output. */ -}; -static const map Output_Map = CCreateMap -("TECPLOT", TECPLOT) -("TECPLOT_BINARY", TECPLOT_BINARY) -("FIELDVIEW", FIELDVIEW) -("FIELDVIEW_BINARY", FIELDVIEW_BINARY) -("CSV", CSV) -("CGNS", CGNS_SOL) -("PARAVIEW", PARAVIEW); - -/*! - * \brief type of multigrid cycle - */ -enum MG_CYCLE { - V_CYCLE = 0, /*!< \brief V cycle. */ - W_CYCLE = 1, /*!< \brief W cycle. */ - FULLMG_CYCLE = 2 /*!< \brief FullMG cycle. */ -}; -static const map MG_Cycle_Map = CCreateMap -("V_CYCLE", V_CYCLE) -("W_CYCLE", W_CYCLE) -("FULLMG_CYCLE", FULLMG_CYCLE); - -/*! - * \brief type of solution output variables - */ -enum ENUM_OUTPUT_VARS { - DENSITY = 1, /*!< \brief Density. */ - VEL_X = 2, /*!< \brief X-component of velocity. */ - VEL_Y = 3, /*!< \brief Y-component of velocity. */ - VEL_Z = 4, /*!< \brief Z-component of velocity. */ - PRESSURE = 5, /*!< \brief Static pressure. */ - MACH = 6, /*!< \brief Mach number. */ - TEMPERATURE = 7, /*!< \brief Temperature. */ - LAM_VISC = 8, /*!< \brief Laminar viscosity. */ - EDDY_VISC = 9 /*!< \brief Eddy viscosity. */ -}; -static const map Output_Vars_Map = CCreateMap -("DENSITY", DENSITY) -("VEL_X", VEL_X) -("VEL_Y", VEL_Y) -("VEL_Z", VEL_Z) -("PRESSURE", PRESSURE) -("MACH", MACH) -("TEMPERATURE", TEMPERATURE) -("LAM_VISC", LAM_VISC) -("EDDY_VISC", EDDY_VISC); - -/*! - * \brief types of design parameterizations - */ -enum ENUM_PARAM { - TRANSLATION = 0, /*!< \brief Surface movement as design variable. */ - ROTATION = 1, /*!< \brief Surface rotation as design variable. */ - SCALE = 2, /*!< \brief Surface rotation as design variable. */ - FFD_SETTING = 3, /*!< \brief No surface deformation. */ - FFD_CONTROL_POINT = 4, /*!< \brief Free form deformation for 3D design (change a control point). */ - FFD_CAMBER = 5, /*!< \brief Free form deformation for 3D design (camber change). */ - FFD_THICKNESS = 6, /*!< \brief Free form deformation for 3D design (thickness change). */ - FFD_DIHEDRAL_ANGLE = 7, /*!< \brief Free form deformation for 3D design (change the dihedral angle). */ - FFD_TWIST_ANGLE = 8, /*!< \brief Free form deformation for 3D design (change the twist angle). */ - FFD_ROTATION = 9, /*!< \brief Free form deformation for 3D design (rotation around a line). */ - FFD_CONTROL_POINT_2D = 10, /*!< \brief Free form deformation for 2D design (change a control point). */ - FFD_CAMBER_2D = 11, /*!< \brief Free form deformation for 3D design (camber change). */ - FFD_THICKNESS_2D = 12, /*!< \brief Free form deformation for 3D design (thickness change). */ - FFD_CONTROL_SURFACE = 13, /*!< \brief Free form deformation for 3D design (control surface). */ - HICKS_HENNE = 14, /*!< \brief Hicks-Henne bump function for airfoil deformation. */ - PARABOLIC = 15, /*!< \brief Parabolic airfoil definition as design variables. */ - NACA_4DIGITS = 16, /*!< \brief The four digits NACA airfoil family as design variables. */ - AIRFOIL = 17, /*!< \brief Airfoil definition as design variables. */ - SURFACE_FILE = 18 /*!< Nodal coordinates set using a surface file. */ -}; -static const map Param_Map = CCreateMap -("FFD_SETTING", FFD_SETTING) -("FFD_CONTROL_POINT_2D", FFD_CONTROL_POINT_2D) -("FFD_CAMBER_2D", FFD_CAMBER_2D) -("FFD_THICKNESS_2D", FFD_THICKNESS_2D) -("HICKS_HENNE", HICKS_HENNE) -("NACA_4DIGITS", NACA_4DIGITS) -("TRANSLATION", TRANSLATION) -("ROTATION", ROTATION) -("SCALE", SCALE) -("FFD_CONTROL_POINT", FFD_CONTROL_POINT) -("FFD_DIHEDRAL_ANGLE", FFD_DIHEDRAL_ANGLE) -("FFD_TWIST_ANGLE", FFD_TWIST_ANGLE) -("FFD_ROTATION", FFD_ROTATION) -("FFD_CONTROL_SURFACE", FFD_CONTROL_SURFACE) -("FFD_CAMBER", FFD_CAMBER) -("FFD_THICKNESS", FFD_THICKNESS) -("PARABOLIC", PARABOLIC) -("AIRFOIL", AIRFOIL) -("SURFACE_FILE", SURFACE_FILE); - -/*! - * \brief types of solvers for solving linear systems - */ -enum ENUM_LINEAR_SOLVER { - STEEPEST_DESCENT = 1, /*!< \brief Steepest descent method for point inversion algoritm (Free-Form). */ - NEWTON = 2, /*!< \brief Newton method for point inversion algorithm (Free-Form). */ - QUASI_NEWTON = 3, /*!< \brief Quasi Newton method for point inversion algorithm (Free-Form). */ - CONJUGATE_GRADIENT = 4, /*!< \brief Preconditionated conjugate gradient method for grid deformation. */ - FGMRES = 5, /*!< \brief Flexible Generalized Minimal Residual method. */ - BCGSTAB = 6, /*!< \brief BCGSTAB - Biconjugate Gradient Stabilized Method (main solver). */ - RESTARTED_FGMRES = 7, /*!< \brief Flexible Generalized Minimal Residual method with restart. */ - SMOOTHER_LUSGS = 8, /*!< \brief LU_SGS smoother. */ - SMOOTHER_JACOBI = 9, /*!< \brief Jacobi smoother. */ - SMOOTHER_ILU = 10, /*!< \brief ILU smoother. */ - SMOOTHER_LINELET = 11 /*!< \brief Linelet smoother. */ -}; -static const map Linear_Solver_Map = CCreateMap -("STEEPEST_DESCENT", STEEPEST_DESCENT) -("NEWTON", NEWTON) -("QUASI_NEWTON", QUASI_NEWTON) -("CONJUGATE_GRADIENT", CONJUGATE_GRADIENT) -("BCGSTAB", BCGSTAB) -("FGMRES", FGMRES) -("RESTARTED_FGMRES", RESTARTED_FGMRES) -("SMOOTHER_LUSGS", SMOOTHER_LUSGS) -("SMOOTHER_JACOBI", SMOOTHER_JACOBI) -("SMOOTHER_LINELET", SMOOTHER_LINELET) -("SMOOTHER_ILU0", SMOOTHER_ILU); - -/*! - * \brief types surface continuity at the intersection with the FFD - */ -enum ENUM_FFD_CONTINUITY { - DERIVATIVE_1ST = 1, /*!< \brief First derivative continuity. */ - DERIVATIVE_2ND = 2 /*!< \brief Second derivative continuity. */ -}; -static const map Continuity_Map = CCreateMap -("1ST_DERIVATIVE", DERIVATIVE_1ST) -("2ND_DERIVATIVE", DERIVATIVE_2ND); - -/*! - * \brief types of sensitivity smoothing - */ -enum ENUM_SENS_SMOOTHING { - NO_SMOOTH = 0, /*!< \brief No smoothing. */ - SOBOLEV = 1, /*!< \brief Sobolev gradient smoothing. */ - BIGRID = 2 /*!< \brief Bi-grid technique smoothing. */ -}; -static const map Sens_Smoothing_Map = CCreateMap -("NONE", NO_SMOOTH) -("SOBOLEV", SOBOLEV) -("BIGRID", BIGRID); - -/*! - * \brief types of preconditioners for the linear solver - */ -enum ENUM_LINEAR_SOLVER_PREC { - JACOBI = 1, /*!< \brief Jacobi preconditioner. */ - LU_SGS = 2, /*!< \brief LU SGS preconditioner. */ - LINELET = 3, /*!< \brief Line implicit preconditioner. */ - ILU = 4 /*!< \brief ILU(0) preconditioner. */ -}; -static const map Linear_Solver_Prec_Map = CCreateMap -("JACOBI", JACOBI) -("LU_SGS", LU_SGS) -("LINELET", LINELET) -("ILU0", ILU); - -/*! - * \brief types of analytic definitions for various geometries - */ -enum ENUM_GEO_ANALYTIC { - NO_GEO_ANALYTIC = 0, /*!< \brief No analytic definition of the geometry. */ - NACA0012_AIRFOIL = 1, /*!< \brief Use the analytical definition of the NACA0012 for doing the grid adaptation. */ - NACA4412_AIRFOIL = 2, /*!< \brief Use the analytical definition of the NACA4412 for doing the grid adaptation. */ - CYLINDER = 3, /*!< \brief Use the analytical definition of a cylinder for doing the grid adaptation. */ - BIPARABOLIC = 4 /*!< \brief Use the analytical definition of a biparabolic airfoil for doing the grid adaptation. */ -}; -static const map Geo_Analytic_Map = CCreateMap -("NONE", NO_GEO_ANALYTIC) -("NACA0012_AIRFOIL", NACA0012_AIRFOIL) -("NACA4412_AIRFOIL", NACA4412_AIRFOIL) -("CYLINDER", CYLINDER) -("BIPARABOLIC", BIPARABOLIC); - -/*! - * \brief types of axis orientation - */ -enum ENUM_AXIS_ORIENTATION { - X_AXIS = 0, /*!< \brief X axis orientation. */ - Y_AXIS = 1, /*!< \brief Y axis orientation. */ - Z_AXIS = 2 /*!< \brief Z axis orientation. */ -}; -static const map Axis_Orientation_Map = CCreateMap -("X_AXIS", X_AXIS) -("Y_AXIS", Y_AXIS) -("Z_AXIS", Z_AXIS); - -/*! - * \brief types of schemes for unsteady computations - */ -enum ENUM_UNSTEADY { - STEADY = 0, /*!< \brief A steady computation. */ - TIME_STEPPING = 1, /*!< \brief Use a time stepping strategy for unsteady computations. */ - DT_STEPPING_1ST = 2, /*!< \brief Use a dual time stepping strategy for unsteady computations (1st order). */ - DT_STEPPING_2ND = 3, /*!< \brief Use a dual time stepping strategy for unsteady computations (2nd order). */ - ROTATIONAL_FRAME = 4, /*!< \brief Use a rotational source term. */ - TIME_SPECTRAL = 5 /*!< \brief Use a time spectral source term. */ - -}; -static const map Unsteady_Map = CCreateMap -("NO", STEADY) -("TIME_STEPPING", TIME_STEPPING) -("DUAL_TIME_STEPPING-1ST_ORDER", DT_STEPPING_1ST) -("DUAL_TIME_STEPPING-2ND_ORDER", DT_STEPPING_2ND) -("TIME_SPECTRAL", TIME_SPECTRAL) -("ROTATIONAL_FRAME", ROTATIONAL_FRAME); - -/*! - * \brief types of criteria to determine when the solution is converged - */ -enum ENUM_CONVERGE_CRIT { - CAUCHY = 1, /*!< \brief Cauchy criteria to establish the convergence of the code. */ - RESIDUAL = 2 /*!< \brief Residual criteria to establish the convergence of the code. */ -}; -static const map Converge_Crit_Map = CCreateMap -("CAUCHY", CAUCHY) -("RESIDUAL", RESIDUAL); - -/*! - * \brief types of element stiffnesses imposed for FEA mesh deformation - */ -enum ENUM_DEFORM_STIFFNESS { - CONSTANT_STIFFNESS = 0, /*!< \brief Impose a constant stiffness for each element (steel). */ - INVERSE_VOLUME = 1, /*!< \brief Impose a stiffness for each element that is inversely proportional to cell volume. */ - WALL_DISTANCE = 2 /*!< \brief Impose a stiffness for each element that is proportional to the distance from the deforming surface. */ -}; -static const map Deform_Stiffness_Map = CCreateMap -("CONSTANT_STIFFNESS", CONSTANT_STIFFNESS) -("INVERSE_VOLUME", INVERSE_VOLUME) -("WALL_DISTANCE", WALL_DISTANCE); - -/*! - * \brief The direct differentation variables. - */ -enum ENUM_DIRECTDIFF_VAR { - NO_DERIVATIVE = 0, - D_MACH = 1, /*!< \brief Derivative with respect to the mach number */ - D_AOA = 2, /*!< \brief Derivative with respect to the angle of attack */ - D_PRESSURE = 3, /*!< \brief Derivative with respect to the freestream pressure */ - D_TEMPERATURE = 4,/*!< \brief Derivative with respect to the freestream temperature */ - D_DENSITY = 5, - D_TURB2LAM = 6, - D_SIDESLIP = 7, - D_VISCOSITY = 8, - D_REYNOLDS = 9, - D_DESIGN = 10 -}; -static const map DirectDiff_Var_Map = CCreateMap -("NONE", NO_DERIVATIVE) -("MACH", D_MACH) -("AOA", D_AOA) -("PRESSURE", D_PRESSURE) -("TEMPERATURE", D_TEMPERATURE) -("DENSITY", D_DENSITY) -("TURB2LAM", D_TURB2LAM) -("SIDESLIP", D_SIDESLIP) -("VISCOSITY", D_VISCOSITY) -("REYNOLDS", D_REYNOLDS) -("DESIGN_VARIABLES", D_DESIGN); - -/*! - * \brief types of schemes for dynamic structural computations - */ -enum ENUM_DYNAMIC { - STATIC = 0, /*!< \brief A static structural computation. */ - DYNAMIC = 1 /*!< \brief Use a time stepping strategy for dynamic computations. */ -}; -static const map Dynamic_Map = CCreateMap -("NO", STATIC) -("YES", DYNAMIC); - -/* END_CONFIG_ENUMS */ - -class COptionBase{ -private: -public: - COptionBase() {}; - virtual ~COptionBase() = 0; - // virtual string SetValue(string) {SU2MPI::PrintAndFinalize("shouldn't be here"); return "";}; - virtual string SetValue(vector) = 0; - virtual void SetDefault() = 0; - - string optionCheckMultipleValues(vector & option_value, string type_id, string option_name) { - if (option_value.size() != 1) { - string newString; - newString.append(option_name); - newString.append(": multiple values for type "); - newString.append(type_id); - return newString; - } - return ""; - } - - string badValue(vector & option_value, string type_id, string option_name) { - string newString; - newString.append(option_name); - newString.append(": improper option value for type "); - newString.append(type_id); - return newString; - } -}; - -inline COptionBase::~COptionBase() {} - - -template -class COptionEnum : public COptionBase{ - - map m; - unsigned short & field; // Reference to the feildname - Tenum def; // Default value - string name; // identifier for the option - -public: - COptionEnum(string option_field_name, const map m, unsigned short & option_field, Tenum default_value) : field(option_field) { - this->m = m; - this->def = default_value; - this->name = option_field_name; - } - - ~COptionEnum() {}; - string SetValue(vector option_value) { - // Check if there is more than one string - string out = optionCheckMultipleValues(option_value, "enum", this->name); - if (out.compare("") != 0) { - return out; - } - - // Check to see if the enum value is in the map - if (this->m.find(option_value[0]) == m.end()) { - string str; - str.append(this->name); - str.append(": invalid option value "); - str.append(option_value[0]); - str.append(". Check current SU2 options in config_template.cfg."); - return str; - } - // If it is there, set the option value - Tenum val = this->m[option_value[0]]; - this->field = val; - return ""; - } - - void SetDefault() { - this->field = this->def; - } -}; - -class COptionDouble : public COptionBase{ - su2double & field; // Reference to the fieldname - su2double def; // Default value - string name; // identifier for the option - -public: - COptionDouble(string option_field_name, su2double & option_field, su2double default_value) : field(option_field) { - this->def = default_value; - this->name = option_field_name; - } - - ~COptionDouble() {}; - string SetValue(vector option_value) { - // check if there is more than one value - string out = optionCheckMultipleValues(option_value, "su2double", this->name); - if (out.compare("") != 0) { - return out; - } - istringstream is(option_value[0]); - su2double val; - if (is >> val) { - this->field = val; - return ""; - } - return badValue(option_value, "su2double", this->name); - } - void SetDefault() { - this->field = this->def; - } -}; - -class COptionString : public COptionBase{ - string & field; // Reference to the fieldname - string def; // Default value - string name; // identifier for the option - -public: - COptionString(string option_field_name, string & option_field, string default_value) : field(option_field) { - this->def = default_value; - this->name = option_field_name; - } - - ~COptionString() {}; - string SetValue(vector option_value) { - // check if there is more than one value - string out = optionCheckMultipleValues(option_value, "su2double", this->name); - if (out.compare("") != 0) { - return out; - } - this->field.assign(option_value[0]); - return ""; - } - void SetDefault() { - this->field = this->def; - } -}; - -class COptionInt : public COptionBase{ - int & field; // Reference to the feildname - int def; // Default value - string name; // identifier for the option - -public: - COptionInt(string option_field_name, int & option_field, int default_value) : field(option_field) { - this->def = default_value; - this->name = option_field_name; - } - - ~COptionInt() {}; - string SetValue(vector option_value) { - string out = optionCheckMultipleValues(option_value, "int", this->name); - if (out.compare("") != 0) { - return out; - } - istringstream is(option_value[0]); - int val; - if (is >> val) { - this->field = val; - return ""; - } - return badValue(option_value, "int", this->name); - } - void SetDefault() { - this->field = this->def; - } -}; - -class COptionULong : public COptionBase{ - unsigned long & field; // Reference to the feildname - unsigned long def; // Default value - string name; // identifier for the option - -public: - COptionULong(string option_field_name, unsigned long & option_field, unsigned long default_value) : field(option_field) { - this->def = default_value; - this->name = option_field_name; - } - - ~COptionULong() {}; - string SetValue(vector option_value) { - string out = optionCheckMultipleValues(option_value, "unsigned long", this->name); - if (out.compare("") != 0) { - return out; - } - istringstream is(option_value[0]); - unsigned long val; - if (is >> val) { - this->field = val; - return ""; - } - return badValue(option_value, "unsigned long", this->name); - } - void SetDefault() { - this->field = this->def; - } -}; - -class COptionUShort : public COptionBase{ - unsigned short & field; // Reference to the feildname - unsigned short def; // Default value - string name; // identifier for the option - -public: - COptionUShort(string option_field_name, unsigned short & option_field, unsigned short default_value) : field(option_field) { - this->def = default_value; - this->name = option_field_name; - } - - ~COptionUShort() {}; - string SetValue(vector option_value) { - string out = optionCheckMultipleValues(option_value, "unsigned short", this->name); - if (out.compare("") != 0) { - return out; - } - istringstream is(option_value[0]); - unsigned short val; - if (is >> val) { - this->field = val; - return ""; - } - return badValue(option_value, "unsigned short", this->name); - } - void SetDefault() { - this->field = this->def; - } -}; - -class COptionLong : public COptionBase{ - long & field; // Reference to the feildname - long def; // Default value - string name; // identifier for the option - -public: - COptionLong(string option_field_name, long & option_field, long default_value) : field(option_field) { - this->def = default_value; - this->name = option_field_name; - } - - ~COptionLong() {}; - string SetValue(vector option_value) { - string out = optionCheckMultipleValues(option_value, "long", this->name); - if (out.compare("") != 0) { - return out; - } - istringstream is(option_value[0]); - long val; - if (is >> val) { - this->field = val; - return ""; - } - return badValue(option_value, "long", this->name); - } - void SetDefault() { - this->field = this->def; - } -}; - - -class COptionBool : public COptionBase{ - bool & field; // Reference to the feildname - bool def; // Default value - string name; // identifier for the option - -public: - COptionBool(string option_field_name, bool & option_field, bool default_value) : field(option_field) { - this->def = default_value; - this->name = option_field_name; - } - - ~COptionBool() {}; - string SetValue(vector option_value) { - // check if there is more than one value - string out = optionCheckMultipleValues(option_value, "bool", this->name); - if (out.compare("") != 0) { - return out; - } - if (option_value[0].compare("YES") == 0) { - this->field = true; - return ""; - } - if (option_value[0].compare("NO") == 0) { - this->field = false; - return ""; - } - return badValue(option_value, "bool", this->name); - } - void SetDefault() { - this->field = this->def; - } -}; - -template -class COptionEnumList : public COptionBase{ - - map m; - unsigned short * & field; // Reference to the feildname - string name; // identifier for the option - unsigned short & size; - -public: - COptionEnumList(string option_field_name, const map m, unsigned short * & option_field, unsigned short & list_size) : field(option_field) , size(list_size) { - this->m = m; - this->name = option_field_name; - } - - ~COptionEnumList() {}; - string SetValue(vector option_value) { - if (option_value.size() == 1 && option_value[0].compare("NONE") == 0) { - this->size = 0; - return ""; - } - // size is the length of the option list - this->size = option_value.size(); - unsigned short * enums = new unsigned short[size]; - for (int i = 0; i < this->size; i++) { - // Check to see if the enum value is in the map - if (this->m.find(option_value[i]) == m.end()) { - string str; - str.append(this->name); - str.append(": invalid option value "); - str.append(option_value[i]); - str.append(". Check current SU2 options in config_template.cfg."); - return str; - } - // If it is there, set the option value - enums[i] = this->m[option_value[i]]; - } - this->field = enums; - return ""; - } - - void SetDefault() { - // No default to set - size = 0; - } -}; - -class COptionDoubleArray : public COptionBase{ - su2double * & field; // Reference to the feildname - string name; // identifier for the option - const int size; - su2double * default_value; - -public: - COptionDoubleArray(string option_field_name, const int list_size, su2double * & option_field, su2double * default_value) : field(option_field), size(list_size) { - this->name = option_field_name; - this->default_value = default_value; - } - - ~COptionDoubleArray() {}; - string SetValue(vector option_value) { - // Check that the size is correct - if (option_value.size() != (unsigned long)this->size) { - string newstring; - newstring.append(this->name); - newstring.append(": wrong number of arguments: "); - stringstream ss; - ss << this->size; - newstring.append(ss.str()); - newstring.append(" expected, "); - stringstream ss2; - ss2 << option_value.size(); - newstring.append(ss2.str()); - newstring.append(" found"); - return newstring; - } - su2double * vals = new su2double[this->size]; - for (int i = 0; i < this->size; i++) { - istringstream is(option_value[i]); - su2double val; - if (!(is >> val)) { - delete [] vals; - return badValue(option_value, "su2double array", this->name); - } - vals[i] = val; - } - this->field = vals; - return ""; - } - - void SetDefault() { - this->field = this->default_value; - } -}; - -class COptionDoubleList : public COptionBase{ - su2double * & field; // Reference to the feildname - string name; // identifier for the option - unsigned short & size; - -public: - COptionDoubleList(string option_field_name, unsigned short & list_size, su2double * & option_field) : field(option_field), size(list_size) { - this->name = option_field_name; - } - - ~COptionDoubleList() {}; - string SetValue(vector option_value) { - // The size is the length of option_value - unsigned short option_size = option_value.size(); - if (option_size == 1 && option_value[0].compare("NONE") == 0) { - // No options - this->size = 0; - return ""; - } - - this->size = option_size; - - // Parse all of the options - su2double * vals = new su2double[option_size]; - for (unsigned long i = 0; i < option_size; i++) { - istringstream is(option_value[i]); - su2double val; - if (!(is >> val)) { - delete [] vals; - return badValue(option_value, "su2double list", this->name); - } - vals[i] = val; - } - this->field = vals; - return ""; - } - - void SetDefault() { - this->size = 0; // There is no default value for list - } -}; - -class COptionUShortList : public COptionBase{ - unsigned short * & field; // Reference to the feildname - string name; // identifier for the option - unsigned short & size; - -public: - COptionUShortList(string option_field_name, unsigned short & list_size, unsigned short * & option_field) : field(option_field), size(list_size) { - this->name = option_field_name; - } - - ~COptionUShortList() {}; - string SetValue(vector option_value) { - // The size is the length of option_value - unsigned short option_size = option_value.size(); - if (option_size == 1 && option_value[0].compare("NONE") == 0) { - // No options - this->size = 0; - return ""; - } - this->size = option_size; - - // Parse all of the options - unsigned short * vals = new unsigned short[option_size]; - for (unsigned long i = 0; i < option_size; i++) { - istringstream is(option_value[i]); - unsigned short val; - if (!(is >> val)) { - delete [] vals; - return badValue(option_value, "unsigned short", this->name); - } - vals[i] = val; - } - this->field = vals; - return ""; - } - - void SetDefault() { - this->size = 0; // There is no default value for list - } -}; - -class COptionStringList : public COptionBase{ - string * & field; // Reference to the feildname - string name; // identifier for the option - unsigned short & size; - -public: - COptionStringList(string option_field_name, unsigned short & list_size, string * & option_field) : field(option_field), size(list_size) { - this->name = option_field_name; - } - - ~COptionStringList() {}; - string SetValue(vector option_value) { - // The size is the length of option_value - unsigned short option_size = option_value.size(); - if (option_size == 1 && option_value[0].compare("NONE") == 0) { - this->size = 0; - return ""; - } - this->size = option_size; - - // Parse all of the options - string * vals = new string[option_size]; - for (unsigned long i = 0; i < option_size; i++) { - vals[i].assign(option_value[i]); - } - this->field = vals; - return ""; - } - - void SetDefault() { - this->size = 0; // There is no default value for list - } -}; - -class COptionConvect : public COptionBase{ - string name; // identifier for the option - unsigned short & space; - unsigned short & centered; - unsigned short & upwind; - -public: - COptionConvect(string option_field_name, unsigned short & space_field, unsigned short & centered_field, unsigned short & upwind_field) : space(space_field), centered(centered_field), upwind(upwind_field) { - this->name = option_field_name; - } - - ~COptionConvect() {}; - string SetValue(vector option_value) { - - string out = optionCheckMultipleValues(option_value, "unsigned short", this->name); - if (out.compare("") != 0) { - return out; - } - - if (Centered_Map.count(option_value[0])) { - this->space = Space_Map.find("SPACE_CENTERED")->second; - this->centered = Centered_Map.find(option_value[0])->second; - this->upwind = NO_UPWIND; - return ""; - } - if (Upwind_Map.count(option_value[0])) { - this->space = Space_Map.find("SPACE_UPWIND")->second; - this->upwind = Upwind_Map.find(option_value[0])->second; - this->centered = NO_CENTERED; - return ""; - } - // Make them defined in case something weird happens - this->centered = NO_CENTERED; - this->upwind = NO_UPWIND; - this->space = SPACE_CENTERED; - return badValue(option_value, "convect", this->name); - - } - - void SetDefault() { - this->centered = NO_CENTERED; - this->upwind = NO_UPWIND; - this->space = SPACE_CENTERED; - } -}; - -class COptionMathProblem : public COptionBase{ - string name; // identifier for the option - bool & adjoint; - bool & restart; - bool & disc_adjoint; - bool adjoint_def; - bool restart_def; - bool disc_adjoint_def; - -public: - COptionMathProblem(string option_field_name, bool & adjoint_field, bool adjoint_default, bool & restart_field, bool restart_default, bool & disc_adjoint_field, bool disc_adjoint_default) : adjoint(adjoint_field), restart(restart_field), disc_adjoint(disc_adjoint_field){ - this->name = option_field_name; - this->adjoint_def = adjoint_default; - this->restart_def = restart_default; - this->disc_adjoint_def = disc_adjoint_default; - } - - ~COptionMathProblem() {}; - string SetValue(vector option_value) { - string out = optionCheckMultipleValues(option_value, "unsigned short", this->name); - if (out.compare("") != 0) { - return out; - } - if (option_value[0] == "ADJOINT") { - return badValue(option_value, "math problem (try CONTINUOUS_ADJOINT)", this->name); - } - if (Math_Problem_Map.find(option_value[0]) == Math_Problem_Map.end()) { - return badValue(option_value, "math problem", this->name); - } - if (option_value[0] == "DIRECT") { - this->adjoint = false; - this->restart = false; - this->disc_adjoint = false; - return ""; - } - if (option_value[0] == "CONTINUOUS_ADJOINT") { - this->adjoint= true; - this->restart= true; - this->disc_adjoint = false; - return ""; - } - if (option_value[0] == "DISCRETE_ADJOINT"){ - this->disc_adjoint = true; - this->restart = true; - this->adjoint= false; - return ""; - } - return "option in math problem map not considered in constructor"; - } - - void SetDefault() { - this->adjoint = this->adjoint_def; - this->restart = this->restart_def; - this->disc_adjoint = this->disc_adjoint_def; - } -}; - -class COptionDVParam : public COptionBase{ - string name; // identifier for the option - unsigned short & nDV; - su2double ** & paramDV; - string * & FFDTag; - unsigned short* & design_variable; - -public: - COptionDVParam(string option_field_name, unsigned short & nDV_field, su2double** & paramDV_field, string* & FFDTag_field, unsigned short * & design_variable_field) : nDV(nDV_field), paramDV(paramDV_field), FFDTag(FFDTag_field), design_variable(design_variable_field) { - this->name = option_field_name; - } - - ~COptionDVParam() {}; - - string SetValue(vector option_value) { - if ((option_value.size() == 1) && (option_value[0].compare("NONE") == 0)) { - this->nDV = 0; - return ""; - } - - // Cannot have ; at the beginning or the end - if (option_value[0].compare(";") == 0) { - string newstring; - newstring.append(this->name); - newstring.append(": may not have beginning semicolon"); - return newstring; - } - if (option_value[option_value.size()-1].compare(";") == 0) { - string newstring; - newstring.append(this->name); - newstring.append(": may not have ending semicolon"); - return newstring; - } - - - // use the ";" token to determine the number of design variables - // This works because semicolon is not one of the delimiters in tokenize string - this->nDV = 0; - //unsigned int num_semi = 0; - for (unsigned int i = 0; i < static_cast(option_value.size()); i++) { - if (option_value[i].compare(";") == 0) { - this->nDV++; - // num_semi++; - } - } - - // One more design variable than semicolon - this->nDV++; - - if ( (this->nDV > 0) && (this->design_variable == NULL) ) { - string newstring; - newstring.append(this->name); - newstring.append(": Design_Variable array has not been allocated. Check that DV_KIND appears before DV_PARAM in configuration file."); - return newstring; - } - - this->paramDV = new su2double*[this->nDV]; - for (unsigned short iDV = 0; iDV < this->nDV; iDV++) { - this->paramDV[iDV] = new su2double[MAX_PARAMETERS]; - } - - this->FFDTag = new string[this->nDV]; - - unsigned short nParamDV = 0; - stringstream ss; - unsigned int i = 0; - for (unsigned short iDV = 0; iDV < this->nDV; iDV++) { - switch (this->design_variable[iDV]) { - case FFD_SETTING: nParamDV = 0; break; - case FFD_CONTROL_POINT_2D: nParamDV = 5; break; - case FFD_CAMBER_2D: nParamDV = 2; break; - case FFD_THICKNESS_2D: nParamDV = 2; break; - case HICKS_HENNE: nParamDV = 2; break; - case SCALE: nParamDV = 0; break; - case TRANSLATION: nParamDV = 3; break; - case ROTATION: nParamDV = 6; break; - case NACA_4DIGITS: nParamDV = 3; break; - case PARABOLIC: nParamDV = 2; break; - case AIRFOIL: nParamDV = 2; break; - case FFD_CONTROL_POINT: nParamDV = 7; break; - case FFD_DIHEDRAL_ANGLE: nParamDV = 7; break; - case FFD_TWIST_ANGLE: nParamDV = 7; break; - case FFD_ROTATION: nParamDV = 7; break; - case FFD_CONTROL_SURFACE: nParamDV = 7; break; - case FFD_CAMBER: nParamDV = 3; break; - case FFD_THICKNESS: nParamDV = 3; break; - case SURFACE_FILE: nParamDV = 0; break; - default : { - string newstring; - newstring.append(this->name); - newstring.append(": undefined design variable type found in configuration file."); - return newstring; - } - } - - for (unsigned short iParamDV = 0; iParamDV < nParamDV; iParamDV++) { - - ss << option_value[i] << " "; - - if ((iParamDV == 0) && - ((this->design_variable[iDV] == FFD_SETTING) || - (this->design_variable[iDV] == FFD_CONTROL_POINT_2D) || - (this->design_variable[iDV] == FFD_CAMBER_2D) || - (this->design_variable[iDV] == FFD_THICKNESS_2D) || - (this->design_variable[iDV] == FFD_CONTROL_POINT) || - (this->design_variable[iDV] == FFD_DIHEDRAL_ANGLE) || - (this->design_variable[iDV] == FFD_TWIST_ANGLE) || - (this->design_variable[iDV] == FFD_ROTATION) || - (this->design_variable[iDV] == FFD_CONTROL_SURFACE) || - (this->design_variable[iDV] == FFD_CAMBER) || - (this->design_variable[iDV] == FFD_THICKNESS))) { - ss >> this->FFDTag[iDV]; - this->paramDV[iDV][iParamDV] = 0; - } - else - ss >> this->paramDV[iDV][iParamDV]; - - i++; - } - if (iDV < (this->nDV-1)) { - if (option_value[i].compare(";") != 0) { - string newstring; - newstring.append(this->name); - newstring.append(": a design variable in the configuration file has the wrong number of parameters"); - return newstring; - } - i++; - } - } - - // Need to return something... - return ""; - } - - void SetDefault() { - this->nDV = 0; - this->paramDV = NULL; - this->FFDTag = NULL; - // Don't mess with the Design_Variable because it's an input, not modified - } -}; - -class COptionFFDDef : public COptionBase{ - string name; - unsigned short & nFFD; - su2double ** & CoordFFD; - string * & FFDTag; - -public: - COptionFFDDef(string option_field_name, unsigned short & nFFD_field, su2double** & coordFFD_field, string* & FFDTag_field) : nFFD(nFFD_field), CoordFFD(coordFFD_field), FFDTag(FFDTag_field) { - this->name = option_field_name; - } - - ~COptionFFDDef() {}; - - string SetValue(vector option_value) { - if ((option_value.size() == 1) && (option_value[0].compare("NONE") == 0)) { - this->nFFD = 0; - return ""; - } - - // Cannot have ; at the beginning or the end - if (option_value[0].compare(";") == 0) { - string newstring; - newstring.append(this->name); - newstring.append(": may not have beginning semicolon"); - return newstring; - } - if (option_value[option_value.size()-1].compare(";") == 0) { - string newstring; - newstring.append(this->name); - newstring.append(": may not have ending semicolon"); - return newstring; - } - - - // use the ";" token to determine the number of design variables - // This works because semicolon is not one of the delimiters in tokenize string - this->nFFD = 0; - for (unsigned int i = 0; i < static_cast(option_value.size()); i++) { - if (option_value[i].compare(";") == 0) { - this->nFFD++; - } - } - - // One more design variable than semicolon - this->nFFD++; - - this->CoordFFD = new su2double*[this->nFFD]; - for (unsigned short iFFD = 0; iFFD < this->nFFD; iFFD++) { - this->CoordFFD[iFFD] = new su2double[25]; - } - - this->FFDTag = new string[this->nFFD]; - - unsigned short nCoordFFD = 0; - stringstream ss; - unsigned int i = 0; - - for (unsigned short iFFD = 0; iFFD < this->nFFD; iFFD++) { - - nCoordFFD = 25; - - for (unsigned short iCoordFFD = 0; iCoordFFD < nCoordFFD; iCoordFFD++) { - - ss << option_value[i] << " "; - - if (iCoordFFD == 0) ss >> this->FFDTag[iFFD]; - else ss >> this->CoordFFD[iFFD][iCoordFFD-1]; - - i++; - } - - if (iFFD < (this->nFFD-1)) { - if (option_value[i].compare(";") != 0) { - string newstring; - newstring.append(this->name); - newstring.append(": a FFD box in the configuration file has the wrong number of parameters"); - return newstring; - } - i++; - } - - } - - // Need to return something... - return ""; - } - - void SetDefault() { - this->nFFD = 0; - this->CoordFFD = NULL; - this->FFDTag = NULL; - } - -}; - -class COptionFFDDegree : public COptionBase{ - string name; - unsigned short & nFFD; - unsigned short ** & DegreeFFD; - -public: - COptionFFDDegree(string option_field_name, unsigned short & nFFD_field, unsigned short** & degreeFFD_field) : nFFD(nFFD_field), DegreeFFD(degreeFFD_field) { - this->name = option_field_name; - } - - ~COptionFFDDegree() {}; - - string SetValue(vector option_value) { - if ((option_value.size() == 1) && (option_value[0].compare("NONE") == 0)) { - this->nFFD = 0; - return ""; - } - - // Cannot have ; at the beginning or the end - if (option_value[0].compare(";") == 0) { - string newstring; - newstring.append(this->name); - newstring.append(": may not have beginning semicolon"); - return newstring; - } - if (option_value[option_value.size()-1].compare(";") == 0) { - string newstring; - newstring.append(this->name); - newstring.append(": may not have ending semicolon"); - return newstring; - } - - - // use the ";" token to determine the number of design variables - // This works because semicolon is not one of the delimiters in tokenize string - this->nFFD = 0; - for (unsigned int i = 0; i < static_cast(option_value.size()); i++) { - if (option_value[i].compare(";") == 0) { - this->nFFD++; - } - } - - // One more design variable than semicolon - this->nFFD++; - - this->DegreeFFD = new unsigned short*[this->nFFD]; - for (unsigned short iFFD = 0; iFFD < this->nFFD; iFFD++) { - this->DegreeFFD[iFFD] = new unsigned short[3]; - } - - unsigned short nDegreeFFD = 0; - stringstream ss; - unsigned int i = 0; - - for (unsigned short iFFD = 0; iFFD < this->nFFD; iFFD++) { - - nDegreeFFD = 3; - - for (unsigned short iDegreeFFD = 0; iDegreeFFD < nDegreeFFD; iDegreeFFD++) { - ss << option_value[i] << " "; - ss >> this->DegreeFFD[iFFD][iDegreeFFD]; - i++; - } - - if (iFFD < (this->nFFD-1)) { - if (option_value[i].compare(";") != 0) { - string newstring; - newstring.append(this->name); - newstring.append(": a FFD degree in the configuration file has the wrong number of parameters"); - return newstring; - } - i++; - } - - } - - // Need to return something... - return ""; - } - - void SetDefault() { - this->nFFD = 0; - this->DegreeFFD = NULL; - } - -}; - -// Class where the option is represented by (String, su2double, string, su2double, ...) -class COptionStringDoubleList : public COptionBase{ - string name; // identifier for the option - unsigned short & size; // how many strings are there (same as number of su2doubles) - - string * & s_f; // Reference to the string fields - su2double* & d_f; // reference to the su2double fields - -public: - COptionStringDoubleList(string option_field_name, unsigned short & list_size, string * & string_field, su2double* & double_field) : size(list_size), s_f(string_field), d_f(double_field) { - this->name = option_field_name; - } - - ~COptionStringDoubleList() {}; - string SetValue(vector option_value) { - // There must be an even number of entries (same number of strings and doubles - unsigned short totalVals = option_value.size(); - if ((totalVals % 2) != 0) { - if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { - // It's okay to say its NONE - this->size = 0; - return ""; - } - string newstring; - newstring.append(this->name); - newstring.append(": must have an even number of entries"); - return newstring; - } - unsigned short nVals = totalVals / 2; - this->size = nVals; - this->s_f = new string[nVals]; - this->d_f = new su2double[nVals]; - - for (unsigned long i = 0; i < nVals; i++) { - this->s_f[i].assign(option_value[2*i]); // 2 because have su2double and string - istringstream is(option_value[2*i + 1]); - su2double val; - if (!(is >> val)) { - return badValue(option_value, "string su2double", this->name); - } - this->d_f[i] = val; - } - // Need to return something... - return ""; - } - - void SetDefault() { - this->size = 0; // There is no default value for list - } -}; - -class COptionInlet : public COptionBase{ - string name; // identifier for the option - unsigned short & size; - string * & marker; - su2double * & ttotal; - su2double * & ptotal; - su2double ** & flowdir; - -public: - COptionInlet(string option_field_name, unsigned short & nMarker_Inlet, string* & Marker_Inlet, su2double* & Ttotal, su2double* & Ptotal, su2double** & FlowDir) : size(nMarker_Inlet), marker(Marker_Inlet), ttotal(Ttotal), ptotal(Ptotal), flowdir(FlowDir) { - this->name = option_field_name; - } - - ~COptionInlet() {}; - string SetValue(vector option_value) { - - unsigned short totalVals = option_value.size(); - if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { - this->size = 0; - this->marker = NULL; - this->ttotal = NULL; - this->ptotal = NULL; - this->flowdir = NULL; - return ""; - } - - if (totalVals % 6 != 0) { - string newstring; - newstring.append(this->name); - newstring.append(": must have a number of entries divisible by 6"); - this->size = 0; - this->marker = NULL; - this->ttotal = NULL; - this->ptotal = NULL; - this->flowdir = NULL; - return newstring; - } - - unsigned short nVals = totalVals / 6; - this->size = nVals; - this->marker = new string[nVals]; - this->ttotal = new su2double[nVals]; - this->ptotal = new su2double[nVals]; - this->flowdir = new su2double*[nVals]; - for (unsigned long i = 0; i < nVals; i++) { - this->flowdir[i] = new su2double[3]; - } - - for (unsigned long i = 0; i < nVals; i++) { - this->marker[i].assign(option_value[6*i]); - istringstream ss_1st(option_value[6*i + 1]); - if (!(ss_1st >> this->ttotal[i])) { - return badValue(option_value, "inlet", this->name); - } - istringstream ss_2nd(option_value[6*i + 2]); - if (!(ss_2nd >> this->ptotal[i])) { - return badValue(option_value, "inlet", this->name); - } - istringstream ss_3rd(option_value[6*i + 3]); - if (!(ss_3rd >> this->flowdir[i][0])) { - return badValue(option_value, "inlet", this->name); - } - istringstream ss_4th(option_value[6*i + 4]); - if (!(ss_4th >> this->flowdir[i][1])) { - return badValue(option_value, "inlet", this->name); - } - istringstream ss_5th(option_value[6*i + 5]); - if (!(ss_5th >> this->flowdir[i][2])) { - return badValue(option_value, "inlet", this->name); - } - } - - return ""; - } - - void SetDefault() { - this->marker = NULL; - this->ttotal = NULL; - this->ptotal = NULL; - this->flowdir = NULL; - this->size = 0; // There is no default value for list - } -}; - -template -class COptionRiemann : public COptionBase{ - -protected: - map m; - string name; // identifier for the option - unsigned short & size; - string * & marker; - unsigned short* & field; // Reference to the field name - su2double * & var1; - su2double * & var2; - su2double ** & flowdir; - -public: - COptionRiemann(string option_field_name, unsigned short & nMarker_Riemann, string* & Marker_Riemann, unsigned short* & option_field, const map m, su2double* & var1, su2double* & var2, su2double** & FlowDir) : size(nMarker_Riemann), - marker(Marker_Riemann), field(option_field), var1(var1), var2(var2), flowdir(FlowDir) { - this->name = option_field_name; - this->m = m; - } - ~COptionRiemann() {}; - - string SetValue(vector option_value) { - - unsigned short totalVals = option_value.size(); - if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { - this->size = 0; - this->marker = NULL; - this->field = 0; - this->var1 = NULL; - this->var2 = NULL; - this->flowdir = NULL; - return ""; - } - - if (totalVals % 7 != 0) { - string newstring; - newstring.append(this->name); - newstring.append(": must have a number of entries divisible by 7"); - this->size = 0; - this->marker = NULL; - this->var1 = NULL; - this->var2 = NULL; - this->flowdir = NULL; - this->field = NULL; - return newstring; - } - - unsigned short nVals = totalVals / 7; - this->size = nVals; - this->marker = new string[nVals]; - this->var1 = new su2double[nVals]; - this->var2 = new su2double[nVals]; - this->flowdir = new su2double*[nVals]; - this->field = new unsigned short[nVals]; - - for (unsigned long i = 0; i < nVals; i++) { - this->flowdir[i] = new su2double[3]; - } - - for (unsigned long i = 0; i < nVals; i++) { - this->marker[i].assign(option_value[7*i]); - // Check to see if the enum value is in the map - if (this->m.find(option_value[7*i + 1]) == m.end()) { - string str; - str.append(this->name); - str.append(": invalid option value "); - str.append(option_value[0]); - str.append(". Check current SU2 options in config_template.cfg."); - return str; - } - Tenum val = this->m[option_value[7*i + 1]]; - this->field[i] = val; - - istringstream ss_1st(option_value[7*i + 2]); - if (!(ss_1st >> this->var1[i])) { - return badValue(option_value, "Riemann", this->name); - } - istringstream ss_2nd(option_value[7*i + 3]); - if (!(ss_2nd >> this->var2[i])) { - return badValue(option_value, "Riemann", this->name); - } - istringstream ss_3rd(option_value[7*i + 4]); - if (!(ss_3rd >> this->flowdir[i][0])) { - return badValue(option_value, "Riemann", this->name); - } - istringstream ss_4th(option_value[7*i + 5]); - if (!(ss_4th >> this->flowdir[i][1])) { - return badValue(option_value, "Riemann", this->name); - } - istringstream ss_5th(option_value[7*i + 6]); - if (!(ss_5th >> this->flowdir[i][2])) { - return badValue(option_value, "Riemann", this->name); - } - } - - return ""; - } - - void SetDefault() { - this->marker = NULL; - this->var1 = NULL; - this->var2 = NULL; - this->flowdir = NULL; - this->size = 0; // There is no default value for list - } -}; - -template -class COptionNRBC : public COptionRiemann { - -public: - COptionNRBC(string option_field_name, unsigned short & nMarker_NRBC, string* & Marker_NRBC, unsigned short* & option_field, - const map m, su2double* & var1, su2double* & var2, su2double** & FlowDir): COptionRiemann(option_field_name, nMarker_NRBC, Marker_NRBC, option_field, - m, var1, var2,FlowDir){} - ~COptionNRBC() {}; - -}; -//template -//class COptionNRBC : public COptionBase{ -// -// map m; -// unsigned short* & field; // Reference to the fieldname -// string name; // identifier for the option -// unsigned short & size; -// string * & marker; -// su2double * & var1; -// su2double * & var2; -// su2double ** & flowdir; -// -//public: -// COptionNRBC(string option_field_name, unsigned short & nMarker_NRBC, string* & Marker_NRBC, unsigned short* & option_field, const map m, su2double* & var1, su2double* & var2, su2double** & FlowDir) : size(nMarker_NRBC), -// marker(Marker_NRBC), field(option_field), var1(var1), var2(var2), flowdir(FlowDir) { -// this->name = option_field_name; -// this->m = m; -// } -// ~COptionNRBC() {}; -// -// string SetValue(vector option_value) { -// -// unsigned long totalVals = option_value.size(); -// if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { -// this->size = 0; -// this->marker = NULL; -// this->field = 0; -// this->var1 = NULL; -// this->var2 = NULL; -// this->flowdir = NULL; -// return ""; -// } -// -// if (totalVals % 7 != 0) { -// string newstring; -// newstring.append(this->name); -// newstring.append(": must have a number of entries divisible by 7"); -// this->size = 0; -// this->marker = NULL; -// this->var1 = NULL; -// this->var2 = NULL; -// this->flowdir = NULL; -// this->field = NULL; -// return newstring; -// } -// -// unsigned long nVals = totalVals / 7; -// this->size = nVals; -// this->marker = new string[nVals]; -// this->var1 = new su2double[nVals]; -// this->var2 = new su2double[nVals]; -// this->flowdir = new su2double*[nVals]; -// this->field = new unsigned short[nVals]; -// -// for (int i = 0; i < nVals; i++) { -// this->flowdir[i] = new su2double[3]; -// } -// -// for (int i = 0; i < nVals; i++) { -// this->marker[i].assign(option_value[7*i]); -// // Check to see if the enum value is in the map -// if (this->m.find(option_value[7*i + 1]) == m.end()) { -// string str; -// str.append(this->name); -// str.append(": invalid option value "); -// str.append(option_value[0]); -// str.append(". Check current SU2 options in config_template.cfg."); -// return str; -// } -// Tenum val = this->m[option_value[7*i + 1]]; -// this->field[i] = val; -// -// istringstream ss_1st(option_value[7*i + 2]); -// if (!(ss_1st >> this->var1[i])) { -// return badValue(option_value, "NRBC", this->name); -// } -// istringstream ss_2nd(option_value[7*i + 3]); -// if (!(ss_2nd >> this->var2[i])) { -// return badValue(option_value, "NRBC", this->name); -// } -// istringstream ss_3rd(option_value[7*i + 4]); -// if (!(ss_3rd >> this->flowdir[i][0])) { -// return badValue(option_value, "NRBC", this->name); -// } -// istringstream ss_4th(option_value[7*i + 5]); -// if (!(ss_4th >> this->flowdir[i][1])) { -// return badValue(option_value, "NRBC", this->name); -// } -// istringstream ss_5th(option_value[7*i + 6]); -// if (!(ss_5th >> this->flowdir[i][2])) { -// return badValue(option_value, "NRBC", this->name); -// } -// } -// -// return ""; -// } -// -// void SetDefault() { -// this->marker = NULL; -// this->var1 = NULL; -// this->var2 = NULL; -// this->flowdir = NULL; -// this->size = 0; // There is no default value for list -// } -//}; - - - - - - -//Inlet condition where the input direction is assumed -class COptionExhaust : public COptionBase{ - string name; // identifier for the option - unsigned short & size; - string * & marker; - su2double * & ttotal; - su2double * & ptotal; - -public: - COptionExhaust(string option_field_name, unsigned short & nMarker_Exhaust, string* & Marker_Exhaust, su2double* & Ttotal, su2double* & Ptotal) : size(nMarker_Exhaust), marker(Marker_Exhaust), ttotal(Ttotal), ptotal(Ptotal) { - this->name = option_field_name; - } - - ~COptionExhaust() {}; - - string SetValue(vector option_value) { - - unsigned short totalVals = option_value.size(); - if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { - this->size = 0; - this->marker = NULL; - this->ttotal = NULL; - this->ptotal = NULL; - return ""; - } - - if (totalVals % 3 != 0) { - string newstring; - newstring.append(this->name); - newstring.append(": must have a number of entries divisible by 3"); - this->size = 0; - this->marker = NULL; - this->ttotal = NULL; - this->ptotal = NULL; - return newstring; - } - - unsigned short nVals = totalVals / 3; - this->size = nVals; - this->marker = new string[nVals]; - this->ttotal = new su2double[nVals]; - this->ptotal = new su2double[nVals]; - - for (unsigned long i = 0; i < nVals; i++) { - this->marker[i].assign(option_value[3*i]); - istringstream ss_1st(option_value[3*i + 1]); - if (!(ss_1st >> this->ttotal[i])) - return badValue(option_value, "exhaust fixed", this->name); - istringstream ss_2nd(option_value[3*i + 2]); - if (!(ss_2nd >> this->ptotal[i])) - return badValue(option_value, "exhaust fixed", this->name); - } - - return ""; - } - - void SetDefault() { - this->marker = NULL; - this->ttotal = NULL; - this->ptotal = NULL; - this->size = 0; // There is no default value for list - } - -}; - -//Inlet condition where the input direction is assumed -class COptionBleed : public COptionBase{ - string name; // identifier for the option - unsigned short & size; - string * & marker; - su2double * & massflow_target; - su2double * & temp_target; - -public: - COptionBleed(string option_field_name, unsigned short & nMarker_Bleed, string* & Marker_Bleed, su2double* & MassFlow_Target, su2double* & Temp_Target) : size(nMarker_Bleed), marker(Marker_Bleed), massflow_target(MassFlow_Target), temp_target(Temp_Target) { - this->name = option_field_name; - } - - ~COptionBleed() {}; - - string SetValue(vector option_value) { - - unsigned short totalVals = option_value.size(); - if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { - this->size = 0; - this->marker = NULL; - this->massflow_target = NULL; - this->temp_target = NULL; - return ""; - } - - if (totalVals % 3 != 0) { - string newstring; - newstring.append(this->name); - newstring.append(": must have a number of entries divisible by 3"); - this->size = 0; - this->marker = NULL; - this->massflow_target = NULL; - this->temp_target = NULL; - return newstring; - } - - unsigned short nVals = totalVals / 3; - this->size = nVals; - this->marker = new string[nVals]; - this->massflow_target = new su2double[nVals]; - this->temp_target = new su2double[nVals]; - - for (unsigned long i = 0; i < nVals; i++) { - this->marker[i].assign(option_value[3*i]); - istringstream ss_1st(option_value[3*i + 1]); - if (!(ss_1st >> this->massflow_target[i])) - return badValue(option_value, "bleed fixed", this->name); - istringstream ss_2nd(option_value[3*i + 2]); - if (!(ss_2nd >> this->temp_target[i])) - return badValue(option_value, "bleed fixed", this->name); - } - - return ""; - } - - void SetDefault() { - this->marker = NULL; - this->massflow_target = NULL; - this->temp_target = NULL; - this->size = 0; // There is no default value for list - } - -}; - -class COptionPeriodic : public COptionBase{ - string name; // identifier for the option - unsigned short & size; - string * & marker_bound; - string * & marker_donor; - su2double ** & rot_center; - su2double ** & rot_angles; - su2double ** & translation; - -public: - COptionPeriodic(const string option_field_name, unsigned short & nMarker_PerBound, - string* & Marker_PerBound, string* & Marker_PerDonor, - su2double** & RotCenter, su2double** & RotAngles, su2double** & Translation) : size(nMarker_PerBound), marker_bound(Marker_PerBound), marker_donor(Marker_PerDonor), rot_center(RotCenter), rot_angles(RotAngles), translation(Translation) { - this->name = option_field_name; - } - - ~COptionPeriodic() {}; - string SetValue(vector option_value) { - - const int mod_num = 11; - - unsigned short totalVals = option_value.size(); - if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { - this->size = 0; - this->marker_bound = NULL; - this->marker_donor = NULL; - this->rot_center = NULL; - this->rot_angles = NULL; - this->translation = NULL; - return ""; - } - - if (totalVals % mod_num != 0) { - string newstring; - newstring.append(this->name); - newstring.append(": must have a number of entries divisible by 11"); - this->size = 0; - this->marker_bound = NULL; - this->marker_donor = NULL; - this->rot_center = NULL; - this->rot_angles = NULL; - this->translation = NULL; - return newstring; - } - - unsigned short nVals = 2 * (totalVals / mod_num); // To account for periodic and donor - this->size = nVals; - this->marker_bound = new string[nVals]; - this->marker_donor = new string[nVals]; - this->rot_center = new su2double*[nVals]; - this->rot_angles = new su2double*[nVals]; - this->translation = new su2double*[nVals]; - for (unsigned long i = 0; i < nVals; i++) { - this->rot_center[i] = new su2double[3]; - this->rot_angles[i] = new su2double[3]; - this->translation[i] = new su2double[3]; - } - - su2double deg2rad = PI_NUMBER/180.0; - - for (unsigned long i = 0; i < (nVals/2); i++) { - this->marker_bound[i].assign(option_value[mod_num*i]); - this->marker_donor[i].assign(option_value[mod_num*i+1]); - istringstream ss_1st(option_value[mod_num*i + 2]); - if (!(ss_1st >> this->rot_center[i][0])) { - return badValue(option_value, "periodic", this->name); - } - istringstream ss_2nd(option_value[mod_num*i + 3]); - if (!(ss_2nd >> this->rot_center[i][1])) { - return badValue(option_value, "periodic", this->name); - } - istringstream ss_3rd(option_value[mod_num*i + 4]); - if (!(ss_3rd >> this->rot_center[i][2])) { - return badValue(option_value, "periodic", this->name); - } - istringstream ss_4th(option_value[mod_num*i + 5]); - if (!(ss_4th >> this->rot_angles[i][0])) { - return badValue(option_value, "periodic", this->name); - } - istringstream ss_5th(option_value[mod_num*i + 6]); - if (!(ss_5th >> this->rot_angles[i][1])) { - return badValue(option_value, "periodic", this->name); - } - istringstream ss_6th(option_value[mod_num*i + 7]); - if (!(ss_6th >> this->rot_angles[i][2])) { - return badValue(option_value, "periodic", this->name); - } - istringstream ss_7th(option_value[mod_num*i + 8]); - if (!(ss_7th >> this->translation[i][0])) { - return badValue(option_value, "periodic", this->name); - } - istringstream ss_8th(option_value[mod_num*i + 9]); - if (!(ss_8th >> this->translation[i][1])) { - return badValue(option_value, "periodic", this->name); - } - istringstream ss_9th(option_value[mod_num*i + 10]); - if (!(ss_9th >> this->translation[i][2])) { - return badValue(option_value, "periodic", this->name); - } - this->rot_angles[i][0] *= deg2rad; - this->rot_angles[i][1] *= deg2rad; - this->rot_angles[i][2] *= deg2rad; - } - - for (unsigned long i = (nVals/2); i < nVals; i++) { - this->marker_bound[i].assign(option_value[mod_num*(i-nVals/2)+1]); - this->marker_donor[i].assign(option_value[mod_num*(i-nVals/2)]); - istringstream ss_1st(option_value[mod_num*(i-nVals/2) + 2]); - if (!(ss_1st >> this->rot_center[i][0])) { - return badValue(option_value, "periodic", this->name); - } - istringstream ss_2nd(option_value[mod_num*(i-nVals/2) + 3]); - if (!(ss_2nd >> this->rot_center[i][1])) { - return badValue(option_value, "periodic", this->name); - } - istringstream ss_3rd(option_value[mod_num*(i-nVals/2) + 4]); - if (!(ss_3rd >> this->rot_center[i][2])) { - return badValue(option_value, "periodic", this->name); - } - istringstream ss_4th(option_value[mod_num*(i-nVals/2) + 5]); - if (!(ss_4th >> this->rot_angles[i][0])) { - return badValue(option_value, "periodic", this->name); - } - istringstream ss_5th(option_value[mod_num*(i-nVals/2) + 6]); - if (!(ss_5th >> this->rot_angles[i][1])) { - return badValue(option_value, "periodic", this->name); - } - istringstream ss_6th(option_value[mod_num*(i-nVals/2) + 7]); - if (!(ss_6th >> this->rot_angles[i][2])) { - return badValue(option_value, "periodic", this->name); - } - istringstream ss_7th(option_value[mod_num*(i-nVals/2) + 8]); - if (!(ss_7th >> this->translation[i][0])) { - return badValue(option_value, "periodic", this->name); - } - istringstream ss_8th(option_value[mod_num*(i-nVals/2) + 9]); - if (!(ss_8th >> this->translation[i][1])) { - return badValue(option_value, "periodic", this->name); - } - istringstream ss_9th(option_value[mod_num*(i-nVals/2) + 10]); - if (!(ss_9th >> this->translation[i][2])) { - return badValue(option_value, "periodic", this->name); - } - /*--- Mirror the rotational angles and translation vector (rotational - center does not need to move) ---*/ - this->rot_center[i][0] *= 1.0; - this->rot_center[i][1] *= 1.0; - this->rot_center[i][2] *= 1.0; - this->rot_angles[i][0] *= -deg2rad; - this->rot_angles[i][1] *= -deg2rad; - this->rot_angles[i][2] *= -deg2rad; - this->translation[i][0] *= -1.0; - this->translation[i][1] *= -1.0; - this->translation[i][2] *= -1.0; - } - - return ""; - } - - void SetDefault() { - this->size = 0; - this->marker_bound = NULL; - this->marker_donor = NULL; - this->rot_center = NULL; - this->rot_angles = NULL; - this->translation = NULL; - } -}; - - -class COptionMixingPlane : public COptionBase{ - string name; // identifier for the option - unsigned short & size; - string * & marker_bound; - string * & marker_donor; - -public: - COptionMixingPlane(const string option_field_name, unsigned short & nMarker_MixBound, - string* & Marker_MixBound, string* & Marker_MixDonor) : size(nMarker_MixBound), marker_bound(Marker_MixBound), marker_donor(Marker_MixDonor) { - this->name = option_field_name; - } - - ~COptionMixingPlane() {}; - string SetValue(vector option_value) { - - const int mod_num = 2; - - unsigned long totalVals = option_value.size(); - if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { - this->size = 0; - this->marker_bound = NULL; - this->marker_donor = NULL; - return ""; - } - - if (totalVals % mod_num != 0) { - string newstring; - newstring.append(this->name); - newstring.append(": must have a number of entries divisible by 11"); - this->size = 0; - this->marker_bound = NULL; - this->marker_donor = NULL; - return newstring; - } - - unsigned long nVals = 2 * (totalVals / mod_num); // To account for periodic and donor - this->size = nVals; - this->marker_bound = new string[nVals]; - this->marker_donor = new string[nVals]; - - - for (unsigned short i = 0; i < (nVals/2); i++) { - this->marker_bound[i].assign(option_value[mod_num*i]); - this->marker_donor[i].assign(option_value[mod_num*i+1]); - } - - for (unsigned long i = (nVals/2); i < nVals; i++) { - this->marker_bound[i].assign(option_value[mod_num*(i-nVals/2)+1]); - this->marker_donor[i].assign(option_value[mod_num*(i-nVals/2)]); - } - - - - return ""; - } - - void SetDefault() { - this->size = 0; - this->marker_bound = NULL; - this->marker_donor = NULL; - } -}; - -template -class COptionTurboPerformance : public COptionBase{ - string name; // identifier for the option - unsigned short & size; - string * & marker_turboIn; - string * & marker_turboOut; - map m; - unsigned short* & field; // Reference to the fieldname - -public: - COptionTurboPerformance(const string option_field_name, unsigned short & nMarker_TurboPerf, - string* & Marker_TurboBoundIn, string* & Marker_TurboBoundOut, unsigned short* & option_field, const map m) : size(nMarker_TurboPerf), marker_turboIn(Marker_TurboBoundIn), marker_turboOut(Marker_TurboBoundOut), field(option_field) { - this->name = option_field_name; - this->m = m; - } - - ~COptionTurboPerformance() {}; - string SetValue(vector option_value) { - - const int mod_num = 3; - - unsigned long totalVals = option_value.size(); - if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { - this->size = 0; - this->marker_turboIn= NULL; - this->marker_turboOut = NULL; - this->field = NULL; - return ""; - } - - if (totalVals % mod_num != 0) { - string newstring; - newstring.append(this->name); - newstring.append(": must have a number of entries divisible by 11"); - this->size = 0; - this->marker_turboIn= NULL; - this->marker_turboOut = NULL;; - this->field = NULL; - return newstring; - } - - unsigned long nVals = totalVals / mod_num; - this->size = nVals; - this->marker_turboIn = new string[nVals]; - this->marker_turboOut = new string[nVals]; - this->field = new unsigned short[nVals]; - for (int i = 0; i < nVals; i++) - if (this->m.find(option_value[mod_num*i + 2]) == m.end()) { - string str; - str.append(this->name); - str.append(": invalid option value "); - str.append(option_value[0]); - str.append(". Check current SU2 options in config_template.cfg."); - return str; - } - for (int i = 0; i < nVals; i++) { - this->marker_turboIn[i].assign(option_value[mod_num*i]); - this->marker_turboOut[i].assign(option_value[mod_num*i+1]); - Tenum val = this->m[option_value[mod_num*i + 2]]; - this->field[i] = val; - } - - - return ""; - } - - void SetDefault() { - this->size = 0; - this->marker_turboIn= NULL; - this->marker_turboOut = NULL; - this->field = NULL; - } -}; - - -class COptionPython : public COptionBase{ - string name; -public: - COptionPython(const string name) { - this->name = name; - } - ~COptionPython() {}; - // No checking happens with python options - string SetValue(vector) { - return ""; - } - // No defaults with python options - void SetDefault() { - return; - }; -}; - - - -class COptionActuatorDisk : public COptionBase{ - string name; // identifier for the option - unsigned short & inlet_size; - unsigned short & outlet_size; - string * & marker_inlet; - string * & marker_outlet; - su2double ** & origin; - su2double * & root_radius; - su2double * & tip_radius; - su2double * & press_jump; - su2double * & temp_jump; - su2double * & omega; - unsigned short * & distribution; - -public: - COptionActuatorDisk(const string name, unsigned short & nMarker_ActDisk_Inlet, unsigned short & nMarker_ActDisk_Outlet, string * & Marker_ActDisk_Inlet, string * & Marker_ActDisk_Outlet, su2double ** & ActDisk_Origin, su2double * & ActDisk_RootRadius, su2double * & ActDisk_TipRadius, su2double * & ActDisk_PressJump, su2double * & ActDisk_TempJump, su2double * & ActDisk_Omega, unsigned short * & ActDisk_Distribution) : inlet_size(nMarker_ActDisk_Inlet), outlet_size(nMarker_ActDisk_Outlet), marker_inlet(Marker_ActDisk_Inlet), marker_outlet(Marker_ActDisk_Outlet), origin(ActDisk_Origin), root_radius(ActDisk_RootRadius), tip_radius(ActDisk_TipRadius), press_jump(ActDisk_PressJump), temp_jump(ActDisk_TempJump), omega(ActDisk_Omega), distribution(ActDisk_Distribution) { - this->name = name; - } - - ~COptionActuatorDisk() {}; - string SetValue(vector option_value) { - const int mod_num = 11; - unsigned short totalVals = option_value.size(); - if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { - this->SetDefault(); - return ""; - } - - if (totalVals % mod_num != 0) { - string newstring; - newstring.append(this->name); - newstring.append(": must have a number of entries divisible by 10"); - this->SetDefault(); - return newstring; - } - - unsigned short nVals = totalVals / mod_num; - this->inlet_size = nVals; - this->outlet_size = nVals; - this->marker_inlet = new string[this->inlet_size]; - this->marker_outlet = new string[this->outlet_size]; - this->root_radius = new su2double[this->inlet_size]; - this->tip_radius = new su2double[this->inlet_size]; - this->press_jump = new su2double[this->outlet_size]; - this->temp_jump = new su2double[this->outlet_size]; - this->omega = new su2double[this->inlet_size]; - this->distribution = new unsigned short[this->inlet_size]; - - this->origin = new su2double*[this->inlet_size]; - for (int i = 0; i < this->inlet_size; i++) { - this->origin[i] = new su2double[3]; - } - - string tname = "actuator disk"; - - for (int i = 0; i < this->inlet_size; i++) { - this->marker_inlet[i].assign(option_value[mod_num*i]); - this->marker_outlet[i].assign(option_value[mod_num*i+1]); - istringstream ss_1st(option_value[mod_num*i + 2]); - if (!(ss_1st >> this->origin[i][0])) { - return badValue(option_value, tname, this->name); - } - istringstream ss_2nd(option_value[mod_num*i + 3]); - if (!(ss_2nd >> this->origin[i][1])) { - return badValue(option_value, tname, this->name); - } - istringstream ss_3rd(option_value[mod_num*i + 4]); - if (!(ss_3rd >> this->origin[i][2])) { - return badValue(option_value, tname, this->name); - } - istringstream ss_4th(option_value[mod_num*i + 5]); - if (!(ss_4th >> this->root_radius[i])) { - return badValue(option_value, tname, this->name); - } - istringstream ss_5th(option_value[mod_num*i + 6]); - if (!(ss_5th >> this->tip_radius[i])) { - return badValue(option_value, tname, this->name); - } - istringstream ss_6th(option_value[mod_num*i + 7]); - if (!(ss_6th >> this->press_jump[i])) { - return badValue(option_value, tname, this->name); - } - istringstream ss_7th(option_value[mod_num*i + 8]); - if (!(ss_7th >> this->temp_jump[i])) { - return badValue(option_value, tname, this->name); - } - istringstream ss_8th(option_value[mod_num*i + 9]); - if (!(ss_8th >> this->omega[i])) { - return badValue(option_value, tname, this->name); - } - istringstream ss_9th(option_value[mod_num*i + 10]); - if (!(ss_9th >> this->distribution[i])) { - return badValue(option_value, tname, this->name); - } - } - return ""; - } - void SetDefault() { - this->inlet_size = 0; - this->outlet_size = 0; - this->marker_inlet = NULL; - this->marker_outlet = NULL; - this->origin = NULL; - this->root_radius = NULL; - this->tip_radius = NULL; - this->press_jump = NULL; - this->temp_jump = NULL; - this->omega = NULL; - this->distribution = NULL; - } -}; - +}; + + +/*! + * \brief different regime modes + */ +enum ENUM_2DFORM { + PLANE_STRESS = 0, /*!< \brief Definition of plane stress solver. */ + PLANE_STRAIN = 1 /*!< \brief Definition of plane strain solver. */ +}; +static const map ElasForm_2D = CCreateMap +("PLANE_STRESS", PLANE_STRESS) +("PLANE_STRAIN", PLANE_STRAIN); + + +/*! + * \brief different regime modes + */ +enum ENUM_AITKEN { + NO_RELAXATION = 0, /*!< \brief No relaxation in the strongly coupled approach. */ + FIXED_PARAMETER = 1, /*!< \brief Relaxation with a fixed parameter. */ + AITKEN_DYNAMIC = 2 /*!< \brief Relaxation using Aitken's dynamic parameter. */ +}; +static const map AitkenForm_Map = CCreateMap +("NONE", NO_RELAXATION) +("FIXED_PARAMETER", FIXED_PARAMETER) +("AITKEN_DYNAMIC", AITKEN_DYNAMIC); + + + +/*! + * \brief types Riemann boundary treatments + */ +enum RIEMANN_TYPE { + TOTAL_CONDITIONS_PT = 1, /*!< \brief User specifies total pressure, total temperature, and flow direction. */ + DENSITY_VELOCITY = 2, /*!< \brief User specifies density and velocity, and flow direction. */ + STATIC_PRESSURE = 3, /*!< \brief User specifies static pressure. */ + TOTAL_SUPERSONIC_INFLOW = 4, /*!< \brief User specifies total pressure, total temperature and Velocity components. */ + STATIC_SUPERSONIC_INFLOW_PT = 5, /*!< \brief User specifies static pressure, static temperature, and Mach components. */ + STATIC_SUPERSONIC_INFLOW_PD = 6, /*!< \brief User specifies static pressure, static temperature, and Mach components. */ + MIXING_IN = 7, /*!< \brief User does not specify anything information are retrieved from the other domain */ + MIXING_OUT = 8 /*!< \brief User does not specify anything information are retrieved from the other domain */ +}; + +static const map Riemann_Map = CCreateMap +("TOTAL_CONDITIONS_PT", TOTAL_CONDITIONS_PT) +("DENSITY_VELOCITY", DENSITY_VELOCITY) +("STATIC_PRESSURE", STATIC_PRESSURE) +("TOTAL_SUPERSONIC_INFLOW", TOTAL_SUPERSONIC_INFLOW) +("STATIC_SUPERSONIC_INFLOW_PT", STATIC_SUPERSONIC_INFLOW_PT) +("STATIC_SUPERSONIC_INFLOW_PD", STATIC_SUPERSONIC_INFLOW_PD) +("MIXING_IN", MIXING_IN) +("MIXING_OUT", MIXING_OUT); + + +static const map NRBC_Map = CCreateMap +("TOTAL_CONDITIONS_PT", TOTAL_CONDITIONS_PT) +("DENSITY_VELOCITY", DENSITY_VELOCITY) +("STATIC_PRESSURE", STATIC_PRESSURE) +("TOTAL_SUPERSONIC_INFLOW", TOTAL_SUPERSONIC_INFLOW) +("STATIC_SUPERSONIC_INFLOW_PT", STATIC_SUPERSONIC_INFLOW_PT) +("STATIC_SUPERSONIC_INFLOW_PD", STATIC_SUPERSONIC_INFLOW_PD) +("MIXING_IN", MIXING_IN) +("MIXING_OUT", MIXING_OUT); + + +/*! + * \brief types of mixing process for averaging quantities at the boundaries. + */ +enum MIXINGPROCESS_TYPE { + ALGEBRAIC_AVERAGE = 1, /*!< \brief an algebraic average is computed at the boundary of interest. */ + AREA_AVERAGE = 2, /*!< \brief an area average is computed at the boundary of interest. */ + MIXEDOUT_AVERAGE = 3 /*!< \brief an mixed-out average is computed at the boundary of interest. */ +}; + +static const map MixingProcess_Map = CCreateMap +("ALGEBRAIC_AVERAGE", ALGEBRAIC_AVERAGE) +("AREA_AVERAGE", AREA_AVERAGE) +("MIXEDOUT_AVERAGE", MIXEDOUT_AVERAGE); + +/*! + * \brief types of Turbomachinery performance indicators. + */ +enum TURBO_PERFORMANCE_TYPE { + BLADE = 1, /*!< \brief Turbomachinery blade performances. */ + STAGE = 2, /*!< \brief Turbomachinery blade stage performances. */ + TURBINE = 3 /*!< \brief Turbomachinery turbine performances. */ +}; + +static const map TurboPerformance_Map = CCreateMap +("BLADE", BLADE) +("STAGE", STAGE) +("TURBINE", TURBINE); + +/*! + * \brief types inlet boundary treatments + */ +enum INLET_TYPE { + TOTAL_CONDITIONS = 1, /*!< \brief User specifies total pressure, total temperature, and flow direction. */ + MASS_FLOW = 2 /*!< \brief User specifies density and velocity (mass flow). */ +}; +static const map Inlet_Map = CCreateMap +("TOTAL_CONDITIONS", TOTAL_CONDITIONS) +("MASS_FLOW", MASS_FLOW); + + +/*! + * \brief types of geometric entities based on VTK nomenclature + */ +enum GEO_TYPE { + VERTEX = 1, /*!< \brief VTK nomenclature for defining a vertex element. */ + LINE = 3, /*!< \brief VTK nomenclature for defining a line element. */ + TRIANGLE = 5, /*!< \brief VTK nomenclature for defining a triangle element. */ + QUADRILATERAL = 9, /*!< \brief VTK nomenclature for defining a quadrilateral element. */ + TETRAHEDRON = 10, /*!< \brief VTK nomenclature for defining a tetrahedron element. */ + HEXAHEDRON = 12, /*!< \brief VTK nomenclature for defining a hexahedron element. */ + PRISM = 13, /*!< \brief VTK nomenclature for defining a prism element. */ + PYRAMID = 14 /*!< \brief VTK nomenclature for defining a pyramid element. */ +}; + +/*! + * \brief types of objective functions + */ +enum ENUM_OBJECTIVE { + DRAG_COEFFICIENT = 1, /*!< \brief Drag objective function definition. */ + LIFT_COEFFICIENT = 2, /*!< \brief Lift objective function definition. */ + SIDEFORCE_COEFFICIENT = 3, /*!< \brief Side force objective function definition. */ + EFFICIENCY = 4, /*!< \brief Efficiency objective function definition. */ + INVERSE_DESIGN_PRESSURE = 5, /*!< \brief Pressure objective function definition (inverse design). */ + INVERSE_DESIGN_HEATFLUX = 6, /*!< \brief Heat flux objective function definition (inverse design). */ + TOTAL_HEATFLUX = 7, /*!< \brief Total heat flux. */ + MAXIMUM_HEATFLUX = 8, /*!< \brief Maximum heat flux. */ + MOMENT_X_COEFFICIENT = 9, /*!< \brief Pitching moment objective function definition. */ + MOMENT_Y_COEFFICIENT = 10, /*!< \brief Rolling moment objective function definition. */ + MOMENT_Z_COEFFICIENT = 11, /*!< \brief Yawing objective function definition. */ + EQUIVALENT_AREA = 12, /*!< \brief Equivalent area objective function definition. */ + NEARFIELD_PRESSURE = 13, /*!< \brief NearField Pressure objective function definition. */ + FORCE_X_COEFFICIENT = 14, /*!< \brief X-direction force objective function definition. */ + FORCE_Y_COEFFICIENT = 15, /*!< \brief Y-direction force objective function definition. */ + FORCE_Z_COEFFICIENT = 16, /*!< \brief Z-direction force objective function definition. */ + THRUST_COEFFICIENT = 17, /*!< \brief Thrust objective function definition. */ + TORQUE_COEFFICIENT = 18, /*!< \brief Torque objective function definition. */ + FIGURE_OF_MERIT = 19, /*!< \brief Rotor Figure of Merit objective function definition. */ + FREE_SURFACE = 20, /*!< \brief Free Surface objective function definition. */ + MAX_THICKNESS = 21, /*!< \brief Maximum thickness. */ + MIN_THICKNESS = 22, /*!< \brief Minimum thickness. */ + MAX_THICK_SEC1 = 23, /*!< \brief Maximum thickness in section 1. */ + MAX_THICK_SEC2 = 24, /*!< \brief Maximum thickness in section 2. */ + MAX_THICK_SEC3 = 25, /*!< \brief Maximum thickness in section 3. */ + MAX_THICK_SEC4 = 26, /*!< \brief Maximum thickness in section 4. */ + MAX_THICK_SEC5 = 27, /*!< \brief Maximum thickness in section 5. */ + AVG_TOTAL_PRESSURE = 28, /*!< \brief Total Pressure objective function definition. */ + AVG_OUTLET_PRESSURE = 29, /*!< \brief Static Pressure objective function definition. */ + MASS_FLOW_RATE = 30, /*!< \brief Mass Flow Rate objective function definition. */ + OUTLET_CHAIN_RULE=31 /*!<\brief Objective function defined via chain rule on primitive variable gradients. */ +}; + +static const map Objective_Map = CCreateMap +("DRAG", DRAG_COEFFICIENT) +("LIFT", LIFT_COEFFICIENT) +("SIDEFORCE", SIDEFORCE_COEFFICIENT) +("EFFICIENCY", EFFICIENCY) +("INVERSE_DESIGN_PRESSURE", INVERSE_DESIGN_PRESSURE) +("INVERSE_DESIGN_HEATFLUX", INVERSE_DESIGN_HEATFLUX) +("MOMENT_X", MOMENT_X_COEFFICIENT) +("MOMENT_Y", MOMENT_Y_COEFFICIENT) +("MOMENT_Z", MOMENT_Z_COEFFICIENT) +("EQUIVALENT_AREA", EQUIVALENT_AREA) +("NEARFIELD_PRESSURE", NEARFIELD_PRESSURE) +("FORCE_X", FORCE_X_COEFFICIENT) +("FORCE_Y", FORCE_Y_COEFFICIENT) +("FORCE_Z", FORCE_Z_COEFFICIENT) +("THRUST", THRUST_COEFFICIENT) +("TORQUE", TORQUE_COEFFICIENT) +("TOTAL_HEATFLUX", TOTAL_HEATFLUX) +("MAXIMUM_HEATFLUX", MAXIMUM_HEATFLUX) +("FIGURE_OF_MERIT", FIGURE_OF_MERIT) +("FREE_SURFACE", FREE_SURFACE) +("MAX_THICKNESS", MAX_THICKNESS) +("MIN_THICKNESS", MIN_THICKNESS) +("MAX_THICK_SEC1", MAX_THICK_SEC1) +("MAX_THICK_SEC2", MAX_THICK_SEC2) +("MAX_THICK_SEC3", MAX_THICK_SEC3) +("MAX_THICK_SEC4", MAX_THICK_SEC4) +("MAX_THICK_SEC5", MAX_THICK_SEC5) +("AVG_TOTAL_PRESSURE", AVG_TOTAL_PRESSURE) +("AVG_OUTLET_PRESSURE", AVG_OUTLET_PRESSURE) +("MASS_FLOW_RATE", MASS_FLOW_RATE) +("OUTLET_CHAIN_RULE", OUTLET_CHAIN_RULE); + +/*! + * \brief types of residual criteria equations + */ + +enum ENUM_RESIDUAL { + RHO_RESIDUAL = 1, /*!< \brief Rho equation residual criteria equation. */ + RHO_ENERGY_RESIDUAL = 2 /*!< \brief RhoE equation residual criteria equation. */ +}; + +static const map Residual_Map = CCreateMap +("RHO", RHO_RESIDUAL) +("RHO_ENERGY", RHO_ENERGY_RESIDUAL); + +/*! + * \brief types of sensitivities to compute + */ +enum ENUM_SENS { + SENS_GEOMETRY = 1, /*!< \brief Geometrical sensitivity. */ + SENS_MACH = 2, /*!< \brief Mach number sensitivity. */ + SENS_AOA = 3, /*!< \brief Angle of attack sensitivity. */ + SENS_AOS = 4 /*!< \brief Angle of Sideslip sensitivity. */ +}; +static const map Sens_Map = CCreateMap +("SENS_GEOMETRY", SENS_GEOMETRY) +("SENS_MACH", SENS_MACH) +("SENS_AOA", SENS_AOA) +("SENS_AOS", SENS_AOS); + +/*! + * \brief types of grid adaptation/refinement + */ +enum ENUM_ADAPT { + NO_ADAPT = 0, /*!< \brief No grid adaptation. */ + FULL = 1, /*!< \brief Do a complete grid refinement of all the computational grids. */ + FULL_FLOW = 2, /*!< \brief Do a complete grid refinement of the flow grid. */ + FULL_ADJOINT = 3, /*!< \brief Do a complete grid refinement of the adjoint grid. */ + GRAD_FLOW = 5, /*!< \brief Do a gradient based grid adaptation of the flow grid. */ + GRAD_ADJOINT = 6, /*!< \brief Do a gradient based grid adaptation of the adjoint grid. */ + GRAD_FLOW_ADJ = 7, /*!< \brief Do a gradient based grid adaptation of the flow and adjoint grid. */ + COMPUTABLE = 9, /*!< \brief Apply a computable error grid adaptation. */ + REMAINING = 10, /*!< \brief Apply a remaining error grid adaptation. */ + WAKE = 12, /*!< \brief Do a grid refinement on the wake. */ + SMOOTHING = 14, /*!< \brief Do a grid smoothing of the geometry. */ + SUPERSONIC_SHOCK = 15, /*!< \brief Do a grid smoothing. */ + PERIODIC = 17 /*!< \brief Add the periodic halo cells. */ +}; +static const map Adapt_Map = CCreateMap +("NONE", NO_ADAPT) +("FULL", FULL) +("FULL_FLOW", FULL_FLOW) +("FULL_ADJOINT", FULL_ADJOINT) +("GRAD_FLOW", GRAD_FLOW) +("GRAD_ADJOINT", GRAD_ADJOINT) +("GRAD_FLOW_ADJ", GRAD_FLOW_ADJ) +("COMPUTABLE", COMPUTABLE) +("REMAINING", REMAINING) +("WAKE", WAKE) +("SMOOTHING", SMOOTHING) +("SUPERSONIC_SHOCK", SUPERSONIC_SHOCK) +("PERIODIC", PERIODIC); + +/*! + * \brief types of input file formats + */ +enum ENUM_INPUT { + SU2 = 1, /*!< \brief SU2 input format. */ + CGNS = 2 /*!< \brief CGNS input format for the computational grid. */ +}; +static const map Input_Map = CCreateMap +("SU2", SU2) +("CGNS", CGNS); + +const int CGNS_STRING_SIZE = 33;/*!< \brief Length of strings used in the CGNS format. */ + +/*! + * \brief type of solution output file formats + */ +enum ENUM_OUTPUT { + TECPLOT = 1, /*!< \brief Tecplot format for the solution output. */ + TECPLOT_BINARY = 2, /*!< \brief Tecplot binary format for the solution output. */ + FIELDVIEW = 3, /*!< \brief FieldView format for the solution output. */ + FIELDVIEW_BINARY = 4, /*!< \brief FieldView binary format for the solution output. */ + CSV = 5, /*!< \brief Comma-separated values format for the solution output. */ + CGNS_SOL = 6, /*!< \brief CGNS format for the solution output. */ + PARAVIEW = 7 /*!< \brief Paraview format for the solution output. */ +}; +static const map Output_Map = CCreateMap +("TECPLOT", TECPLOT) +("TECPLOT_BINARY", TECPLOT_BINARY) +("FIELDVIEW", FIELDVIEW) +("FIELDVIEW_BINARY", FIELDVIEW_BINARY) +("CSV", CSV) +("CGNS", CGNS_SOL) +("PARAVIEW", PARAVIEW); + +/*! + * \brief type of multigrid cycle + */ +enum MG_CYCLE { + V_CYCLE = 0, /*!< \brief V cycle. */ + W_CYCLE = 1, /*!< \brief W cycle. */ + FULLMG_CYCLE = 2 /*!< \brief FullMG cycle. */ +}; +static const map MG_Cycle_Map = CCreateMap +("V_CYCLE", V_CYCLE) +("W_CYCLE", W_CYCLE) +("FULLMG_CYCLE", FULLMG_CYCLE); + +/*! + * \brief type of solution output variables + */ +enum ENUM_OUTPUT_VARS { + DENSITY = 1, /*!< \brief Density. */ + VEL_X = 2, /*!< \brief X-component of velocity. */ + VEL_Y = 3, /*!< \brief Y-component of velocity. */ + VEL_Z = 4, /*!< \brief Z-component of velocity. */ + PRESSURE = 5, /*!< \brief Static pressure. */ + MACH = 6, /*!< \brief Mach number. */ + TEMPERATURE = 7, /*!< \brief Temperature. */ + LAM_VISC = 8, /*!< \brief Laminar viscosity. */ + EDDY_VISC = 9 /*!< \brief Eddy viscosity. */ +}; +static const map Output_Vars_Map = CCreateMap +("DENSITY", DENSITY) +("VEL_X", VEL_X) +("VEL_Y", VEL_Y) +("VEL_Z", VEL_Z) +("PRESSURE", PRESSURE) +("MACH", MACH) +("TEMPERATURE", TEMPERATURE) +("LAM_VISC", LAM_VISC) +("EDDY_VISC", EDDY_VISC); + +/*! + * \brief types of design parameterizations + */ +enum ENUM_PARAM { + TRANSLATION = 0, /*!< \brief Surface movement as design variable. */ + ROTATION = 1, /*!< \brief Surface rotation as design variable. */ + SCALE = 2, /*!< \brief Surface rotation as design variable. */ + FFD_SETTING = 3, /*!< \brief No surface deformation. */ + FFD_CONTROL_POINT = 4, /*!< \brief Free form deformation for 3D design (change a control point). */ + FFD_CAMBER = 5, /*!< \brief Free form deformation for 3D design (camber change). */ + FFD_THICKNESS = 6, /*!< \brief Free form deformation for 3D design (thickness change). */ + FFD_DIHEDRAL_ANGLE = 7, /*!< \brief Free form deformation for 3D design (change the dihedral angle). */ + FFD_TWIST_ANGLE = 8, /*!< \brief Free form deformation for 3D design (change the twist angle). */ + FFD_ROTATION = 9, /*!< \brief Free form deformation for 3D design (rotation around a line). */ + FFD_CONTROL_POINT_2D = 10, /*!< \brief Free form deformation for 2D design (change a control point). */ + FFD_CAMBER_2D = 11, /*!< \brief Free form deformation for 3D design (camber change). */ + FFD_THICKNESS_2D = 12, /*!< \brief Free form deformation for 3D design (thickness change). */ + FFD_CONTROL_SURFACE = 13, /*!< \brief Free form deformation for 3D design (control surface). */ + HICKS_HENNE = 14, /*!< \brief Hicks-Henne bump function for airfoil deformation. */ + PARABOLIC = 15, /*!< \brief Parabolic airfoil definition as design variables. */ + NACA_4DIGITS = 16, /*!< \brief The four digits NACA airfoil family as design variables. */ + AIRFOIL = 17, /*!< \brief Airfoil definition as design variables. */ + SURFACE_FILE = 18 /*!< Nodal coordinates set using a surface file. */ +}; +static const map Param_Map = CCreateMap +("FFD_SETTING", FFD_SETTING) +("FFD_CONTROL_POINT_2D", FFD_CONTROL_POINT_2D) +("FFD_CAMBER_2D", FFD_CAMBER_2D) +("FFD_THICKNESS_2D", FFD_THICKNESS_2D) +("HICKS_HENNE", HICKS_HENNE) +("NACA_4DIGITS", NACA_4DIGITS) +("TRANSLATION", TRANSLATION) +("ROTATION", ROTATION) +("SCALE", SCALE) +("FFD_CONTROL_POINT", FFD_CONTROL_POINT) +("FFD_DIHEDRAL_ANGLE", FFD_DIHEDRAL_ANGLE) +("FFD_TWIST_ANGLE", FFD_TWIST_ANGLE) +("FFD_ROTATION", FFD_ROTATION) +("FFD_CONTROL_SURFACE", FFD_CONTROL_SURFACE) +("FFD_CAMBER", FFD_CAMBER) +("FFD_THICKNESS", FFD_THICKNESS) +("PARABOLIC", PARABOLIC) +("AIRFOIL", AIRFOIL) +("SURFACE_FILE", SURFACE_FILE); + +/*! + * \brief types of solvers for solving linear systems + */ +enum ENUM_LINEAR_SOLVER { + STEEPEST_DESCENT = 1, /*!< \brief Steepest descent method for point inversion algoritm (Free-Form). */ + NEWTON = 2, /*!< \brief Newton method for point inversion algorithm (Free-Form). */ + QUASI_NEWTON = 3, /*!< \brief Quasi Newton method for point inversion algorithm (Free-Form). */ + CONJUGATE_GRADIENT = 4, /*!< \brief Preconditionated conjugate gradient method for grid deformation. */ + FGMRES = 5, /*!< \brief Flexible Generalized Minimal Residual method. */ + BCGSTAB = 6, /*!< \brief BCGSTAB - Biconjugate Gradient Stabilized Method (main solver). */ + RESTARTED_FGMRES = 7, /*!< \brief Flexible Generalized Minimal Residual method with restart. */ + SMOOTHER_LUSGS = 8, /*!< \brief LU_SGS smoother. */ + SMOOTHER_JACOBI = 9, /*!< \brief Jacobi smoother. */ + SMOOTHER_ILU = 10, /*!< \brief ILU smoother. */ + SMOOTHER_LINELET = 11 /*!< \brief Linelet smoother. */ +}; +static const map Linear_Solver_Map = CCreateMap +("STEEPEST_DESCENT", STEEPEST_DESCENT) +("NEWTON", NEWTON) +("QUASI_NEWTON", QUASI_NEWTON) +("CONJUGATE_GRADIENT", CONJUGATE_GRADIENT) +("BCGSTAB", BCGSTAB) +("FGMRES", FGMRES) +("RESTARTED_FGMRES", RESTARTED_FGMRES) +("SMOOTHER_LUSGS", SMOOTHER_LUSGS) +("SMOOTHER_JACOBI", SMOOTHER_JACOBI) +("SMOOTHER_LINELET", SMOOTHER_LINELET) +("SMOOTHER_ILU0", SMOOTHER_ILU); + +/*! + * \brief types surface continuity at the intersection with the FFD + */ +enum ENUM_FFD_CONTINUITY { + DERIVATIVE_1ST = 1, /*!< \brief First derivative continuity. */ + DERIVATIVE_2ND = 2 /*!< \brief Second derivative continuity. */ +}; +static const map Continuity_Map = CCreateMap +("1ST_DERIVATIVE", DERIVATIVE_1ST) +("2ND_DERIVATIVE", DERIVATIVE_2ND); + +/*! + * \brief types of sensitivity smoothing + */ +enum ENUM_SENS_SMOOTHING { + NO_SMOOTH = 0, /*!< \brief No smoothing. */ + SOBOLEV = 1, /*!< \brief Sobolev gradient smoothing. */ + BIGRID = 2 /*!< \brief Bi-grid technique smoothing. */ +}; +static const map Sens_Smoothing_Map = CCreateMap +("NONE", NO_SMOOTH) +("SOBOLEV", SOBOLEV) +("BIGRID", BIGRID); + +/*! + * \brief types of preconditioners for the linear solver + */ +enum ENUM_LINEAR_SOLVER_PREC { + JACOBI = 1, /*!< \brief Jacobi preconditioner. */ + LU_SGS = 2, /*!< \brief LU SGS preconditioner. */ + LINELET = 3, /*!< \brief Line implicit preconditioner. */ + ILU = 4 /*!< \brief ILU(0) preconditioner. */ +}; +static const map Linear_Solver_Prec_Map = CCreateMap +("JACOBI", JACOBI) +("LU_SGS", LU_SGS) +("LINELET", LINELET) +("ILU0", ILU); + +/*! + * \brief types of analytic definitions for various geometries + */ +enum ENUM_GEO_ANALYTIC { + NO_GEO_ANALYTIC = 0, /*!< \brief No analytic definition of the geometry. */ + NACA0012_AIRFOIL = 1, /*!< \brief Use the analytical definition of the NACA0012 for doing the grid adaptation. */ + NACA4412_AIRFOIL = 2, /*!< \brief Use the analytical definition of the NACA4412 for doing the grid adaptation. */ + CYLINDER = 3, /*!< \brief Use the analytical definition of a cylinder for doing the grid adaptation. */ + BIPARABOLIC = 4 /*!< \brief Use the analytical definition of a biparabolic airfoil for doing the grid adaptation. */ +}; +static const map Geo_Analytic_Map = CCreateMap +("NONE", NO_GEO_ANALYTIC) +("NACA0012_AIRFOIL", NACA0012_AIRFOIL) +("NACA4412_AIRFOIL", NACA4412_AIRFOIL) +("CYLINDER", CYLINDER) +("BIPARABOLIC", BIPARABOLIC); + +/*! + * \brief types of axis orientation + */ +enum ENUM_AXIS_ORIENTATION { + X_AXIS = 0, /*!< \brief X axis orientation. */ + Y_AXIS = 1, /*!< \brief Y axis orientation. */ + Z_AXIS = 2 /*!< \brief Z axis orientation. */ +}; +static const map Axis_Orientation_Map = CCreateMap +("X_AXIS", X_AXIS) +("Y_AXIS", Y_AXIS) +("Z_AXIS", Z_AXIS); + +/*! + * \brief types of schemes for unsteady computations + */ +enum ENUM_UNSTEADY { + STEADY = 0, /*!< \brief A steady computation. */ + TIME_STEPPING = 1, /*!< \brief Use a time stepping strategy for unsteady computations. */ + DT_STEPPING_1ST = 2, /*!< \brief Use a dual time stepping strategy for unsteady computations (1st order). */ + DT_STEPPING_2ND = 3, /*!< \brief Use a dual time stepping strategy for unsteady computations (2nd order). */ + ROTATIONAL_FRAME = 4, /*!< \brief Use a rotational source term. */ + TIME_SPECTRAL = 5 /*!< \brief Use a time spectral source term. */ + +}; +static const map Unsteady_Map = CCreateMap +("NO", STEADY) +("TIME_STEPPING", TIME_STEPPING) +("DUAL_TIME_STEPPING-1ST_ORDER", DT_STEPPING_1ST) +("DUAL_TIME_STEPPING-2ND_ORDER", DT_STEPPING_2ND) +("TIME_SPECTRAL", TIME_SPECTRAL) +("ROTATIONAL_FRAME", ROTATIONAL_FRAME); + +/*! + * \brief types of criteria to determine when the solution is converged + */ +enum ENUM_CONVERGE_CRIT { + CAUCHY = 1, /*!< \brief Cauchy criteria to establish the convergence of the code. */ + RESIDUAL = 2 /*!< \brief Residual criteria to establish the convergence of the code. */ +}; +static const map Converge_Crit_Map = CCreateMap +("CAUCHY", CAUCHY) +("RESIDUAL", RESIDUAL); + +/*! + * \brief types of element stiffnesses imposed for FEA mesh deformation + */ +enum ENUM_DEFORM_STIFFNESS { + CONSTANT_STIFFNESS = 0, /*!< \brief Impose a constant stiffness for each element (steel). */ + INVERSE_VOLUME = 1, /*!< \brief Impose a stiffness for each element that is inversely proportional to cell volume. */ + WALL_DISTANCE = 2 /*!< \brief Impose a stiffness for each element that is proportional to the distance from the deforming surface. */ +}; +static const map Deform_Stiffness_Map = CCreateMap +("CONSTANT_STIFFNESS", CONSTANT_STIFFNESS) +("INVERSE_VOLUME", INVERSE_VOLUME) +("WALL_DISTANCE", WALL_DISTANCE); + +/*! + * \brief The direct differentation variables. + */ +enum ENUM_DIRECTDIFF_VAR { + NO_DERIVATIVE = 0, + D_MACH = 1, /*!< \brief Derivative with respect to the mach number */ + D_AOA = 2, /*!< \brief Derivative with respect to the angle of attack */ + D_PRESSURE = 3, /*!< \brief Derivative with respect to the freestream pressure */ + D_TEMPERATURE = 4,/*!< \brief Derivative with respect to the freestream temperature */ + D_DENSITY = 5, + D_TURB2LAM = 6, + D_SIDESLIP = 7, + D_VISCOSITY = 8, + D_REYNOLDS = 9, + D_DESIGN = 10 +}; +static const map DirectDiff_Var_Map = CCreateMap +("NONE", NO_DERIVATIVE) +("MACH", D_MACH) +("AOA", D_AOA) +("PRESSURE", D_PRESSURE) +("TEMPERATURE", D_TEMPERATURE) +("DENSITY", D_DENSITY) +("TURB2LAM", D_TURB2LAM) +("SIDESLIP", D_SIDESLIP) +("VISCOSITY", D_VISCOSITY) +("REYNOLDS", D_REYNOLDS) +("DESIGN_VARIABLES", D_DESIGN); + +/*! + * \brief types of schemes for dynamic structural computations + */ +enum ENUM_DYNAMIC { + STATIC = 0, /*!< \brief A static structural computation. */ + DYNAMIC = 1 /*!< \brief Use a time stepping strategy for dynamic computations. */ +}; +static const map Dynamic_Map = CCreateMap +("NO", STATIC) +("YES", DYNAMIC); + +/* END_CONFIG_ENUMS */ + +class COptionBase{ +private: +public: + COptionBase() {}; + virtual ~COptionBase() = 0; + // virtual string SetValue(string) {SU2MPI::PrintAndFinalize("shouldn't be here"); return "";}; + virtual string SetValue(vector) = 0; + virtual void SetDefault() = 0; + + string optionCheckMultipleValues(vector & option_value, string type_id, string option_name) { + if (option_value.size() != 1) { + string newString; + newString.append(option_name); + newString.append(": multiple values for type "); + newString.append(type_id); + return newString; + } + return ""; + } + + string badValue(vector & option_value, string type_id, string option_name) { + string newString; + newString.append(option_name); + newString.append(": improper option value for type "); + newString.append(type_id); + return newString; + } +}; + +inline COptionBase::~COptionBase() {} + + +template +class COptionEnum : public COptionBase{ + + map m; + unsigned short & field; // Reference to the feildname + Tenum def; // Default value + string name; // identifier for the option + +public: + COptionEnum(string option_field_name, const map m, unsigned short & option_field, Tenum default_value) : field(option_field) { + this->m = m; + this->def = default_value; + this->name = option_field_name; + } + + ~COptionEnum() {}; + string SetValue(vector option_value) { + // Check if there is more than one string + string out = optionCheckMultipleValues(option_value, "enum", this->name); + if (out.compare("") != 0) { + return out; + } + + // Check to see if the enum value is in the map + if (this->m.find(option_value[0]) == m.end()) { + string str; + str.append(this->name); + str.append(": invalid option value "); + str.append(option_value[0]); + str.append(". Check current SU2 options in config_template.cfg."); + return str; + } + // If it is there, set the option value + Tenum val = this->m[option_value[0]]; + this->field = val; + return ""; + } + + void SetDefault() { + this->field = this->def; + } +}; + +class COptionDouble : public COptionBase{ + su2double & field; // Reference to the fieldname + su2double def; // Default value + string name; // identifier for the option + +public: + COptionDouble(string option_field_name, su2double & option_field, su2double default_value) : field(option_field) { + this->def = default_value; + this->name = option_field_name; + } + + ~COptionDouble() {}; + string SetValue(vector option_value) { + // check if there is more than one value + string out = optionCheckMultipleValues(option_value, "su2double", this->name); + if (out.compare("") != 0) { + return out; + } + istringstream is(option_value[0]); + su2double val; + if (is >> val) { + this->field = val; + return ""; + } + return badValue(option_value, "su2double", this->name); + } + void SetDefault() { + this->field = this->def; + } +}; + +class COptionString : public COptionBase{ + string & field; // Reference to the fieldname + string def; // Default value + string name; // identifier for the option + +public: + COptionString(string option_field_name, string & option_field, string default_value) : field(option_field) { + this->def = default_value; + this->name = option_field_name; + } + + ~COptionString() {}; + string SetValue(vector option_value) { + // check if there is more than one value + string out = optionCheckMultipleValues(option_value, "su2double", this->name); + if (out.compare("") != 0) { + return out; + } + this->field.assign(option_value[0]); + return ""; + } + void SetDefault() { + this->field = this->def; + } +}; + +class COptionInt : public COptionBase{ + int & field; // Reference to the feildname + int def; // Default value + string name; // identifier for the option + +public: + COptionInt(string option_field_name, int & option_field, int default_value) : field(option_field) { + this->def = default_value; + this->name = option_field_name; + } + + ~COptionInt() {}; + string SetValue(vector option_value) { + string out = optionCheckMultipleValues(option_value, "int", this->name); + if (out.compare("") != 0) { + return out; + } + istringstream is(option_value[0]); + int val; + if (is >> val) { + this->field = val; + return ""; + } + return badValue(option_value, "int", this->name); + } + void SetDefault() { + this->field = this->def; + } +}; + +class COptionULong : public COptionBase{ + unsigned long & field; // Reference to the feildname + unsigned long def; // Default value + string name; // identifier for the option + +public: + COptionULong(string option_field_name, unsigned long & option_field, unsigned long default_value) : field(option_field) { + this->def = default_value; + this->name = option_field_name; + } + + ~COptionULong() {}; + string SetValue(vector option_value) { + string out = optionCheckMultipleValues(option_value, "unsigned long", this->name); + if (out.compare("") != 0) { + return out; + } + istringstream is(option_value[0]); + unsigned long val; + if (is >> val) { + this->field = val; + return ""; + } + return badValue(option_value, "unsigned long", this->name); + } + void SetDefault() { + this->field = this->def; + } +}; + +class COptionUShort : public COptionBase{ + unsigned short & field; // Reference to the feildname + unsigned short def; // Default value + string name; // identifier for the option + +public: + COptionUShort(string option_field_name, unsigned short & option_field, unsigned short default_value) : field(option_field) { + this->def = default_value; + this->name = option_field_name; + } + + ~COptionUShort() {}; + string SetValue(vector option_value) { + string out = optionCheckMultipleValues(option_value, "unsigned short", this->name); + if (out.compare("") != 0) { + return out; + } + istringstream is(option_value[0]); + unsigned short val; + if (is >> val) { + this->field = val; + return ""; + } + return badValue(option_value, "unsigned short", this->name); + } + void SetDefault() { + this->field = this->def; + } +}; + +class COptionLong : public COptionBase{ + long & field; // Reference to the feildname + long def; // Default value + string name; // identifier for the option + +public: + COptionLong(string option_field_name, long & option_field, long default_value) : field(option_field) { + this->def = default_value; + this->name = option_field_name; + } + + ~COptionLong() {}; + string SetValue(vector option_value) { + string out = optionCheckMultipleValues(option_value, "long", this->name); + if (out.compare("") != 0) { + return out; + } + istringstream is(option_value[0]); + long val; + if (is >> val) { + this->field = val; + return ""; + } + return badValue(option_value, "long", this->name); + } + void SetDefault() { + this->field = this->def; + } +}; + + +class COptionBool : public COptionBase{ + bool & field; // Reference to the feildname + bool def; // Default value + string name; // identifier for the option + +public: + COptionBool(string option_field_name, bool & option_field, bool default_value) : field(option_field) { + this->def = default_value; + this->name = option_field_name; + } + + ~COptionBool() {}; + string SetValue(vector option_value) { + // check if there is more than one value + string out = optionCheckMultipleValues(option_value, "bool", this->name); + if (out.compare("") != 0) { + return out; + } + if (option_value[0].compare("YES") == 0) { + this->field = true; + return ""; + } + if (option_value[0].compare("NO") == 0) { + this->field = false; + return ""; + } + return badValue(option_value, "bool", this->name); + } + void SetDefault() { + this->field = this->def; + } +}; + +template +class COptionEnumList : public COptionBase{ + + map m; + unsigned short * & field; // Reference to the feildname + string name; // identifier for the option + unsigned short & size; + +public: + COptionEnumList(string option_field_name, const map m, unsigned short * & option_field, unsigned short & list_size) : field(option_field) , size(list_size) { + this->m = m; + this->name = option_field_name; + } + + ~COptionEnumList() {}; + string SetValue(vector option_value) { + if (option_value.size() == 1 && option_value[0].compare("NONE") == 0) { + this->size = 0; + return ""; + } + // size is the length of the option list + this->size = option_value.size(); + unsigned short * enums = new unsigned short[size]; + for (int i = 0; i < this->size; i++) { + // Check to see if the enum value is in the map + if (this->m.find(option_value[i]) == m.end()) { + string str; + str.append(this->name); + str.append(": invalid option value "); + str.append(option_value[i]); + str.append(". Check current SU2 options in config_template.cfg."); + return str; + } + // If it is there, set the option value + enums[i] = this->m[option_value[i]]; + } + this->field = enums; + return ""; + } + + void SetDefault() { + // No default to set + size = 0; + } +}; + +class COptionDoubleArray : public COptionBase{ + su2double * & field; // Reference to the feildname + string name; // identifier for the option + const int size; + su2double * default_value; + +public: + COptionDoubleArray(string option_field_name, const int list_size, su2double * & option_field, su2double * default_value) : field(option_field), size(list_size) { + this->name = option_field_name; + this->default_value = default_value; + } + + ~COptionDoubleArray() {}; + string SetValue(vector option_value) { + // Check that the size is correct + if (option_value.size() != (unsigned long)this->size) { + string newstring; + newstring.append(this->name); + newstring.append(": wrong number of arguments: "); + stringstream ss; + ss << this->size; + newstring.append(ss.str()); + newstring.append(" expected, "); + stringstream ss2; + ss2 << option_value.size(); + newstring.append(ss2.str()); + newstring.append(" found"); + return newstring; + } + su2double * vals = new su2double[this->size]; + for (int i = 0; i < this->size; i++) { + istringstream is(option_value[i]); + su2double val; + if (!(is >> val)) { + delete [] vals; + return badValue(option_value, "su2double array", this->name); + } + vals[i] = val; + } + this->field = vals; + return ""; + } + + void SetDefault() { + this->field = this->default_value; + } +}; + +class COptionDoubleList : public COptionBase{ + su2double * & field; // Reference to the feildname + string name; // identifier for the option + unsigned short & size; + +public: + COptionDoubleList(string option_field_name, unsigned short & list_size, su2double * & option_field) : field(option_field), size(list_size) { + this->name = option_field_name; + } + + ~COptionDoubleList() {}; + string SetValue(vector option_value) { + // The size is the length of option_value + unsigned short option_size = option_value.size(); + if (option_size == 1 && option_value[0].compare("NONE") == 0) { + // No options + this->size = 0; + return ""; + } + + this->size = option_size; + + // Parse all of the options + su2double * vals = new su2double[option_size]; + for (unsigned long i = 0; i < option_size; i++) { + istringstream is(option_value[i]); + su2double val; + if (!(is >> val)) { + delete [] vals; + return badValue(option_value, "su2double list", this->name); + } + vals[i] = val; + } + this->field = vals; + return ""; + } + + void SetDefault() { + this->size = 0; // There is no default value for list + } +}; + +class COptionUShortList : public COptionBase{ + unsigned short * & field; // Reference to the feildname + string name; // identifier for the option + unsigned short & size; + +public: + COptionUShortList(string option_field_name, unsigned short & list_size, unsigned short * & option_field) : field(option_field), size(list_size) { + this->name = option_field_name; + } + + ~COptionUShortList() {}; + string SetValue(vector option_value) { + // The size is the length of option_value + unsigned short option_size = option_value.size(); + if (option_size == 1 && option_value[0].compare("NONE") == 0) { + // No options + this->size = 0; + return ""; + } + this->size = option_size; + + // Parse all of the options + unsigned short * vals = new unsigned short[option_size]; + for (unsigned long i = 0; i < option_size; i++) { + istringstream is(option_value[i]); + unsigned short val; + if (!(is >> val)) { + delete [] vals; + return badValue(option_value, "unsigned short", this->name); + } + vals[i] = val; + } + this->field = vals; + return ""; + } + + void SetDefault() { + this->size = 0; // There is no default value for list + } +}; + +class COptionStringList : public COptionBase{ + string * & field; // Reference to the feildname + string name; // identifier for the option + unsigned short & size; + +public: + COptionStringList(string option_field_name, unsigned short & list_size, string * & option_field) : field(option_field), size(list_size) { + this->name = option_field_name; + } + + ~COptionStringList() {}; + string SetValue(vector option_value) { + // The size is the length of option_value + unsigned short option_size = option_value.size(); + if (option_size == 1 && option_value[0].compare("NONE") == 0) { + this->size = 0; + return ""; + } + this->size = option_size; + + // Parse all of the options + string * vals = new string[option_size]; + for (unsigned long i = 0; i < option_size; i++) { + vals[i].assign(option_value[i]); + } + this->field = vals; + return ""; + } + + void SetDefault() { + this->size = 0; // There is no default value for list + } +}; + +class COptionConvect : public COptionBase{ + string name; // identifier for the option + unsigned short & space; + unsigned short & centered; + unsigned short & upwind; + +public: + COptionConvect(string option_field_name, unsigned short & space_field, unsigned short & centered_field, unsigned short & upwind_field) : space(space_field), centered(centered_field), upwind(upwind_field) { + this->name = option_field_name; + } + + ~COptionConvect() {}; + string SetValue(vector option_value) { + + string out = optionCheckMultipleValues(option_value, "unsigned short", this->name); + if (out.compare("") != 0) { + return out; + } + + if (Centered_Map.count(option_value[0])) { + this->space = Space_Map.find("SPACE_CENTERED")->second; + this->centered = Centered_Map.find(option_value[0])->second; + this->upwind = NO_UPWIND; + return ""; + } + if (Upwind_Map.count(option_value[0])) { + this->space = Space_Map.find("SPACE_UPWIND")->second; + this->upwind = Upwind_Map.find(option_value[0])->second; + this->centered = NO_CENTERED; + return ""; + } + // Make them defined in case something weird happens + this->centered = NO_CENTERED; + this->upwind = NO_UPWIND; + this->space = SPACE_CENTERED; + return badValue(option_value, "convect", this->name); + + } + + void SetDefault() { + this->centered = NO_CENTERED; + this->upwind = NO_UPWIND; + this->space = SPACE_CENTERED; + } +}; + +class COptionMathProblem : public COptionBase{ + string name; // identifier for the option + bool & adjoint; + bool & restart; + bool & disc_adjoint; + bool adjoint_def; + bool restart_def; + bool disc_adjoint_def; + +public: + COptionMathProblem(string option_field_name, bool & adjoint_field, bool adjoint_default, bool & restart_field, bool restart_default, bool & disc_adjoint_field, bool disc_adjoint_default) : adjoint(adjoint_field), restart(restart_field), disc_adjoint(disc_adjoint_field){ + this->name = option_field_name; + this->adjoint_def = adjoint_default; + this->restart_def = restart_default; + this->disc_adjoint_def = disc_adjoint_default; + } + + ~COptionMathProblem() {}; + string SetValue(vector option_value) { + string out = optionCheckMultipleValues(option_value, "unsigned short", this->name); + if (out.compare("") != 0) { + return out; + } + if (option_value[0] == "ADJOINT") { + return badValue(option_value, "math problem (try CONTINUOUS_ADJOINT)", this->name); + } + if (Math_Problem_Map.find(option_value[0]) == Math_Problem_Map.end()) { + return badValue(option_value, "math problem", this->name); + } + if (option_value[0] == "DIRECT") { + this->adjoint = false; + this->restart = false; + this->disc_adjoint = false; + return ""; + } + if (option_value[0] == "CONTINUOUS_ADJOINT") { + this->adjoint= true; + this->restart= true; + this->disc_adjoint = false; + return ""; + } + if (option_value[0] == "DISCRETE_ADJOINT"){ + this->disc_adjoint = true; + this->restart = true; + this->adjoint= false; + return ""; + } + return "option in math problem map not considered in constructor"; + } + + void SetDefault() { + this->adjoint = this->adjoint_def; + this->restart = this->restart_def; + this->disc_adjoint = this->disc_adjoint_def; + } +}; + +class COptionDVParam : public COptionBase{ + string name; // identifier for the option + unsigned short & nDV; + su2double ** & paramDV; + string * & FFDTag; + unsigned short* & design_variable; + +public: + COptionDVParam(string option_field_name, unsigned short & nDV_field, su2double** & paramDV_field, string* & FFDTag_field, unsigned short * & design_variable_field) : nDV(nDV_field), paramDV(paramDV_field), FFDTag(FFDTag_field), design_variable(design_variable_field) { + this->name = option_field_name; + } + + ~COptionDVParam() {}; + + string SetValue(vector option_value) { + if ((option_value.size() == 1) && (option_value[0].compare("NONE") == 0)) { + this->nDV = 0; + return ""; + } + + // Cannot have ; at the beginning or the end + if (option_value[0].compare(";") == 0) { + string newstring; + newstring.append(this->name); + newstring.append(": may not have beginning semicolon"); + return newstring; + } + if (option_value[option_value.size()-1].compare(";") == 0) { + string newstring; + newstring.append(this->name); + newstring.append(": may not have ending semicolon"); + return newstring; + } + + + // use the ";" token to determine the number of design variables + // This works because semicolon is not one of the delimiters in tokenize string + this->nDV = 0; + //unsigned int num_semi = 0; + for (unsigned int i = 0; i < static_cast(option_value.size()); i++) { + if (option_value[i].compare(";") == 0) { + this->nDV++; + // num_semi++; + } + } + + // One more design variable than semicolon + this->nDV++; + + if ( (this->nDV > 0) && (this->design_variable == NULL) ) { + string newstring; + newstring.append(this->name); + newstring.append(": Design_Variable array has not been allocated. Check that DV_KIND appears before DV_PARAM in configuration file."); + return newstring; + } + + this->paramDV = new su2double*[this->nDV]; + for (unsigned short iDV = 0; iDV < this->nDV; iDV++) { + this->paramDV[iDV] = new su2double[MAX_PARAMETERS]; + } + + this->FFDTag = new string[this->nDV]; + + unsigned short nParamDV = 0; + stringstream ss; + unsigned int i = 0; + for (unsigned short iDV = 0; iDV < this->nDV; iDV++) { + switch (this->design_variable[iDV]) { + case FFD_SETTING: nParamDV = 0; break; + case FFD_CONTROL_POINT_2D: nParamDV = 5; break; + case FFD_CAMBER_2D: nParamDV = 2; break; + case FFD_THICKNESS_2D: nParamDV = 2; break; + case HICKS_HENNE: nParamDV = 2; break; + case SCALE: nParamDV = 0; break; + case TRANSLATION: nParamDV = 3; break; + case ROTATION: nParamDV = 6; break; + case NACA_4DIGITS: nParamDV = 3; break; + case PARABOLIC: nParamDV = 2; break; + case AIRFOIL: nParamDV = 2; break; + case FFD_CONTROL_POINT: nParamDV = 7; break; + case FFD_DIHEDRAL_ANGLE: nParamDV = 7; break; + case FFD_TWIST_ANGLE: nParamDV = 7; break; + case FFD_ROTATION: nParamDV = 7; break; + case FFD_CONTROL_SURFACE: nParamDV = 7; break; + case FFD_CAMBER: nParamDV = 3; break; + case FFD_THICKNESS: nParamDV = 3; break; + case SURFACE_FILE: nParamDV = 0; break; + default : { + string newstring; + newstring.append(this->name); + newstring.append(": undefined design variable type found in configuration file."); + return newstring; + } + } + + for (unsigned short iParamDV = 0; iParamDV < nParamDV; iParamDV++) { + + ss << option_value[i] << " "; + + if ((iParamDV == 0) && + ((this->design_variable[iDV] == FFD_SETTING) || + (this->design_variable[iDV] == FFD_CONTROL_POINT_2D) || + (this->design_variable[iDV] == FFD_CAMBER_2D) || + (this->design_variable[iDV] == FFD_THICKNESS_2D) || + (this->design_variable[iDV] == FFD_CONTROL_POINT) || + (this->design_variable[iDV] == FFD_DIHEDRAL_ANGLE) || + (this->design_variable[iDV] == FFD_TWIST_ANGLE) || + (this->design_variable[iDV] == FFD_ROTATION) || + (this->design_variable[iDV] == FFD_CONTROL_SURFACE) || + (this->design_variable[iDV] == FFD_CAMBER) || + (this->design_variable[iDV] == FFD_THICKNESS))) { + ss >> this->FFDTag[iDV]; + this->paramDV[iDV][iParamDV] = 0; + } + else + ss >> this->paramDV[iDV][iParamDV]; + + i++; + } + if (iDV < (this->nDV-1)) { + if (option_value[i].compare(";") != 0) { + string newstring; + newstring.append(this->name); + newstring.append(": a design variable in the configuration file has the wrong number of parameters"); + return newstring; + } + i++; + } + } + + // Need to return something... + return ""; + } + + void SetDefault() { + this->nDV = 0; + this->paramDV = NULL; + this->FFDTag = NULL; + // Don't mess with the Design_Variable because it's an input, not modified + } +}; + +class COptionFFDDef : public COptionBase{ + string name; + unsigned short & nFFD; + su2double ** & CoordFFD; + string * & FFDTag; + +public: + COptionFFDDef(string option_field_name, unsigned short & nFFD_field, su2double** & coordFFD_field, string* & FFDTag_field) : nFFD(nFFD_field), CoordFFD(coordFFD_field), FFDTag(FFDTag_field) { + this->name = option_field_name; + } + + ~COptionFFDDef() {}; + + string SetValue(vector option_value) { + if ((option_value.size() == 1) && (option_value[0].compare("NONE") == 0)) { + this->nFFD = 0; + return ""; + } + + // Cannot have ; at the beginning or the end + if (option_value[0].compare(";") == 0) { + string newstring; + newstring.append(this->name); + newstring.append(": may not have beginning semicolon"); + return newstring; + } + if (option_value[option_value.size()-1].compare(";") == 0) { + string newstring; + newstring.append(this->name); + newstring.append(": may not have ending semicolon"); + return newstring; + } + + + // use the ";" token to determine the number of design variables + // This works because semicolon is not one of the delimiters in tokenize string + this->nFFD = 0; + for (unsigned int i = 0; i < static_cast(option_value.size()); i++) { + if (option_value[i].compare(";") == 0) { + this->nFFD++; + } + } + + // One more design variable than semicolon + this->nFFD++; + + this->CoordFFD = new su2double*[this->nFFD]; + for (unsigned short iFFD = 0; iFFD < this->nFFD; iFFD++) { + this->CoordFFD[iFFD] = new su2double[25]; + } + + this->FFDTag = new string[this->nFFD]; + + unsigned short nCoordFFD = 0; + stringstream ss; + unsigned int i = 0; + + for (unsigned short iFFD = 0; iFFD < this->nFFD; iFFD++) { + + nCoordFFD = 25; + + for (unsigned short iCoordFFD = 0; iCoordFFD < nCoordFFD; iCoordFFD++) { + + ss << option_value[i] << " "; + + if (iCoordFFD == 0) ss >> this->FFDTag[iFFD]; + else ss >> this->CoordFFD[iFFD][iCoordFFD-1]; + + i++; + } + + if (iFFD < (this->nFFD-1)) { + if (option_value[i].compare(";") != 0) { + string newstring; + newstring.append(this->name); + newstring.append(": a FFD box in the configuration file has the wrong number of parameters"); + return newstring; + } + i++; + } + + } + + // Need to return something... + return ""; + } + + void SetDefault() { + this->nFFD = 0; + this->CoordFFD = NULL; + this->FFDTag = NULL; + } + +}; + +class COptionFFDDegree : public COptionBase{ + string name; + unsigned short & nFFD; + unsigned short ** & DegreeFFD; + +public: + COptionFFDDegree(string option_field_name, unsigned short & nFFD_field, unsigned short** & degreeFFD_field) : nFFD(nFFD_field), DegreeFFD(degreeFFD_field) { + this->name = option_field_name; + } + + ~COptionFFDDegree() {}; + + string SetValue(vector option_value) { + if ((option_value.size() == 1) && (option_value[0].compare("NONE") == 0)) { + this->nFFD = 0; + return ""; + } + + // Cannot have ; at the beginning or the end + if (option_value[0].compare(";") == 0) { + string newstring; + newstring.append(this->name); + newstring.append(": may not have beginning semicolon"); + return newstring; + } + if (option_value[option_value.size()-1].compare(";") == 0) { + string newstring; + newstring.append(this->name); + newstring.append(": may not have ending semicolon"); + return newstring; + } + + + // use the ";" token to determine the number of design variables + // This works because semicolon is not one of the delimiters in tokenize string + this->nFFD = 0; + for (unsigned int i = 0; i < static_cast(option_value.size()); i++) { + if (option_value[i].compare(";") == 0) { + this->nFFD++; + } + } + + // One more design variable than semicolon + this->nFFD++; + + this->DegreeFFD = new unsigned short*[this->nFFD]; + for (unsigned short iFFD = 0; iFFD < this->nFFD; iFFD++) { + this->DegreeFFD[iFFD] = new unsigned short[3]; + } + + unsigned short nDegreeFFD = 0; + stringstream ss; + unsigned int i = 0; + + for (unsigned short iFFD = 0; iFFD < this->nFFD; iFFD++) { + + nDegreeFFD = 3; + + for (unsigned short iDegreeFFD = 0; iDegreeFFD < nDegreeFFD; iDegreeFFD++) { + ss << option_value[i] << " "; + ss >> this->DegreeFFD[iFFD][iDegreeFFD]; + i++; + } + + if (iFFD < (this->nFFD-1)) { + if (option_value[i].compare(";") != 0) { + string newstring; + newstring.append(this->name); + newstring.append(": a FFD degree in the configuration file has the wrong number of parameters"); + return newstring; + } + i++; + } + + } + + // Need to return something... + return ""; + } + + void SetDefault() { + this->nFFD = 0; + this->DegreeFFD = NULL; + } + +}; + +// Class where the option is represented by (String, su2double, string, su2double, ...) +class COptionStringDoubleList : public COptionBase{ + string name; // identifier for the option + unsigned short & size; // how many strings are there (same as number of su2doubles) + + string * & s_f; // Reference to the string fields + su2double* & d_f; // reference to the su2double fields + +public: + COptionStringDoubleList(string option_field_name, unsigned short & list_size, string * & string_field, su2double* & double_field) : size(list_size), s_f(string_field), d_f(double_field) { + this->name = option_field_name; + } + + ~COptionStringDoubleList() {}; + string SetValue(vector option_value) { + // There must be an even number of entries (same number of strings and doubles + unsigned short totalVals = option_value.size(); + if ((totalVals % 2) != 0) { + if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { + // It's okay to say its NONE + this->size = 0; + return ""; + } + string newstring; + newstring.append(this->name); + newstring.append(": must have an even number of entries"); + return newstring; + } + unsigned short nVals = totalVals / 2; + this->size = nVals; + this->s_f = new string[nVals]; + this->d_f = new su2double[nVals]; + + for (unsigned long i = 0; i < nVals; i++) { + this->s_f[i].assign(option_value[2*i]); // 2 because have su2double and string + istringstream is(option_value[2*i + 1]); + su2double val; + if (!(is >> val)) { + return badValue(option_value, "string su2double", this->name); + } + this->d_f[i] = val; + } + // Need to return something... + return ""; + } + + void SetDefault() { + this->size = 0; // There is no default value for list + } +}; + +class COptionInlet : public COptionBase{ + string name; // identifier for the option + unsigned short & size; + string * & marker; + su2double * & ttotal; + su2double * & ptotal; + su2double ** & flowdir; + +public: + COptionInlet(string option_field_name, unsigned short & nMarker_Inlet, string* & Marker_Inlet, su2double* & Ttotal, su2double* & Ptotal, su2double** & FlowDir) : size(nMarker_Inlet), marker(Marker_Inlet), ttotal(Ttotal), ptotal(Ptotal), flowdir(FlowDir) { + this->name = option_field_name; + } + + ~COptionInlet() {}; + string SetValue(vector option_value) { + + unsigned short totalVals = option_value.size(); + if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { + this->size = 0; + this->marker = NULL; + this->ttotal = NULL; + this->ptotal = NULL; + this->flowdir = NULL; + return ""; + } + + if (totalVals % 6 != 0) { + string newstring; + newstring.append(this->name); + newstring.append(": must have a number of entries divisible by 6"); + this->size = 0; + this->marker = NULL; + this->ttotal = NULL; + this->ptotal = NULL; + this->flowdir = NULL; + return newstring; + } + + unsigned short nVals = totalVals / 6; + this->size = nVals; + this->marker = new string[nVals]; + this->ttotal = new su2double[nVals]; + this->ptotal = new su2double[nVals]; + this->flowdir = new su2double*[nVals]; + for (unsigned long i = 0; i < nVals; i++) { + this->flowdir[i] = new su2double[3]; + } + + for (unsigned long i = 0; i < nVals; i++) { + this->marker[i].assign(option_value[6*i]); + istringstream ss_1st(option_value[6*i + 1]); + if (!(ss_1st >> this->ttotal[i])) { + return badValue(option_value, "inlet", this->name); + } + istringstream ss_2nd(option_value[6*i + 2]); + if (!(ss_2nd >> this->ptotal[i])) { + return badValue(option_value, "inlet", this->name); + } + istringstream ss_3rd(option_value[6*i + 3]); + if (!(ss_3rd >> this->flowdir[i][0])) { + return badValue(option_value, "inlet", this->name); + } + istringstream ss_4th(option_value[6*i + 4]); + if (!(ss_4th >> this->flowdir[i][1])) { + return badValue(option_value, "inlet", this->name); + } + istringstream ss_5th(option_value[6*i + 5]); + if (!(ss_5th >> this->flowdir[i][2])) { + return badValue(option_value, "inlet", this->name); + } + } + + return ""; + } + + void SetDefault() { + this->marker = NULL; + this->ttotal = NULL; + this->ptotal = NULL; + this->flowdir = NULL; + this->size = 0; // There is no default value for list + } +}; + +template +class COptionRiemann : public COptionBase{ + +protected: + map m; + string name; // identifier for the option + unsigned short & size; + string * & marker; + unsigned short* & field; // Reference to the field name + su2double * & var1; + su2double * & var2; + su2double ** & flowdir; + +public: + COptionRiemann(string option_field_name, unsigned short & nMarker_Riemann, string* & Marker_Riemann, unsigned short* & option_field, const map m, su2double* & var1, su2double* & var2, su2double** & FlowDir) : size(nMarker_Riemann), + marker(Marker_Riemann), field(option_field), var1(var1), var2(var2), flowdir(FlowDir) { + this->name = option_field_name; + this->m = m; + } + ~COptionRiemann() {}; + + string SetValue(vector option_value) { + + unsigned short totalVals = option_value.size(); + if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { + this->size = 0; + this->marker = NULL; + this->field = 0; + this->var1 = NULL; + this->var2 = NULL; + this->flowdir = NULL; + return ""; + } + + if (totalVals % 7 != 0) { + string newstring; + newstring.append(this->name); + newstring.append(": must have a number of entries divisible by 7"); + this->size = 0; + this->marker = NULL; + this->var1 = NULL; + this->var2 = NULL; + this->flowdir = NULL; + this->field = NULL; + return newstring; + } + + unsigned short nVals = totalVals / 7; + this->size = nVals; + this->marker = new string[nVals]; + this->var1 = new su2double[nVals]; + this->var2 = new su2double[nVals]; + this->flowdir = new su2double*[nVals]; + this->field = new unsigned short[nVals]; + + for (unsigned long i = 0; i < nVals; i++) { + this->flowdir[i] = new su2double[3]; + } + + for (unsigned long i = 0; i < nVals; i++) { + this->marker[i].assign(option_value[7*i]); + // Check to see if the enum value is in the map + if (this->m.find(option_value[7*i + 1]) == m.end()) { + string str; + str.append(this->name); + str.append(": invalid option value "); + str.append(option_value[0]); + str.append(". Check current SU2 options in config_template.cfg."); + return str; + } + Tenum val = this->m[option_value[7*i + 1]]; + this->field[i] = val; + + istringstream ss_1st(option_value[7*i + 2]); + if (!(ss_1st >> this->var1[i])) { + return badValue(option_value, "Riemann", this->name); + } + istringstream ss_2nd(option_value[7*i + 3]); + if (!(ss_2nd >> this->var2[i])) { + return badValue(option_value, "Riemann", this->name); + } + istringstream ss_3rd(option_value[7*i + 4]); + if (!(ss_3rd >> this->flowdir[i][0])) { + return badValue(option_value, "Riemann", this->name); + } + istringstream ss_4th(option_value[7*i + 5]); + if (!(ss_4th >> this->flowdir[i][1])) { + return badValue(option_value, "Riemann", this->name); + } + istringstream ss_5th(option_value[7*i + 6]); + if (!(ss_5th >> this->flowdir[i][2])) { + return badValue(option_value, "Riemann", this->name); + } + } + + return ""; + } + + void SetDefault() { + this->marker = NULL; + this->var1 = NULL; + this->var2 = NULL; + this->flowdir = NULL; + this->size = 0; // There is no default value for list + } +}; + +template +class COptionNRBC : public COptionRiemann { + +public: + COptionNRBC(string option_field_name, unsigned short & nMarker_NRBC, string* & Marker_NRBC, unsigned short* & option_field, + const map m, su2double* & var1, su2double* & var2, su2double** & FlowDir): COptionRiemann(option_field_name, nMarker_NRBC, Marker_NRBC, option_field, + m, var1, var2,FlowDir){} + ~COptionNRBC() {}; + +}; +//template +//class COptionNRBC : public COptionBase{ +// +// map m; +// unsigned short* & field; // Reference to the fieldname +// string name; // identifier for the option +// unsigned short & size; +// string * & marker; +// su2double * & var1; +// su2double * & var2; +// su2double ** & flowdir; +// +//public: +// COptionNRBC(string option_field_name, unsigned short & nMarker_NRBC, string* & Marker_NRBC, unsigned short* & option_field, const map m, su2double* & var1, su2double* & var2, su2double** & FlowDir) : size(nMarker_NRBC), +// marker(Marker_NRBC), field(option_field), var1(var1), var2(var2), flowdir(FlowDir) { +// this->name = option_field_name; +// this->m = m; +// } +// ~COptionNRBC() {}; +// +// string SetValue(vector option_value) { +// +// unsigned long totalVals = option_value.size(); +// if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { +// this->size = 0; +// this->marker = NULL; +// this->field = 0; +// this->var1 = NULL; +// this->var2 = NULL; +// this->flowdir = NULL; +// return ""; +// } +// +// if (totalVals % 7 != 0) { +// string newstring; +// newstring.append(this->name); +// newstring.append(": must have a number of entries divisible by 7"); +// this->size = 0; +// this->marker = NULL; +// this->var1 = NULL; +// this->var2 = NULL; +// this->flowdir = NULL; +// this->field = NULL; +// return newstring; +// } +// +// unsigned long nVals = totalVals / 7; +// this->size = nVals; +// this->marker = new string[nVals]; +// this->var1 = new su2double[nVals]; +// this->var2 = new su2double[nVals]; +// this->flowdir = new su2double*[nVals]; +// this->field = new unsigned short[nVals]; +// +// for (int i = 0; i < nVals; i++) { +// this->flowdir[i] = new su2double[3]; +// } +// +// for (int i = 0; i < nVals; i++) { +// this->marker[i].assign(option_value[7*i]); +// // Check to see if the enum value is in the map +// if (this->m.find(option_value[7*i + 1]) == m.end()) { +// string str; +// str.append(this->name); +// str.append(": invalid option value "); +// str.append(option_value[0]); +// str.append(". Check current SU2 options in config_template.cfg."); +// return str; +// } +// Tenum val = this->m[option_value[7*i + 1]]; +// this->field[i] = val; +// +// istringstream ss_1st(option_value[7*i + 2]); +// if (!(ss_1st >> this->var1[i])) { +// return badValue(option_value, "NRBC", this->name); +// } +// istringstream ss_2nd(option_value[7*i + 3]); +// if (!(ss_2nd >> this->var2[i])) { +// return badValue(option_value, "NRBC", this->name); +// } +// istringstream ss_3rd(option_value[7*i + 4]); +// if (!(ss_3rd >> this->flowdir[i][0])) { +// return badValue(option_value, "NRBC", this->name); +// } +// istringstream ss_4th(option_value[7*i + 5]); +// if (!(ss_4th >> this->flowdir[i][1])) { +// return badValue(option_value, "NRBC", this->name); +// } +// istringstream ss_5th(option_value[7*i + 6]); +// if (!(ss_5th >> this->flowdir[i][2])) { +// return badValue(option_value, "NRBC", this->name); +// } +// } +// +// return ""; +// } +// +// void SetDefault() { +// this->marker = NULL; +// this->var1 = NULL; +// this->var2 = NULL; +// this->flowdir = NULL; +// this->size = 0; // There is no default value for list +// } +//}; + + + + + + +//Inlet condition where the input direction is assumed +class COptionExhaust : public COptionBase{ + string name; // identifier for the option + unsigned short & size; + string * & marker; + su2double * & ttotal; + su2double * & ptotal; + +public: + COptionExhaust(string option_field_name, unsigned short & nMarker_Exhaust, string* & Marker_Exhaust, su2double* & Ttotal, su2double* & Ptotal) : size(nMarker_Exhaust), marker(Marker_Exhaust), ttotal(Ttotal), ptotal(Ptotal) { + this->name = option_field_name; + } + + ~COptionExhaust() {}; + + string SetValue(vector option_value) { + + unsigned short totalVals = option_value.size(); + if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { + this->size = 0; + this->marker = NULL; + this->ttotal = NULL; + this->ptotal = NULL; + return ""; + } + + if (totalVals % 3 != 0) { + string newstring; + newstring.append(this->name); + newstring.append(": must have a number of entries divisible by 3"); + this->size = 0; + this->marker = NULL; + this->ttotal = NULL; + this->ptotal = NULL; + return newstring; + } + + unsigned short nVals = totalVals / 3; + this->size = nVals; + this->marker = new string[nVals]; + this->ttotal = new su2double[nVals]; + this->ptotal = new su2double[nVals]; + + for (unsigned long i = 0; i < nVals; i++) { + this->marker[i].assign(option_value[3*i]); + istringstream ss_1st(option_value[3*i + 1]); + if (!(ss_1st >> this->ttotal[i])) + return badValue(option_value, "exhaust fixed", this->name); + istringstream ss_2nd(option_value[3*i + 2]); + if (!(ss_2nd >> this->ptotal[i])) + return badValue(option_value, "exhaust fixed", this->name); + } + + return ""; + } + + void SetDefault() { + this->marker = NULL; + this->ttotal = NULL; + this->ptotal = NULL; + this->size = 0; // There is no default value for list + } + +}; + +//Inlet condition where the input direction is assumed +class COptionBleed : public COptionBase{ + string name; // identifier for the option + unsigned short & size; + string * & marker; + su2double * & massflow_target; + su2double * & temp_target; + +public: + COptionBleed(string option_field_name, unsigned short & nMarker_Bleed, string* & Marker_Bleed, su2double* & MassFlow_Target, su2double* & Temp_Target) : size(nMarker_Bleed), marker(Marker_Bleed), massflow_target(MassFlow_Target), temp_target(Temp_Target) { + this->name = option_field_name; + } + + ~COptionBleed() {}; + + string SetValue(vector option_value) { + + unsigned short totalVals = option_value.size(); + if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { + this->size = 0; + this->marker = NULL; + this->massflow_target = NULL; + this->temp_target = NULL; + return ""; + } + + if (totalVals % 3 != 0) { + string newstring; + newstring.append(this->name); + newstring.append(": must have a number of entries divisible by 3"); + this->size = 0; + this->marker = NULL; + this->massflow_target = NULL; + this->temp_target = NULL; + return newstring; + } + + unsigned short nVals = totalVals / 3; + this->size = nVals; + this->marker = new string[nVals]; + this->massflow_target = new su2double[nVals]; + this->temp_target = new su2double[nVals]; + + for (unsigned long i = 0; i < nVals; i++) { + this->marker[i].assign(option_value[3*i]); + istringstream ss_1st(option_value[3*i + 1]); + if (!(ss_1st >> this->massflow_target[i])) + return badValue(option_value, "bleed fixed", this->name); + istringstream ss_2nd(option_value[3*i + 2]); + if (!(ss_2nd >> this->temp_target[i])) + return badValue(option_value, "bleed fixed", this->name); + } + + return ""; + } + + void SetDefault() { + this->marker = NULL; + this->massflow_target = NULL; + this->temp_target = NULL; + this->size = 0; // There is no default value for list + } + +}; + +class COptionPeriodic : public COptionBase{ + string name; // identifier for the option + unsigned short & size; + string * & marker_bound; + string * & marker_donor; + su2double ** & rot_center; + su2double ** & rot_angles; + su2double ** & translation; + +public: + COptionPeriodic(const string option_field_name, unsigned short & nMarker_PerBound, + string* & Marker_PerBound, string* & Marker_PerDonor, + su2double** & RotCenter, su2double** & RotAngles, su2double** & Translation) : size(nMarker_PerBound), marker_bound(Marker_PerBound), marker_donor(Marker_PerDonor), rot_center(RotCenter), rot_angles(RotAngles), translation(Translation) { + this->name = option_field_name; + } + + ~COptionPeriodic() {}; + string SetValue(vector option_value) { + + const int mod_num = 11; + + unsigned short totalVals = option_value.size(); + if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { + this->size = 0; + this->marker_bound = NULL; + this->marker_donor = NULL; + this->rot_center = NULL; + this->rot_angles = NULL; + this->translation = NULL; + return ""; + } + + if (totalVals % mod_num != 0) { + string newstring; + newstring.append(this->name); + newstring.append(": must have a number of entries divisible by 11"); + this->size = 0; + this->marker_bound = NULL; + this->marker_donor = NULL; + this->rot_center = NULL; + this->rot_angles = NULL; + this->translation = NULL; + return newstring; + } + + unsigned short nVals = 2 * (totalVals / mod_num); // To account for periodic and donor + this->size = nVals; + this->marker_bound = new string[nVals]; + this->marker_donor = new string[nVals]; + this->rot_center = new su2double*[nVals]; + this->rot_angles = new su2double*[nVals]; + this->translation = new su2double*[nVals]; + for (unsigned long i = 0; i < nVals; i++) { + this->rot_center[i] = new su2double[3]; + this->rot_angles[i] = new su2double[3]; + this->translation[i] = new su2double[3]; + } + + su2double deg2rad = PI_NUMBER/180.0; + + for (unsigned long i = 0; i < (nVals/2); i++) { + this->marker_bound[i].assign(option_value[mod_num*i]); + this->marker_donor[i].assign(option_value[mod_num*i+1]); + istringstream ss_1st(option_value[mod_num*i + 2]); + if (!(ss_1st >> this->rot_center[i][0])) { + return badValue(option_value, "periodic", this->name); + } + istringstream ss_2nd(option_value[mod_num*i + 3]); + if (!(ss_2nd >> this->rot_center[i][1])) { + return badValue(option_value, "periodic", this->name); + } + istringstream ss_3rd(option_value[mod_num*i + 4]); + if (!(ss_3rd >> this->rot_center[i][2])) { + return badValue(option_value, "periodic", this->name); + } + istringstream ss_4th(option_value[mod_num*i + 5]); + if (!(ss_4th >> this->rot_angles[i][0])) { + return badValue(option_value, "periodic", this->name); + } + istringstream ss_5th(option_value[mod_num*i + 6]); + if (!(ss_5th >> this->rot_angles[i][1])) { + return badValue(option_value, "periodic", this->name); + } + istringstream ss_6th(option_value[mod_num*i + 7]); + if (!(ss_6th >> this->rot_angles[i][2])) { + return badValue(option_value, "periodic", this->name); + } + istringstream ss_7th(option_value[mod_num*i + 8]); + if (!(ss_7th >> this->translation[i][0])) { + return badValue(option_value, "periodic", this->name); + } + istringstream ss_8th(option_value[mod_num*i + 9]); + if (!(ss_8th >> this->translation[i][1])) { + return badValue(option_value, "periodic", this->name); + } + istringstream ss_9th(option_value[mod_num*i + 10]); + if (!(ss_9th >> this->translation[i][2])) { + return badValue(option_value, "periodic", this->name); + } + this->rot_angles[i][0] *= deg2rad; + this->rot_angles[i][1] *= deg2rad; + this->rot_angles[i][2] *= deg2rad; + } + + for (unsigned long i = (nVals/2); i < nVals; i++) { + this->marker_bound[i].assign(option_value[mod_num*(i-nVals/2)+1]); + this->marker_donor[i].assign(option_value[mod_num*(i-nVals/2)]); + istringstream ss_1st(option_value[mod_num*(i-nVals/2) + 2]); + if (!(ss_1st >> this->rot_center[i][0])) { + return badValue(option_value, "periodic", this->name); + } + istringstream ss_2nd(option_value[mod_num*(i-nVals/2) + 3]); + if (!(ss_2nd >> this->rot_center[i][1])) { + return badValue(option_value, "periodic", this->name); + } + istringstream ss_3rd(option_value[mod_num*(i-nVals/2) + 4]); + if (!(ss_3rd >> this->rot_center[i][2])) { + return badValue(option_value, "periodic", this->name); + } + istringstream ss_4th(option_value[mod_num*(i-nVals/2) + 5]); + if (!(ss_4th >> this->rot_angles[i][0])) { + return badValue(option_value, "periodic", this->name); + } + istringstream ss_5th(option_value[mod_num*(i-nVals/2) + 6]); + if (!(ss_5th >> this->rot_angles[i][1])) { + return badValue(option_value, "periodic", this->name); + } + istringstream ss_6th(option_value[mod_num*(i-nVals/2) + 7]); + if (!(ss_6th >> this->rot_angles[i][2])) { + return badValue(option_value, "periodic", this->name); + } + istringstream ss_7th(option_value[mod_num*(i-nVals/2) + 8]); + if (!(ss_7th >> this->translation[i][0])) { + return badValue(option_value, "periodic", this->name); + } + istringstream ss_8th(option_value[mod_num*(i-nVals/2) + 9]); + if (!(ss_8th >> this->translation[i][1])) { + return badValue(option_value, "periodic", this->name); + } + istringstream ss_9th(option_value[mod_num*(i-nVals/2) + 10]); + if (!(ss_9th >> this->translation[i][2])) { + return badValue(option_value, "periodic", this->name); + } + /*--- Mirror the rotational angles and translation vector (rotational + center does not need to move) ---*/ + this->rot_center[i][0] *= 1.0; + this->rot_center[i][1] *= 1.0; + this->rot_center[i][2] *= 1.0; + this->rot_angles[i][0] *= -deg2rad; + this->rot_angles[i][1] *= -deg2rad; + this->rot_angles[i][2] *= -deg2rad; + this->translation[i][0] *= -1.0; + this->translation[i][1] *= -1.0; + this->translation[i][2] *= -1.0; + } + + return ""; + } + + void SetDefault() { + this->size = 0; + this->marker_bound = NULL; + this->marker_donor = NULL; + this->rot_center = NULL; + this->rot_angles = NULL; + this->translation = NULL; + } +}; + + +class COptionMixingPlane : public COptionBase{ + string name; // identifier for the option + unsigned short & size; + string * & marker_bound; + string * & marker_donor; + +public: + COptionMixingPlane(const string option_field_name, unsigned short & nMarker_MixBound, + string* & Marker_MixBound, string* & Marker_MixDonor) : size(nMarker_MixBound), marker_bound(Marker_MixBound), marker_donor(Marker_MixDonor) { + this->name = option_field_name; + } + + ~COptionMixingPlane() {}; + string SetValue(vector option_value) { + + const int mod_num = 2; + + unsigned long totalVals = option_value.size(); + if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { + this->size = 0; + this->marker_bound = NULL; + this->marker_donor = NULL; + return ""; + } + + if (totalVals % mod_num != 0) { + string newstring; + newstring.append(this->name); + newstring.append(": must have a number of entries divisible by 11"); + this->size = 0; + this->marker_bound = NULL; + this->marker_donor = NULL; + return newstring; + } + + unsigned long nVals = 2 * (totalVals / mod_num); // To account for periodic and donor + this->size = nVals; + this->marker_bound = new string[nVals]; + this->marker_donor = new string[nVals]; + + + for (unsigned short i = 0; i < (nVals/2); i++) { + this->marker_bound[i].assign(option_value[mod_num*i]); + this->marker_donor[i].assign(option_value[mod_num*i+1]); + } + + for (unsigned long i = (nVals/2); i < nVals; i++) { + this->marker_bound[i].assign(option_value[mod_num*(i-nVals/2)+1]); + this->marker_donor[i].assign(option_value[mod_num*(i-nVals/2)]); + } + + + + return ""; + } + + void SetDefault() { + this->size = 0; + this->marker_bound = NULL; + this->marker_donor = NULL; + } +}; + +template +class COptionTurboPerformance : public COptionBase{ + string name; // identifier for the option + unsigned short & size; + string * & marker_turboIn; + string * & marker_turboOut; + map m; + unsigned short* & field; // Reference to the fieldname + +public: + COptionTurboPerformance(const string option_field_name, unsigned short & nMarker_TurboPerf, + string* & Marker_TurboBoundIn, string* & Marker_TurboBoundOut, unsigned short* & option_field, const map m) : size(nMarker_TurboPerf), marker_turboIn(Marker_TurboBoundIn), marker_turboOut(Marker_TurboBoundOut), field(option_field) { + this->name = option_field_name; + this->m = m; + } + + ~COptionTurboPerformance() {}; + string SetValue(vector option_value) { + + const int mod_num = 3; + + unsigned long totalVals = option_value.size(); + if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { + this->size = 0; + this->marker_turboIn= NULL; + this->marker_turboOut = NULL; + this->field = NULL; + return ""; + } + + if (totalVals % mod_num != 0) { + string newstring; + newstring.append(this->name); + newstring.append(": must have a number of entries divisible by 11"); + this->size = 0; + this->marker_turboIn= NULL; + this->marker_turboOut = NULL;; + this->field = NULL; + return newstring; + } + + unsigned long nVals = totalVals / mod_num; + this->size = nVals; + this->marker_turboIn = new string[nVals]; + this->marker_turboOut = new string[nVals]; + this->field = new unsigned short[nVals]; + for (unsigned long i = 0; i < nVals; i++) + if (this->m.find(option_value[mod_num*i + 2]) == m.end()) { + string str; + str.append(this->name); + str.append(": invalid option value "); + str.append(option_value[0]); + str.append(". Check current SU2 options in config_template.cfg."); + return str; + } + for (unsigned long i = 0; i < nVals; i++) { + this->marker_turboIn[i].assign(option_value[mod_num*i]); + this->marker_turboOut[i].assign(option_value[mod_num*i+1]); + Tenum val = this->m[option_value[mod_num*i + 2]]; + this->field[i] = val; + } + + + return ""; + } + + void SetDefault() { + this->size = 0; + this->marker_turboIn= NULL; + this->marker_turboOut = NULL; + this->field = NULL; + } +}; + + +class COptionPython : public COptionBase{ + string name; +public: + COptionPython(const string name) { + this->name = name; + } + ~COptionPython() {}; + // No checking happens with python options + string SetValue(vector) { + return ""; + } + // No defaults with python options + void SetDefault() { + return; + }; +}; + + + +class COptionActuatorDisk : public COptionBase{ + string name; // identifier for the option + unsigned short & inlet_size; + unsigned short & outlet_size; + string * & marker_inlet; + string * & marker_outlet; + su2double ** & origin; + su2double * & root_radius; + su2double * & tip_radius; + su2double * & press_jump; + su2double * & temp_jump; + su2double * & omega; + unsigned short * & distribution; + +public: + COptionActuatorDisk(const string name, unsigned short & nMarker_ActDisk_Inlet, unsigned short & nMarker_ActDisk_Outlet, string * & Marker_ActDisk_Inlet, string * & Marker_ActDisk_Outlet, su2double ** & ActDisk_Origin, su2double * & ActDisk_RootRadius, su2double * & ActDisk_TipRadius, su2double * & ActDisk_PressJump, su2double * & ActDisk_TempJump, su2double * & ActDisk_Omega, unsigned short * & ActDisk_Distribution) : inlet_size(nMarker_ActDisk_Inlet), outlet_size(nMarker_ActDisk_Outlet), marker_inlet(Marker_ActDisk_Inlet), marker_outlet(Marker_ActDisk_Outlet), origin(ActDisk_Origin), root_radius(ActDisk_RootRadius), tip_radius(ActDisk_TipRadius), press_jump(ActDisk_PressJump), temp_jump(ActDisk_TempJump), omega(ActDisk_Omega), distribution(ActDisk_Distribution) { + this->name = name; + } + + ~COptionActuatorDisk() {}; + string SetValue(vector option_value) { + const int mod_num = 11; + unsigned short totalVals = option_value.size(); + if ((totalVals == 1) && (option_value[0].compare("NONE") == 0)) { + this->SetDefault(); + return ""; + } + + if (totalVals % mod_num != 0) { + string newstring; + newstring.append(this->name); + newstring.append(": must have a number of entries divisible by 10"); + this->SetDefault(); + return newstring; + } + + unsigned short nVals = totalVals / mod_num; + this->inlet_size = nVals; + this->outlet_size = nVals; + this->marker_inlet = new string[this->inlet_size]; + this->marker_outlet = new string[this->outlet_size]; + this->root_radius = new su2double[this->inlet_size]; + this->tip_radius = new su2double[this->inlet_size]; + this->press_jump = new su2double[this->outlet_size]; + this->temp_jump = new su2double[this->outlet_size]; + this->omega = new su2double[this->inlet_size]; + this->distribution = new unsigned short[this->inlet_size]; + + this->origin = new su2double*[this->inlet_size]; + for (int i = 0; i < this->inlet_size; i++) { + this->origin[i] = new su2double[3]; + } + + string tname = "actuator disk"; + + for (int i = 0; i < this->inlet_size; i++) { + this->marker_inlet[i].assign(option_value[mod_num*i]); + this->marker_outlet[i].assign(option_value[mod_num*i+1]); + istringstream ss_1st(option_value[mod_num*i + 2]); + if (!(ss_1st >> this->origin[i][0])) { + return badValue(option_value, tname, this->name); + } + istringstream ss_2nd(option_value[mod_num*i + 3]); + if (!(ss_2nd >> this->origin[i][1])) { + return badValue(option_value, tname, this->name); + } + istringstream ss_3rd(option_value[mod_num*i + 4]); + if (!(ss_3rd >> this->origin[i][2])) { + return badValue(option_value, tname, this->name); + } + istringstream ss_4th(option_value[mod_num*i + 5]); + if (!(ss_4th >> this->root_radius[i])) { + return badValue(option_value, tname, this->name); + } + istringstream ss_5th(option_value[mod_num*i + 6]); + if (!(ss_5th >> this->tip_radius[i])) { + return badValue(option_value, tname, this->name); + } + istringstream ss_6th(option_value[mod_num*i + 7]); + if (!(ss_6th >> this->press_jump[i])) { + return badValue(option_value, tname, this->name); + } + istringstream ss_7th(option_value[mod_num*i + 8]); + if (!(ss_7th >> this->temp_jump[i])) { + return badValue(option_value, tname, this->name); + } + istringstream ss_8th(option_value[mod_num*i + 9]); + if (!(ss_8th >> this->omega[i])) { + return badValue(option_value, tname, this->name); + } + istringstream ss_9th(option_value[mod_num*i + 10]); + if (!(ss_9th >> this->distribution[i])) { + return badValue(option_value, tname, this->name); + } + } + return ""; + } + void SetDefault() { + this->inlet_size = 0; + this->outlet_size = 0; + this->marker_inlet = NULL; + this->marker_outlet = NULL; + this->origin = NULL; + this->root_radius = NULL; + this->tip_radius = NULL; + this->press_jump = NULL; + this->temp_jump = NULL; + this->omega = NULL; + this->distribution = NULL; + } +}; + diff --git a/Common/include/primal_grid_structure.hpp b/Common/include/primal_grid_structure.hpp index fd292944bb0..6dfdfaec1d2 100644 --- a/Common/include/primal_grid_structure.hpp +++ b/Common/include/primal_grid_structure.hpp @@ -1,1217 +1,1217 @@ -/*! - * \file primal_grid_structure.hpp - * \brief Headers of the main subroutines for storing the primal grid structure. - * The subroutines and functions are in the primal_grid_structure.cpp file. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -#include "./mpi_structure.hpp" - -#include -#include -#include - -#include "dual_grid_structure.hpp" -#include "config_structure.hpp" - -using namespace std; - -/*! - * \class CPrimalGrid - * \brief Class to define the numerical primal grid. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CPrimalGrid { -protected: - unsigned long *Nodes; /*!< \brief Vector to store the global nodes of an element. */ - long *Neighbor_Elements; /*!< \brief Vector to store the elements surronding an element. */ - su2double *Coord_CG; /*!< \brief Coordinates of the center-of-gravity of the element. */ - su2double **Coord_FaceElems_CG; /*!< \brief Coordinates of the center-of-gravity of the face of the - elements. */ - static unsigned short nDim; /*!< \brief Dimension of the element (2D or 3D) useful for triangles, - quadrilateral and edges. */ - unsigned long DomainElement; /*!< \brief Only for boundaries, in this variable the 3D elements which - correspond with a boundary element is stored. */ - bool Divide; /*!< \brief Marker used to know if we are going to divide this element - in the adaptation proccess. */ - -public: - - /*! - * \brief Constructor of the class. - */ - CPrimalGrid(void); - - /*! - * \overload - * \param[in] val_nNodes - Number of nodes of the element. - * \param[in] val_nFaces - Number of faces of the element. - * \param[in] val_VTK_Type - Type of the element using the vtk nomenclature. - */ - CPrimalGrid(unsigned short val_nNodes, unsigned short val_nFaces, unsigned short val_VTK_Type); - - /*! - * \brief Destructor of the class. - */ - virtual ~CPrimalGrid(void); - - /*! - * \brief Get the elements that surround an element. - * \param[in] val_face - Local index of the face. - * \return Global index of the element. - */ - long GetNeighbor_Elements(unsigned short val_face); - - /*! - * \brief Set the elements that surround an element. - * \param[in] val_elem - Global index of the element. - * \param[in] val_face - Local index of the face. - */ - void SetNeighbor_Elements(unsigned long val_elem, unsigned short val_face); - - /*! - * \brief Set the center of gravity of an element (including edges). - * \param[in] val_coord - Coordinates of the element. - */ - void SetCoord_CG(su2double **val_coord); - - /*! - * \brief Get the center of gravity of an element (including edges). - * \param[in] val_dim - Coordinate of the center of gravity. - * \return Coordinates of the center of gravity. - */ - su2double GetCG(unsigned short val_dim); - - /*! - * \brief Get the CG of a face of an element. - * \param[in] val_face - Local index of the face. - * \param[in] val_dim - Coordinate of the center of gravity. - * \return Coordinates of the center of gravity. - */ - su2double GetFaceCG(unsigned short val_face, unsigned short val_dim); - - /*! - * \brief Get all the neighbors of an element. - * \return List of all the neighbor of an element. - */ - void GetAllNeighbor_Elements(void); - - /*! - * \brief Set that an element must be divided in the adaptation stage. - * \param[in] val_divide - TRUE if the element must be divided; otherwise FALSE. - */ - void SetDivide(bool val_divide); - - /*! - * \brief Get if an element must be divided in the adaptation stage. - * \return TRUE if the element must be divided; otherwise FALSE. - */ - bool GetDivide(void); - - /*! - * \brief A virtual member. - * \param[in] val_domainelement Index of the domain element which has a face shared by this boundary element. - */ - virtual void SetDomainElement(unsigned long val_domainelement); - - /*! - * \brief A virtual member. - * \return Relate the boundary element which a face of a domain element. - */ - virtual unsigned long GetDomainElement(void); - - /*! - * \brief A pure virtual member. - */ - virtual void Change_Orientation(void) = 0; - - /*! - * \brief A pure virtual member. - * \return Kind of element using the vtk nomenclature. - */ - virtual unsigned short GetVTK_Type(void) = 0; - - /*! - * \brief A pure virtual member. - * \return Type of the element using VTK nomenclature. - */ - virtual unsigned short GetRotation_Type(void); - - /*! - * \brief A pure virtual member. - * \param[in] val_rotation_type - Kind of rotation/traslation that must be applied. - */ - virtual void SetRotation_Type(unsigned short val_rotation_type); - - /*! - * \brief A pure virtual member. - * \param[in] val_node - Local index of the node. - * \return Number of neighbors nodes of a node in the element. - */ - virtual unsigned short GetnNeighbor_Nodes(unsigned short val_node) = 0; - - /*! - * \brief A pure virtual member. - * \return Number of neighbors elements of a element. - */ - virtual unsigned short GetnNeighbor_Elements(void) = 0; - - /*! - * \brief A pure virtual member. - * \return Number of nodes of an element. - */ - virtual unsigned short GetnNodes(void) = 0; - - /*! - * \brief A pure virtual member. - * \return Number of faces of an element. - */ - virtual unsigned short GetnFaces(void) = 0; - - /*! - * \brief A pure virtual member. - * \param[in] val_face - Local index of a face. - * \return Local index of the nodes that compose a face. - */ - virtual unsigned short GetnNodesFace(unsigned short val_face) = 0; - - /*! - * \brief A pure virtual member. - * \return Maximum number of nodes that compose a face. - */ - virtual unsigned short GetMaxNodesFace(void) = 0; - - /*! - * \brief A pure virtual member. - * \param[in] val_node - Local index of a node. - * \return Global index of the node. - */ - virtual unsigned long GetNode(unsigned short val_node) = 0; - - - /*! - * \brief A pure virtual member. - * \param[in] val_node - Local index of a node. - * \param[in] val_point - Point associated to the node. - */ - virtual void SetNode(unsigned short val_node, unsigned long val_point); - - /*! - * \brief A pure virtual member. - * \param[in] val_face - Local index of the face. - * \param[in] val_index - Local index of the nodes that compose the face. - * \return - Local index of the nodes that compose the face. - */ - virtual unsigned short GetFaces(unsigned short val_face, unsigned short val_index) = 0; - - /*! - * \brief A pure virtual member. - * \param[in] val_node - Local index of a node. - * \param[in] val_index - Local (to the neighbor nodes of val_node) index of the nodes that - are neighbor to val_node. - * \return Local index of the nodes that are neighbor to val_node. - */ - virtual unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) = 0; -}; - -/*! - * \class CVertexMPI - * \brief Class for vertex element definition. This kind - * of element is used in the parallelization stuff. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CVertexMPI : public CPrimalGrid { -private: - static unsigned short nFaces; /*!< \brief Number of faces of the element. */ - static unsigned short nNodes; /*!< \brief Number of nodes of the element. */ - static unsigned short VTK_Type; /*!< \brief Type of element using VTK nomenclature. */ - unsigned short Rotation_Type; /*!< \brief Definition of the rotation, traslation of the - solution at the vertex. */ - static unsigned short maxNodesFace; /*!< \brief Maximum number of nodes for a face. */ - static unsigned short nNeighbor_Elements; /*!< \brief Number of Neighbor_Elements. */ - -public: - - /*! - * \brief Constructor using the nodes and index. - * \param[in] val_point - Index of the 1st triangle point read from the grid file. - * \param[in] val_nDim - Number of dimension of the problem (2D or 3D). - */ - CVertexMPI(unsigned long val_point, unsigned short val_nDim); - - /*! - * \brief Destructor of the class. - */ - ~CVertexMPI(void); - - /*! - * \brief Get the nodes shared by the line. - * \param[in] val_node - Local (to the line) index of the node (a line has 2 nodes). - * \return Global index of the line node. - */ - unsigned long GetNode(unsigned short val_node); - - /*! - * \brief Set the point associated at a node. - * \param[in] val_node - Local index of a node. - * \param[in] val_point - Point associated to the node. - */ - void SetNode(unsigned short val_node, unsigned long val_point); - - /*! - * \brief Get the number of nodes of an element. - * \return Number of nodes that composes an element. - */ - unsigned short GetnNodes(void); - - /*! - * \brief Get the type of the element using VTK nomenclature. - * \return Type of the element using VTK nomenclature. - */ - unsigned short GetVTK_Type(void); - - /*! - * \brief Get the type of rotation/traslation that must be applied. - * \return Type of the element using VTK nomenclature. - */ - unsigned short GetRotation_Type(void); - - /*! - * \brief Set the type of rotation/traslation that must be applied. - * \param[in] val_rotation_type - Kind of rotation/traslation that must be applied. - */ - void SetRotation_Type(unsigned short val_rotation_type); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - void Change_Orientation(void); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - unsigned short GetnNeighbor_Elements(void); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - unsigned short GetnNeighbor_Nodes(unsigned short val_node); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - unsigned short GetnFaces(void); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - unsigned short GetnNodesFace(unsigned short val_face); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - unsigned short GetMaxNodesFace(void); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - unsigned short GetFaces(unsigned short val_face, unsigned short val_index); - - /*! - * \brief This function does nothing (it comes from a pure virtual function, that implies the - * definition of the function in all the derived classes). - */ - unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index); -}; - -/*! - * \class CLine - * \brief Class for line element definition. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CLine : public CPrimalGrid { -private: - static unsigned short Faces[1][2]; /*!< \brief Matrix to store the local nodes of all the faces. */ - static unsigned short Neighbor_Nodes[2][1]; /*!< \brief Neighbor to a nodes in the element. */ - static unsigned short nNodesFace[1]; /*!< \brief Number of nodes of each face of the element. */ - static unsigned short nNeighbor_Nodes[2]; /*!< \brief Number of Neighbor to a nodes in the element. */ - static unsigned short nFaces; /*!< \brief Number of faces of the element. */ - static unsigned short nNodes; /*!< \brief Number of nodes of the element. */ - static unsigned short VTK_Type; /*!< \brief Type of element using VTK nomenclature. */ - static unsigned short maxNodesFace; /*!< \brief Maximum number of nodes for a face. */ - static unsigned short nNeighbor_Elements; /*!< \brief Number of Neighbor_Elements. */ - -public: - - /*! - * \brief Constructor using the nodes and index. - * \param[in] val_point_0 - Index of the 1st triangle point read from the grid file. - * \param[in] val_point_1 - Index of the 2nd triangle point read from the grid file. - * \param[in] val_nDim - Number of dimension of the problem (2D or 3D). - */ - CLine(unsigned long val_point_0, unsigned long val_point_1, unsigned short val_nDim); - - /*! - * \brief Destructor of the class. - */ - ~CLine(void); - - /*! - * \brief Get the nodes shared by the line. - * \param[in] val_node - Local (to the line) index of the node (a line has 2 nodes). - * \return Global index of the line node. - */ - unsigned long GetNode(unsigned short val_node); - - /*! - * \brief Set the point associated at a node. - * \param[in] val_node - Local index of a node. - * \param[in] val_point - Point associated to the node. - */ - void SetNode(unsigned short val_node, unsigned long val_point); - - /*! - * \brief Get the face index of and element. - * \param[in] val_face - Local index of the face. - * \param[in] val_index - Local (to the face) index of the nodes that compose the face. - * \return Local (to the line) index of the nodes that compose the face. - */ - unsigned short GetFaces(unsigned short val_face, unsigned short val_index); - - /*! - * \brief Get the local index of the neighbors to a node (given the local index). - * \param[in] val_node - Local (to the line) index of a node. - * \param[in] val_index - Local (to the neighbor nodes of val_node) index of the nodes - that are neighbor to val_node (each face is composed by 3 nodes). - * \return Local (to the line) index of the nodes that are neighbor to val_node. - */ - unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index); - - /*! - * \brief Get the number of neighbors nodes of a node. - * \param[in] val_node - Local (to the line) index of a node. - * \return Number if neighbors of a node val_node. - */ - unsigned short GetnNeighbor_Nodes(unsigned short val_node); - - /*! - * \brief Get the number of nodes that composes a face of an element. - * \param[in] val_face - Local index of the face. - * \return Number of nodes that composes a face of an element. - */ - unsigned short GetnNodesFace(unsigned short val_face); - - /*! - * \brief Get the number of nodes of an element. - * \return Number of nodes that composes an element. - */ - unsigned short GetnNodes(void); - - /*! - * \brief Get the number of faces of an element. - * \return Number of faces of an element. - */ - unsigned short GetnFaces(void); - - /*! - * \brief Get the Maximum number of nodes of a face of an element. - * \return Maximum number of nodes of a face of an element. - */ - unsigned short GetMaxNodesFace(void); - - /*! - * \brief Get the type of the element using VTK nomenclature. - * \return Type of the element using VTK nomenclature. - */ - unsigned short GetVTK_Type(void); - - /*! - * \brief Get the number of element that are neighbor to this element. - * \return Number of neighbor elements. - */ - unsigned short GetnNeighbor_Elements(void); - - /*! - * \brief Set the domain element which shares a face with the boundary element. - * \param[in] val_domainelement - Global index of the element. - */ - void SetDomainElement(unsigned long val_domainelement); - - /*! - * \brief Get the domain element which shares a face with the boundary element. - * \return Domain element which shares a face with the boundary element. - */ - unsigned long GetDomainElement(void); - - /*! - * \brief Change the orientation of an element. - */ - void Change_Orientation(void); -}; - -/*! - * \class CTriangle - * \brief Class for triangle element definition. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CTriangle : public CPrimalGrid { -private: - static unsigned short Faces[3][2]; /*!< \brief Matrix to store the local nodes of all the faces. */ - static unsigned short Neighbor_Nodes[3][2]; /*!< \brief Neighbor to a nodes in the element. */ - static unsigned short nNodesFace[3]; /*!< \brief Number of nodes of each face of the element. */ - static unsigned short nNeighbor_Nodes[3]; /*!< \brief Number of Neighbor to a nodes in the element. */ - static unsigned short nFaces; /*!< \brief Number of faces of the element. */ - static unsigned short nNodes; /*!< \brief Number of nodes of the element. */ - static unsigned short VTK_Type; /*!< \brief Type of element using VTK nomenclature. */ - static unsigned short maxNodesFace; /*!< \brief Maximum number of nodes for a face. */ - static unsigned short nNeighbor_Elements; /*!< \brief Number of Neighbor_Elements. */ - -public: - - /*! - * \brief Constructor using the nodes and index. - * \param[in] val_point_0 - Index of the 1st triangle point read from the grid file. - * \param[in] val_point_1 - Index of the 2nd triangle point read from the grid file. - * \param[in] val_point_2 - Index of the 3th triangle point read from the grid file. - * \param[in] val_nDim - Number of dimension of the problem (2D or 3D), be careful a triangle could be 2D or 3D. - */ - CTriangle(unsigned long val_point_0, unsigned long val_point_1, - unsigned long val_point_2, unsigned short val_nDim); - - /*! - * \brief Destructor of the class. - */ - ~CTriangle(void); - - /*! - * \brief Get the nodes shared by the triangle. - * \param[in] val_node - Local (to the triangle) index of the node (a triangle has 3 nodes). - * \return Global index of the triangle node. - */ - unsigned long GetNode(unsigned short val_node); - - /*! - * \brief Set the point associated at a node. - * \param[in] val_node - Local index of a node. - * \param[in] val_point - Point associated to the node. - */ - void SetNode(unsigned short val_node, unsigned long val_point); - - /*! - * \brief Get the face index of and element. - * \param[in] val_face - Local index of the face. - * \param[in] val_index - Local (to the face) index of the nodes that compose the face. - * \return Local (to the triangle) index of the nodes that compose the face. - */ - unsigned short GetFaces(unsigned short val_face, unsigned short val_index); - - /*! - * \brief Get the local index of the neighbors to a node (given the local index). - * \param[in] val_node - Local (to the triangle) index of a node. - * \param[in] val_index - Local (to the neighbor nodes of val_node) index of the nodes that - are neighbor to val_node (each face is composed by 3 nodes). - * \return Local (to the triangle) index of the nodes that are neighbor to val_node. - */ - unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index); - - /*! - * \brief Get the number of neighbors nodes of a node. - * \param[in] val_node - Local (to the triangle) index of a node. - * \return Number if neighbors of a node val_node. - */ - unsigned short GetnNeighbor_Nodes(unsigned short val_node); - - /*! - * \brief Get the number of nodes that composes a face of an element. - * \param[in] val_face - Local index of the face. - * \return Number of nodes that composes a face of an element. - */ - unsigned short GetnNodesFace(unsigned short val_face); - - /*! - * \brief Get the number of nodes of an element. - * \return Number of nodes that composes an element. - */ - unsigned short GetnNodes(void); - - /*! - * \brief Get the number of faces of an element. - * \return Number of faces of an element. - */ - unsigned short GetnFaces(void); - - /*! - * \brief Get the Maximum number of nodes of a face of an element. - * \return Maximum number of nodes of a face of an element. - */ - unsigned short GetMaxNodesFace(void); - - /*! - * \brief Get the type of the element using VTK nomenclature. - * \return Type of the element using VTK nomenclature. - */ - unsigned short GetVTK_Type(void); - - /*! - * \brief Get the number of element that are neighbor to this element. - * \return Number of neighbor elements. - */ - unsigned short GetnNeighbor_Elements(void); - - /*! - * \brief Change the orientation of an element. - */ - void Change_Orientation(void); - - /*! - * \brief Set the domain element which shares a face with the boundary element. - * \param[in] val_domainelement - Global index of the element. - */ - void SetDomainElement(unsigned long val_domainelement); - - /*! - * \brief Get the domain element which shares a face with the boundary element. - * \return Domain element which shares a face with the boundary element. - */ - unsigned long GetDomainElement(void); -}; - -/*! - * \class CQuadrilateral - * \brief Class for quadrilateral element definition. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CQuadrilateral : public CPrimalGrid { -private: - static unsigned short Faces[4][2]; /*!< \brief Matrix to store the local nodes of all the faces. */ - static unsigned short Neighbor_Nodes[4][2]; /*!< \brief Neighbor to a nodes in the element. */ - static unsigned short nNodesFace[4]; /*!< \brief Number of nodes of each face of the element. */ - static unsigned short nNeighbor_Nodes[4]; /*!< \brief Number of Neighbor to a nodes in the element. */ - static unsigned short nFaces; /*!< \brief Number of faces of the element. */ - static unsigned short nNodes; /*!< \brief Number of nodes of the element. */ - static unsigned short VTK_Type; /*!< \brief Type of element using VTK nomenclature. */ - static unsigned short maxNodesFace; /*!< \brief Maximum number of nodes for a face. */ - static unsigned short nNeighbor_Elements; /*!< \brief Number of neighbor elements. */ - -public: - - /*! - * \brief Constructor using the nodes and index. - * \param[in] val_point_0 - Index of the 1st point read from the grid file. - * \param[in] val_point_1 - Index of the 2nd point read from the grid file. - * \param[in] val_point_2 - Index of the 3th point read from the grid file. - * \param[in] val_point_3 - Index of the 4th point read from the grid file. - * \param[in] val_nDim - Number of dimension of the problem (2D or 3D). - */ - CQuadrilateral(unsigned long val_point_0, unsigned long val_point_1, - unsigned long val_point_2, unsigned long val_point_3, unsigned short val_nDim); - - /*! - * \brief Destructor of the class. - */ - ~CQuadrilateral(void); - - /*! - * \brief Get the nodes shared by the triangle. - * \param[in] val_node - Local (to the quadrilateral) index of the node (a quadrilateral has 4 nodes). - * \return Global index of the triangle node. - */ - unsigned long GetNode(unsigned short val_node); - - /*! - * \brief Set the point associated at a node. - * \param[in] val_node - Local index of a node. - * \param[in] val_point - Point associated to the node. - */ - void SetNode(unsigned short val_node, unsigned long val_point); - - /*! - * \brief Get the face index of and element. - * \param[in] val_face - Local index of the face. - * \param[in] val_index - Local (to the face) index of the nodes that compose the face. - * \return Local (to the quadrilateral) index of the nodes that compose the face. - */ - unsigned short GetFaces(unsigned short val_face, unsigned short val_index); - - /*! - * \brief Get the local index of the neighbors to a node (given the local index). - * \param[in] val_node - Local (to the element) index of a node. - * \param[in] val_index - Local (to the neighbor nodes of val_node) index of the nodes that are neighbor to val_node. - * \return Local (to the quadrilateral) index of the nodes that are neighbor to val_node. - */ - unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index); - - /*! - * \brief Get the number of neighbors nodes of a node. - * \param[in] val_node - Local (to the element) index of a node. - * \return Number if neighbors of a node val_node. - */ - unsigned short GetnNeighbor_Nodes(unsigned short val_node); - - /*! - * \brief Get the number of nodes that composes a face of an element. - * \param[in] val_face - Local index of the face. - * \return Number of nodes that composes a face of an element. - */ - unsigned short GetnNodesFace(unsigned short val_face); - - /*! - * \brief Get the number of nodes of an element. - * \return Number of nodes that composes an element. - */ - unsigned short GetnNodes(void); - - /*! - * \brief Get the number of faces of an element. - * \return Number of faces of an element. - */ - unsigned short GetnFaces(void); - - /*! - * \brief Get the Maximum number of nodes of a face of an element. - * \return Maximum number of nodes of a face of an element. - */ - unsigned short GetMaxNodesFace(void); - - /*! - * \brief Get the type of the element using VTK nomenclature. - * \return Type of the element using VTK nomenclature. - */ - unsigned short GetVTK_Type(void); - - /*! - * \brief Get the number of element that are neighbor to this element. - * \return Number of neighbor elements. - */ - unsigned short GetnNeighbor_Elements(void); - - /*! - * \brief Change the orientation of an element. - */ - void Change_Orientation(void); - - /*! - * \brief Set the domain element which shares a face with the boundary element. - * \param[in] val_domainelement - Global index of the element. - */ - void SetDomainElement(unsigned long val_domainelement); - - /*! - * \brief Get the domain element which shares a face with the boundary element. - * \return Domain element which shares a face with the boundary element. - */ - unsigned long GetDomainElement(void); -}; - -/*! - * \class CTetrahedron - * \brief Class for tetrahedron element definition. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CTetrahedron : public CPrimalGrid { -private: - static unsigned short Faces[4][3]; /*!< \brief Matrix to store the local nodes of all the faces. */ - static unsigned short Neighbor_Nodes[4][3]; /*!< \brief Neighbor to a nodes in the element. */ - static unsigned short nNodesFace[4]; /*!< \brief Number of nodes of each face of the element. */ - static unsigned short nNeighbor_Nodes[4]; /*!< \brief Number of Neighbor to a nodes in the element. */ - static unsigned short nFaces; /*!< \brief Number of faces of the element. */ - static unsigned short nNodes; /*!< \brief Number of nodes of the element. */ - static unsigned short VTK_Type; /*!< \brief Type of element using VTK nomenclature. */ - static unsigned short maxNodesFace; /*!< \brief Maximum number of nodes for a face. */ - static unsigned short nNeighbor_Elements; /*!< \brief Number of neighbor elements. */ - -public: - - /*! - * \brief Constructor using the nodes and index. - * \param[in] val_point_0 - Index of the 1st point read from the grid file. - * \param[in] val_point_1 - Index of the 2nd point read from the grid file. - * \param[in] val_point_2 - Index of the 3th point read from the grid file. - * \param[in] val_point_3 - Index of the 4th point read from the grid file. - */ - CTetrahedron(unsigned long val_point_0, unsigned long val_point_1, - unsigned long val_point_2, unsigned long val_point_3); - - /*! - * \brief Destructor of the class. - */ - ~CTetrahedron(void); - - /*! - * \brief Get the nodes shared by the tetrahedron. - * \param[in] val_node - Local (to the tetrahedron) index of the node (a tetrahedron has 4 nodes). - * \return Global index of the tetrahedron node. - */ - unsigned long GetNode(unsigned short val_node); - - /*! - * \brief Set the point associated at a node. - * \param[in] val_node - Local index of a node. - * \param[in] val_point - Point associated to the node. - */ - void SetNode(unsigned short val_node, unsigned long val_point); - - /*! - * \brief Get the face index of and element. - * \param[in] val_face - Local index of the face. - * \param[in] val_index - Local (to the face) index of the nodes that compose the face. - * \return Local (to the element) index of the nodes that compose the face. - */ - unsigned short GetFaces(unsigned short val_face, unsigned short val_index); - - /*! - * \brief Get the local index of the neighbors to a node (given the local index). - * \param[in] val_node - Local (to the element) index of a node. - * \param[in] val_index - Local (to the neighbor nodes of val_node) index of the nodes that are neighbor to val_node. - * \return Local (to the element) index of the nodes that are neighbor to val_node. - */ - unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index); - - /*! - * \brief Get the number of neighbors nodes of a node. - * \param[in] val_node - Local (to the element) index of a node. - * \return Number if neighbors of a node val_node. - */ - unsigned short GetnNeighbor_Nodes(unsigned short val_node); - - /*! - * \brief Get the number of nodes that composes a face of an element. - * \param[in] val_face - Local index of the face. - * \return Number of nodes that composes a face of an element. - */ - unsigned short GetnNodesFace(unsigned short val_face); - - /*! - * \brief Get the number of nodes of an element. - * \return Number of nodes that composes an element. - */ - unsigned short GetnNodes(void); - - /*! - * \brief Get the number of faces of an element. - * \return Number of faces of an element. - */ - unsigned short GetnFaces(void); - - /*! - * \brief Get the Maximum number of nodes of a face of an element. - * \return Maximum number of nodes of a face of an element. - */ - unsigned short GetMaxNodesFace(void); - - /*! - * \brief Get the type of the element using VTK nomenclature. - * \return Type of the element using VTK nomenclature. - */ - unsigned short GetVTK_Type(void); - - /*! - * \brief Get the number of element that are neighbor to this element. - * \return Number of neighbor elements. - */ - unsigned short GetnNeighbor_Elements(void); - - /*! - * \brief Change the orientation of an element. - */ - void Change_Orientation(void); -}; - -/*! - * \class CHexahedron - * \brief Class for hexahedron element definition. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CHexahedron : public CPrimalGrid { -private: - static unsigned short Faces[6][4]; /*!< \brief Matrix to store the local nodes of all the faces. */ - static unsigned short Neighbor_Nodes[8][3]; /*!< \brief Neighbor to a nodes in the element. */ - static unsigned short nNodesFace[6]; /*!< \brief Number of nodes of each face of the element. */ - static unsigned short nNeighbor_Nodes[8]; /*!< \brief Number of Neighbor to a nodes in the element. */ - static unsigned short nFaces; /*!< \brief Number of faces of the element. */ - static unsigned short nNodes; /*!< \brief Number of nodes of the element. */ - static unsigned short VTK_Type; /*!< \brief Type of element using VTK nomenclature. */ - static unsigned short maxNodesFace; /*!< \brief Maximum number of nodes for a face. */ - static unsigned short nNeighbor_Elements; /*!< \brief Number of neighbor elements. */ - -public: - - /*! - * \brief Constructor using the nodes and index. - * \param[in] val_point_0 - Index of the 1st point read from the grid file. - * \param[in] val_point_1 - Index of the 2nd point read from the grid file. - * \param[in] val_point_2 - Index of the 3th point read from the grid file. - * \param[in] val_point_3 - Index of the 4th point read from the grid file. - * \param[in] val_point_4 - Index of the 5td point read from the grid file. - * \param[in] val_point_5 - Index of the 6th point read from the grid file. - * \param[in] val_point_6 - Index of the 7th point read from the grid file. - * \param[in] val_point_7 - Index of the 8th point read from the grid file. - */ - CHexahedron(unsigned long val_point_0, unsigned long val_point_1, - unsigned long val_point_2, unsigned long val_point_3, - unsigned long val_point_4, unsigned long val_point_5, - unsigned long val_point_6, unsigned long val_point_7); - - /*! - * \brief Destructor of the class. - */ - ~CHexahedron(void); - - /*! - * \brief Get the nodes shared by the triangle. - * \param[in] val_node - Local (to the triangle) index of the node (a triangle has 3 nodes). - * \return Global index of the triangle node. - */ - unsigned long GetNode(unsigned short val_node); - - /*! - * \brief Set the point associated at a node. - * \param[in] val_node - Local index of a node. - * \param[in] val_point - Point associated to the node. - */ - void SetNode(unsigned short val_node, unsigned long val_point); - - /*! - * \brief Get the face index of and element. - * \param[in] val_face - Local index of the face. - * \param[in] val_index - Local (to the face) index of the nodes that compose the face. - * \return Local (to the element) index of the nodes that compose the face. - */ - unsigned short GetFaces(unsigned short val_face, unsigned short val_index); - - /*! - * \brief Get the local index of the neighbors to a node (given the local index). - * \param[in] val_node - Local (to the element) index of a node. - * \param[in] val_index - Local (to the neighbor nodes of val_node) index of the nodes - * that are neighbor to val_node. - * \return Local (to the element) index of the nodes that are neighbor to val_node. - */ - unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index); - - /*! - * \brief Get the number of neighbors nodes of a node. - * \param[in] val_node - Local (to the element) index of a node. - * \return Number if neighbors of a node val_node. - */ - unsigned short GetnNeighbor_Nodes(unsigned short val_node); - - /*! - * \brief Get the number of nodes that composes a face of an element. - * \param[in] val_face - Local index of the face. - * \return Number of nodes that composes a face of an element. - */ - unsigned short GetnNodesFace(unsigned short val_face); - - /*! - * \brief Get the number of nodes of an element. - * \return Number of nodes that composes an element. - */ - unsigned short GetnNodes(void); - - /*! - * \brief Get the number of faces of an element. - * \return Number of faces of an element. - */ - unsigned short GetnFaces(void); - - /*! - * \brief Get the Maximum number of nodes of a face of an element. - * \return Maximum number of nodes of a face of an element. - */ - unsigned short GetMaxNodesFace(void); - - /*! - * \brief Get the type of the element using VTK nomenclature. - * \return Type of the element using VTK nomenclature. - */ - unsigned short GetVTK_Type(void); - - /*! - * \brief Get the number of element that are neighbor to this element. - * \return Number of neighbor elements. - */ - unsigned short GetnNeighbor_Elements(void); - - /*! - * \brief Change the orientation of an element. - */ - void Change_Orientation(void); -}; - -/*! - * \class CPrism - * \brief Class for prism element definition. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CPrism : public CPrimalGrid { -private: - static unsigned short Faces[5][4]; /*!< \brief Matrix to store the local nodes of all the faces. */ - static unsigned short Neighbor_Nodes[6][3]; /*!< \brief Neighbor to a nodes in the element. */ - static unsigned short nNodesFace[5]; /*!< \brief Number of nodes of each face of the element. */ - static unsigned short nNeighbor_Nodes[6]; /*!< \brief Number of Neighbor to a nodes in the element. */ - static unsigned short nFaces; /*!< \brief Number of faces of the element. */ - static unsigned short nNodes; /*!< \brief Number of nodes of the element. */ - static unsigned short VTK_Type; /*!< \brief Type of element using VTK nomenclature. */ - static unsigned short maxNodesFace; /*!< \brief Maximum number of nodes for a face. */ - static unsigned short nNeighbor_Elements; /*!< \brief Number of neighbor elements. */ - -public: - - /*! - * \brief Constructor using the nodes and index. - * \param[in] val_point_0 - Index of the 1st point read from the grid file. - * \param[in] val_point_1 - Index of the 2nd point read from the grid file. - * \param[in] val_point_2 - Index of the 3th point read from the grid file. - * \param[in] val_point_3 - Index of the 4th point read from the grid file. - * \param[in] val_point_4 - Index of the 5th point read from the grid file. - * \param[in] val_point_5 - Index of the 6th point read from the grid file. - */ - CPrism(unsigned long val_point_0, unsigned long val_point_1, - unsigned long val_point_2, unsigned long val_point_3, - unsigned long val_point_4, unsigned long val_point_5); - - /*! - * \brief Destructor of the class. - */ - ~CPrism(void); - - /*! - * \brief Get the nodes shared by the triangle. - * \param[in] val_node - Local (to the triangle) index of the node (a prism has 6 nodes). - * \return Global index of the prism node. - */ - unsigned long GetNode(unsigned short val_node); - - /*! - * \brief Set the point associated at a node. - * \param[in] val_node - Local index of a node. - * \param[in] val_point - Point associated to the node. - */ - void SetNode(unsigned short val_node, unsigned long val_point); - - /*! - * \brief Get the face index of and element. - * \param[in] val_face - Local index of the face. - * \param[in] val_index - Local (to the face) index of the nodes that compose the face. - * \return Local (to the element) index of the nodes that compose the face. - */ - unsigned short GetFaces(unsigned short val_face, unsigned short val_index); - - /*! - * \brief Get the local index of the neighbors to a node (given the local index). - * \param[in] val_node - Local (to the element) index of a node. - * \param[in] val_index - Local (to the neighbor nodes of val_node) index of the nodes that are neighbor to val_node. - * \return Local (to the element) index of the nodes that are neighbor to val_node. - */ - unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index); - - /*! - * \brief Get the number of neighbors nodes of a node. - * \param[in] val_node - Local (to the element) index of a node. - * \return Number if neighbors of a node val_node. - */ - unsigned short GetnNeighbor_Nodes(unsigned short val_node); - - /*! - * \brief Get the number of nodes that composes a face of an element. - * \param[in] val_face - Local index of the face. - * \return Number of nodes that composes a face of an element. - */ - unsigned short GetnNodesFace(unsigned short val_face); - - /*! - * \brief Get the number of nodes of an element. - * \return Number of nodes that composes an element. - */ - unsigned short GetnNodes(void); - - /*! - * \brief Get the number of faces of an element. - * \return Number of faces of an element. - */ - unsigned short GetnFaces(void); - - /*! - * \brief Get the Maximum number of nodes of a face of an element. - * \return Maximum number of nodes of a face of an element. - */ - unsigned short GetMaxNodesFace(void); - - /*! - * \brief Get the type of the element using VTK nomenclature. - * \return Type of the element using VTK nomenclature. - */ - unsigned short GetVTK_Type(void); - - /*! - * \brief Get the number of element that are neighbor to this element. - * \return Number of neighbor elements. - */ - unsigned short GetnNeighbor_Elements(void); - - /*! - * \brief Change the orientation of an element. - */ - void Change_Orientation(void); -}; - -/*! - * \class CPyramid - * \brief Class for pyramid element definition. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CPyramid : public CPrimalGrid { -private: - static unsigned short Faces[5][4]; /*!< \brief Matrix to store the local nodes of all the faces. */ - static unsigned short Neighbor_Nodes[5][4]; /*!< \brief Neighbor to a nodes in the element. */ - static unsigned short nNodesFace[5]; /*!< \brief Number of nodes of each face of the element. */ - static unsigned short nNeighbor_Nodes[5]; /*!< \brief Number of Neighbor to a nodes in the element. */ - static unsigned short nFaces; /*!< \brief Number of faces of the element. */ - static unsigned short nNodes; /*!< \brief Number of nodes of the element. */ - static unsigned short VTK_Type; /*!< \brief Type of element using VTK nomenclature. */ - static unsigned short maxNodesFace; /*!< \brief Maximum number of nodes for a face. */ - static unsigned short nNeighbor_Elements; /*!< \brief Number of neighbor elements. */ - -public: - - /*! - * \brief Constructor using the nodes and index. - * \param[in] val_point_0 - Index of the 1st point read from the grid file. - * \param[in] val_point_1 - Index of the 2nd point read from the grid file. - * \param[in] val_point_2 - Index of the 3th point read from the grid file. - * \param[in] val_point_3 - Index of the 4th point read from the grid file. - * \param[in] val_point_4 - Index of the 5th point read from the grid file. - */ - CPyramid(unsigned long val_point_0, unsigned long val_point_1, - unsigned long val_point_2, unsigned long val_point_3, - unsigned long val_point_4); - - /*! - * \brief Destructor of the class. - */ - ~CPyramid(void); - - /*! - * \brief Get the nodes shared by the pyramid. - * \param[in] val_node - Local (to the pyramid) index of the node (a pyramid has 3 nodes). - * \return Global index of the pyramid node. - */ - unsigned long GetNode(unsigned short val_node); - - /*! - * \brief Set the point associated at a node. - * \param[in] val_node - Local index of a node. - * \param[in] val_point - Point associated to the node. - */ - void SetNode(unsigned short val_node, unsigned long val_point); - - /*! - * \brief Get the face index of and element. - * \param[in] val_face - Local index of the face. - * \param[in] val_index - Local (to the face) index of the nodes that compose the face. - * \return Local (to the element) index of the nodes that compose the face. - */ - unsigned short GetFaces(unsigned short val_face, unsigned short val_index); - - /*! - * \brief Get the local index of the neighbors to a node (given the local index). - * \param[in] val_node - Local (to the element) index of a node. - * \param[in] val_index - Local (to the neighbor nodes of val_node) index of the nodes that are neighbor to val_node. - * \return Local (to the element) index of the nodes that are neighbor to val_node. - */ - unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index); - - /*! - * \brief Get the number of neighbors nodes of a node. - * \param[in] val_node - Local (to the element) index of a node. - * \return Number if neighbors of a node val_node. - */ - unsigned short GetnNeighbor_Nodes(unsigned short val_node); - - /*! - * \brief Get the number of nodes that composes a face of an element. - * \param[in] val_face - Local index of the face. - * \return Number of nodes that composes a face of an element. - */ - unsigned short GetnNodesFace(unsigned short val_face); - - /*! - * \brief Get the number of nodes of an element. - * \return Number of nodes that composes an element. - */ - unsigned short GetnNodes(void); - - /*! - * \brief Get the number of faces of an element. - * \return Number of faces of an element. - */ - unsigned short GetnFaces(void); - - /*! - * \brief Get the Maximum number of nodes of a face of an element. - * \return Maximum number of nodes of a face of an element. - */ - unsigned short GetMaxNodesFace(void); - - /*! - * \brief Get the type of the element using VTK nomenclature. - * \return Type of the element using VTK nomenclature. - */ - unsigned short GetVTK_Type(void); - - /*! - * \brief Get the number of element that are neighbor to this element. - * \return Number of neighbor elements. - */ - unsigned short GetnNeighbor_Elements(void); - - /*! - * \brief Change the orientation of an element. - */ - void Change_Orientation(void); -}; - -#include "primal_grid_structure.inl" +/*! + * \file primal_grid_structure.hpp + * \brief Headers of the main subroutines for storing the primal grid structure. + * The subroutines and functions are in the primal_grid_structure.cpp file. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +#include "./mpi_structure.hpp" + +#include +#include +#include + +#include "dual_grid_structure.hpp" +#include "config_structure.hpp" + +using namespace std; + +/*! + * \class CPrimalGrid + * \brief Class to define the numerical primal grid. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CPrimalGrid { +protected: + unsigned long *Nodes; /*!< \brief Vector to store the global nodes of an element. */ + long *Neighbor_Elements; /*!< \brief Vector to store the elements surronding an element. */ + su2double *Coord_CG; /*!< \brief Coordinates of the center-of-gravity of the element. */ + su2double **Coord_FaceElems_CG; /*!< \brief Coordinates of the center-of-gravity of the face of the + elements. */ + static unsigned short nDim; /*!< \brief Dimension of the element (2D or 3D) useful for triangles, + quadrilateral and edges. */ + unsigned long DomainElement; /*!< \brief Only for boundaries, in this variable the 3D elements which + correspond with a boundary element is stored. */ + bool Divide; /*!< \brief Marker used to know if we are going to divide this element + in the adaptation proccess. */ + +public: + + /*! + * \brief Constructor of the class. + */ + CPrimalGrid(void); + + /*! + * \overload + * \param[in] val_nNodes - Number of nodes of the element. + * \param[in] val_nFaces - Number of faces of the element. + * \param[in] val_VTK_Type - Type of the element using the vtk nomenclature. + */ + CPrimalGrid(unsigned short val_nNodes, unsigned short val_nFaces, unsigned short val_VTK_Type); + + /*! + * \brief Destructor of the class. + */ + virtual ~CPrimalGrid(void); + + /*! + * \brief Get the elements that surround an element. + * \param[in] val_face - Local index of the face. + * \return Global index of the element. + */ + long GetNeighbor_Elements(unsigned short val_face); + + /*! + * \brief Set the elements that surround an element. + * \param[in] val_elem - Global index of the element. + * \param[in] val_face - Local index of the face. + */ + void SetNeighbor_Elements(unsigned long val_elem, unsigned short val_face); + + /*! + * \brief Set the center of gravity of an element (including edges). + * \param[in] val_coord - Coordinates of the element. + */ + void SetCoord_CG(su2double **val_coord); + + /*! + * \brief Get the center of gravity of an element (including edges). + * \param[in] val_dim - Coordinate of the center of gravity. + * \return Coordinates of the center of gravity. + */ + su2double GetCG(unsigned short val_dim); + + /*! + * \brief Get the CG of a face of an element. + * \param[in] val_face - Local index of the face. + * \param[in] val_dim - Coordinate of the center of gravity. + * \return Coordinates of the center of gravity. + */ + su2double GetFaceCG(unsigned short val_face, unsigned short val_dim); + + /*! + * \brief Get all the neighbors of an element. + * \return List of all the neighbor of an element. + */ + void GetAllNeighbor_Elements(void); + + /*! + * \brief Set that an element must be divided in the adaptation stage. + * \param[in] val_divide - TRUE if the element must be divided; otherwise FALSE. + */ + void SetDivide(bool val_divide); + + /*! + * \brief Get if an element must be divided in the adaptation stage. + * \return TRUE if the element must be divided; otherwise FALSE. + */ + bool GetDivide(void); + + /*! + * \brief A virtual member. + * \param[in] val_domainelement Index of the domain element which has a face shared by this boundary element. + */ + virtual void SetDomainElement(unsigned long val_domainelement); + + /*! + * \brief A virtual member. + * \return Relate the boundary element which a face of a domain element. + */ + virtual unsigned long GetDomainElement(void); + + /*! + * \brief A pure virtual member. + */ + virtual void Change_Orientation(void) = 0; + + /*! + * \brief A pure virtual member. + * \return Kind of element using the vtk nomenclature. + */ + virtual unsigned short GetVTK_Type(void) = 0; + + /*! + * \brief A pure virtual member. + * \return Type of the element using VTK nomenclature. + */ + virtual unsigned short GetRotation_Type(void); + + /*! + * \brief A pure virtual member. + * \param[in] val_rotation_type - Kind of rotation/traslation that must be applied. + */ + virtual void SetRotation_Type(unsigned short val_rotation_type); + + /*! + * \brief A pure virtual member. + * \param[in] val_node - Local index of the node. + * \return Number of neighbors nodes of a node in the element. + */ + virtual unsigned short GetnNeighbor_Nodes(unsigned short val_node) = 0; + + /*! + * \brief A pure virtual member. + * \return Number of neighbors elements of a element. + */ + virtual unsigned short GetnNeighbor_Elements(void) = 0; + + /*! + * \brief A pure virtual member. + * \return Number of nodes of an element. + */ + virtual unsigned short GetnNodes(void) = 0; + + /*! + * \brief A pure virtual member. + * \return Number of faces of an element. + */ + virtual unsigned short GetnFaces(void) = 0; + + /*! + * \brief A pure virtual member. + * \param[in] val_face - Local index of a face. + * \return Local index of the nodes that compose a face. + */ + virtual unsigned short GetnNodesFace(unsigned short val_face) = 0; + + /*! + * \brief A pure virtual member. + * \return Maximum number of nodes that compose a face. + */ + virtual unsigned short GetMaxNodesFace(void) = 0; + + /*! + * \brief A pure virtual member. + * \param[in] val_node - Local index of a node. + * \return Global index of the node. + */ + virtual unsigned long GetNode(unsigned short val_node) = 0; + + + /*! + * \brief A pure virtual member. + * \param[in] val_node - Local index of a node. + * \param[in] val_point - Point associated to the node. + */ + virtual void SetNode(unsigned short val_node, unsigned long val_point); + + /*! + * \brief A pure virtual member. + * \param[in] val_face - Local index of the face. + * \param[in] val_index - Local index of the nodes that compose the face. + * \return - Local index of the nodes that compose the face. + */ + virtual unsigned short GetFaces(unsigned short val_face, unsigned short val_index) = 0; + + /*! + * \brief A pure virtual member. + * \param[in] val_node - Local index of a node. + * \param[in] val_index - Local (to the neighbor nodes of val_node) index of the nodes that + are neighbor to val_node. + * \return Local index of the nodes that are neighbor to val_node. + */ + virtual unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) = 0; +}; + +/*! + * \class CVertexMPI + * \brief Class for vertex element definition. This kind + * of element is used in the parallelization stuff. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CVertexMPI : public CPrimalGrid { +private: + static unsigned short nFaces; /*!< \brief Number of faces of the element. */ + static unsigned short nNodes; /*!< \brief Number of nodes of the element. */ + static unsigned short VTK_Type; /*!< \brief Type of element using VTK nomenclature. */ + unsigned short Rotation_Type; /*!< \brief Definition of the rotation, traslation of the + solution at the vertex. */ + static unsigned short maxNodesFace; /*!< \brief Maximum number of nodes for a face. */ + static unsigned short nNeighbor_Elements; /*!< \brief Number of Neighbor_Elements. */ + +public: + + /*! + * \brief Constructor using the nodes and index. + * \param[in] val_point - Index of the 1st triangle point read from the grid file. + * \param[in] val_nDim - Number of dimension of the problem (2D or 3D). + */ + CVertexMPI(unsigned long val_point, unsigned short val_nDim); + + /*! + * \brief Destructor of the class. + */ + ~CVertexMPI(void); + + /*! + * \brief Get the nodes shared by the line. + * \param[in] val_node - Local (to the line) index of the node (a line has 2 nodes). + * \return Global index of the line node. + */ + unsigned long GetNode(unsigned short val_node); + + /*! + * \brief Set the point associated at a node. + * \param[in] val_node - Local index of a node. + * \param[in] val_point - Point associated to the node. + */ + void SetNode(unsigned short val_node, unsigned long val_point); + + /*! + * \brief Get the number of nodes of an element. + * \return Number of nodes that composes an element. + */ + unsigned short GetnNodes(void); + + /*! + * \brief Get the type of the element using VTK nomenclature. + * \return Type of the element using VTK nomenclature. + */ + unsigned short GetVTK_Type(void); + + /*! + * \brief Get the type of rotation/traslation that must be applied. + * \return Type of the element using VTK nomenclature. + */ + unsigned short GetRotation_Type(void); + + /*! + * \brief Set the type of rotation/traslation that must be applied. + * \param[in] val_rotation_type - Kind of rotation/traslation that must be applied. + */ + void SetRotation_Type(unsigned short val_rotation_type); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + void Change_Orientation(void); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + unsigned short GetnNeighbor_Elements(void); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + unsigned short GetnNeighbor_Nodes(unsigned short val_node); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + unsigned short GetnFaces(void); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + unsigned short GetnNodesFace(unsigned short val_face); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + unsigned short GetMaxNodesFace(void); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + unsigned short GetFaces(unsigned short val_face, unsigned short val_index); + + /*! + * \brief This function does nothing (it comes from a pure virtual function, that implies the + * definition of the function in all the derived classes). + */ + unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index); +}; + +/*! + * \class CLine + * \brief Class for line element definition. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CLine : public CPrimalGrid { +private: + static unsigned short Faces[1][2]; /*!< \brief Matrix to store the local nodes of all the faces. */ + static unsigned short Neighbor_Nodes[2][1]; /*!< \brief Neighbor to a nodes in the element. */ + static unsigned short nNodesFace[1]; /*!< \brief Number of nodes of each face of the element. */ + static unsigned short nNeighbor_Nodes[2]; /*!< \brief Number of Neighbor to a nodes in the element. */ + static unsigned short nFaces; /*!< \brief Number of faces of the element. */ + static unsigned short nNodes; /*!< \brief Number of nodes of the element. */ + static unsigned short VTK_Type; /*!< \brief Type of element using VTK nomenclature. */ + static unsigned short maxNodesFace; /*!< \brief Maximum number of nodes for a face. */ + static unsigned short nNeighbor_Elements; /*!< \brief Number of Neighbor_Elements. */ + +public: + + /*! + * \brief Constructor using the nodes and index. + * \param[in] val_point_0 - Index of the 1st triangle point read from the grid file. + * \param[in] val_point_1 - Index of the 2nd triangle point read from the grid file. + * \param[in] val_nDim - Number of dimension of the problem (2D or 3D). + */ + CLine(unsigned long val_point_0, unsigned long val_point_1, unsigned short val_nDim); + + /*! + * \brief Destructor of the class. + */ + ~CLine(void); + + /*! + * \brief Get the nodes shared by the line. + * \param[in] val_node - Local (to the line) index of the node (a line has 2 nodes). + * \return Global index of the line node. + */ + unsigned long GetNode(unsigned short val_node); + + /*! + * \brief Set the point associated at a node. + * \param[in] val_node - Local index of a node. + * \param[in] val_point - Point associated to the node. + */ + void SetNode(unsigned short val_node, unsigned long val_point); + + /*! + * \brief Get the face index of and element. + * \param[in] val_face - Local index of the face. + * \param[in] val_index - Local (to the face) index of the nodes that compose the face. + * \return Local (to the line) index of the nodes that compose the face. + */ + unsigned short GetFaces(unsigned short val_face, unsigned short val_index); + + /*! + * \brief Get the local index of the neighbors to a node (given the local index). + * \param[in] val_node - Local (to the line) index of a node. + * \param[in] val_index - Local (to the neighbor nodes of val_node) index of the nodes + that are neighbor to val_node (each face is composed by 3 nodes). + * \return Local (to the line) index of the nodes that are neighbor to val_node. + */ + unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index); + + /*! + * \brief Get the number of neighbors nodes of a node. + * \param[in] val_node - Local (to the line) index of a node. + * \return Number if neighbors of a node val_node. + */ + unsigned short GetnNeighbor_Nodes(unsigned short val_node); + + /*! + * \brief Get the number of nodes that composes a face of an element. + * \param[in] val_face - Local index of the face. + * \return Number of nodes that composes a face of an element. + */ + unsigned short GetnNodesFace(unsigned short val_face); + + /*! + * \brief Get the number of nodes of an element. + * \return Number of nodes that composes an element. + */ + unsigned short GetnNodes(void); + + /*! + * \brief Get the number of faces of an element. + * \return Number of faces of an element. + */ + unsigned short GetnFaces(void); + + /*! + * \brief Get the Maximum number of nodes of a face of an element. + * \return Maximum number of nodes of a face of an element. + */ + unsigned short GetMaxNodesFace(void); + + /*! + * \brief Get the type of the element using VTK nomenclature. + * \return Type of the element using VTK nomenclature. + */ + unsigned short GetVTK_Type(void); + + /*! + * \brief Get the number of element that are neighbor to this element. + * \return Number of neighbor elements. + */ + unsigned short GetnNeighbor_Elements(void); + + /*! + * \brief Set the domain element which shares a face with the boundary element. + * \param[in] val_domainelement - Global index of the element. + */ + void SetDomainElement(unsigned long val_domainelement); + + /*! + * \brief Get the domain element which shares a face with the boundary element. + * \return Domain element which shares a face with the boundary element. + */ + unsigned long GetDomainElement(void); + + /*! + * \brief Change the orientation of an element. + */ + void Change_Orientation(void); +}; + +/*! + * \class CTriangle + * \brief Class for triangle element definition. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CTriangle : public CPrimalGrid { +private: + static unsigned short Faces[3][2]; /*!< \brief Matrix to store the local nodes of all the faces. */ + static unsigned short Neighbor_Nodes[3][2]; /*!< \brief Neighbor to a nodes in the element. */ + static unsigned short nNodesFace[3]; /*!< \brief Number of nodes of each face of the element. */ + static unsigned short nNeighbor_Nodes[3]; /*!< \brief Number of Neighbor to a nodes in the element. */ + static unsigned short nFaces; /*!< \brief Number of faces of the element. */ + static unsigned short nNodes; /*!< \brief Number of nodes of the element. */ + static unsigned short VTK_Type; /*!< \brief Type of element using VTK nomenclature. */ + static unsigned short maxNodesFace; /*!< \brief Maximum number of nodes for a face. */ + static unsigned short nNeighbor_Elements; /*!< \brief Number of Neighbor_Elements. */ + +public: + + /*! + * \brief Constructor using the nodes and index. + * \param[in] val_point_0 - Index of the 1st triangle point read from the grid file. + * \param[in] val_point_1 - Index of the 2nd triangle point read from the grid file. + * \param[in] val_point_2 - Index of the 3th triangle point read from the grid file. + * \param[in] val_nDim - Number of dimension of the problem (2D or 3D), be careful a triangle could be 2D or 3D. + */ + CTriangle(unsigned long val_point_0, unsigned long val_point_1, + unsigned long val_point_2, unsigned short val_nDim); + + /*! + * \brief Destructor of the class. + */ + ~CTriangle(void); + + /*! + * \brief Get the nodes shared by the triangle. + * \param[in] val_node - Local (to the triangle) index of the node (a triangle has 3 nodes). + * \return Global index of the triangle node. + */ + unsigned long GetNode(unsigned short val_node); + + /*! + * \brief Set the point associated at a node. + * \param[in] val_node - Local index of a node. + * \param[in] val_point - Point associated to the node. + */ + void SetNode(unsigned short val_node, unsigned long val_point); + + /*! + * \brief Get the face index of and element. + * \param[in] val_face - Local index of the face. + * \param[in] val_index - Local (to the face) index of the nodes that compose the face. + * \return Local (to the triangle) index of the nodes that compose the face. + */ + unsigned short GetFaces(unsigned short val_face, unsigned short val_index); + + /*! + * \brief Get the local index of the neighbors to a node (given the local index). + * \param[in] val_node - Local (to the triangle) index of a node. + * \param[in] val_index - Local (to the neighbor nodes of val_node) index of the nodes that + are neighbor to val_node (each face is composed by 3 nodes). + * \return Local (to the triangle) index of the nodes that are neighbor to val_node. + */ + unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index); + + /*! + * \brief Get the number of neighbors nodes of a node. + * \param[in] val_node - Local (to the triangle) index of a node. + * \return Number if neighbors of a node val_node. + */ + unsigned short GetnNeighbor_Nodes(unsigned short val_node); + + /*! + * \brief Get the number of nodes that composes a face of an element. + * \param[in] val_face - Local index of the face. + * \return Number of nodes that composes a face of an element. + */ + unsigned short GetnNodesFace(unsigned short val_face); + + /*! + * \brief Get the number of nodes of an element. + * \return Number of nodes that composes an element. + */ + unsigned short GetnNodes(void); + + /*! + * \brief Get the number of faces of an element. + * \return Number of faces of an element. + */ + unsigned short GetnFaces(void); + + /*! + * \brief Get the Maximum number of nodes of a face of an element. + * \return Maximum number of nodes of a face of an element. + */ + unsigned short GetMaxNodesFace(void); + + /*! + * \brief Get the type of the element using VTK nomenclature. + * \return Type of the element using VTK nomenclature. + */ + unsigned short GetVTK_Type(void); + + /*! + * \brief Get the number of element that are neighbor to this element. + * \return Number of neighbor elements. + */ + unsigned short GetnNeighbor_Elements(void); + + /*! + * \brief Change the orientation of an element. + */ + void Change_Orientation(void); + + /*! + * \brief Set the domain element which shares a face with the boundary element. + * \param[in] val_domainelement - Global index of the element. + */ + void SetDomainElement(unsigned long val_domainelement); + + /*! + * \brief Get the domain element which shares a face with the boundary element. + * \return Domain element which shares a face with the boundary element. + */ + unsigned long GetDomainElement(void); +}; + +/*! + * \class CQuadrilateral + * \brief Class for quadrilateral element definition. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CQuadrilateral : public CPrimalGrid { +private: + static unsigned short Faces[4][2]; /*!< \brief Matrix to store the local nodes of all the faces. */ + static unsigned short Neighbor_Nodes[4][2]; /*!< \brief Neighbor to a nodes in the element. */ + static unsigned short nNodesFace[4]; /*!< \brief Number of nodes of each face of the element. */ + static unsigned short nNeighbor_Nodes[4]; /*!< \brief Number of Neighbor to a nodes in the element. */ + static unsigned short nFaces; /*!< \brief Number of faces of the element. */ + static unsigned short nNodes; /*!< \brief Number of nodes of the element. */ + static unsigned short VTK_Type; /*!< \brief Type of element using VTK nomenclature. */ + static unsigned short maxNodesFace; /*!< \brief Maximum number of nodes for a face. */ + static unsigned short nNeighbor_Elements; /*!< \brief Number of neighbor elements. */ + +public: + + /*! + * \brief Constructor using the nodes and index. + * \param[in] val_point_0 - Index of the 1st point read from the grid file. + * \param[in] val_point_1 - Index of the 2nd point read from the grid file. + * \param[in] val_point_2 - Index of the 3th point read from the grid file. + * \param[in] val_point_3 - Index of the 4th point read from the grid file. + * \param[in] val_nDim - Number of dimension of the problem (2D or 3D). + */ + CQuadrilateral(unsigned long val_point_0, unsigned long val_point_1, + unsigned long val_point_2, unsigned long val_point_3, unsigned short val_nDim); + + /*! + * \brief Destructor of the class. + */ + ~CQuadrilateral(void); + + /*! + * \brief Get the nodes shared by the triangle. + * \param[in] val_node - Local (to the quadrilateral) index of the node (a quadrilateral has 4 nodes). + * \return Global index of the triangle node. + */ + unsigned long GetNode(unsigned short val_node); + + /*! + * \brief Set the point associated at a node. + * \param[in] val_node - Local index of a node. + * \param[in] val_point - Point associated to the node. + */ + void SetNode(unsigned short val_node, unsigned long val_point); + + /*! + * \brief Get the face index of and element. + * \param[in] val_face - Local index of the face. + * \param[in] val_index - Local (to the face) index of the nodes that compose the face. + * \return Local (to the quadrilateral) index of the nodes that compose the face. + */ + unsigned short GetFaces(unsigned short val_face, unsigned short val_index); + + /*! + * \brief Get the local index of the neighbors to a node (given the local index). + * \param[in] val_node - Local (to the element) index of a node. + * \param[in] val_index - Local (to the neighbor nodes of val_node) index of the nodes that are neighbor to val_node. + * \return Local (to the quadrilateral) index of the nodes that are neighbor to val_node. + */ + unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index); + + /*! + * \brief Get the number of neighbors nodes of a node. + * \param[in] val_node - Local (to the element) index of a node. + * \return Number if neighbors of a node val_node. + */ + unsigned short GetnNeighbor_Nodes(unsigned short val_node); + + /*! + * \brief Get the number of nodes that composes a face of an element. + * \param[in] val_face - Local index of the face. + * \return Number of nodes that composes a face of an element. + */ + unsigned short GetnNodesFace(unsigned short val_face); + + /*! + * \brief Get the number of nodes of an element. + * \return Number of nodes that composes an element. + */ + unsigned short GetnNodes(void); + + /*! + * \brief Get the number of faces of an element. + * \return Number of faces of an element. + */ + unsigned short GetnFaces(void); + + /*! + * \brief Get the Maximum number of nodes of a face of an element. + * \return Maximum number of nodes of a face of an element. + */ + unsigned short GetMaxNodesFace(void); + + /*! + * \brief Get the type of the element using VTK nomenclature. + * \return Type of the element using VTK nomenclature. + */ + unsigned short GetVTK_Type(void); + + /*! + * \brief Get the number of element that are neighbor to this element. + * \return Number of neighbor elements. + */ + unsigned short GetnNeighbor_Elements(void); + + /*! + * \brief Change the orientation of an element. + */ + void Change_Orientation(void); + + /*! + * \brief Set the domain element which shares a face with the boundary element. + * \param[in] val_domainelement - Global index of the element. + */ + void SetDomainElement(unsigned long val_domainelement); + + /*! + * \brief Get the domain element which shares a face with the boundary element. + * \return Domain element which shares a face with the boundary element. + */ + unsigned long GetDomainElement(void); +}; + +/*! + * \class CTetrahedron + * \brief Class for tetrahedron element definition. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CTetrahedron : public CPrimalGrid { +private: + static unsigned short Faces[4][3]; /*!< \brief Matrix to store the local nodes of all the faces. */ + static unsigned short Neighbor_Nodes[4][3]; /*!< \brief Neighbor to a nodes in the element. */ + static unsigned short nNodesFace[4]; /*!< \brief Number of nodes of each face of the element. */ + static unsigned short nNeighbor_Nodes[4]; /*!< \brief Number of Neighbor to a nodes in the element. */ + static unsigned short nFaces; /*!< \brief Number of faces of the element. */ + static unsigned short nNodes; /*!< \brief Number of nodes of the element. */ + static unsigned short VTK_Type; /*!< \brief Type of element using VTK nomenclature. */ + static unsigned short maxNodesFace; /*!< \brief Maximum number of nodes for a face. */ + static unsigned short nNeighbor_Elements; /*!< \brief Number of neighbor elements. */ + +public: + + /*! + * \brief Constructor using the nodes and index. + * \param[in] val_point_0 - Index of the 1st point read from the grid file. + * \param[in] val_point_1 - Index of the 2nd point read from the grid file. + * \param[in] val_point_2 - Index of the 3th point read from the grid file. + * \param[in] val_point_3 - Index of the 4th point read from the grid file. + */ + CTetrahedron(unsigned long val_point_0, unsigned long val_point_1, + unsigned long val_point_2, unsigned long val_point_3); + + /*! + * \brief Destructor of the class. + */ + ~CTetrahedron(void); + + /*! + * \brief Get the nodes shared by the tetrahedron. + * \param[in] val_node - Local (to the tetrahedron) index of the node (a tetrahedron has 4 nodes). + * \return Global index of the tetrahedron node. + */ + unsigned long GetNode(unsigned short val_node); + + /*! + * \brief Set the point associated at a node. + * \param[in] val_node - Local index of a node. + * \param[in] val_point - Point associated to the node. + */ + void SetNode(unsigned short val_node, unsigned long val_point); + + /*! + * \brief Get the face index of and element. + * \param[in] val_face - Local index of the face. + * \param[in] val_index - Local (to the face) index of the nodes that compose the face. + * \return Local (to the element) index of the nodes that compose the face. + */ + unsigned short GetFaces(unsigned short val_face, unsigned short val_index); + + /*! + * \brief Get the local index of the neighbors to a node (given the local index). + * \param[in] val_node - Local (to the element) index of a node. + * \param[in] val_index - Local (to the neighbor nodes of val_node) index of the nodes that are neighbor to val_node. + * \return Local (to the element) index of the nodes that are neighbor to val_node. + */ + unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index); + + /*! + * \brief Get the number of neighbors nodes of a node. + * \param[in] val_node - Local (to the element) index of a node. + * \return Number if neighbors of a node val_node. + */ + unsigned short GetnNeighbor_Nodes(unsigned short val_node); + + /*! + * \brief Get the number of nodes that composes a face of an element. + * \param[in] val_face - Local index of the face. + * \return Number of nodes that composes a face of an element. + */ + unsigned short GetnNodesFace(unsigned short val_face); + + /*! + * \brief Get the number of nodes of an element. + * \return Number of nodes that composes an element. + */ + unsigned short GetnNodes(void); + + /*! + * \brief Get the number of faces of an element. + * \return Number of faces of an element. + */ + unsigned short GetnFaces(void); + + /*! + * \brief Get the Maximum number of nodes of a face of an element. + * \return Maximum number of nodes of a face of an element. + */ + unsigned short GetMaxNodesFace(void); + + /*! + * \brief Get the type of the element using VTK nomenclature. + * \return Type of the element using VTK nomenclature. + */ + unsigned short GetVTK_Type(void); + + /*! + * \brief Get the number of element that are neighbor to this element. + * \return Number of neighbor elements. + */ + unsigned short GetnNeighbor_Elements(void); + + /*! + * \brief Change the orientation of an element. + */ + void Change_Orientation(void); +}; + +/*! + * \class CHexahedron + * \brief Class for hexahedron element definition. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CHexahedron : public CPrimalGrid { +private: + static unsigned short Faces[6][4]; /*!< \brief Matrix to store the local nodes of all the faces. */ + static unsigned short Neighbor_Nodes[8][3]; /*!< \brief Neighbor to a nodes in the element. */ + static unsigned short nNodesFace[6]; /*!< \brief Number of nodes of each face of the element. */ + static unsigned short nNeighbor_Nodes[8]; /*!< \brief Number of Neighbor to a nodes in the element. */ + static unsigned short nFaces; /*!< \brief Number of faces of the element. */ + static unsigned short nNodes; /*!< \brief Number of nodes of the element. */ + static unsigned short VTK_Type; /*!< \brief Type of element using VTK nomenclature. */ + static unsigned short maxNodesFace; /*!< \brief Maximum number of nodes for a face. */ + static unsigned short nNeighbor_Elements; /*!< \brief Number of neighbor elements. */ + +public: + + /*! + * \brief Constructor using the nodes and index. + * \param[in] val_point_0 - Index of the 1st point read from the grid file. + * \param[in] val_point_1 - Index of the 2nd point read from the grid file. + * \param[in] val_point_2 - Index of the 3th point read from the grid file. + * \param[in] val_point_3 - Index of the 4th point read from the grid file. + * \param[in] val_point_4 - Index of the 5td point read from the grid file. + * \param[in] val_point_5 - Index of the 6th point read from the grid file. + * \param[in] val_point_6 - Index of the 7th point read from the grid file. + * \param[in] val_point_7 - Index of the 8th point read from the grid file. + */ + CHexahedron(unsigned long val_point_0, unsigned long val_point_1, + unsigned long val_point_2, unsigned long val_point_3, + unsigned long val_point_4, unsigned long val_point_5, + unsigned long val_point_6, unsigned long val_point_7); + + /*! + * \brief Destructor of the class. + */ + ~CHexahedron(void); + + /*! + * \brief Get the nodes shared by the triangle. + * \param[in] val_node - Local (to the triangle) index of the node (a triangle has 3 nodes). + * \return Global index of the triangle node. + */ + unsigned long GetNode(unsigned short val_node); + + /*! + * \brief Set the point associated at a node. + * \param[in] val_node - Local index of a node. + * \param[in] val_point - Point associated to the node. + */ + void SetNode(unsigned short val_node, unsigned long val_point); + + /*! + * \brief Get the face index of and element. + * \param[in] val_face - Local index of the face. + * \param[in] val_index - Local (to the face) index of the nodes that compose the face. + * \return Local (to the element) index of the nodes that compose the face. + */ + unsigned short GetFaces(unsigned short val_face, unsigned short val_index); + + /*! + * \brief Get the local index of the neighbors to a node (given the local index). + * \param[in] val_node - Local (to the element) index of a node. + * \param[in] val_index - Local (to the neighbor nodes of val_node) index of the nodes + * that are neighbor to val_node. + * \return Local (to the element) index of the nodes that are neighbor to val_node. + */ + unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index); + + /*! + * \brief Get the number of neighbors nodes of a node. + * \param[in] val_node - Local (to the element) index of a node. + * \return Number if neighbors of a node val_node. + */ + unsigned short GetnNeighbor_Nodes(unsigned short val_node); + + /*! + * \brief Get the number of nodes that composes a face of an element. + * \param[in] val_face - Local index of the face. + * \return Number of nodes that composes a face of an element. + */ + unsigned short GetnNodesFace(unsigned short val_face); + + /*! + * \brief Get the number of nodes of an element. + * \return Number of nodes that composes an element. + */ + unsigned short GetnNodes(void); + + /*! + * \brief Get the number of faces of an element. + * \return Number of faces of an element. + */ + unsigned short GetnFaces(void); + + /*! + * \brief Get the Maximum number of nodes of a face of an element. + * \return Maximum number of nodes of a face of an element. + */ + unsigned short GetMaxNodesFace(void); + + /*! + * \brief Get the type of the element using VTK nomenclature. + * \return Type of the element using VTK nomenclature. + */ + unsigned short GetVTK_Type(void); + + /*! + * \brief Get the number of element that are neighbor to this element. + * \return Number of neighbor elements. + */ + unsigned short GetnNeighbor_Elements(void); + + /*! + * \brief Change the orientation of an element. + */ + void Change_Orientation(void); +}; + +/*! + * \class CPrism + * \brief Class for prism element definition. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CPrism : public CPrimalGrid { +private: + static unsigned short Faces[5][4]; /*!< \brief Matrix to store the local nodes of all the faces. */ + static unsigned short Neighbor_Nodes[6][3]; /*!< \brief Neighbor to a nodes in the element. */ + static unsigned short nNodesFace[5]; /*!< \brief Number of nodes of each face of the element. */ + static unsigned short nNeighbor_Nodes[6]; /*!< \brief Number of Neighbor to a nodes in the element. */ + static unsigned short nFaces; /*!< \brief Number of faces of the element. */ + static unsigned short nNodes; /*!< \brief Number of nodes of the element. */ + static unsigned short VTK_Type; /*!< \brief Type of element using VTK nomenclature. */ + static unsigned short maxNodesFace; /*!< \brief Maximum number of nodes for a face. */ + static unsigned short nNeighbor_Elements; /*!< \brief Number of neighbor elements. */ + +public: + + /*! + * \brief Constructor using the nodes and index. + * \param[in] val_point_0 - Index of the 1st point read from the grid file. + * \param[in] val_point_1 - Index of the 2nd point read from the grid file. + * \param[in] val_point_2 - Index of the 3th point read from the grid file. + * \param[in] val_point_3 - Index of the 4th point read from the grid file. + * \param[in] val_point_4 - Index of the 5th point read from the grid file. + * \param[in] val_point_5 - Index of the 6th point read from the grid file. + */ + CPrism(unsigned long val_point_0, unsigned long val_point_1, + unsigned long val_point_2, unsigned long val_point_3, + unsigned long val_point_4, unsigned long val_point_5); + + /*! + * \brief Destructor of the class. + */ + ~CPrism(void); + + /*! + * \brief Get the nodes shared by the triangle. + * \param[in] val_node - Local (to the triangle) index of the node (a prism has 6 nodes). + * \return Global index of the prism node. + */ + unsigned long GetNode(unsigned short val_node); + + /*! + * \brief Set the point associated at a node. + * \param[in] val_node - Local index of a node. + * \param[in] val_point - Point associated to the node. + */ + void SetNode(unsigned short val_node, unsigned long val_point); + + /*! + * \brief Get the face index of and element. + * \param[in] val_face - Local index of the face. + * \param[in] val_index - Local (to the face) index of the nodes that compose the face. + * \return Local (to the element) index of the nodes that compose the face. + */ + unsigned short GetFaces(unsigned short val_face, unsigned short val_index); + + /*! + * \brief Get the local index of the neighbors to a node (given the local index). + * \param[in] val_node - Local (to the element) index of a node. + * \param[in] val_index - Local (to the neighbor nodes of val_node) index of the nodes that are neighbor to val_node. + * \return Local (to the element) index of the nodes that are neighbor to val_node. + */ + unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index); + + /*! + * \brief Get the number of neighbors nodes of a node. + * \param[in] val_node - Local (to the element) index of a node. + * \return Number if neighbors of a node val_node. + */ + unsigned short GetnNeighbor_Nodes(unsigned short val_node); + + /*! + * \brief Get the number of nodes that composes a face of an element. + * \param[in] val_face - Local index of the face. + * \return Number of nodes that composes a face of an element. + */ + unsigned short GetnNodesFace(unsigned short val_face); + + /*! + * \brief Get the number of nodes of an element. + * \return Number of nodes that composes an element. + */ + unsigned short GetnNodes(void); + + /*! + * \brief Get the number of faces of an element. + * \return Number of faces of an element. + */ + unsigned short GetnFaces(void); + + /*! + * \brief Get the Maximum number of nodes of a face of an element. + * \return Maximum number of nodes of a face of an element. + */ + unsigned short GetMaxNodesFace(void); + + /*! + * \brief Get the type of the element using VTK nomenclature. + * \return Type of the element using VTK nomenclature. + */ + unsigned short GetVTK_Type(void); + + /*! + * \brief Get the number of element that are neighbor to this element. + * \return Number of neighbor elements. + */ + unsigned short GetnNeighbor_Elements(void); + + /*! + * \brief Change the orientation of an element. + */ + void Change_Orientation(void); +}; + +/*! + * \class CPyramid + * \brief Class for pyramid element definition. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CPyramid : public CPrimalGrid { +private: + static unsigned short Faces[5][4]; /*!< \brief Matrix to store the local nodes of all the faces. */ + static unsigned short Neighbor_Nodes[5][4]; /*!< \brief Neighbor to a nodes in the element. */ + static unsigned short nNodesFace[5]; /*!< \brief Number of nodes of each face of the element. */ + static unsigned short nNeighbor_Nodes[5]; /*!< \brief Number of Neighbor to a nodes in the element. */ + static unsigned short nFaces; /*!< \brief Number of faces of the element. */ + static unsigned short nNodes; /*!< \brief Number of nodes of the element. */ + static unsigned short VTK_Type; /*!< \brief Type of element using VTK nomenclature. */ + static unsigned short maxNodesFace; /*!< \brief Maximum number of nodes for a face. */ + static unsigned short nNeighbor_Elements; /*!< \brief Number of neighbor elements. */ + +public: + + /*! + * \brief Constructor using the nodes and index. + * \param[in] val_point_0 - Index of the 1st point read from the grid file. + * \param[in] val_point_1 - Index of the 2nd point read from the grid file. + * \param[in] val_point_2 - Index of the 3th point read from the grid file. + * \param[in] val_point_3 - Index of the 4th point read from the grid file. + * \param[in] val_point_4 - Index of the 5th point read from the grid file. + */ + CPyramid(unsigned long val_point_0, unsigned long val_point_1, + unsigned long val_point_2, unsigned long val_point_3, + unsigned long val_point_4); + + /*! + * \brief Destructor of the class. + */ + ~CPyramid(void); + + /*! + * \brief Get the nodes shared by the pyramid. + * \param[in] val_node - Local (to the pyramid) index of the node (a pyramid has 3 nodes). + * \return Global index of the pyramid node. + */ + unsigned long GetNode(unsigned short val_node); + + /*! + * \brief Set the point associated at a node. + * \param[in] val_node - Local index of a node. + * \param[in] val_point - Point associated to the node. + */ + void SetNode(unsigned short val_node, unsigned long val_point); + + /*! + * \brief Get the face index of and element. + * \param[in] val_face - Local index of the face. + * \param[in] val_index - Local (to the face) index of the nodes that compose the face. + * \return Local (to the element) index of the nodes that compose the face. + */ + unsigned short GetFaces(unsigned short val_face, unsigned short val_index); + + /*! + * \brief Get the local index of the neighbors to a node (given the local index). + * \param[in] val_node - Local (to the element) index of a node. + * \param[in] val_index - Local (to the neighbor nodes of val_node) index of the nodes that are neighbor to val_node. + * \return Local (to the element) index of the nodes that are neighbor to val_node. + */ + unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index); + + /*! + * \brief Get the number of neighbors nodes of a node. + * \param[in] val_node - Local (to the element) index of a node. + * \return Number if neighbors of a node val_node. + */ + unsigned short GetnNeighbor_Nodes(unsigned short val_node); + + /*! + * \brief Get the number of nodes that composes a face of an element. + * \param[in] val_face - Local index of the face. + * \return Number of nodes that composes a face of an element. + */ + unsigned short GetnNodesFace(unsigned short val_face); + + /*! + * \brief Get the number of nodes of an element. + * \return Number of nodes that composes an element. + */ + unsigned short GetnNodes(void); + + /*! + * \brief Get the number of faces of an element. + * \return Number of faces of an element. + */ + unsigned short GetnFaces(void); + + /*! + * \brief Get the Maximum number of nodes of a face of an element. + * \return Maximum number of nodes of a face of an element. + */ + unsigned short GetMaxNodesFace(void); + + /*! + * \brief Get the type of the element using VTK nomenclature. + * \return Type of the element using VTK nomenclature. + */ + unsigned short GetVTK_Type(void); + + /*! + * \brief Get the number of element that are neighbor to this element. + * \return Number of neighbor elements. + */ + unsigned short GetnNeighbor_Elements(void); + + /*! + * \brief Change the orientation of an element. + */ + void Change_Orientation(void); +}; + +#include "primal_grid_structure.inl" diff --git a/Common/include/primal_grid_structure.inl b/Common/include/primal_grid_structure.inl index 9b91ec02f5e..bbb22887d11 100644 --- a/Common/include/primal_grid_structure.inl +++ b/Common/include/primal_grid_structure.inl @@ -1,248 +1,248 @@ -/*! - * \file primal_grid_structure.inl - * \brief In-Line subroutines of the primal_grid_structure.hpp file. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -inline unsigned short CPrimalGrid::GetnNodesFace(unsigned short val_face) { return 0; } - -inline void CPrimalGrid::SetDomainElement(unsigned long val_domainelement) { DomainElement = val_domainelement; } - -inline void CPrimalGrid::SetRotation_Type(unsigned short val_rotation_type) { } - -inline unsigned short CPrimalGrid::GetRotation_Type(void) { return 0; } - -inline unsigned long CPrimalGrid::GetDomainElement(void) { return DomainElement; } - -inline void CPrimalGrid::SetNeighbor_Elements(unsigned long val_elem, unsigned short val_face) { Neighbor_Elements[val_face] = val_elem; } - -inline long CPrimalGrid::GetNeighbor_Elements(unsigned short val_face) { return Neighbor_Elements[val_face]; } - -inline su2double CPrimalGrid::GetCG(unsigned short val_dim) { return Coord_CG[val_dim]; } - -inline su2double CPrimalGrid::GetFaceCG(unsigned short val_face, unsigned short val_dim) { return Coord_FaceElems_CG[val_face][val_dim]; } - -inline void CPrimalGrid::SetDivide (bool val_divide) { Divide = val_divide; } - -inline bool CPrimalGrid::GetDivide (void) { return Divide; } - -inline void CPrimalGrid::SetNode(unsigned short val_node, unsigned long val_point) { } - -inline unsigned short CVertexMPI::GetnNodes(void) { return nNodes; } - -inline unsigned long CVertexMPI::GetNode(unsigned short val_node) { return Nodes[val_node]; } - -inline void CVertexMPI::SetNode(unsigned short val_node, unsigned long val_point) { Nodes[val_node] = val_point; } - -inline unsigned short CVertexMPI::GetVTK_Type(void) { return VTK_Type; } - -inline unsigned short CVertexMPI::GetRotation_Type(void) { return Rotation_Type; } - -inline void CVertexMPI::SetRotation_Type(unsigned short val_rotation_type) { Rotation_Type = val_rotation_type; } - -inline unsigned short CVertexMPI::GetnNeighbor_Nodes(unsigned short val_node) { return 0; } - -inline unsigned short CVertexMPI::GetnNeighbor_Elements(void) { return 0; } - -inline unsigned short CVertexMPI::GetnFaces(void) { return 0; } - -inline unsigned short CVertexMPI::GetnNodesFace(unsigned short val_face) { return 0; } - -inline unsigned short CVertexMPI::GetMaxNodesFace(void) { return 0; } - -inline unsigned short CVertexMPI::GetFaces(unsigned short val_face, unsigned short val_index) { return 0; } - -inline unsigned short CVertexMPI::GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) { return 0; } - -inline unsigned short CLine::GetFaces(unsigned short val_face, unsigned short val_index) { return Faces[val_face][val_index]; } - -inline unsigned short CLine::GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) { return Neighbor_Nodes[val_node][val_index]; } - -inline unsigned short CLine::GetnNodesFace(unsigned short val_face) { return nNodesFace[val_face]; } - -inline unsigned short CLine::GetnNeighbor_Nodes(unsigned short val_node) { return nNeighbor_Nodes[val_node]; } - -inline unsigned long CLine::GetNode(unsigned short val_node) { return Nodes[val_node]; } - -inline void CLine::SetNode(unsigned short val_node, unsigned long val_point) { Nodes[val_node] = val_point; } - -inline unsigned short CLine::GetnNodes(void) { return nNodes; } - -inline unsigned short CLine::GetnFaces(void) { return nFaces; } - -inline unsigned short CLine::GetVTK_Type(void) { return VTK_Type; } - -inline unsigned short CLine::GetMaxNodesFace(void) { return maxNodesFace; } - -inline unsigned short CLine::GetnNeighbor_Elements(void) { return nNeighbor_Elements; } - -inline void CLine::SetDomainElement(unsigned long val_domainelement) {DomainElement = val_domainelement; } - -inline unsigned long CLine::GetDomainElement(void) { return DomainElement; } - -inline unsigned short CTriangle::GetFaces(unsigned short val_face, unsigned short val_index) { return Faces[val_face][val_index]; } - -inline unsigned short CTriangle::GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) { return Neighbor_Nodes[val_node][val_index]; } - -inline unsigned short CTriangle::GetnNodesFace(unsigned short val_face) { return nNodesFace[val_face]; } - -inline unsigned short CTriangle::GetnNeighbor_Nodes(unsigned short val_node) { return nNeighbor_Nodes[val_node]; } - -inline unsigned long CTriangle::GetNode(unsigned short val_node) { return Nodes[val_node]; } - -inline void CTriangle::SetNode(unsigned short val_node, unsigned long val_point) { Nodes[val_node] = val_point; } - -inline unsigned short CTriangle::GetnNodes(void) { return nNodes; } - -inline unsigned short CTriangle::GetnFaces(void) { return nFaces; } - -inline unsigned short CTriangle::GetVTK_Type(void) { return VTK_Type; } - -inline unsigned short CTriangle::GetMaxNodesFace(void) { return maxNodesFace; } - -inline unsigned short CTriangle::GetnNeighbor_Elements(void) { return nNeighbor_Elements; } - -inline void CTriangle::SetDomainElement(unsigned long val_domainelement) { DomainElement = val_domainelement; } - -inline unsigned long CTriangle::GetDomainElement(void) { return DomainElement; } - -inline unsigned short CQuadrilateral::GetFaces(unsigned short val_face, unsigned short val_index) { return Faces[val_face][val_index]; } - -inline unsigned short CQuadrilateral::GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) { return Neighbor_Nodes[val_node][val_index]; } - -inline unsigned short CQuadrilateral::GetnNodesFace(unsigned short val_face) { return nNodesFace[val_face]; } - -inline unsigned short CQuadrilateral::GetnNeighbor_Nodes(unsigned short val_node) { return nNeighbor_Nodes[val_node]; } - -inline unsigned long CQuadrilateral::GetNode(unsigned short val_node) { return Nodes[val_node]; } - -inline void CQuadrilateral::SetNode(unsigned short val_node, unsigned long val_point) { Nodes[val_node] = val_point; } - -inline unsigned short CQuadrilateral::GetnNodes(void) { return nNodes; } - -inline unsigned short CQuadrilateral::GetnFaces(void) { return nFaces; } - -inline unsigned short CQuadrilateral::GetVTK_Type(void) { return VTK_Type; } - -inline unsigned short CQuadrilateral::GetMaxNodesFace(void) { return maxNodesFace; } - -inline unsigned short CQuadrilateral::GetnNeighbor_Elements(void) { return nNeighbor_Elements; } - -inline void CQuadrilateral::SetDomainElement(unsigned long val_domainelement) { DomainElement = val_domainelement; } - -inline unsigned long CQuadrilateral::GetDomainElement(void) { return DomainElement; } - -inline unsigned short CTetrahedron::GetFaces(unsigned short val_face, unsigned short val_index) { return Faces[val_face][val_index]; } - -inline unsigned short CTetrahedron::GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) { return Neighbor_Nodes[val_node][val_index]; } - -inline unsigned short CTetrahedron::GetnNodesFace(unsigned short val_face) { return nNodesFace[val_face]; } - -inline unsigned short CTetrahedron::GetnNeighbor_Nodes(unsigned short val_node) { return nNeighbor_Nodes[val_node]; } - -inline unsigned long CTetrahedron::GetNode(unsigned short val_node) { return Nodes[val_node]; } - -inline void CTetrahedron::SetNode(unsigned short val_node, unsigned long val_point) { Nodes[val_node] = val_point; } - -inline unsigned short CTetrahedron::GetnNodes(void) { return nNodes; } - -inline unsigned short CTetrahedron::GetnFaces(void) { return nFaces; } - -inline unsigned short CTetrahedron::GetVTK_Type(void) { return VTK_Type; } - -inline unsigned short CTetrahedron::GetMaxNodesFace(void) { return maxNodesFace; } - -inline unsigned short CTetrahedron::GetnNeighbor_Elements(void) { return nNeighbor_Elements; } - -inline unsigned short CHexahedron::GetFaces(unsigned short val_face, unsigned short val_index) { return Faces[val_face][val_index]; } - -inline unsigned short CHexahedron::GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) { return Neighbor_Nodes[val_node][val_index]; } - -inline unsigned short CHexahedron::GetnNodesFace(unsigned short val_face) { return nNodesFace[val_face]; } - -inline unsigned short CHexahedron::GetnNeighbor_Nodes(unsigned short val_node) { return nNeighbor_Nodes[val_node]; } - -inline unsigned long CHexahedron::GetNode(unsigned short val_node) { return Nodes[val_node]; } - -inline void CHexahedron::SetNode(unsigned short val_node, unsigned long val_point) { Nodes[val_node] = val_point; } - -inline unsigned short CHexahedron::GetnNodes(void) { return nNodes; } - -inline unsigned short CHexahedron::GetnFaces(void) { return nFaces; } - -inline unsigned short CHexahedron::GetVTK_Type(void) { return VTK_Type; } - -inline unsigned short CHexahedron::GetMaxNodesFace(void) { return maxNodesFace; } - -inline unsigned short CHexahedron::GetnNeighbor_Elements(void) { return nNeighbor_Elements; } - -inline unsigned short CPrism::GetFaces(unsigned short val_face, unsigned short val_index) { return Faces[val_face][val_index]; } - -inline unsigned short CPrism::GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) { return Neighbor_Nodes[val_node][val_index]; } - -inline unsigned short CPrism::GetnNodesFace(unsigned short val_face) { return nNodesFace[val_face]; } - -inline unsigned short CPrism::GetnNeighbor_Nodes(unsigned short val_node) { return nNeighbor_Nodes[val_node]; } - -inline unsigned long CPrism::GetNode(unsigned short val_node) { return Nodes[val_node]; } - -inline void CPrism::SetNode(unsigned short val_node, unsigned long val_point) { Nodes[val_node] = val_point; } - -inline unsigned short CPrism::GetnNodes(void) { return nNodes; } - -inline unsigned short CPrism::GetnFaces(void) { return nFaces; } - -inline unsigned short CPrism::GetVTK_Type(void) { return VTK_Type; } - -inline unsigned short CPrism::GetMaxNodesFace(void) { return maxNodesFace; } - -inline unsigned short CPrism::GetnNeighbor_Elements(void) { return nNeighbor_Elements; } - -inline unsigned short CPyramid::GetFaces(unsigned short val_face, unsigned short val_index) { return Faces[val_face][val_index]; } - -inline unsigned short CPyramid::GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) { return Neighbor_Nodes[val_node][val_index]; } - -inline unsigned short CPyramid::GetnNodesFace(unsigned short val_face) { return nNodesFace[val_face]; } - -inline unsigned short CPyramid::GetnNeighbor_Nodes(unsigned short val_node) { return nNeighbor_Nodes[val_node]; } - -inline unsigned long CPyramid::GetNode(unsigned short val_node) { return Nodes[val_node]; } - -inline void CPyramid::SetNode(unsigned short val_node, unsigned long val_point) { Nodes[val_node] = val_point; } - -inline unsigned short CPyramid::GetnNodes(void) { return nNodes; } - -inline unsigned short CPyramid::GetnFaces(void) { return nFaces; } - -inline unsigned short CPyramid::GetVTK_Type(void) { return VTK_Type; } - -inline unsigned short CPyramid::GetMaxNodesFace(void) { return maxNodesFace; } - -inline unsigned short CPyramid::GetnNeighbor_Elements(void) { return nNeighbor_Elements; } +/*! + * \file primal_grid_structure.inl + * \brief In-Line subroutines of the primal_grid_structure.hpp file. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +inline unsigned short CPrimalGrid::GetnNodesFace(unsigned short val_face) { return 0; } + +inline void CPrimalGrid::SetDomainElement(unsigned long val_domainelement) { DomainElement = val_domainelement; } + +inline void CPrimalGrid::SetRotation_Type(unsigned short val_rotation_type) { } + +inline unsigned short CPrimalGrid::GetRotation_Type(void) { return 0; } + +inline unsigned long CPrimalGrid::GetDomainElement(void) { return DomainElement; } + +inline void CPrimalGrid::SetNeighbor_Elements(unsigned long val_elem, unsigned short val_face) { Neighbor_Elements[val_face] = val_elem; } + +inline long CPrimalGrid::GetNeighbor_Elements(unsigned short val_face) { return Neighbor_Elements[val_face]; } + +inline su2double CPrimalGrid::GetCG(unsigned short val_dim) { return Coord_CG[val_dim]; } + +inline su2double CPrimalGrid::GetFaceCG(unsigned short val_face, unsigned short val_dim) { return Coord_FaceElems_CG[val_face][val_dim]; } + +inline void CPrimalGrid::SetDivide (bool val_divide) { Divide = val_divide; } + +inline bool CPrimalGrid::GetDivide (void) { return Divide; } + +inline void CPrimalGrid::SetNode(unsigned short val_node, unsigned long val_point) { } + +inline unsigned short CVertexMPI::GetnNodes(void) { return nNodes; } + +inline unsigned long CVertexMPI::GetNode(unsigned short val_node) { return Nodes[val_node]; } + +inline void CVertexMPI::SetNode(unsigned short val_node, unsigned long val_point) { Nodes[val_node] = val_point; } + +inline unsigned short CVertexMPI::GetVTK_Type(void) { return VTK_Type; } + +inline unsigned short CVertexMPI::GetRotation_Type(void) { return Rotation_Type; } + +inline void CVertexMPI::SetRotation_Type(unsigned short val_rotation_type) { Rotation_Type = val_rotation_type; } + +inline unsigned short CVertexMPI::GetnNeighbor_Nodes(unsigned short val_node) { return 0; } + +inline unsigned short CVertexMPI::GetnNeighbor_Elements(void) { return 0; } + +inline unsigned short CVertexMPI::GetnFaces(void) { return 0; } + +inline unsigned short CVertexMPI::GetnNodesFace(unsigned short val_face) { return 0; } + +inline unsigned short CVertexMPI::GetMaxNodesFace(void) { return 0; } + +inline unsigned short CVertexMPI::GetFaces(unsigned short val_face, unsigned short val_index) { return 0; } + +inline unsigned short CVertexMPI::GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) { return 0; } + +inline unsigned short CLine::GetFaces(unsigned short val_face, unsigned short val_index) { return Faces[val_face][val_index]; } + +inline unsigned short CLine::GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) { return Neighbor_Nodes[val_node][val_index]; } + +inline unsigned short CLine::GetnNodesFace(unsigned short val_face) { return nNodesFace[val_face]; } + +inline unsigned short CLine::GetnNeighbor_Nodes(unsigned short val_node) { return nNeighbor_Nodes[val_node]; } + +inline unsigned long CLine::GetNode(unsigned short val_node) { return Nodes[val_node]; } + +inline void CLine::SetNode(unsigned short val_node, unsigned long val_point) { Nodes[val_node] = val_point; } + +inline unsigned short CLine::GetnNodes(void) { return nNodes; } + +inline unsigned short CLine::GetnFaces(void) { return nFaces; } + +inline unsigned short CLine::GetVTK_Type(void) { return VTK_Type; } + +inline unsigned short CLine::GetMaxNodesFace(void) { return maxNodesFace; } + +inline unsigned short CLine::GetnNeighbor_Elements(void) { return nNeighbor_Elements; } + +inline void CLine::SetDomainElement(unsigned long val_domainelement) {DomainElement = val_domainelement; } + +inline unsigned long CLine::GetDomainElement(void) { return DomainElement; } + +inline unsigned short CTriangle::GetFaces(unsigned short val_face, unsigned short val_index) { return Faces[val_face][val_index]; } + +inline unsigned short CTriangle::GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) { return Neighbor_Nodes[val_node][val_index]; } + +inline unsigned short CTriangle::GetnNodesFace(unsigned short val_face) { return nNodesFace[val_face]; } + +inline unsigned short CTriangle::GetnNeighbor_Nodes(unsigned short val_node) { return nNeighbor_Nodes[val_node]; } + +inline unsigned long CTriangle::GetNode(unsigned short val_node) { return Nodes[val_node]; } + +inline void CTriangle::SetNode(unsigned short val_node, unsigned long val_point) { Nodes[val_node] = val_point; } + +inline unsigned short CTriangle::GetnNodes(void) { return nNodes; } + +inline unsigned short CTriangle::GetnFaces(void) { return nFaces; } + +inline unsigned short CTriangle::GetVTK_Type(void) { return VTK_Type; } + +inline unsigned short CTriangle::GetMaxNodesFace(void) { return maxNodesFace; } + +inline unsigned short CTriangle::GetnNeighbor_Elements(void) { return nNeighbor_Elements; } + +inline void CTriangle::SetDomainElement(unsigned long val_domainelement) { DomainElement = val_domainelement; } + +inline unsigned long CTriangle::GetDomainElement(void) { return DomainElement; } + +inline unsigned short CQuadrilateral::GetFaces(unsigned short val_face, unsigned short val_index) { return Faces[val_face][val_index]; } + +inline unsigned short CQuadrilateral::GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) { return Neighbor_Nodes[val_node][val_index]; } + +inline unsigned short CQuadrilateral::GetnNodesFace(unsigned short val_face) { return nNodesFace[val_face]; } + +inline unsigned short CQuadrilateral::GetnNeighbor_Nodes(unsigned short val_node) { return nNeighbor_Nodes[val_node]; } + +inline unsigned long CQuadrilateral::GetNode(unsigned short val_node) { return Nodes[val_node]; } + +inline void CQuadrilateral::SetNode(unsigned short val_node, unsigned long val_point) { Nodes[val_node] = val_point; } + +inline unsigned short CQuadrilateral::GetnNodes(void) { return nNodes; } + +inline unsigned short CQuadrilateral::GetnFaces(void) { return nFaces; } + +inline unsigned short CQuadrilateral::GetVTK_Type(void) { return VTK_Type; } + +inline unsigned short CQuadrilateral::GetMaxNodesFace(void) { return maxNodesFace; } + +inline unsigned short CQuadrilateral::GetnNeighbor_Elements(void) { return nNeighbor_Elements; } + +inline void CQuadrilateral::SetDomainElement(unsigned long val_domainelement) { DomainElement = val_domainelement; } + +inline unsigned long CQuadrilateral::GetDomainElement(void) { return DomainElement; } + +inline unsigned short CTetrahedron::GetFaces(unsigned short val_face, unsigned short val_index) { return Faces[val_face][val_index]; } + +inline unsigned short CTetrahedron::GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) { return Neighbor_Nodes[val_node][val_index]; } + +inline unsigned short CTetrahedron::GetnNodesFace(unsigned short val_face) { return nNodesFace[val_face]; } + +inline unsigned short CTetrahedron::GetnNeighbor_Nodes(unsigned short val_node) { return nNeighbor_Nodes[val_node]; } + +inline unsigned long CTetrahedron::GetNode(unsigned short val_node) { return Nodes[val_node]; } + +inline void CTetrahedron::SetNode(unsigned short val_node, unsigned long val_point) { Nodes[val_node] = val_point; } + +inline unsigned short CTetrahedron::GetnNodes(void) { return nNodes; } + +inline unsigned short CTetrahedron::GetnFaces(void) { return nFaces; } + +inline unsigned short CTetrahedron::GetVTK_Type(void) { return VTK_Type; } + +inline unsigned short CTetrahedron::GetMaxNodesFace(void) { return maxNodesFace; } + +inline unsigned short CTetrahedron::GetnNeighbor_Elements(void) { return nNeighbor_Elements; } + +inline unsigned short CHexahedron::GetFaces(unsigned short val_face, unsigned short val_index) { return Faces[val_face][val_index]; } + +inline unsigned short CHexahedron::GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) { return Neighbor_Nodes[val_node][val_index]; } + +inline unsigned short CHexahedron::GetnNodesFace(unsigned short val_face) { return nNodesFace[val_face]; } + +inline unsigned short CHexahedron::GetnNeighbor_Nodes(unsigned short val_node) { return nNeighbor_Nodes[val_node]; } + +inline unsigned long CHexahedron::GetNode(unsigned short val_node) { return Nodes[val_node]; } + +inline void CHexahedron::SetNode(unsigned short val_node, unsigned long val_point) { Nodes[val_node] = val_point; } + +inline unsigned short CHexahedron::GetnNodes(void) { return nNodes; } + +inline unsigned short CHexahedron::GetnFaces(void) { return nFaces; } + +inline unsigned short CHexahedron::GetVTK_Type(void) { return VTK_Type; } + +inline unsigned short CHexahedron::GetMaxNodesFace(void) { return maxNodesFace; } + +inline unsigned short CHexahedron::GetnNeighbor_Elements(void) { return nNeighbor_Elements; } + +inline unsigned short CPrism::GetFaces(unsigned short val_face, unsigned short val_index) { return Faces[val_face][val_index]; } + +inline unsigned short CPrism::GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) { return Neighbor_Nodes[val_node][val_index]; } + +inline unsigned short CPrism::GetnNodesFace(unsigned short val_face) { return nNodesFace[val_face]; } + +inline unsigned short CPrism::GetnNeighbor_Nodes(unsigned short val_node) { return nNeighbor_Nodes[val_node]; } + +inline unsigned long CPrism::GetNode(unsigned short val_node) { return Nodes[val_node]; } + +inline void CPrism::SetNode(unsigned short val_node, unsigned long val_point) { Nodes[val_node] = val_point; } + +inline unsigned short CPrism::GetnNodes(void) { return nNodes; } + +inline unsigned short CPrism::GetnFaces(void) { return nFaces; } + +inline unsigned short CPrism::GetVTK_Type(void) { return VTK_Type; } + +inline unsigned short CPrism::GetMaxNodesFace(void) { return maxNodesFace; } + +inline unsigned short CPrism::GetnNeighbor_Elements(void) { return nNeighbor_Elements; } + +inline unsigned short CPyramid::GetFaces(unsigned short val_face, unsigned short val_index) { return Faces[val_face][val_index]; } + +inline unsigned short CPyramid::GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index) { return Neighbor_Nodes[val_node][val_index]; } + +inline unsigned short CPyramid::GetnNodesFace(unsigned short val_face) { return nNodesFace[val_face]; } + +inline unsigned short CPyramid::GetnNeighbor_Nodes(unsigned short val_node) { return nNeighbor_Nodes[val_node]; } + +inline unsigned long CPyramid::GetNode(unsigned short val_node) { return Nodes[val_node]; } + +inline void CPyramid::SetNode(unsigned short val_node, unsigned long val_point) { Nodes[val_node] = val_point; } + +inline unsigned short CPyramid::GetnNodes(void) { return nNodes; } + +inline unsigned short CPyramid::GetnFaces(void) { return nFaces; } + +inline unsigned short CPyramid::GetVTK_Type(void) { return VTK_Type; } + +inline unsigned short CPyramid::GetMaxNodesFace(void) { return maxNodesFace; } + +inline unsigned short CPyramid::GetnNeighbor_Elements(void) { return nNeighbor_Elements; } diff --git a/Common/include/vector_structure.hpp b/Common/include/vector_structure.hpp index f09ad9e9226..2572beeea1c 100644 --- a/Common/include/vector_structure.hpp +++ b/Common/include/vector_structure.hpp @@ -34,7 +34,6 @@ #include -// #include #include #include #include diff --git a/Common/src/dual_grid_structure.cpp b/Common/src/dual_grid_structure.cpp index 13e63014ac4..8e1c6fa4249 100644 --- a/Common/src/dual_grid_structure.cpp +++ b/Common/src/dual_grid_structure.cpp @@ -1,551 +1,551 @@ -/*! - * \file dual_grid_structure.cpp - * \brief Main classes for defining the dual grid - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/dual_grid_structure.hpp" - -unsigned short CDualGrid::nDim = 0; - -CDualGrid::CDualGrid(unsigned short val_nDim) { nDim = val_nDim;} - -CDualGrid::~CDualGrid() {} - -CPoint::CPoint(unsigned short val_nDim, unsigned long val_globalindex, CConfig *config) : CDualGrid(val_nDim) { - unsigned short iDim, jDim; - - /*--- Element, point and edge structures initialization ---*/ - - Elem.clear(); nElem = 0; - Point.clear(); nPoint = 0; - Edge.clear(); - - Volume = NULL; Vertex = NULL; - Coord = NULL; Coord_Old = NULL; Coord_Sum = NULL; - Coord_n = NULL; Coord_n1 = NULL; Coord_p1 = NULL; - GridVel = NULL; GridVel_Grad = NULL; - - /*--- Volume (0 -> Vol_nP1, 1-> Vol_n, 2 -> Vol_nM1 ) and coordinates of the control volume ---*/ - - if (config->GetUnsteady_Simulation() == NO) { Volume = new su2double[1]; Volume[0] = 0.0; } - else { Volume = new su2double[3]; Volume[0] = 0.0; Volume[1] = 0.0; Volume[2] = 0.0; } - Coord = new su2double[nDim]; - - /*--- Indicator if the control volume has been agglomerated ---*/ - - Agglomerate = false; - - /*--- Flip the normal orientation ---*/ - - Flip_Orientation = false; - - /*--- Indicator if the point is going to be moved in a volumetric deformation ---*/ - - Move = true; - - /*--- Identify boundaries, physical boundaries (not send-receive - condition), detect if an element belong to the domain or it must - be computed with other processor ---*/ - - Boundary = false; - PhysicalBoundary = false; - SolidBoundary = false; - Domain = true; - - /*--- Set the global index in the parallel simulation ---*/ - - GlobalIndex = val_globalindex; - - /*--- Set the color for mesh partitioning ---*/ - - color = 0; - - /*--- For smoothing the numerical grid coordinates ---*/ - - if (config->GetSmoothNumGrid()) { - Coord_Old = new su2double[nDim]; - Coord_Sum = new su2double[nDim]; - } - - /*--- Storage of grid velocities for dynamic meshes ---*/ - - if (config->GetGrid_Movement()) { - GridVel = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim ++) - GridVel[iDim] = 0.0; - - /*--- Gradient of the grid velocity ---*/ - - GridVel_Grad = new su2double*[nDim]; - for (iDim = 0; iDim < nDim; iDim++) { - GridVel_Grad[iDim] = new su2double[nDim]; - for (jDim = 0; jDim < nDim; jDim++) - GridVel_Grad[iDim][jDim] = 0.0; - } - - /*--- Structures for storing old node coordinates for computing grid - velocities via finite differencing with dynamically deforming meshes. ---*/ - - if (config->GetUnsteady_Simulation() != NO) { - Coord_p1 = new su2double[nDim]; - Coord_n = new su2double[nDim]; - Coord_n1 = new su2double[nDim]; - } - } - - /*--- Intialize the value of the curvature ---*/ - - Curvature = 0.0; - -} - -CPoint::CPoint(su2double val_coord_0, su2double val_coord_1, unsigned long val_globalindex, CConfig *config) : CDualGrid(2) { - unsigned short iDim, jDim; - - /*--- Element, point and edge structures initialization ---*/ - - Elem.clear(); nElem = 0; - Point.clear(); nPoint = 0; - Edge.clear(); - - Volume = NULL; Vertex = NULL; - Coord = NULL; Coord_Old = NULL; Coord_Sum = NULL; - Coord_n = NULL; Coord_n1 = NULL; Coord_p1 = NULL; - GridVel = NULL; GridVel_Grad = NULL; - - /*--- Volume (0 -> Vol_nP1, 1-> Vol_n, 2 -> Vol_nM1 ) and coordinates of the control volume ---*/ - - if (config->GetUnsteady_Simulation() == NO) { Volume = new su2double[1]; Volume[0] = 0.0; } - else { Volume = new su2double[3]; Volume[0] = 0.0; Volume[1] = 0.0; Volume[2] = 0.0; } - Coord = new su2double[nDim]; Coord[0] = val_coord_0; Coord[1] = val_coord_1; - - /*--- Indicator if the control volume has been agglomerated ---*/ - - Agglomerate = false; - - /*--- Flip the normal orientation ---*/ - - Flip_Orientation = false; - - /*--- Indicator if the point is going to be moved in a volumetric deformation ---*/ - - Move = true; - - /*--- Identify boundaries, physical boundaries (not send-receive - condition), detect if an element belong to the domain or it must - be computed with other processor ---*/ - - Boundary = false; - PhysicalBoundary = false; - SolidBoundary = false; - Domain = true; - - /*--- Set the color for mesh partitioning ---*/ - - color = 0; - - /*--- Set the global index in the parallel simulation ---*/ - - GlobalIndex = val_globalindex; - - /*--- For smoothing the numerical grid coordinates ---*/ - - if (config->GetSmoothNumGrid()) { - Coord_Old = new su2double[nDim]; - Coord_Sum = new su2double[nDim]; - } - - /*--- Storage of grid velocities for dynamic meshes ---*/ - - if (config->GetGrid_Movement()) { - GridVel = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim ++) - GridVel[iDim] = 0.0; - - /*--- Gradient of the grid velocity ---*/ - - GridVel_Grad = new su2double*[nDim]; - for (iDim = 0; iDim < nDim; iDim++) { - GridVel_Grad[iDim] = new su2double[nDim]; - for (jDim = 0; jDim < nDim; jDim++) - GridVel_Grad[iDim][jDim] = 0.0; - } - - /*--- Structures for storing old node coordinates for computing grid - velocities via finite differencing with dynamically deforming meshes. ---*/ - - if (config->GetUnsteady_Simulation() != NO) { - Coord_p1 = new su2double[nDim]; - Coord_n = new su2double[nDim]; - Coord_n1 = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim ++) { - Coord_p1[iDim] = Coord[iDim]; - Coord_n[iDim] = Coord[iDim]; - Coord_n1[iDim] = Coord[iDim]; - } - } - } - - /*--- Intialize the value of the curvature ---*/ - - Curvature = 0.0; - -} - -CPoint::CPoint(su2double val_coord_0, su2double val_coord_1, su2double val_coord_2, unsigned long val_globalindex, CConfig *config) : CDualGrid(3) { - unsigned short iDim, jDim; - - /*--- Element, point and edge structures initialization ---*/ - - Elem.clear(); nElem = 0; - Point.clear(); nPoint = 0; - Edge.clear(); - - Volume = NULL; Vertex = NULL; - Coord = NULL; Coord_Old = NULL; Coord_Sum = NULL; - Coord_n = NULL; Coord_n1 = NULL; Coord_p1 = NULL; - GridVel = NULL; GridVel_Grad = NULL; - - /*--- Volume (0 -> Vol_nP1, 1-> Vol_n, 2 -> Vol_nM1 ) and coordinates of the control volume ---*/ - - if (config->GetUnsteady_Simulation() == NO) { Volume = new su2double[1]; Volume[0] = 0.0; } - else { Volume = new su2double[3]; Volume[0] = 0.0; Volume[1] = 0.0; Volume[2] = 0.0; } - Coord = new su2double[nDim]; Coord[0] = val_coord_0; Coord[1] = val_coord_1; Coord[2] = val_coord_2; - - /*--- Indicator if the control volume has been agglomerated ---*/ - - Agglomerate = false; - - /*--- Indicator if the point is going to be moved in a volumetric deformation ---*/ - - Move = true; - - /*--- Flip the normal orientation ---*/ - - Flip_Orientation = false; - - /*--- Identify boundaries, physical boundaries (not send-receive - condition), detect if an element belong to the domain or it must - be computed with other processor ---*/ - - Boundary = false; - PhysicalBoundary = false; - SolidBoundary = false; - Domain = true; - - /*--- Set the color for mesh partitioning ---*/ - - color = 0; - - /*--- Set the global index in the parallel simulation ---*/ - - GlobalIndex = val_globalindex; - - /*--- For smoothing the numerical grid coordinates ---*/ - - if (config->GetSmoothNumGrid()) { - Coord_Old = new su2double[nDim]; - Coord_Sum = new su2double[nDim]; - } - - /*--- Storage of grid velocities for dynamic meshes ---*/ - - if (config->GetGrid_Movement()) { - GridVel = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim ++) - GridVel[iDim] = 0.0; - - /*--- Gradient of the grid velocity ---*/ - - GridVel_Grad = new su2double*[nDim]; - for (iDim = 0; iDim < nDim; iDim++) { - GridVel_Grad[iDim] = new su2double[nDim]; - for (jDim = 0; jDim < nDim; jDim++) - GridVel_Grad[iDim][jDim] = 0.0; - } - - /*--- Structures for storing old node coordinates for computing grid - velocities via finite differencing with dynamically deforming meshes. ---*/ - - if (config->GetUnsteady_Simulation() != NO) { - Coord_p1 = new su2double[nDim]; - Coord_n = new su2double[nDim]; - Coord_n1 = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim ++) { - Coord_p1[iDim] = Coord[iDim]; - Coord_n[iDim] = Coord[iDim]; - Coord_n1[iDim] = Coord[iDim]; - } - } - } - - /*--- Intialize the value of the curvature ---*/ - - Curvature = 0.0; - -} - -CPoint::~CPoint() { - - Elem.~vector(); - Point.~vector(); - Edge.~vector(); - Children_CV.~vector(); - - if (Volume != NULL) delete[] Volume; - if (Vertex != NULL) delete[] Vertex; - if (Coord != NULL) delete[] Coord; - if (Coord_Old != NULL) delete[] Coord_Old; - if (Coord_Sum != NULL) delete[] Coord_Sum; - if (Coord_n != NULL) delete[] Coord_n; - if (Coord_n1 != NULL) delete[] Coord_n1; - if (Coord_p1 != NULL) delete[] Coord_p1; - if (GridVel != NULL) delete[] GridVel; - if (GridVel_Grad != NULL) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - delete [] GridVel_Grad[iDim]; - delete [] GridVel_Grad; - } - -} - -void CPoint::SetPoint(unsigned long val_point) { - unsigned short iPoint; - bool new_point; - - /*--- Look for the point in the list ---*/ - - new_point = true; - for (iPoint = 0; iPoint < GetnPoint(); iPoint++) - if (Point[iPoint] == val_point) { - new_point = false; - break; - } - - /*--- Store the point structure and dimensionalizate edge structure ---*/ - - if (new_point) { - Point.push_back(val_point); - Edge.push_back(-1); - nPoint = Point.size(); - } -} - -void CPoint::SetBoundary(unsigned short val_nmarker) { - unsigned short imarker; - - /*--- To be sure that we are not goint to initializate twice the same vertex ---*/ - - if (!Boundary) { - Vertex = new long[val_nmarker]; - - /*--- The initialization is made with -1 ---*/ - - for (imarker = 0; imarker < val_nmarker; imarker++) - Vertex[imarker] = -1; - } - Boundary = true; - -} - -CEdge::CEdge(unsigned long val_iPoint, unsigned long val_jPoint, unsigned short val_nDim) : CDualGrid(val_nDim) { - unsigned short iDim; - - /*--- Pointers initialization ---*/ - - Coord_CG = NULL; - Normal = NULL; - Nodes = NULL; - - /*--- Allocate center of gravity coordinates, nodes, and face normal ---*/ - - Coord_CG = new su2double[nDim]; - Nodes = new unsigned long[2]; - Normal = new su2double [nDim]; - - /*--- Initializate the structure ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - Coord_CG[iDim] = 0.0; - Normal[iDim] = 0.0; - } - - Nodes[0] = val_iPoint; - Nodes[1] = val_jPoint; - -} - -CEdge::~CEdge() { - - if (Coord_CG != NULL) delete[] Coord_CG; - if (Normal != NULL) delete[] Normal; - if (Nodes != NULL) delete[] Nodes; - -} - -void CEdge::SetCoord_CG(su2double **val_coord) { - unsigned short iDim, iNode; - - for (iDim = 0; iDim < nDim; iDim++) { - Coord_CG[iDim] = 0.0; - for (iNode = 0; iNode < 2; iNode++) - Coord_CG[iDim] += val_coord[iNode][iDim]/2.0; - } -} - -su2double CEdge::GetVolume(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG, su2double *val_coord_Point) { - unsigned short iDim; - su2double vec_a[3] = {0.0,0.0,0.0}, vec_b[3] = {0.0,0.0,0.0}, vec_c[3] = {0.0,0.0,0.0}, vec_d[3] = {0.0,0.0,0.0}, Local_Volume; - - for (iDim = 0; iDim < nDim; iDim++) { - vec_a[iDim] = val_coord_Edge_CG[iDim]-val_coord_Point[iDim]; - vec_b[iDim] = val_coord_FaceElem_CG[iDim]-val_coord_Point[iDim]; - vec_c[iDim] = val_coord_Elem_CG[iDim]-val_coord_Point[iDim]; - } - - vec_d[0] = vec_a[1]*vec_b[2]-vec_a[2]*vec_b[1]; - vec_d[1] = -(vec_a[0]*vec_b[2]-vec_a[2]*vec_b[0]); - vec_d[2] = vec_a[0]*vec_b[1]-vec_a[1]*vec_b[0]; - - Local_Volume = fabs(vec_c[0]*vec_d[0] + vec_c[1]*vec_d[1] + vec_c[2]*vec_d[2])/6.0; - - return Local_Volume; -} - -su2double CEdge::GetVolume(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG, su2double *val_coord_Point) { - unsigned short iDim; - su2double vec_a[2] = {0.0,0.0}, vec_b[2] = {0.0,0.0}, Local_Volume; - - for (iDim = 0; iDim < nDim; iDim++) { - vec_a[iDim] = val_coord_Elem_CG[iDim]-val_coord_Point[iDim]; - vec_b[iDim] = val_coord_Edge_CG[iDim]-val_coord_Point[iDim]; - } - - Local_Volume = 0.5*fabs(vec_a[0]*vec_b[1]-vec_a[1]*vec_b[0]); - - return Local_Volume; -} - -void CEdge::SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG) { - unsigned short iDim; - su2double vec_a[3] = {0.0,0.0,0.0}, vec_b[3] = {0.0,0.0,0.0}, Dim_Normal[3]; - - for (iDim = 0; iDim < nDim; iDim++) { - vec_a[iDim] = val_coord_Elem_CG[iDim]-val_coord_Edge_CG[iDim]; - vec_b[iDim] = val_coord_FaceElem_CG[iDim]-val_coord_Edge_CG[iDim]; - } - - Dim_Normal[0] = 0.5*(vec_a[1]*vec_b[2]-vec_a[2]*vec_b[1]); - Dim_Normal[1] = -0.5*(vec_a[0]*vec_b[2]-vec_a[2]*vec_b[0]); - Dim_Normal[2] = 0.5*(vec_a[0]*vec_b[1]-vec_a[1]*vec_b[0]); - - Normal[0] += Dim_Normal[0]; - Normal[1] += Dim_Normal[1]; - Normal[2] += Dim_Normal[2]; - -} - -void CEdge::SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG) { - su2double Dim_Normal[2]; - - Dim_Normal[0] = val_coord_Elem_CG[1]-val_coord_Edge_CG[1]; - Dim_Normal[1] = -(val_coord_Elem_CG[0]-val_coord_Edge_CG[0]); - - Normal[0] += Dim_Normal[0]; - Normal[1] += Dim_Normal[1]; - -} - -CVertex::CVertex(unsigned long val_point, unsigned short val_nDim) : CDualGrid(val_nDim) { - unsigned short iDim; - - /*--- Pointers initialization ---*/ - - Nodes = NULL; - Normal = NULL; - - /*--- Allocate node, and face normal ---*/ - - Nodes = new unsigned long[1]; - Normal = new su2double [nDim]; - - /*--- Initializate the structure ---*/ - - Nodes[0] = val_point; - for (iDim = 0; iDim < nDim; iDim ++) Normal[iDim] = 0.0; - - /*--- Set to zero the variation of the coordinates ---*/ - - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - -} - -CVertex::~CVertex() { - - if (Normal != NULL) delete[] Normal; - if (Nodes != NULL) delete[] Nodes; - -} - -void CVertex::SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG) { - su2double vec_a[3] = {0.0,0.0,0.0}, vec_b[3] = {0.0,0.0,0.0}, Dim_Normal[3] = {0.0,0.0,0.0}; - unsigned short iDim; - - for (iDim = 0; iDim < nDim; iDim++) { - vec_a[iDim] = val_coord_Elem_CG[iDim]-val_coord_Edge_CG[iDim]; - vec_b[iDim] = val_coord_FaceElem_CG[iDim]-val_coord_Edge_CG[iDim]; - } - - Dim_Normal[0] = 0.5*(vec_a[1]*vec_b[2]-vec_a[2]*vec_b[1]); - Dim_Normal[1] = -0.5*(vec_a[0]*vec_b[2]-vec_a[2]*vec_b[0]); - Dim_Normal[2] = 0.5*(vec_a[0]*vec_b[1]-vec_a[1]*vec_b[0]); - - Normal[0] += Dim_Normal[0]; - Normal[1] += Dim_Normal[1]; - Normal[2] += Dim_Normal[2]; - -} - -void CVertex::SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG) { - su2double Dim_Normal[2]; - - Dim_Normal[0] = val_coord_Elem_CG[1]-val_coord_Edge_CG[1]; - Dim_Normal[1] = -(val_coord_Elem_CG[0]-val_coord_Edge_CG[0]); - - Normal[0] += Dim_Normal[0]; - Normal[1] += Dim_Normal[1]; - -} - -void CVertex::AddNormal(su2double *val_face_normal) { - - Normal[0] += val_face_normal[0]; - Normal[1] += val_face_normal[1]; - if (nDim == 3) Normal[2] += val_face_normal[2]; -} +/*! + * \file dual_grid_structure.cpp + * \brief Main classes for defining the dual grid + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/dual_grid_structure.hpp" + +unsigned short CDualGrid::nDim = 0; + +CDualGrid::CDualGrid(unsigned short val_nDim) { nDim = val_nDim;} + +CDualGrid::~CDualGrid() {} + +CPoint::CPoint(unsigned short val_nDim, unsigned long val_globalindex, CConfig *config) : CDualGrid(val_nDim) { + unsigned short iDim, jDim; + + /*--- Element, point and edge structures initialization ---*/ + + Elem.clear(); nElem = 0; + Point.clear(); nPoint = 0; + Edge.clear(); + + Volume = NULL; Vertex = NULL; + Coord = NULL; Coord_Old = NULL; Coord_Sum = NULL; + Coord_n = NULL; Coord_n1 = NULL; Coord_p1 = NULL; + GridVel = NULL; GridVel_Grad = NULL; + + /*--- Volume (0 -> Vol_nP1, 1-> Vol_n, 2 -> Vol_nM1 ) and coordinates of the control volume ---*/ + + if (config->GetUnsteady_Simulation() == NO) { Volume = new su2double[1]; Volume[0] = 0.0; } + else { Volume = new su2double[3]; Volume[0] = 0.0; Volume[1] = 0.0; Volume[2] = 0.0; } + Coord = new su2double[nDim]; + + /*--- Indicator if the control volume has been agglomerated ---*/ + + Agglomerate = false; + + /*--- Flip the normal orientation ---*/ + + Flip_Orientation = false; + + /*--- Indicator if the point is going to be moved in a volumetric deformation ---*/ + + Move = true; + + /*--- Identify boundaries, physical boundaries (not send-receive + condition), detect if an element belong to the domain or it must + be computed with other processor ---*/ + + Boundary = false; + PhysicalBoundary = false; + SolidBoundary = false; + Domain = true; + + /*--- Set the global index in the parallel simulation ---*/ + + GlobalIndex = val_globalindex; + + /*--- Set the color for mesh partitioning ---*/ + + color = 0; + + /*--- For smoothing the numerical grid coordinates ---*/ + + if (config->GetSmoothNumGrid()) { + Coord_Old = new su2double[nDim]; + Coord_Sum = new su2double[nDim]; + } + + /*--- Storage of grid velocities for dynamic meshes ---*/ + + if (config->GetGrid_Movement()) { + GridVel = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim ++) + GridVel[iDim] = 0.0; + + /*--- Gradient of the grid velocity ---*/ + + GridVel_Grad = new su2double*[nDim]; + for (iDim = 0; iDim < nDim; iDim++) { + GridVel_Grad[iDim] = new su2double[nDim]; + for (jDim = 0; jDim < nDim; jDim++) + GridVel_Grad[iDim][jDim] = 0.0; + } + + /*--- Structures for storing old node coordinates for computing grid + velocities via finite differencing with dynamically deforming meshes. ---*/ + + if (config->GetUnsteady_Simulation() != NO) { + Coord_p1 = new su2double[nDim]; + Coord_n = new su2double[nDim]; + Coord_n1 = new su2double[nDim]; + } + } + + /*--- Intialize the value of the curvature ---*/ + + Curvature = 0.0; + +} + +CPoint::CPoint(su2double val_coord_0, su2double val_coord_1, unsigned long val_globalindex, CConfig *config) : CDualGrid(2) { + unsigned short iDim, jDim; + + /*--- Element, point and edge structures initialization ---*/ + + Elem.clear(); nElem = 0; + Point.clear(); nPoint = 0; + Edge.clear(); + + Volume = NULL; Vertex = NULL; + Coord = NULL; Coord_Old = NULL; Coord_Sum = NULL; + Coord_n = NULL; Coord_n1 = NULL; Coord_p1 = NULL; + GridVel = NULL; GridVel_Grad = NULL; + + /*--- Volume (0 -> Vol_nP1, 1-> Vol_n, 2 -> Vol_nM1 ) and coordinates of the control volume ---*/ + + if (config->GetUnsteady_Simulation() == NO) { Volume = new su2double[1]; Volume[0] = 0.0; } + else { Volume = new su2double[3]; Volume[0] = 0.0; Volume[1] = 0.0; Volume[2] = 0.0; } + Coord = new su2double[nDim]; Coord[0] = val_coord_0; Coord[1] = val_coord_1; + + /*--- Indicator if the control volume has been agglomerated ---*/ + + Agglomerate = false; + + /*--- Flip the normal orientation ---*/ + + Flip_Orientation = false; + + /*--- Indicator if the point is going to be moved in a volumetric deformation ---*/ + + Move = true; + + /*--- Identify boundaries, physical boundaries (not send-receive + condition), detect if an element belong to the domain or it must + be computed with other processor ---*/ + + Boundary = false; + PhysicalBoundary = false; + SolidBoundary = false; + Domain = true; + + /*--- Set the color for mesh partitioning ---*/ + + color = 0; + + /*--- Set the global index in the parallel simulation ---*/ + + GlobalIndex = val_globalindex; + + /*--- For smoothing the numerical grid coordinates ---*/ + + if (config->GetSmoothNumGrid()) { + Coord_Old = new su2double[nDim]; + Coord_Sum = new su2double[nDim]; + } + + /*--- Storage of grid velocities for dynamic meshes ---*/ + + if (config->GetGrid_Movement()) { + GridVel = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim ++) + GridVel[iDim] = 0.0; + + /*--- Gradient of the grid velocity ---*/ + + GridVel_Grad = new su2double*[nDim]; + for (iDim = 0; iDim < nDim; iDim++) { + GridVel_Grad[iDim] = new su2double[nDim]; + for (jDim = 0; jDim < nDim; jDim++) + GridVel_Grad[iDim][jDim] = 0.0; + } + + /*--- Structures for storing old node coordinates for computing grid + velocities via finite differencing with dynamically deforming meshes. ---*/ + + if (config->GetUnsteady_Simulation() != NO) { + Coord_p1 = new su2double[nDim]; + Coord_n = new su2double[nDim]; + Coord_n1 = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim ++) { + Coord_p1[iDim] = Coord[iDim]; + Coord_n[iDim] = Coord[iDim]; + Coord_n1[iDim] = Coord[iDim]; + } + } + } + + /*--- Intialize the value of the curvature ---*/ + + Curvature = 0.0; + +} + +CPoint::CPoint(su2double val_coord_0, su2double val_coord_1, su2double val_coord_2, unsigned long val_globalindex, CConfig *config) : CDualGrid(3) { + unsigned short iDim, jDim; + + /*--- Element, point and edge structures initialization ---*/ + + Elem.clear(); nElem = 0; + Point.clear(); nPoint = 0; + Edge.clear(); + + Volume = NULL; Vertex = NULL; + Coord = NULL; Coord_Old = NULL; Coord_Sum = NULL; + Coord_n = NULL; Coord_n1 = NULL; Coord_p1 = NULL; + GridVel = NULL; GridVel_Grad = NULL; + + /*--- Volume (0 -> Vol_nP1, 1-> Vol_n, 2 -> Vol_nM1 ) and coordinates of the control volume ---*/ + + if (config->GetUnsteady_Simulation() == NO) { Volume = new su2double[1]; Volume[0] = 0.0; } + else { Volume = new su2double[3]; Volume[0] = 0.0; Volume[1] = 0.0; Volume[2] = 0.0; } + Coord = new su2double[nDim]; Coord[0] = val_coord_0; Coord[1] = val_coord_1; Coord[2] = val_coord_2; + + /*--- Indicator if the control volume has been agglomerated ---*/ + + Agglomerate = false; + + /*--- Indicator if the point is going to be moved in a volumetric deformation ---*/ + + Move = true; + + /*--- Flip the normal orientation ---*/ + + Flip_Orientation = false; + + /*--- Identify boundaries, physical boundaries (not send-receive + condition), detect if an element belong to the domain or it must + be computed with other processor ---*/ + + Boundary = false; + PhysicalBoundary = false; + SolidBoundary = false; + Domain = true; + + /*--- Set the color for mesh partitioning ---*/ + + color = 0; + + /*--- Set the global index in the parallel simulation ---*/ + + GlobalIndex = val_globalindex; + + /*--- For smoothing the numerical grid coordinates ---*/ + + if (config->GetSmoothNumGrid()) { + Coord_Old = new su2double[nDim]; + Coord_Sum = new su2double[nDim]; + } + + /*--- Storage of grid velocities for dynamic meshes ---*/ + + if (config->GetGrid_Movement()) { + GridVel = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim ++) + GridVel[iDim] = 0.0; + + /*--- Gradient of the grid velocity ---*/ + + GridVel_Grad = new su2double*[nDim]; + for (iDim = 0; iDim < nDim; iDim++) { + GridVel_Grad[iDim] = new su2double[nDim]; + for (jDim = 0; jDim < nDim; jDim++) + GridVel_Grad[iDim][jDim] = 0.0; + } + + /*--- Structures for storing old node coordinates for computing grid + velocities via finite differencing with dynamically deforming meshes. ---*/ + + if (config->GetUnsteady_Simulation() != NO) { + Coord_p1 = new su2double[nDim]; + Coord_n = new su2double[nDim]; + Coord_n1 = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim ++) { + Coord_p1[iDim] = Coord[iDim]; + Coord_n[iDim] = Coord[iDim]; + Coord_n1[iDim] = Coord[iDim]; + } + } + } + + /*--- Intialize the value of the curvature ---*/ + + Curvature = 0.0; + +} + +CPoint::~CPoint() { + + Elem.~vector(); + Point.~vector(); + Edge.~vector(); + Children_CV.~vector(); + + if (Volume != NULL) delete[] Volume; + if (Vertex != NULL) delete[] Vertex; + if (Coord != NULL) delete[] Coord; + if (Coord_Old != NULL) delete[] Coord_Old; + if (Coord_Sum != NULL) delete[] Coord_Sum; + if (Coord_n != NULL) delete[] Coord_n; + if (Coord_n1 != NULL) delete[] Coord_n1; + if (Coord_p1 != NULL) delete[] Coord_p1; + if (GridVel != NULL) delete[] GridVel; + if (GridVel_Grad != NULL) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + delete [] GridVel_Grad[iDim]; + delete [] GridVel_Grad; + } + +} + +void CPoint::SetPoint(unsigned long val_point) { + unsigned short iPoint; + bool new_point; + + /*--- Look for the point in the list ---*/ + + new_point = true; + for (iPoint = 0; iPoint < GetnPoint(); iPoint++) + if (Point[iPoint] == val_point) { + new_point = false; + break; + } + + /*--- Store the point structure and dimensionalizate edge structure ---*/ + + if (new_point) { + Point.push_back(val_point); + Edge.push_back(-1); + nPoint = Point.size(); + } +} + +void CPoint::SetBoundary(unsigned short val_nmarker) { + unsigned short imarker; + + /*--- To be sure that we are not goint to initializate twice the same vertex ---*/ + + if (!Boundary) { + Vertex = new long[val_nmarker]; + + /*--- The initialization is made with -1 ---*/ + + for (imarker = 0; imarker < val_nmarker; imarker++) + Vertex[imarker] = -1; + } + Boundary = true; + +} + +CEdge::CEdge(unsigned long val_iPoint, unsigned long val_jPoint, unsigned short val_nDim) : CDualGrid(val_nDim) { + unsigned short iDim; + + /*--- Pointers initialization ---*/ + + Coord_CG = NULL; + Normal = NULL; + Nodes = NULL; + + /*--- Allocate center of gravity coordinates, nodes, and face normal ---*/ + + Coord_CG = new su2double[nDim]; + Nodes = new unsigned long[2]; + Normal = new su2double [nDim]; + + /*--- Initializate the structure ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + Coord_CG[iDim] = 0.0; + Normal[iDim] = 0.0; + } + + Nodes[0] = val_iPoint; + Nodes[1] = val_jPoint; + +} + +CEdge::~CEdge() { + + if (Coord_CG != NULL) delete[] Coord_CG; + if (Normal != NULL) delete[] Normal; + if (Nodes != NULL) delete[] Nodes; + +} + +void CEdge::SetCoord_CG(su2double **val_coord) { + unsigned short iDim, iNode; + + for (iDim = 0; iDim < nDim; iDim++) { + Coord_CG[iDim] = 0.0; + for (iNode = 0; iNode < 2; iNode++) + Coord_CG[iDim] += val_coord[iNode][iDim]/2.0; + } +} + +su2double CEdge::GetVolume(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG, su2double *val_coord_Point) { + unsigned short iDim; + su2double vec_a[3] = {0.0,0.0,0.0}, vec_b[3] = {0.0,0.0,0.0}, vec_c[3] = {0.0,0.0,0.0}, vec_d[3] = {0.0,0.0,0.0}, Local_Volume; + + for (iDim = 0; iDim < nDim; iDim++) { + vec_a[iDim] = val_coord_Edge_CG[iDim]-val_coord_Point[iDim]; + vec_b[iDim] = val_coord_FaceElem_CG[iDim]-val_coord_Point[iDim]; + vec_c[iDim] = val_coord_Elem_CG[iDim]-val_coord_Point[iDim]; + } + + vec_d[0] = vec_a[1]*vec_b[2]-vec_a[2]*vec_b[1]; + vec_d[1] = -(vec_a[0]*vec_b[2]-vec_a[2]*vec_b[0]); + vec_d[2] = vec_a[0]*vec_b[1]-vec_a[1]*vec_b[0]; + + Local_Volume = fabs(vec_c[0]*vec_d[0] + vec_c[1]*vec_d[1] + vec_c[2]*vec_d[2])/6.0; + + return Local_Volume; +} + +su2double CEdge::GetVolume(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG, su2double *val_coord_Point) { + unsigned short iDim; + su2double vec_a[2] = {0.0,0.0}, vec_b[2] = {0.0,0.0}, Local_Volume; + + for (iDim = 0; iDim < nDim; iDim++) { + vec_a[iDim] = val_coord_Elem_CG[iDim]-val_coord_Point[iDim]; + vec_b[iDim] = val_coord_Edge_CG[iDim]-val_coord_Point[iDim]; + } + + Local_Volume = 0.5*fabs(vec_a[0]*vec_b[1]-vec_a[1]*vec_b[0]); + + return Local_Volume; +} + +void CEdge::SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG) { + unsigned short iDim; + su2double vec_a[3] = {0.0,0.0,0.0}, vec_b[3] = {0.0,0.0,0.0}, Dim_Normal[3]; + + for (iDim = 0; iDim < nDim; iDim++) { + vec_a[iDim] = val_coord_Elem_CG[iDim]-val_coord_Edge_CG[iDim]; + vec_b[iDim] = val_coord_FaceElem_CG[iDim]-val_coord_Edge_CG[iDim]; + } + + Dim_Normal[0] = 0.5*(vec_a[1]*vec_b[2]-vec_a[2]*vec_b[1]); + Dim_Normal[1] = -0.5*(vec_a[0]*vec_b[2]-vec_a[2]*vec_b[0]); + Dim_Normal[2] = 0.5*(vec_a[0]*vec_b[1]-vec_a[1]*vec_b[0]); + + Normal[0] += Dim_Normal[0]; + Normal[1] += Dim_Normal[1]; + Normal[2] += Dim_Normal[2]; + +} + +void CEdge::SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG) { + su2double Dim_Normal[2]; + + Dim_Normal[0] = val_coord_Elem_CG[1]-val_coord_Edge_CG[1]; + Dim_Normal[1] = -(val_coord_Elem_CG[0]-val_coord_Edge_CG[0]); + + Normal[0] += Dim_Normal[0]; + Normal[1] += Dim_Normal[1]; + +} + +CVertex::CVertex(unsigned long val_point, unsigned short val_nDim) : CDualGrid(val_nDim) { + unsigned short iDim; + + /*--- Pointers initialization ---*/ + + Nodes = NULL; + Normal = NULL; + + /*--- Allocate node, and face normal ---*/ + + Nodes = new unsigned long[1]; + Normal = new su2double [nDim]; + + /*--- Initializate the structure ---*/ + + Nodes[0] = val_point; + for (iDim = 0; iDim < nDim; iDim ++) Normal[iDim] = 0.0; + + /*--- Set to zero the variation of the coordinates ---*/ + + VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; + +} + +CVertex::~CVertex() { + + if (Normal != NULL) delete[] Normal; + if (Nodes != NULL) delete[] Nodes; + +} + +void CVertex::SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG) { + su2double vec_a[3] = {0.0,0.0,0.0}, vec_b[3] = {0.0,0.0,0.0}, Dim_Normal[3] = {0.0,0.0,0.0}; + unsigned short iDim; + + for (iDim = 0; iDim < nDim; iDim++) { + vec_a[iDim] = val_coord_Elem_CG[iDim]-val_coord_Edge_CG[iDim]; + vec_b[iDim] = val_coord_FaceElem_CG[iDim]-val_coord_Edge_CG[iDim]; + } + + Dim_Normal[0] = 0.5*(vec_a[1]*vec_b[2]-vec_a[2]*vec_b[1]); + Dim_Normal[1] = -0.5*(vec_a[0]*vec_b[2]-vec_a[2]*vec_b[0]); + Dim_Normal[2] = 0.5*(vec_a[0]*vec_b[1]-vec_a[1]*vec_b[0]); + + Normal[0] += Dim_Normal[0]; + Normal[1] += Dim_Normal[1]; + Normal[2] += Dim_Normal[2]; + +} + +void CVertex::SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_Elem_CG) { + su2double Dim_Normal[2]; + + Dim_Normal[0] = val_coord_Elem_CG[1]-val_coord_Edge_CG[1]; + Dim_Normal[1] = -(val_coord_Elem_CG[0]-val_coord_Edge_CG[0]); + + Normal[0] += Dim_Normal[0]; + Normal[1] += Dim_Normal[1]; + +} + +void CVertex::AddNormal(su2double *val_face_normal) { + + Normal[0] += val_face_normal[0]; + Normal[1] += val_face_normal[1]; + if (nDim == 3) Normal[2] += val_face_normal[2]; +} diff --git a/Common/src/geometry_structure.cpp b/Common/src/geometry_structure.cpp index 26cebd0187c..9612047adb0 100644 --- a/Common/src/geometry_structure.cpp +++ b/Common/src/geometry_structure.cpp @@ -1,15251 +1,15251 @@ -/*! - * \file geometry_structure.cpp - * \brief Main subroutines for creating the primal grid and multigrid structure. - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#include "../include/geometry_structure.hpp" - -/*--- Epsilon definition ---*/ - -#define EPSILON 0.000001 - -/*--- Cross product ---*/ - -#define CROSS(dest,v1,v2) \ -(dest)[0] = (v1)[1]*(v2)[2] - (v1)[2]*(v2)[1]; \ -(dest)[1] = (v1)[2]*(v2)[0] - (v1)[0]*(v2)[2]; \ -(dest)[2] = (v1)[0]*(v2)[1] - (v1)[1]*(v2)[0]; - -/*--- Cross product ---*/ - -#define DOT(v1,v2) ((v1)[0]*(v2)[0] + (v1)[1]*(v2)[1] + (v1)[2]*(v2)[2]); - -/*--- a = b - c ---*/ - -#define SUB(dest,v1,v2) \ -(dest)[0] = (v1)[0] - (v2)[0]; \ -(dest)[1] = (v1)[1] - (v2)[1]; \ -(dest)[2] = (v1)[2] - (v2)[2]; - -CGeometry::CGeometry(void) { - - nEdge = 0; - nPoint = 0; - nElem = 0; - - nElem_Bound = NULL; - Tag_to_Marker = NULL; - elem = NULL; - face = NULL; - bound = NULL; - node = NULL; - edge = NULL; - vertex = NULL; - nVertex = NULL; - newBound = NULL; - nNewElem_Bound = NULL; - Marker_All_SendRecv = NULL; - - // PeriodicPoint[MAX_NUMBER_PERIODIC][2].clear(); - // PeriodicElem[MAX_NUMBER_PERIODIC].clear(); - // XCoordList.clear(); - - // Xcoord_plane.clear(); - // Ycoord_plane.clear(); - // Zcoord_plane.clear(); - // FaceArea_plane.clear(); - // Plane_points.clear(); - -} - -CGeometry::~CGeometry(void) { - - unsigned long iElem, iElem_Bound, iFace, iVertex, iEdge; - unsigned short iMarker; - - if (elem != NULL) { - for (iElem = 0; iElem < nElem; iElem++) - if (elem[iElem] != NULL) delete elem[iElem]; - delete[] elem; - } - - if (bound != NULL) { - for (iMarker = 0; iMarker < nMarker; iMarker++) { - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - if (bound[iMarker][iElem_Bound] != NULL) delete bound[iMarker][iElem_Bound]; - } - } - delete[] bound; - } - - if (face != NULL) { - for (iFace = 0; iFace < nFace; iFace ++) - if (face[iFace] != NULL) delete face[iFace]; - delete[] face; - } - -// if (node != NULL) { -// for (iPoint = 0; iPoint < nPoint; iPoint ++) -// if (node[iPoint] != NULL) delete node[iPoint]; -// delete[] node; -// } - - if (edge != NULL) { - for (iEdge = 0; iEdge < nEdge; iEdge ++) - if (edge[iEdge] != NULL) delete [] edge[iEdge]; - delete[] edge; - } - - if (vertex != NULL) { - for (iMarker = 0; iMarker < nMarker; iMarker++) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - if (vertex[iMarker][iVertex] != NULL) delete [] vertex[iMarker][iVertex]; - } - } - delete[] vertex; - } - - if (newBound != NULL) { - for (iMarker = 0; iMarker < nMarker; iMarker++) { - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - if (newBound[iMarker][iElem_Bound] != NULL) delete [] newBound[iMarker][iElem_Bound]; - } - } - delete[] newBound; - } - - if (nElem_Bound != NULL) delete[] nElem_Bound; - if (nVertex != NULL) delete[] nVertex; - if (nNewElem_Bound != NULL) delete[] nNewElem_Bound; - if (Marker_All_SendRecv != NULL) delete[] Marker_All_SendRecv; - if (Tag_to_Marker != NULL) delete[] Tag_to_Marker; - - // PeriodicPoint[MAX_NUMBER_PERIODIC][2].~vector(); - // PeriodicElem[MAX_NUMBER_PERIODIC].~vector(); - // XCoordList.~vector(); - - // Xcoord_plane.~vector() - // Ycoord_plane.~vector() - // Zcoord_plane.~vector() - // FaceArea_plane.~vector() - // Plane_points.~vector() - -} - -su2double CGeometry::Point2Plane_Distance(su2double *Coord, su2double *iCoord, su2double *jCoord, su2double *kCoord) { - su2double CrossProduct[3], iVector[3], jVector[3], distance, modulus; - unsigned short iDim; - - for (iDim = 0; iDim < 3; iDim ++) { - iVector[iDim] = jCoord[iDim] - iCoord[iDim]; - jVector[iDim] = kCoord[iDim] - iCoord[iDim]; - } - - CrossProduct[0] = iVector[1]*jVector[2] - iVector[2]*jVector[1]; - CrossProduct[1] = iVector[2]*jVector[0] - iVector[0]*jVector[2]; - CrossProduct[2] = iVector[0]*jVector[1] - iVector[1]*jVector[0]; - - modulus = sqrt(CrossProduct[0]*CrossProduct[0]+CrossProduct[1]*CrossProduct[1]+CrossProduct[2]*CrossProduct[2]); - - distance = 0.0; - for (iDim = 0; iDim < 3; iDim ++) - distance += CrossProduct[iDim]*(Coord[iDim]-iCoord[iDim]); - distance /= modulus; - - return distance; - -} - -long CGeometry::FindEdge(unsigned long first_point, unsigned long second_point) { - unsigned long iPoint = 0; - unsigned short iNode; - for (iNode = 0; iNode < node[first_point]->GetnPoint(); iNode++) { - iPoint = node[first_point]->GetPoint(iNode); - if (iPoint == second_point) break; - } - - if (iPoint == second_point) return node[first_point]->GetEdge(iNode); - else { - cout << "\n\n !!! Error !!!\n" << endl; - cout <<"Can't find the edge that connects "<< first_point <<" and "<< second_point <<"."<< endl; - exit(EXIT_FAILURE); - return -1; - } -} - -bool CGeometry::CheckEdge(unsigned long first_point, unsigned long second_point) { - unsigned long iPoint = 0; - unsigned short iNode; - for (iNode = 0; iNode < node[first_point]->GetnPoint(); iNode++) { - iPoint = node[first_point]->GetPoint(iNode); - if (iPoint == second_point) break; - } - - if (iPoint == second_point) return true; - else return false; - -} - -void CGeometry::SetEdges(void) { - unsigned long iPoint, jPoint; - long iEdge; - unsigned short jNode, iNode; - long TestEdge = 0; - - nEdge = 0; - for (iPoint = 0; iPoint < nPoint; iPoint++) - for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) { - jPoint = node[iPoint]->GetPoint(iNode); - for (jNode = 0; jNode < node[jPoint]->GetnPoint(); jNode++) - if (node[jPoint]->GetPoint(jNode) == iPoint) { - TestEdge = node[jPoint]->GetEdge(jNode); - break; - } - if (TestEdge == -1) { - node[iPoint]->SetEdge(nEdge, iNode); - node[jPoint]->SetEdge(nEdge, jNode); - nEdge++; - } - } - - edge = new CEdge*[nEdge]; - - for (iPoint = 0; iPoint < nPoint; iPoint++) - for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) { - jPoint = node[iPoint]->GetPoint(iNode); - iEdge = FindEdge(iPoint, jPoint); - if (iPoint < jPoint) edge[iEdge] = new CEdge(iPoint, jPoint, nDim); - } -} - -void CGeometry::SetFaces(void) { - // unsigned long iPoint, jPoint, iFace; - // unsigned short jNode, iNode; - // long TestFace = 0; - // - // nFace = 0; - // for (iPoint = 0; iPoint < nPoint; iPoint++) - // for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) { - // jPoint = node[iPoint]->GetPoint(iNode); - // for (jNode = 0; jNode < node[jPoint]->GetnPoint(); jNode++) - // if (node[jPoint]->GetPoint(jNode) == iPoint) { - // TestFace = node[jPoint]->GetFace(jNode); - // break; - // } - // if (TestFace == -1) { - // node[iPoint]->SetFace(nFace, iNode); - // node[jPoint]->SetFace(nFace, jNode); - // nFace++; - // } - // } - // - // face = new CFace*[nFace]; - // - // for (iPoint = 0; iPoint < nPoint; iPoint++) - // for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) { - // jPoint = node[iPoint]->GetPoint(iNode); - // iFace = FindFace(iPoint, jPoint); - // if (iPoint < jPoint) face[iFace] = new CFace(iPoint, jPoint, nDim); - // } -} - -void CGeometry::TestGeometry(void) { - - ofstream para_file; - - para_file.open("test_geometry.dat", ios::out); - - su2double *Normal = new su2double[nDim]; - - for (unsigned long iEdge = 0; iEdge < nEdge; iEdge++) { - para_file << "Edge index: " << iEdge << endl; - para_file << " Point index: " << edge[iEdge]->GetNode(0) << "\t" << edge[iEdge]->GetNode(1) << endl; - edge[iEdge]->GetNormal(Normal); - para_file << " Face normal : "; - for (unsigned short iDim = 0; iDim < nDim; iDim++) - para_file << Normal[iDim] << "\t"; - para_file << endl; - } - - para_file << endl; - para_file << endl; - para_file << endl; - para_file << endl; - - for (unsigned short iMarker =0; iMarker < nMarker; iMarker++) { - para_file << "Marker index: " << iMarker << endl; - for (unsigned long iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - para_file << " Vertex index: " << iVertex << endl; - para_file << " Point index: " << vertex[iMarker][iVertex]->GetNode() << endl; - para_file << " Point coordinates : "; - for (unsigned short iDim = 0; iDim < nDim; iDim++) { - para_file << node[vertex[iMarker][iVertex]->GetNode()]->GetCoord(iDim) << "\t";} - para_file << endl; - vertex[iMarker][iVertex]->GetNormal(Normal); - para_file << " Face normal : "; - for (unsigned short iDim = 0; iDim < nDim; iDim++) - para_file << Normal[iDim] << "\t"; - para_file << endl; - } - } - -} - -void CGeometry::SetSpline(vector &x, vector &y, unsigned long n, su2double yp1, su2double ypn, vector &y2) { - unsigned long i, k; - su2double p, qn, sig, un, *u; - - u = new su2double [n]; - - if (yp1 > 0.99e30) // The lower boundary condition is set either to be "nat - y2[0]=u[0]=0.0; // -ural" - else { // or else to have a specified first derivative. - y2[0] = -0.5; - u[0]=(3.0/(x[1]-x[0]))*((y[1]-y[0])/(x[1]-x[0])-yp1); - } - - for (i=2; i<=n-1; i++) { // This is the decomposition loop of the tridiagonal al- - sig=(x[i-1]-x[i-2])/(x[i]-x[i-2]); // gorithm. y2 and u are used for tem- - p=sig*y2[i-2]+2.0; // porary storage of the decomposed - y2[i-1]=(sig-1.0)/p; // factors. - - su2double a1 = (y[i]-y[i-1])/(x[i]-x[i-1]); if (x[i] == x[i-1]) a1 = 1.0; - su2double a2 = (y[i-1]-y[i-2])/(x[i-1]-x[i-2]); if (x[i-1] == x[i-2]) a2 = 1.0; - u[i-1]= a1 - a2; - u[i-1]=(6.0*u[i-1]/(x[i]-x[i-2])-sig*u[i-2])/p; - - } - - if (ypn > 0.99e30) // The upper boundary condition is set either to be - qn=un=0.0; // "natural" - else { // or else to have a specified first derivative. - qn=0.5; - un=(3.0/(x[n-1]-x[n-2]))*(ypn-(y[n-1]-y[n-2])/(x[n-1]-x[n-2])); - } - y2[n-1]=(un-qn*u[n-2])/(qn*y2[n-2]+1.0); - for (k=n-1; k>=1; k--) // This is the backsubstitution loop of the tridiagonal - y2[k-1]=y2[k-1]*y2[k]+u[k-1]; // algorithm. - - delete[] u; - -} - -su2double CGeometry::GetSpline(vector&xa, vector&ya, vector&y2a, unsigned long n, su2double x) { - unsigned long klo, khi, k; - su2double h, b, a, y; - - if (x < xa[0]) x = xa[0]; // Clip max and min values - if (x > xa[n-1]) x = xa[n-1]; - - klo = 1; // We will find the right place in the table by means of - khi = n; // bisection. This is optimal if sequential calls to this - while (khi-klo > 1) { // routine are at random values of x. If sequential calls - k = (khi+klo) >> 1; // are in order, and closely spaced, one would do better - if (xa[k-1] > x) khi = k; // to store previous values of klo and khi and test if - else klo=k; // they remain appropriate on the next call. - } // klo and khi now bracket the input value of x - h = xa[khi-1] - xa[klo-1]; - if (h == 0.0) h = EPS; // cout << "Bad xa input to routine splint" << endl; // The xa’s must be distinct. - a = (xa[khi-1]-x)/h; - b = (x-xa[klo-1])/h; // Cubic spline polynomial is now evaluated. - y = a*ya[klo-1]+b*ya[khi-1]+((a*a*a-a)*y2a[klo-1]+(b*b*b-b)*y2a[khi-1])*(h*h)/6.0; - - return y; -} - -bool CGeometry::SegmentIntersectsPlane(su2double *Segment_P0, su2double *Segment_P1, su2double Variable_P0, su2double Variable_P1, - su2double *Plane_P0, su2double *Plane_Normal, su2double *Intersection, su2double &Variable_Interp) { - su2double u[3], v[3], Denominator, Numerator, Aux, ModU; - unsigned short iDim; - - for (iDim = 0; iDim < 3; iDim++) { - u[iDim] = Segment_P1[iDim] - Segment_P0[iDim]; - v[iDim] = Plane_P0[iDim] - Segment_P0[iDim]; - } - - ModU = sqrt(u[0]*u[0]+u[1]*u[1]+u[2]*u[2]); - - Numerator = Plane_Normal[0]*v[0] + Plane_Normal[1]*v[1] + Plane_Normal[2]*v[2]; - Denominator = Plane_Normal[0]*u[0] + Plane_Normal[1]*u[1] + Plane_Normal[2]*u[2]; - - if (fabs(Denominator) <= 0.0) return (false); // No intersection. - - Aux = Numerator / Denominator; - - if (Aux < 0.0 || Aux > 1.0) return (false); // No intersection. - - for (iDim = 0; iDim < 3; iDim++) - Intersection[iDim] = Segment_P0[iDim] + Aux * u[iDim]; - - - /*--- Check that the intersection is in the segment ---*/ - - for (iDim = 0; iDim < 3; iDim++) { - u[iDim] = Segment_P0[iDim] - Intersection[iDim]; - v[iDim] = Segment_P1[iDim] - Intersection[iDim]; - } - - Variable_Interp = Variable_P0 + (Variable_P1 - Variable_P0)*sqrt(u[0]*u[0]+u[1]*u[1]+u[2]*u[2])/ModU; - - Denominator = Plane_Normal[0]*u[0] + Plane_Normal[1]*u[1] + Plane_Normal[2]*u[2]; - Numerator = Plane_Normal[0]*v[0] + Plane_Normal[1]*v[1] + Plane_Normal[2]*v[2]; - - Aux = Numerator * Denominator; - - if (Aux > 0.0) return (false); // Intersection outside the segment. - - return (true); - -} - -bool CGeometry::RayIntersectsTriangle(su2double orig[3], su2double dir[3], - su2double vert0[3], su2double vert1[3], su2double vert2[3], - su2double *intersect) { - - su2double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; - su2double det, inv_det, t, u, v; - - /*--- Find vectors for two edges sharing vert0 ---*/ - - SUB(edge1, vert1, vert0); - SUB(edge2, vert2, vert0); - - /*--- Begin calculating determinant - also used to calculate U parameter ---*/ - - CROSS(pvec, dir, edge2); - - /*--- If determinant is near zero, ray lies in plane of triangle ---*/ - - det = DOT(edge1, pvec); - - - if (det > -EPSILON && det < EPSILON) return(false); - - inv_det = 1.0 / det; - - /*--- Calculate distance from vert0 to ray origin ---*/ - - SUB(tvec, orig, vert0); - - /*--- Calculate U parameter and test bounds ---*/ - - u = inv_det * DOT(tvec, pvec); - - if (u < 0.0 || u > 1.0) return(false); - - /*--- prepare to test V parameter ---*/ - - CROSS(qvec, tvec, edge1); - - /*--- Calculate V parameter and test bounds ---*/ - - v = inv_det * DOT(dir, qvec); - - if (v < 0.0 || u + v > 1.0) return(false); - - /*--- Calculate t, ray intersects triangle ---*/ - - t = inv_det * DOT(edge2, qvec); - - /*--- Compute the intersection point in cartesian coordinates ---*/ - - intersect[0] = orig[0] + (t * dir[0]); - intersect[1] = orig[1] + (t * dir[1]); - intersect[2] = orig[2] + (t * dir[2]); - - return (true); - -} - -bool CGeometry::SegmentIntersectsTriangle(su2double point0[3], su2double point1[3], - su2double vert0[3], su2double vert1[3], su2double vert2[3]) { - - su2double dir[3], intersect[3], u[3], v[3], edge1[3], edge2[3], Plane_Normal[3], Denominator, Numerator, Aux; - - SUB(dir, point1, point0); - - if (RayIntersectsTriangle(point0, dir, vert0, vert1, vert2, intersect)) { - - /*--- Check that the intersection is in the segment ---*/ - - SUB(u, point0, intersect); - SUB(v, point1, intersect); - - SUB(edge1, vert1, vert0); - SUB(edge2, vert2, vert0); - CROSS(Plane_Normal, edge1, edge2); - - Denominator = DOT(Plane_Normal, u); - Numerator = DOT(Plane_Normal, v); - - Aux = Numerator * Denominator; - - /*--- Intersection outside the segment ---*/ - - if (Aux > 0.0) return (false); - - } - else { - - /*--- No intersection with the ray ---*/ - - return (false); - - } - - /*--- Intersection inside the segment ---*/ - - return (true); - -} - -void CGeometry::ComputeAirfoil_Section(su2double *Plane_P0, su2double *Plane_Normal, - su2double MinXCoord, su2double MaxXCoord, su2double *FlowVariable, - vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, - vector &Zcoord_Airfoil, vector &Variable_Airfoil, - bool original_surface, CConfig *config) { - - unsigned short iMarker, iNode, jNode, iDim; - bool intersect; - long MinDist_Point, MinDistAngle_Point; - unsigned long iPoint, jPoint, iElem, Trailing_Point, Airfoil_Point, iVertex, jVertex; - su2double Segment_P0[3] = {0.0, 0.0, 0.0}, Segment_P1[3] = {0.0, 0.0, 0.0}, Variable_P0 = 0.0, Variable_P1 = 0.0, Intersection[3] = {0.0, 0.0, 0.0}, Trailing_Coord, MinDist_Value, MinDistAngle_Value, Dist_Value, - Airfoil_Tangent[3] = {0.0, 0.0, 0.0}, Segment[3] = {0.0, 0.0, 0.0}, Length, Angle_Value, MaxAngle = 30, *VarCoord = NULL, CosValue, Variable_Interp; - vector Xcoord, Ycoord, Zcoord, Variable; - vector Duplicate; - vector::iterator it; - int rank = MASTER_NODE; - su2double **Coord_Variation = NULL; - -#ifdef HAVE_MPI - unsigned long nLocalVertex, nGlobalVertex, MaxLocalVertex, *Buffer_Send_nVertex, *Buffer_Receive_nVertex, nBuffer; - int nProcessor, iProcessor; - su2double *Buffer_Send_Coord, *Buffer_Receive_Coord; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - Xcoord_Airfoil.clear(); - Ycoord_Airfoil.clear(); - Zcoord_Airfoil.clear(); - Variable_Airfoil.clear(); - - /*--- Set the right plane in 2D (note the change in Y-Z plane) ---*/ - - if (nDim == 2) { - Plane_P0[0] = 0.0; Plane_P0[1] = 0.0; Plane_P0[2] = 0.0; - Plane_Normal[0] = 0.0; Plane_Normal[1] = 1.0; Plane_Normal[2] = 0.0; - } - - /*--- the grid variation is stored using a vertices information, - we should go from vertex to points ---*/ - - if (original_surface == false) { - - Coord_Variation = new su2double *[nPoint]; - for (iPoint = 0; iPoint < nPoint; iPoint++) - Coord_Variation[iPoint] = new su2double [nDim]; - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_GeoEval(iMarker) == YES) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - VarCoord = vertex[iMarker][iVertex]->GetVarCoord(); - iPoint = vertex[iMarker][iVertex]->GetNode(); - for (iDim = 0; iDim < nDim; iDim++) - Coord_Variation[iPoint][iDim] = VarCoord[iDim]; - } - } - } - - } - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (config->GetMarker_All_GeoEval(iMarker) == YES) { - for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) { - for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { - iPoint = bound[iMarker][iElem]->GetNode(iNode); - for (jNode = 0; jNode < bound[iMarker][iElem]->GetnNodes(); jNode++) { - jPoint = bound[iMarker][iElem]->GetNode(jNode); - - if ((jPoint > iPoint) && ((node[iPoint]->GetCoord(0) > MinXCoord) && (node[iPoint]->GetCoord(0) < MaxXCoord))) { - - Segment_P0[0] = 0.0; Segment_P0[1] = 0.0; Segment_P0[2] = 0.0; Variable_P0 = 0.0; - Segment_P1[0] = 0.0; Segment_P1[1] = 0.0; Segment_P1[2] = 0.0; Variable_P1 = 0.0; - - for (iDim = 0; iDim < nDim; iDim++) { - if (original_surface == true) { - Segment_P0[iDim] = node[iPoint]->GetCoord(iDim); - Segment_P1[iDim] = node[jPoint]->GetCoord(iDim); - } - else { - Segment_P0[iDim] = node[iPoint]->GetCoord(iDim) + Coord_Variation[iPoint][iDim]; - Segment_P1[iDim] = node[jPoint]->GetCoord(iDim) + Coord_Variation[jPoint][iDim]; - } - } - - if (FlowVariable != NULL) { - Variable_P0 = FlowVariable[iPoint]; - Variable_P1 = FlowVariable[jPoint]; - } - - /*--- In 2D add the points directly (note the change between Y and Z coordinate) ---*/ - - if (nDim == 2) { - Xcoord.push_back(Segment_P0[0]); Xcoord.push_back(Segment_P1[0]); - Ycoord.push_back(Segment_P0[2]); Ycoord.push_back(Segment_P1[2]); - Zcoord.push_back(Segment_P0[1]); Zcoord.push_back(Segment_P1[1]); - Variable.push_back(Variable_P0); Variable.push_back(Variable_P1); - } - /*--- In 3D compute the intersection ---*/ - - else if (nDim == 3) { - intersect = SegmentIntersectsPlane(Segment_P0, Segment_P1, Variable_P0, Variable_P1, Plane_P0, Plane_Normal, Intersection, Variable_Interp); - if (intersect == true) { - Xcoord.push_back(Intersection[0]); - Ycoord.push_back(Intersection[1]); - Zcoord.push_back(Intersection[2]); - Variable.push_back(Variable_Interp); - } - } - - } - - } - } - } - } - } - - if (original_surface == false) { - - for (iPoint = 0; iPoint < nPoint; iPoint++) - delete [] Coord_Variation[iPoint]; - delete [] Coord_Variation; - - } - - -#ifdef HAVE_MPI - - /*--- Copy the coordinates of all the points in the plane to the master node ---*/ - - nLocalVertex = 0, nGlobalVertex = 0, MaxLocalVertex = 0; - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); - - Buffer_Send_nVertex = new unsigned long [1]; - Buffer_Receive_nVertex = new unsigned long [nProcessor]; - - nLocalVertex = Xcoord.size(); - - Buffer_Send_nVertex[0] = nLocalVertex; - - SU2_MPI::Allreduce(&nLocalVertex, &nGlobalVertex, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalVertex, &MaxLocalVertex, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - - Buffer_Send_Coord = new su2double [MaxLocalVertex*4]; - Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex*4]; - nBuffer = MaxLocalVertex*4; - - for (iVertex = 0; iVertex < nLocalVertex; iVertex++) { - Buffer_Send_Coord[iVertex*4 + 0] = Xcoord[iVertex]; - Buffer_Send_Coord[iVertex*4 + 1] = Ycoord[iVertex]; - Buffer_Send_Coord[iVertex*4 + 2] = Zcoord[iVertex]; - Buffer_Send_Coord[iVertex*4 + 3] = Variable[iVertex]; - } - - SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer, MPI_DOUBLE, MPI_COMM_WORLD); - - /*--- Clean the vectors before adding the new vertices only to the master node ---*/ - - Xcoord.clear(); - Ycoord.clear(); - Zcoord.clear(); - Variable.clear(); - - /*--- Copy the boundary to the master node vectors ---*/ - if (rank == MASTER_NODE) { - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { - Xcoord.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalVertex*4 + iVertex*4 + 0] ); - Ycoord.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalVertex*4 + iVertex*4 + 1] ); - Zcoord.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalVertex*4 + iVertex*4 + 2] ); - Variable.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalVertex*4 + iVertex*4 + 3] ); - } - } - } - - delete[] Buffer_Send_Coord; delete[] Buffer_Receive_Coord; - delete[] Buffer_Send_nVertex; delete[] Buffer_Receive_nVertex; - -#endif - - if ((rank == MASTER_NODE) && (Xcoord.size() != 0)) { - - /*--- Create a list with the duplicated points ---*/ - - for (iVertex = 0; iVertex < Xcoord.size()-1; iVertex++) { - for (jVertex = iVertex+1; jVertex < Xcoord.size(); jVertex++) { - Segment[0] = Xcoord[jVertex] - Xcoord[iVertex]; - Segment[1] = Ycoord[jVertex] - Ycoord[iVertex]; - Segment[2] = Zcoord[jVertex] - Zcoord[iVertex]; - Dist_Value = sqrt(pow(Segment[0], 2.0) + pow(Segment[1], 2.0) + pow(Segment[2], 2.0)); - if (Dist_Value < 1E-6) { - Duplicate.push_back (jVertex); - } - } - } - - sort(Duplicate.begin(), Duplicate.end()); - it = unique(Duplicate.begin(), Duplicate.end()); - Duplicate.resize(it - Duplicate.begin()); - - /*--- Remove duplicated points (starting from the back) ---*/ - - for (iVertex = Duplicate.size(); iVertex > 0; iVertex--) { - Xcoord.erase (Xcoord.begin() + Duplicate[iVertex-1]); - Ycoord.erase (Ycoord.begin() + Duplicate[iVertex-1]); - Zcoord.erase (Zcoord.begin() + Duplicate[iVertex-1]); - Variable.erase (Variable.begin() + Duplicate[iVertex-1]); - } - - if (Xcoord.size() != 1) { - - /*--- Find the trailing edge ---*/ - - Trailing_Point = 0; Trailing_Coord = Xcoord[0]; - for (iVertex = 1; iVertex < Xcoord.size(); iVertex++) { - if (Xcoord[iVertex] > Trailing_Coord) { - Trailing_Point = iVertex; Trailing_Coord = Xcoord[iVertex]; - } - } - - /*--- Add the trailing edge to the list, and remove from the original list ---*/ - Xcoord_Airfoil.push_back(Xcoord[Trailing_Point]); Ycoord_Airfoil.push_back(Ycoord[Trailing_Point]); Zcoord_Airfoil.push_back(Zcoord[Trailing_Point]); Variable_Airfoil.push_back(Variable[Trailing_Point]); - Xcoord.erase (Xcoord.begin() + Trailing_Point); Ycoord.erase (Ycoord.begin() + Trailing_Point); Zcoord.erase (Zcoord.begin() + Trailing_Point); Variable.erase (Variable.begin() + Trailing_Point); - - /*--- Find the next point using the right hand side rule ---*/ - MinDist_Value = 1E6; MinDist_Point = 0; - for (iVertex = 0; iVertex < Xcoord.size(); iVertex++) { - Segment[0] = Xcoord[iVertex] - Xcoord_Airfoil[0]; - Segment[1] = Ycoord[iVertex] - Ycoord_Airfoil[0]; - Segment[2] = Zcoord[iVertex] - Zcoord_Airfoil[0]; - Dist_Value = sqrt(pow(Segment[0], 2.0) + pow(Segment[1], 2.0) + pow(Segment[2], 2.0)); - Segment[0] /= Dist_Value; Segment[1] /= Dist_Value; Segment[2] /= Dist_Value; - - if ((Dist_Value < MinDist_Value) && (Segment[2] > 0.0)) { MinDist_Point = iVertex; MinDist_Value = Dist_Value; } - } - - Xcoord_Airfoil.push_back(Xcoord[MinDist_Point]); Ycoord_Airfoil.push_back(Ycoord[MinDist_Point]); Zcoord_Airfoil.push_back(Zcoord[MinDist_Point]); Variable_Airfoil.push_back(Variable[MinDist_Point]); - Xcoord.erase (Xcoord.begin() + MinDist_Point); Ycoord.erase (Ycoord.begin() + MinDist_Point); Zcoord.erase (Zcoord.begin() + MinDist_Point); Variable.erase (Variable.begin() + MinDist_Point); - - /*--- Algorithm for the rest of the points ---*/ - do { - - /*--- Last added point in the list ---*/ - Airfoil_Point = Xcoord_Airfoil.size() - 1; - - /*--- Compute the slope of the curve ---*/ - Airfoil_Tangent[0] = Xcoord_Airfoil[Airfoil_Point] - Xcoord_Airfoil[Airfoil_Point-1]; - Airfoil_Tangent[1] = Ycoord_Airfoil[Airfoil_Point] - Ycoord_Airfoil[Airfoil_Point-1]; - Airfoil_Tangent[2] = Zcoord_Airfoil[Airfoil_Point] - Zcoord_Airfoil[Airfoil_Point-1]; - Length = sqrt(pow(Airfoil_Tangent[0], 2.0) + pow(Airfoil_Tangent[1], 2.0) + pow(Airfoil_Tangent[2], 2.0)); - Airfoil_Tangent[0] /= Length; Airfoil_Tangent[1] /= Length; Airfoil_Tangent[2] /= Length; - - /*--- Find the closest point with the right slope ---*/ - MinDist_Value = 1E6; MinDistAngle_Value = 180; - MinDist_Point = -1; MinDistAngle_Point = -1; - for (iVertex = 0; iVertex < Xcoord.size(); iVertex++) { - - Segment[0] = Xcoord[iVertex] - Xcoord_Airfoil[Airfoil_Point]; - Segment[1] = Ycoord[iVertex] - Ycoord_Airfoil[Airfoil_Point]; - Segment[2] = Zcoord[iVertex] - Zcoord_Airfoil[Airfoil_Point]; - - /*--- Compute the distance to each point ---*/ - Dist_Value = sqrt(pow(Segment[0], 2.0) + pow(Segment[1], 2.0) + pow(Segment[2], 2.0)); - - /*--- Compute the angle of the point ---*/ - Segment[0] /= Dist_Value; Segment[1] /= Dist_Value; Segment[2] /= Dist_Value; - - /*--- Clip the value of the cosine, this is important due to the round errors ---*/ - CosValue = Airfoil_Tangent[0]*Segment[0] + Airfoil_Tangent[1]*Segment[1] + Airfoil_Tangent[2]*Segment[2]; - if (CosValue >= 1.0) CosValue = 1.0; - if (CosValue <= -1.0) CosValue = -1.0; - - Angle_Value = acos(CosValue) * 180 / PI_NUMBER; - - if (Dist_Value < MinDist_Value) { MinDist_Point = iVertex; MinDist_Value = Dist_Value; } - if ((Dist_Value < MinDistAngle_Value) && (Angle_Value < MaxAngle)) {MinDistAngle_Point = iVertex; MinDistAngle_Value = Dist_Value;} - - } - - if ( MinDistAngle_Point != -1) MinDist_Point = MinDistAngle_Point; - - /*--- Add and remove the min distance to the list ---*/ - Xcoord_Airfoil.push_back(Xcoord[MinDist_Point]); Ycoord_Airfoil.push_back(Ycoord[MinDist_Point]); Zcoord_Airfoil.push_back(Zcoord[MinDist_Point]); Variable_Airfoil.push_back(Variable[MinDist_Point]); - Xcoord.erase(Xcoord.begin() + MinDist_Point); Ycoord.erase(Ycoord.begin() + MinDist_Point); Zcoord.erase(Zcoord.begin() + MinDist_Point); Variable.erase(Variable.begin() + MinDist_Point); - - } while (Xcoord.size() != 0); - - /*--- Clean the vector before using them again for storing the upper or the lower side ---*/ - - Xcoord.clear(); Ycoord.clear(); Zcoord.clear(); Variable.clear(); - - } - - - } - -} - - -void CGeometry::RegisterCoordinates(CConfig *config){ - unsigned short iDim; - unsigned long iPoint; - - for (iPoint = 0; iPoint < nPoint; iPoint++){ - for (iDim = 0; iDim < nDim; iDim++){ - AD::RegisterInput(node[iPoint]->GetCoord()[iDim]); - } - } -} - -void CGeometry::UpdateGeometry(CGeometry **geometry_container, CConfig *config){ - - unsigned short iMesh; - geometry_container[MESH_0]->Set_MPI_Coord(config); - - geometry_container[MESH_0]->SetCoord_CG(); - geometry_container[MESH_0]->SetControlVolume(config, UPDATE); - geometry_container[MESH_0]->SetBoundControlVolume(config, UPDATE); - - for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++){ - /*--- Update the control volume structures ---*/ - - geometry_container[iMesh]->SetControlVolume(config,geometry_container[iMesh-1], UPDATE); - geometry_container[iMesh]->SetBoundControlVolume(config,geometry_container[iMesh-1], UPDATE); - geometry_container[iMesh]->SetCoord(geometry_container[iMesh-1]); - - } - if (config->GetKind_Solver() == DISC_ADJ_RANS) - geometry_container[MESH_0]->ComputeWall_Distance(config); -} - -void CGeometry::ComputeSurf_Curvature(CConfig *config) { - unsigned short iMarker, iNeigh_Point, iDim, iNode, iNeighbor_Nodes, Neighbor_Node; - unsigned long Neighbor_Point, iVertex, iPoint, jPoint, iElem_Bound, iEdge, nLocalVertex, MaxLocalVertex , *Buffer_Send_nVertex, *Buffer_Receive_nVertex, TotalnPointDomain; - int iProcessor, nProcessor; - vector Point_NeighborList, Elem_NeighborList, Point_Triangle, Point_Edge, Point_Critical; - vector::iterator it; - su2double U[3] = {0.0,0.0,0.0}, V[3] = {0.0,0.0,0.0}, W[3] = {0.0,0.0,0.0}, Length_U, Length_V, Length_W, CosValue, Angle_Value, *K, *Angle_Defect, *Area_Vertex, *Angle_Alpha, *Angle_Beta, **NormalMeanK, MeanK, GaussK, MaxPrinK, cot_alpha, cot_beta, delta, X1, X2, X3, Y1, Y2, Y3, radius, *Buffer_Send_Coord, *Buffer_Receive_Coord, *Coord, Dist, MinDist, MaxK, MinK, SigmaK; - bool *Check_Edge; - int rank; - -#ifndef HAVE_MPI - rank = MASTER_NODE; -#else - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Allocate surface curvature ---*/ - K = new su2double [nPoint]; - for (iPoint = 0; iPoint < nPoint; iPoint++) K[iPoint] = 0.0; - - if (nDim == 2) { - - /*--- Loop over all the markers ---*/ - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { - - /*--- Loop through all marker vertices again, this time also - finding the neighbors of each node.---*/ - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - - if (node[iPoint]->GetDomain()) { - /*--- Loop through neighbors. In 2-D, there should be 2 nodes on either - side of this vertex that lie on the same surface. ---*/ - Point_Edge.clear(); - - for (iNeigh_Point = 0; iNeigh_Point < node[iPoint]->GetnPoint(); iNeigh_Point++) { - Neighbor_Point = node[iPoint]->GetPoint(iNeigh_Point); - - /*--- Check if this neighbor lies on the surface. If so, - add to the list of neighbors. ---*/ - if (node[Neighbor_Point]->GetPhysicalBoundary()) { - Point_Edge.push_back(Neighbor_Point); - } - - } - - if (Point_Edge.size() == 2) { - - /*--- Compute the curvature using three points ---*/ - X1 = node[iPoint]->GetCoord(0); - X2 = node[Point_Edge[0]]->GetCoord(0); - X3 = node[Point_Edge[1]]->GetCoord(0); - Y1 = node[iPoint]->GetCoord(1); - Y2 = node[Point_Edge[0]]->GetCoord(1); - Y3 = node[Point_Edge[1]]->GetCoord(1); - - radius = sqrt(((X2-X1)*(X2-X1) + (Y2-Y1)*(Y2-Y1))* - ((X2-X3)*(X2-X3) + (Y2-Y3)*(Y2-Y3))* - ((X3-X1)*(X3-X1) + (Y3-Y1)*(Y3-Y1)))/ - (2.0*fabs(X1*Y2+X2*Y3+X3*Y1-X1*Y3-X2*Y1-X3*Y2)+EPS); - - K[iPoint] = 1.0/radius; - node[iPoint]->SetCurvature(K[iPoint]); - } - - } - - } - - } - - } - - } - - else { - - Angle_Defect = new su2double [nPoint]; - Area_Vertex = new su2double [nPoint]; - for (iPoint = 0; iPoint < nPoint; iPoint++) { - Angle_Defect[iPoint] = 2*PI_NUMBER; - Area_Vertex[iPoint] = 0.0; - } - - Angle_Alpha = new su2double [nEdge]; - Angle_Beta = new su2double [nEdge]; - Check_Edge = new bool [nEdge]; - for (iEdge = 0; iEdge < nEdge; iEdge++) { - Angle_Alpha[iEdge] = 0.0; - Angle_Beta[iEdge] = 0.0; - Check_Edge[iEdge] = true; - } - - NormalMeanK = new su2double *[nPoint]; - for (iPoint = 0; iPoint < nPoint; iPoint++) { - NormalMeanK[iPoint] = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) { - NormalMeanK[iPoint][iDim] = 0.0; - } - } - - /*--- Loop over all the markers ---*/ - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { - - /*--- Loop over all the boundary elements ---*/ - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - - /*--- Only triangles ---*/ - if (bound[iMarker][iElem_Bound]->GetVTK_Type() == TRIANGLE) { - - /*--- Loop over all the nodes of the boundary element ---*/ - for (iNode = 0; iNode < bound[iMarker][iElem_Bound]->GetnNodes(); iNode++) { - - iPoint = bound[iMarker][iElem_Bound]->GetNode(iNode); - - Point_Triangle.clear(); - - for (iNeighbor_Nodes = 0; iNeighbor_Nodes < bound[iMarker][iElem_Bound]->GetnNeighbor_Nodes(iNode); iNeighbor_Nodes++) { - Neighbor_Node = bound[iMarker][iElem_Bound]->GetNeighbor_Nodes(iNode, iNeighbor_Nodes); - Neighbor_Point = bound[iMarker][iElem_Bound]->GetNode(Neighbor_Node); - Point_Triangle.push_back(Neighbor_Point); - } - - iEdge = FindEdge(Point_Triangle[0], Point_Triangle[1]); - - for (iDim = 0; iDim < nDim; iDim++) { - U[iDim] = node[Point_Triangle[0]]->GetCoord(iDim) - node[iPoint]->GetCoord(iDim); - V[iDim] = node[Point_Triangle[1]]->GetCoord(iDim) - node[iPoint]->GetCoord(iDim); - } - - W[0] = 0.5*(U[1]*V[2]-U[2]*V[1]); W[1] = -0.5*(U[0]*V[2]-U[2]*V[0]); W[2] = 0.5*(U[0]*V[1]-U[1]*V[0]); - - Length_U = 0.0, Length_V = 0.0, Length_W = 0.0, CosValue = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { Length_U += U[iDim]*U[iDim]; Length_V += V[iDim]*V[iDim]; Length_W += W[iDim]*W[iDim]; } - Length_U = sqrt(Length_U); Length_V = sqrt(Length_V); Length_W = sqrt(Length_W); - for (iDim = 0; iDim < nDim; iDim++) { U[iDim] /= Length_U; V[iDim] /= Length_V; CosValue += U[iDim]*V[iDim]; } - if (CosValue >= 1.0) CosValue = 1.0; - if (CosValue <= -1.0) CosValue = -1.0; - - Angle_Value = acos(CosValue); - Area_Vertex[iPoint] += Length_W; - Angle_Defect[iPoint] -= Angle_Value; - if (Angle_Alpha[iEdge] == 0.0) Angle_Alpha[iEdge] = Angle_Value; - else Angle_Beta[iEdge] = Angle_Value; - - } - } - } - } - } - - /*--- Compute mean curvature ---*/ - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - if (bound[iMarker][iElem_Bound]->GetVTK_Type() == TRIANGLE) { - for (iNode = 0; iNode < bound[iMarker][iElem_Bound]->GetnNodes(); iNode++) { - iPoint = bound[iMarker][iElem_Bound]->GetNode(iNode); - - for (iNeighbor_Nodes = 0; iNeighbor_Nodes < bound[iMarker][iElem_Bound]->GetnNeighbor_Nodes(iNode); iNeighbor_Nodes++) { - Neighbor_Node = bound[iMarker][iElem_Bound]->GetNeighbor_Nodes(iNode, iNeighbor_Nodes); - jPoint = bound[iMarker][iElem_Bound]->GetNode(Neighbor_Node); - - iEdge = FindEdge(iPoint, jPoint); - - if (Check_Edge[iEdge]) { - - Check_Edge[iEdge] = false; - - if (tan(Angle_Alpha[iEdge]) != 0.0) cot_alpha = 1.0/tan(Angle_Alpha[iEdge]); else cot_alpha = 0.0; - if (tan(Angle_Beta[iEdge]) != 0.0) cot_beta = 1.0/tan(Angle_Beta[iEdge]); else cot_beta = 0.0; - - /*--- iPoint, and jPoint ---*/ - for (iDim = 0; iDim < nDim; iDim++) { - if (Area_Vertex[iPoint] != 0.0) NormalMeanK[iPoint][iDim] += 3.0 * (cot_alpha + cot_beta) * (node[iPoint]->GetCoord(iDim) - node[jPoint]->GetCoord(iDim)) / Area_Vertex[iPoint]; - if (Area_Vertex[jPoint] != 0.0) NormalMeanK[jPoint][iDim] += 3.0 * (cot_alpha + cot_beta) * (node[jPoint]->GetCoord(iDim) - node[iPoint]->GetCoord(iDim)) / Area_Vertex[jPoint]; - } - } - - } - } - } - } - } - } - - /*--- Compute Gauss, mean, max and min principal curvature, - and set the list of critical points ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - - if (node[iPoint]->GetDomain()) { - - if (Area_Vertex[iPoint] != 0.0) GaussK = 3.0*Angle_Defect[iPoint]/Area_Vertex[iPoint]; - else GaussK = 0.0; - - MeanK = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - MeanK += NormalMeanK[iPoint][iDim]*NormalMeanK[iPoint][iDim]; - MeanK = sqrt(MeanK); - - delta = max((MeanK*MeanK - GaussK), 0.0); - - MaxPrinK = MeanK + sqrt(delta); - - /*--- Store the curvature value ---*/ - K[iPoint] = MaxPrinK; - node[iPoint]->SetCurvature(K[iPoint]); - } - - } - } - } - - delete [] Angle_Defect; - delete [] Area_Vertex; - delete [] Angle_Alpha; - delete [] Angle_Beta; - delete [] Check_Edge; - - for (iPoint = 0; iPoint < nPoint; iPoint++) - delete [] NormalMeanK[iPoint]; - delete [] NormalMeanK; - - } - - /*--- Sharp edge detection is based in the statistical - distribution of the curvature ---*/ - - MaxK = K[0]; MinK = K[0]; MeanK = 0.0; TotalnPointDomain = 0; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - MaxK = max(MaxK, fabs(K[iPoint])); - MinK = min(MinK, fabs(K[iPoint])); - MeanK += fabs(K[iPoint]); - TotalnPointDomain++; - } - } - } - } - -#ifdef HAVE_MPI - su2double MyMeanK = MeanK; MeanK = 0.0; - su2double MyMaxK = MaxK; MaxK = 0.0; - unsigned long MynPointDomain = TotalnPointDomain; TotalnPointDomain = 0; - SU2_MPI::Allreduce(&MyMeanK, &MeanK, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyMaxK, &MaxK, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MynPointDomain, &TotalnPointDomain, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#endif - - /*--- Compute the mean ---*/ - MeanK /= su2double(TotalnPointDomain); - - /*--- Compute the standard deviation ---*/ - SigmaK = 0.0; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - SigmaK += (fabs(K[iPoint]) - MeanK) * (fabs(K[iPoint]) - MeanK); - } - } - } - } - -#ifdef HAVE_MPI - su2double MySigmaK = SigmaK; SigmaK = 0.0; - SU2_MPI::Allreduce(&MySigmaK, &SigmaK, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); -#endif - - SigmaK = sqrt(SigmaK/su2double(TotalnPointDomain)); - - if (rank == MASTER_NODE) - cout << "Max K: " << MaxK << ". Mean K: " << MeanK << ". Standard deviation K: " << SigmaK << "." << endl; - - Point_Critical.clear(); - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - if (fabs(K[iPoint]) > MeanK + config->GetRefSharpEdges()*SigmaK) { - Point_Critical.push_back(iPoint); - } - } - } - } - } - - /*--- Variables and buffers needed for MPI ---*/ - -#ifdef HAVE_MPI - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); -#else - nProcessor = 1; -#endif - - Buffer_Send_nVertex = new unsigned long [1]; - Buffer_Receive_nVertex = new unsigned long [nProcessor]; - - /*--- Count the total number of critical edge nodes. ---*/ - - nLocalVertex = Point_Critical.size(); - Buffer_Send_nVertex[0] = nLocalVertex; - - /*--- Communicate to all processors the total number of critical edge nodes. ---*/ - -#ifdef HAVE_MPI - MaxLocalVertex = 0; - SU2_MPI::Allreduce(&nLocalVertex, &MaxLocalVertex, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#else - MaxLocalVertex = nLocalVertex; - Buffer_Receive_nVertex[0] = nLocalVertex; -#endif - - - /*--- Create and initialize to zero some buffers to hold the coordinates - of the boundary nodes that are communicated from each partition (all-to-all). ---*/ - - Buffer_Send_Coord = new su2double [MaxLocalVertex*nDim]; - Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex*nDim]; - -#ifdef HAVE_MPI - unsigned long nBuffer = MaxLocalVertex*nDim; -#endif - - for (iVertex = 0; iVertex < MaxLocalVertex; iVertex++) { - for (iDim = 0; iDim < nDim; iDim++) { - Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; - } - } - - /*--- Retrieve and store the coordinates of the sharp edges boundary nodes on - the local partition and broadcast them to all partitions. ---*/ - - for (iVertex = 0; iVertex < Point_Critical.size(); iVertex++) { - iPoint = Point_Critical[iVertex]; - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[iVertex*nDim+iDim] = node[iPoint]->GetCoord(iDim); - } - -#ifdef HAVE_MPI - SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer, MPI_DOUBLE, MPI_COMM_WORLD); -#else - for (iVertex = 0; iVertex < Point_Critical.size(); iVertex++) { - for (iDim = 0; iDim < nDim; iDim++) { - Buffer_Receive_Coord[iVertex*nDim+iDim] = Buffer_Send_Coord[iVertex*nDim+iDim]; - } - } -#endif - - /*--- Loop over all interior mesh nodes on the local partition and compute - the distances to each of the no-slip boundary nodes in the entire mesh. - Store the minimum distance to the wall for each interior mesh node. ---*/ - - for (iPoint = 0; iPoint < GetnPoint(); iPoint++) { - Coord = node[iPoint]->GetCoord(); - - MinDist = 1E20; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { - Dist = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Dist += (Coord[iDim]-Buffer_Receive_Coord[(iProcessor*MaxLocalVertex+iVertex)*nDim+iDim])* - (Coord[iDim]-Buffer_Receive_Coord[(iProcessor*MaxLocalVertex+iVertex)*nDim+iDim]); - } - if (Dist!=0.0) Dist = sqrt(Dist); - else Dist = 0.0; - if (Dist < MinDist) MinDist = Dist; - } - } - node[iPoint]->SetSharpEdge_Distance(MinDist); - } - - /*--- Deallocate Max curvature ---*/ - delete[] K; - - /*--- Deallocate the buffers needed for the MPI communication. ---*/ - delete[] Buffer_Send_Coord; - delete[] Buffer_Receive_Coord; - delete[] Buffer_Send_nVertex; - delete[] Buffer_Receive_nVertex; - -} - -CPhysicalGeometry::CPhysicalGeometry() : CGeometry() { - - Global_to_Local_Point = NULL; - Local_to_Global_Point = NULL; - Local_to_Global_Marker = NULL; - Global_to_Local_Marker = NULL; - -} - -CPhysicalGeometry::CPhysicalGeometry(CConfig *config, unsigned short val_iZone, unsigned short val_nZone) : CGeometry() { - - Global_to_Local_Point = NULL; - Local_to_Global_Point = NULL; - Local_to_Global_Marker = NULL; - Global_to_Local_Marker = NULL; - - string text_line, Marker_Tag; - ifstream mesh_file; - unsigned short iDim, iMarker, iNodes; - unsigned long iPoint, LocaNodes = 0, iElem_Bound; - su2double *NewCoord; - nZone = val_nZone; - ofstream boundary_file; - string Grid_Marker; - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - string val_mesh_filename = config->GetMesh_FileName(); - unsigned short val_format = config->GetMesh_FileFormat(); - - /*--- Initialize counters for local/global points & elements ---*/ - - if (rank == MASTER_NODE) - cout << endl <<"---------------------- Read Grid File Information -----------------------" << endl; - - switch (val_format) { - case SU2: - Read_SU2_Format_Parallel(config, val_mesh_filename, val_iZone, val_nZone); - LocaNodes = local_node; - break; - case CGNS: - Read_CGNS_Format_Parallel(config, val_mesh_filename, val_iZone, val_nZone); - LocaNodes = local_node; - break; - default: - if (rank == MASTER_NODE) cout << "Unrecognized mesh format specified!" << endl; -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - break; - } - - /*--- After reading the mesh, assert that the dimension is equal to 2 or 3. ---*/ - - assert((nDim == 2) || (nDim == 3)); - - /*--- Loop over the points element to re-scale the mesh, and plot it (only SU2_CFD) ---*/ - - if (config->GetKind_SU2() == SU2_CFD) { - - NewCoord = new su2double [nDim]; - - /*--- The US system uses feet, but SU2 assumes that the grid is in inches ---*/ - - if (config->GetSystemMeasurements() == US) { - for (iPoint = 0; iPoint < LocaNodes; iPoint++) { - for (iDim = 0; iDim < nDim; iDim++) { - NewCoord[iDim] = node[iPoint]->GetCoord(iDim)/12.0; - } - node[iPoint]->SetCoord(NewCoord); - } - } - - delete [] NewCoord; - - } - - /*--- If SU2_DEF then write a file with the boundary information ---*/ - - if ((config->GetKind_SU2() == SU2_DEF) && (rank == MASTER_NODE)) { - - /*--- Open .su2 grid file ---*/ - - boundary_file.open("boundary.su2", ios::out); - - /*--- Loop through and write the boundary info ---*/ - - boundary_file << "NMARK= " << nMarker << endl; - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - Grid_Marker = config->GetMarker_All_TagBound(iMarker); - boundary_file << "MARKER_TAG= " << Grid_Marker << endl; - boundary_file << "MARKER_ELEMS= " << nElem_Bound[iMarker]<< endl; - - if (nDim == 2) { - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - boundary_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ; - for (iNodes = 0; iNodes < bound[iMarker][iElem_Bound]->GetnNodes(); iNodes++) - boundary_file << bound[iMarker][iElem_Bound]->GetNode(iNodes) << "\t" ; - boundary_file << iElem_Bound << endl; - } - } - - if (nDim == 3) { - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - boundary_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ; - for (iNodes = 0; iNodes < bound[iMarker][iElem_Bound]->GetnNodes(); iNodes++) - boundary_file << bound[iMarker][iElem_Bound]->GetNode(iNodes) << "\t" ; - boundary_file << iElem_Bound << endl; - } - } - - } - - boundary_file.close(); - - } - -} - - -CPhysicalGeometry::CPhysicalGeometry(CGeometry *geometry, CConfig *config) { - - Global_to_Local_Point = NULL; - Local_to_Global_Point = NULL; - Local_to_Global_Marker = NULL; - Global_to_Local_Marker = NULL; - - unsigned long iter, iPoint, jPoint, iElem, jElem, iVertex; - unsigned long nElemTotal = 0, nPointTotal = 0, nPointDomainTotal = 0, nElemTriangle = 0, nElemQuadrilateral = 0, nElemTetrahedron = 0, nElemHexahedron = 0, nElemPrism = 0, nElemPyramid = 0; -// unsigned long nPointGhost = 0, nPointPeriodic = 0; - unsigned long iElemTotal, iPointTotal, iPointGhost, iPointDomain, iPointPeriodic, iElemTriangle, iElemQuadrilateral, iElemTetrahedron, iElemHexahedron, iElemPrism, iElemPyramid; - unsigned long nBoundLineTotal = 0, iBoundLineTotal; - unsigned long nBoundTriangleTotal = 0, iBoundTriangleTotal; - unsigned long nBoundQuadrilateralTotal = 0, iBoundQuadrilateralTotal; - unsigned long ReceptorColor = 0, DonorColor = 0, Transformation; - unsigned long *nElem_Color = NULL, **Elem_Color = NULL, Max_nElem_Color = 0; - unsigned long nTotalSendDomain_Periodic = 0, iTotalSendDomain_Periodic = 0, nTotalReceivedDomain_Periodic = 0, iTotalReceivedDomain_Periodic = 0, *nSendDomain_Periodic = NULL, *nReceivedDomain_Periodic = NULL; - unsigned long Buffer_Send_nPointTotal = 0, Buffer_Send_nPointDomainTotal = 0, Buffer_Send_nPointGhost = 0, Buffer_Send_nPointPeriodic = 0; - unsigned long Buffer_Send_nElemTotal, Buffer_Send_nElemTriangle = 0, Buffer_Send_nElemQuadrilateral = 0, Buffer_Send_nElemTetrahedron = 0, Buffer_Send_nElemHexahedron = 0, Buffer_Send_nElemPrism = 0, Buffer_Send_nElemPyramid = 0; - unsigned long Buffer_Send_nTotalSendDomain_Periodic = 0, Buffer_Send_nTotalReceivedDomain_Periodic = 0, *Buffer_Send_nSendDomain_Periodic = NULL, *Buffer_Send_nReceivedDomain_Periodic = NULL; - unsigned long Buffer_Send_nBoundLineTotal = 0, Buffer_Send_nBoundTriangleTotal = 0, Buffer_Send_nBoundQuadrilateralTotal = 0; - unsigned long iVertexDomain, iBoundLine, iBoundTriangle, iBoundQuadrilateral; - - /*--- Need to su2double-check these shorts in case we go to nprocs > ~32,000 ---*/ - - unsigned short iNode, iDim, iMarker, jMarker, nMarkerDomain = 0, iMarkerDomain; - unsigned short nDomain = 0, iDomain, jDomain, nPeriodic = 0, iPeriodic, overhead = 4, Buffer_Send_nMarkerDomain = 0, Buffer_Send_nDim = 0, Buffer_Send_nZone = 0, Buffer_Send_nPeriodic = 0; - - bool *MarkerIn = NULL, **VertexIn = NULL, CheckDomain; - long vnodes_local[8], *Global2Local_Point = NULL; - vector DomainList; - short *Marker_All_SendRecv_Copy = NULL; - string *Marker_All_TagBound_Copy = NULL; - unsigned short nMarker_Max = config->GetnMarker_Max(); - - int rank = MASTER_NODE; - int size = SINGLE_NODE; - - /*--- Some dynamic arrays so we're not allocating too much on the stack ---*/ - - unsigned long *nVertexDomain = new unsigned long[nMarker_Max]; - unsigned long *nBoundLine = new unsigned long[nMarker_Max]; - unsigned long *nBoundTriangle = new unsigned long[nMarker_Max]; - unsigned long *nBoundQuadrilateral = new unsigned long[nMarker_Max]; - unsigned long *Buffer_Send_nVertexDomain = new unsigned long[nMarker_Max]; - unsigned long *Buffer_Send_nBoundLine = new unsigned long[nMarker_Max]; - unsigned long *Buffer_Send_nBoundTriangle = new unsigned long[nMarker_Max]; - unsigned long *Buffer_Send_nBoundQuadrilateral = new unsigned long[nMarker_Max]; - short *Buffer_Send_Marker_All_SendRecv = new short[nMarker_Max]; - char *Marker_All_TagBound = new char[nMarker_Max*MAX_STRING_SIZE]; - char *Buffer_Send_Marker_All_TagBound = new char[nMarker_Max*MAX_STRING_SIZE]; - - -#ifdef HAVE_MPI - - /*--- MPI initialization ---*/ - - MPI_Comm_size(MPI_COMM_WORLD, &size); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - /*--- MPI status and request arrays for non-blocking communications ---*/ - - MPI_Status send_stat[31], recv_stat[31]; - MPI_Request send_req[31], recv_req[31]; - -#endif - - /*--- Define buffer vector interior domain ---*/ - - su2double *Buffer_Send_Coord = NULL, *Buffer_Receive_Coord = NULL; - unsigned long *Buffer_Send_Color = NULL, *Buffer_Receive_Color = NULL; - unsigned long *Buffer_Send_GlobalPointIndex = NULL, *Buffer_Receive_GlobalPointIndex = NULL; - unsigned long *Buffer_Send_Triangle = NULL, *Buffer_Receive_Triangle = NULL; - unsigned long *Buffer_Send_Quadrilateral = NULL, *Buffer_Receive_Quadrilateral = NULL; - unsigned long *Buffer_Send_Tetrahedron = NULL, *Buffer_Receive_Tetrahedron = NULL; - unsigned long *Buffer_Send_Hexahedron = NULL, *Buffer_Receive_Hexahedron = NULL; - unsigned long *Buffer_Send_Prism = NULL, *Buffer_Receive_Prism = NULL; - unsigned long *Buffer_Send_Pyramid = NULL, *Buffer_Receive_Pyramid = NULL; - - /*--- Define buffer vector boundary ---*/ - - unsigned long *Buffer_Send_BoundLine = NULL, *Buffer_Receive_BoundLine = NULL; - unsigned long *Buffer_Send_BoundTriangle = NULL, *Buffer_Receive_BoundTriangle = NULL; - unsigned long *Buffer_Send_BoundQuadrilateral = NULL, *Buffer_Receive_BoundQuadrilateral = NULL; - unsigned long *Buffer_Send_Local2Global_Marker = NULL, *Buffer_Receive_Local2Global_Marker = NULL; - - /*--- Define buffer vector periodic boundary conditions ---*/ - - su2double *Buffer_Send_Center = NULL, *Buffer_Receive_Center = NULL; - su2double *Buffer_Send_Rotation = NULL, *Buffer_Receive_Rotation = NULL; - su2double *Buffer_Send_Translate = NULL, *Buffer_Receive_Translate = NULL; - - /*--- Define buffer vector periodic boundary conditions ---*/ - - unsigned long *Buffer_Send_SendDomain_Periodic = NULL, *Buffer_Receive_SendDomain_Periodic = NULL; - unsigned long *Buffer_Send_SendDomain_PeriodicTrans = NULL, *Buffer_Receive_SendDomain_PeriodicTrans = NULL; - unsigned long *Buffer_Send_SendDomain_PeriodicReceptor = NULL, *Buffer_Receive_SendDomain_PeriodicReceptor = NULL; - unsigned long *Buffer_Send_ReceivedDomain_Periodic = NULL, *Buffer_Receive_ReceivedDomain_Periodic = NULL; - unsigned long *Buffer_Send_ReceivedDomain_PeriodicTrans = NULL, *Buffer_Receive_ReceivedDomain_PeriodicTrans = NULL; - unsigned long *Buffer_Send_ReceivedDomain_PeriodicDonor = NULL, *Buffer_Receive_ReceivedDomain_PeriodicDonor = NULL; - - - /*--- Basic dimensionalization ---*/ - - nDomain = size; - Marker_All_SendRecv = new short[nMarker_Max]; - nSendDomain_Periodic = new unsigned long [nDomain]; - nReceivedDomain_Periodic = new unsigned long [nDomain]; - - /*--- Auxiliar vector based on the original geometry ---*/ - - if (rank == MASTER_NODE) { - - MarkerIn = new bool [geometry->GetnMarker()]; - - VertexIn = new bool* [geometry->GetnMarker()]; - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) - VertexIn[iMarker] = new bool [geometry->GetnElem_Bound(iMarker)]; - - Global2Local_Point = new long[geometry->GetnPoint()]; - - Buffer_Send_nDim = geometry->GetnDim(); - Buffer_Send_nZone = geometry->GetnZone(); - - Buffer_Send_nPeriodic = config->GetnPeriodicIndex(); - Buffer_Send_Center = new su2double[Buffer_Send_nPeriodic*3]; - Buffer_Send_Rotation = new su2double[Buffer_Send_nPeriodic*3]; - Buffer_Send_Translate = new su2double[Buffer_Send_nPeriodic*3]; - - Buffer_Send_nSendDomain_Periodic = new unsigned long [nDomain]; - Buffer_Send_nReceivedDomain_Periodic = new unsigned long [nDomain]; - - /*--- Divide the elements in color list to speed up the grid partitioning ---*/ - - nElem_Color = new unsigned long[nDomain]; - for (iDomain = 0; iDomain < nDomain; iDomain++) nElem_Color[iDomain] = 0; - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - DomainList.clear(); - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { - iPoint = geometry->elem[iElem]->GetNode(iNode); - iDomain = geometry->node[iPoint]->GetColor(); - - CheckDomain = true; - for (jDomain = 0; jDomain < DomainList.size(); jDomain++) { - if (DomainList[jDomain] == iDomain) { CheckDomain = false; break; } - } - - /*--- If the element is not in the list, then add it ---*/ - if (CheckDomain) { - DomainList.push_back(iDomain); - nElem_Color[iDomain]++; - } - - } - } - - /*--- Find the maximum number of elements per color to allocate the list ---*/ - - Max_nElem_Color = 0; - for (iDomain = 0; iDomain < nDomain; iDomain++) { - if (nElem_Color[iDomain] > Max_nElem_Color) Max_nElem_Color = nElem_Color[iDomain]; - } - - /*--- Allocate the element color array ---*/ - - Elem_Color = new unsigned long* [nDomain]; - for (iDomain = 0; iDomain < nDomain; iDomain++) { - Elem_Color[iDomain] = new unsigned long[Max_nElem_Color]; - nElem_Color[iDomain] = 0; - } - - /*--- Create the lement list based on the color ---*/ - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - DomainList.clear(); - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { - iPoint = geometry->elem[iElem]->GetNode(iNode); - iDomain = geometry->node[iPoint]->GetColor(); - - /*--- Check if the element has been already added to the color ---*/ - - CheckDomain = true; - for (jDomain = 0; jDomain < DomainList.size(); jDomain++) { - if (DomainList[jDomain] == iDomain) { CheckDomain = false; break; } - } - - if (CheckDomain) { - DomainList.push_back(iDomain); - Elem_Color[iDomain][nElem_Color[iDomain]] = iElem; - nElem_Color[iDomain]++; - } - - } - } - - - /*--- Create a local copy of config->GetMarker_All_SendRecv and - config->GetMarker_All_TagBound in the master node ---*/ - - Marker_All_SendRecv_Copy = new short [geometry->GetnMarker()]; - Marker_All_TagBound_Copy = new string[geometry->GetnMarker()]; - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - Marker_All_SendRecv_Copy[iMarker] = config->GetMarker_All_SendRecv(iMarker); - Marker_All_TagBound_Copy[iMarker] = config->GetMarker_All_TagBound(iMarker); - } - - - } - - for (iDomain = 0; iDomain < nDomain; iDomain++) { - - if (rank == MASTER_NODE) { - - /*--- Interior dimensionalization. Loop over the original grid to perform the - dimensionalizaton of the domain variables ---*/ - - Buffer_Send_nElemTotal = 0; Buffer_Send_nPointTotal = 0; Buffer_Send_nPointGhost = 0; Buffer_Send_nPointDomainTotal = 0; Buffer_Send_nPointPeriodic = 0; - Buffer_Send_nElemTriangle = 0; Buffer_Send_nElemQuadrilateral = 0; Buffer_Send_nElemTetrahedron = 0; Buffer_Send_nElemHexahedron = 0; Buffer_Send_nElemPrism = 0; Buffer_Send_nElemPyramid = 0; - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) Global2Local_Point[iPoint] = -1; - - for (jElem = 0; jElem < nElem_Color[iDomain]; jElem++) { - - iElem = Elem_Color[iDomain][jElem]; - - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { - iPoint = geometry->elem[iElem]->GetNode(iNode); - if (Global2Local_Point[iPoint] == -1) { - Global2Local_Point[iPoint] = 1; - Buffer_Send_nPointTotal++; - if ( geometry->node[iPoint]->GetColor() != iDomain ) Buffer_Send_nPointGhost++; - else { - if (iPoint > geometry->GetnPointDomain() - 1) { Buffer_Send_nPointGhost++; Buffer_Send_nPointPeriodic++; } - else Buffer_Send_nPointDomainTotal++; - } - } - } - - switch(geometry->elem[iElem]->GetVTK_Type()) { - case TRIANGLE: Buffer_Send_nElemTriangle++; break; - case QUADRILATERAL: Buffer_Send_nElemQuadrilateral++; break; - case TETRAHEDRON: Buffer_Send_nElemTetrahedron++; break; - case HEXAHEDRON: Buffer_Send_nElemHexahedron++; break; - case PRISM: Buffer_Send_nElemPrism++; break; - case PYRAMID: Buffer_Send_nElemPyramid++; break; - } - Buffer_Send_nElemTotal++; - - } - - /*--- Boundary dimensionalization. Dimensionalization with physical boundaries, compute Buffer_Send_nMarkerDomain, - Buffer_Send_nVertexDomain[nMarkerDomain] ---*/ - - Buffer_Send_nMarkerDomain = 0; Buffer_Send_nBoundLineTotal = 0; Buffer_Send_nBoundTriangleTotal = 0; Buffer_Send_nBoundQuadrilateralTotal = 0; - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - Buffer_Send_nVertexDomain[iMarker] = 0; - Buffer_Send_nBoundLine[iMarker] = 0; - Buffer_Send_nBoundTriangle[iMarker] = 0; - Buffer_Send_nBoundQuadrilateral[iMarker] = 0; - - Buffer_Send_Marker_All_SendRecv[iMarker] = Marker_All_SendRecv_Copy[iMarker]; - SPRINTF(&Buffer_Send_Marker_All_TagBound[iMarker*MAX_STRING_SIZE], "%s", Marker_All_TagBound_Copy[iMarker].c_str()); - } - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { - MarkerIn[iMarker] = false; Buffer_Send_nVertexDomain[Buffer_Send_nMarkerDomain] = 0; - - for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { - VertexIn[iMarker][iVertex] = false; - for (iNode = 0; iNode < geometry->bound[iMarker][iVertex]->GetnNodes(); iNode++) { - iPoint = geometry->bound[iMarker][iVertex]->GetNode(iNode); - if (geometry->node[iPoint]->GetColor() == iDomain) VertexIn[iMarker][iVertex] = true; - } - - if (VertexIn[iMarker][iVertex]) { - switch(geometry->bound[iMarker][iVertex]->GetVTK_Type()) { - case LINE: Buffer_Send_nBoundLine[Buffer_Send_nMarkerDomain]++; Buffer_Send_nBoundLineTotal++; break; - case TRIANGLE: Buffer_Send_nBoundTriangle[Buffer_Send_nMarkerDomain]++; Buffer_Send_nBoundTriangleTotal++; break; - case QUADRILATERAL: Buffer_Send_nBoundQuadrilateral[Buffer_Send_nMarkerDomain]++; Buffer_Send_nBoundQuadrilateralTotal++; break; - } - - Buffer_Send_nVertexDomain[Buffer_Send_nMarkerDomain] ++; - MarkerIn[iMarker] = true; - - } - } - - if (MarkerIn[iMarker]) { Buffer_Send_nMarkerDomain++; } - - } - } - - /*--- Copy periodic information from the config file ---*/ - - for (iPeriodic = 0; iPeriodic < Buffer_Send_nPeriodic; iPeriodic++) { - for (iDim = 0; iDim < 3; iDim++) { - Buffer_Send_Center[iDim+iPeriodic*3] = config->GetPeriodicCenter(iPeriodic)[iDim]; - Buffer_Send_Rotation[iDim+iPeriodic*3] = config->GetPeriodicRotation(iPeriodic)[iDim]; - Buffer_Send_Translate[iDim+iPeriodic*3] = config->GetPeriodicTranslate(iPeriodic)[iDim]; - } - } - - /*--- Dimensionalization of the periodic auxiliar vectors ---*/ - - for (jDomain = 0; jDomain < nDomain; jDomain++) { - Buffer_Send_nSendDomain_Periodic[jDomain] = 0; - Buffer_Send_nReceivedDomain_Periodic[jDomain] = 0; - } - Buffer_Send_nTotalSendDomain_Periodic = 0; - Buffer_Send_nTotalReceivedDomain_Periodic = 0; - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { - for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { - iPoint = geometry->bound[iMarker][iVertex]->GetNode(0); - if (iDomain == geometry->node[iPoint]->GetColor()) { - - if (config->GetMarker_All_SendRecv(iMarker) > 0) { - - /*--- Identify the color of the receptor ---*/ - - for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) { - if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker))) { - jPoint = geometry->bound[jMarker][iVertex]->GetNode(0); - ReceptorColor = geometry->node[jPoint]->GetColor(); - } - } - - Buffer_Send_nSendDomain_Periodic[ReceptorColor]++; - Buffer_Send_nTotalSendDomain_Periodic++; - - } - if (config->GetMarker_All_SendRecv(iMarker) < 0) { - - /*--- Identify the color of the donor ---*/ - - for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) { - if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker))) { - jPoint = geometry->bound[jMarker][iVertex]->GetNode(0); - DonorColor = geometry->node[jPoint]->GetColor(); - } - } - - Buffer_Send_nReceivedDomain_Periodic[DonorColor]++; - Buffer_Send_nTotalReceivedDomain_Periodic++; - - } - } - } - } - } - - /*--- Allocate the buffer vectors in the appropiate domain (master, iDomain) ---*/ - - Buffer_Send_Coord = new su2double [Buffer_Send_nPointTotal*Buffer_Send_nDim]; - Buffer_Send_Color = new unsigned long [Buffer_Send_nPointTotal]; - Buffer_Send_GlobalPointIndex = new unsigned long [Buffer_Send_nPointTotal]; - Buffer_Send_Triangle = new unsigned long [Buffer_Send_nElemTriangle*3]; - Buffer_Send_Quadrilateral = new unsigned long [Buffer_Send_nElemQuadrilateral*4]; - Buffer_Send_Tetrahedron = new unsigned long [Buffer_Send_nElemTetrahedron*4]; - Buffer_Send_Hexahedron = new unsigned long [Buffer_Send_nElemHexahedron*8]; - Buffer_Send_Prism = new unsigned long [Buffer_Send_nElemPrism*6]; - Buffer_Send_Pyramid = new unsigned long [Buffer_Send_nElemPyramid*5]; - - Buffer_Send_BoundLine = new unsigned long [Buffer_Send_nBoundLineTotal*2]; - Buffer_Send_BoundTriangle = new unsigned long [Buffer_Send_nBoundTriangleTotal*3]; - Buffer_Send_BoundQuadrilateral = new unsigned long [Buffer_Send_nBoundQuadrilateralTotal*4]; - Buffer_Send_Local2Global_Marker = new unsigned long [Buffer_Send_nMarkerDomain]; - - Buffer_Send_SendDomain_Periodic = new unsigned long [Buffer_Send_nTotalSendDomain_Periodic]; - Buffer_Send_SendDomain_PeriodicTrans = new unsigned long [Buffer_Send_nTotalSendDomain_Periodic]; - Buffer_Send_SendDomain_PeriodicReceptor = new unsigned long [Buffer_Send_nTotalSendDomain_Periodic]; - Buffer_Send_ReceivedDomain_Periodic = new unsigned long [Buffer_Send_nTotalReceivedDomain_Periodic]; - Buffer_Send_ReceivedDomain_PeriodicTrans = new unsigned long [Buffer_Send_nTotalReceivedDomain_Periodic]; - Buffer_Send_ReceivedDomain_PeriodicDonor = new unsigned long [Buffer_Send_nTotalReceivedDomain_Periodic]; - - if (iDomain != MASTER_NODE) { - -#ifdef HAVE_MPI - - SU2_MPI::Isend(&Buffer_Send_nDim, 1, MPI_UNSIGNED_SHORT, iDomain, 0, MPI_COMM_WORLD, &send_req[0]); - SU2_MPI::Isend(&Buffer_Send_nZone, 1, MPI_UNSIGNED_SHORT, iDomain, 1, MPI_COMM_WORLD, &send_req[1]); - SU2_MPI::Isend(&Buffer_Send_nPointTotal, 1, MPI_UNSIGNED_LONG, iDomain, 2, MPI_COMM_WORLD, &send_req[2]); - SU2_MPI::Isend(&Buffer_Send_nPointDomainTotal, 1, MPI_UNSIGNED_LONG, iDomain, 3, MPI_COMM_WORLD, &send_req[3]); -// SU2_MPI::Isend(&Buffer_Send_nPointGhost, 1, MPI_UNSIGNED_LONG, iDomain, 4, MPI_COMM_WORLD, &send_req[4]); -// SU2_MPI::Isend(&Buffer_Send_nPointPeriodic, 1, MPI_UNSIGNED_LONG, iDomain, 5, MPI_COMM_WORLD, &send_req[5]); - SU2_MPI::Isend(&Buffer_Send_nElemTotal, 1, MPI_UNSIGNED_LONG, iDomain, 6, MPI_COMM_WORLD, &send_req[6]); - SU2_MPI::Isend(&Buffer_Send_nElemTriangle, 1, MPI_UNSIGNED_LONG, iDomain, 7, MPI_COMM_WORLD, &send_req[7]); - SU2_MPI::Isend(&Buffer_Send_nElemQuadrilateral, 1, MPI_UNSIGNED_LONG, iDomain, 8, MPI_COMM_WORLD, &send_req[8]); - SU2_MPI::Isend(&Buffer_Send_nElemTetrahedron, 1, MPI_UNSIGNED_LONG, iDomain, 9, MPI_COMM_WORLD, &send_req[9]); - SU2_MPI::Isend(&Buffer_Send_nElemHexahedron, 1, MPI_UNSIGNED_LONG, iDomain, 10, MPI_COMM_WORLD, &send_req[10]); - SU2_MPI::Isend(&Buffer_Send_nElemPrism, 1, MPI_UNSIGNED_LONG, iDomain, 11, MPI_COMM_WORLD, &send_req[11]); - SU2_MPI::Isend(&Buffer_Send_nElemPyramid, 1, MPI_UNSIGNED_LONG, iDomain, 12, MPI_COMM_WORLD, &send_req[12]); - - SU2_MPI::Isend(&Buffer_Send_nBoundLineTotal, 1, MPI_UNSIGNED_LONG, iDomain, 13, MPI_COMM_WORLD, &send_req[13]); - SU2_MPI::Isend(&Buffer_Send_nBoundTriangleTotal, 1, MPI_UNSIGNED_LONG, iDomain, 14, MPI_COMM_WORLD, &send_req[14]); - SU2_MPI::Isend(&Buffer_Send_nBoundQuadrilateralTotal, 1, MPI_UNSIGNED_LONG, iDomain, 15, MPI_COMM_WORLD, &send_req[15]); - SU2_MPI::Isend(&Buffer_Send_nMarkerDomain, 1, MPI_UNSIGNED_SHORT, iDomain, 16, MPI_COMM_WORLD, &send_req[16]); - SU2_MPI::Isend(Buffer_Send_nVertexDomain, nMarker_Max, MPI_UNSIGNED_LONG, iDomain, 17, MPI_COMM_WORLD, &send_req[17]); - SU2_MPI::Isend(Buffer_Send_nBoundLine, nMarker_Max, MPI_UNSIGNED_LONG, iDomain, 18, MPI_COMM_WORLD, &send_req[18]); - SU2_MPI::Isend(Buffer_Send_nBoundTriangle, nMarker_Max, MPI_UNSIGNED_LONG, iDomain, 19, MPI_COMM_WORLD, &send_req[19]); - SU2_MPI::Isend(Buffer_Send_nBoundQuadrilateral, nMarker_Max, MPI_UNSIGNED_LONG, iDomain, 20, MPI_COMM_WORLD, &send_req[20]); - SU2_MPI::Isend(Buffer_Send_Marker_All_SendRecv, nMarker_Max, MPI_SHORT, iDomain, 21, MPI_COMM_WORLD, &send_req[21]); - SU2_MPI::Isend(Buffer_Send_Marker_All_TagBound, nMarker_Max*MAX_STRING_SIZE, MPI_CHAR, iDomain, 22, MPI_COMM_WORLD, &send_req[22]); - - SU2_MPI::Isend(&Buffer_Send_nPeriodic, 1, MPI_UNSIGNED_SHORT, iDomain, 23, MPI_COMM_WORLD, &send_req[23]); - SU2_MPI::Isend(Buffer_Send_Center, nPeriodic*3, MPI_DOUBLE, iDomain, 24, MPI_COMM_WORLD, &send_req[24]); - SU2_MPI::Isend(Buffer_Send_Rotation, nPeriodic*3, MPI_DOUBLE, iDomain, 25, MPI_COMM_WORLD, &send_req[25]); - SU2_MPI::Isend(Buffer_Send_Translate, nPeriodic*3, MPI_DOUBLE, iDomain, 26, MPI_COMM_WORLD, &send_req[26]); - - SU2_MPI::Isend(&Buffer_Send_nTotalSendDomain_Periodic, 1, MPI_UNSIGNED_LONG, iDomain, 27, MPI_COMM_WORLD, &send_req[27]); - SU2_MPI::Isend(&Buffer_Send_nTotalReceivedDomain_Periodic, 1, MPI_UNSIGNED_LONG, iDomain, 28, MPI_COMM_WORLD, &send_req[28]); - SU2_MPI::Isend(Buffer_Send_nSendDomain_Periodic, nDomain, MPI_UNSIGNED_LONG, iDomain, 29, MPI_COMM_WORLD, &send_req[29]); - SU2_MPI::Isend(Buffer_Send_nReceivedDomain_Periodic, nDomain, MPI_UNSIGNED_LONG, iDomain, 30, MPI_COMM_WORLD, &send_req[30]); - - /*--- Wait for this set of non-blocking comm. to complete ---*/ - - SU2_MPI::Waitall(29, send_req, send_stat); - -#endif - - - } else { - - /*--- We are the master node, so simply copy values into place ---*/ - - nDim = Buffer_Send_nDim; - nZone = Buffer_Send_nZone; - - nPeriodic = Buffer_Send_nPeriodic; - - nPointTotal = Buffer_Send_nPointTotal; - nPointDomainTotal = Buffer_Send_nPointDomainTotal; -// nPointGhost = Buffer_Send_nPointGhost; -// nPointPeriodic = Buffer_Send_nPointPeriodic; - - nElemTotal = Buffer_Send_nElemTotal; - nElemTriangle = Buffer_Send_nElemTriangle; - nElemQuadrilateral = Buffer_Send_nElemQuadrilateral; - nElemTetrahedron = Buffer_Send_nElemTetrahedron; - nElemHexahedron = Buffer_Send_nElemHexahedron; - nElemPrism = Buffer_Send_nElemPrism; - nElemPyramid = Buffer_Send_nElemPyramid; - - nelem_triangle = nElemTriangle; - nelem_quad = nElemQuadrilateral; - nelem_tetra = nElemTetrahedron; - nelem_hexa = nElemHexahedron; - nelem_prism = nElemPrism; - nelem_pyramid = nElemPyramid; - - nBoundLineTotal = Buffer_Send_nBoundLineTotal; - nBoundTriangleTotal = Buffer_Send_nBoundTriangleTotal; - nBoundQuadrilateralTotal = Buffer_Send_nBoundQuadrilateralTotal; - nMarkerDomain = Buffer_Send_nMarkerDomain; - - for (iMarker = 0; iMarker < nMarker_Max; iMarker++) { - nVertexDomain[iMarker] = Buffer_Send_nVertexDomain[iMarker]; - nBoundLine[iMarker] = Buffer_Send_nBoundLine[iMarker]; - nBoundTriangle[iMarker] = Buffer_Send_nBoundTriangle[iMarker]; - nBoundQuadrilateral[iMarker] = Buffer_Send_nBoundQuadrilateral[iMarker]; - Marker_All_SendRecv[iMarker] = Buffer_Send_Marker_All_SendRecv[iMarker]; - for (iter = 0; iter < MAX_STRING_SIZE; iter++) - Marker_All_TagBound[iMarker*MAX_STRING_SIZE+iter] = Buffer_Send_Marker_All_TagBound[iMarker*MAX_STRING_SIZE+iter]; - } - - Buffer_Receive_Center = new su2double[nPeriodic*3]; - Buffer_Receive_Rotation = new su2double[nPeriodic*3]; - Buffer_Receive_Translate = new su2double[nPeriodic*3]; - - for (iter = 0; iter < nPeriodic*3; iter++) { - Buffer_Receive_Center[iter] = Buffer_Send_Center[iter]; - Buffer_Receive_Rotation[iter] = Buffer_Send_Rotation[iter]; - Buffer_Receive_Translate[iter] = Buffer_Send_Translate[iter]; - } - - nTotalSendDomain_Periodic = Buffer_Send_nTotalSendDomain_Periodic; - nTotalReceivedDomain_Periodic = Buffer_Send_nTotalReceivedDomain_Periodic; - - for (iter = 0; iter < nDomain; iter++) { - nSendDomain_Periodic[iter] = Buffer_Send_nSendDomain_Periodic[iter]; - nReceivedDomain_Periodic[iter] = Buffer_Send_nReceivedDomain_Periodic[iter]; - } - - } - } - - /*--- Receive the size of buffers---*/ - - if (rank == iDomain) { - - /*--- Receive the size of buffers---*/ - - if (rank != MASTER_NODE) { - -#ifdef HAVE_MPI - - SU2_MPI::Irecv(&nDim, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, 0, MPI_COMM_WORLD, &recv_req[0]); - SU2_MPI::Irecv(&nZone, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, 1, MPI_COMM_WORLD, &recv_req[1]); - SU2_MPI::Irecv(&nPointTotal, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 2, MPI_COMM_WORLD, &recv_req[2]); - SU2_MPI::Irecv(&nPointDomainTotal, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 3, MPI_COMM_WORLD, &recv_req[3]); -// SU2_MPI::Irecv(&nPointGhost, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 4, MPI_COMM_WORLD, &recv_req[4]); -// SU2_MPI::Irecv(&nPointPeriodic, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 5, MPI_COMM_WORLD, &recv_req[5]); - SU2_MPI::Irecv(&nElemTotal, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 6, MPI_COMM_WORLD, &recv_req[6]); - SU2_MPI::Irecv(&nElemTriangle, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 7, MPI_COMM_WORLD, &recv_req[7]); - SU2_MPI::Irecv(&nElemQuadrilateral, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 8, MPI_COMM_WORLD, &recv_req[8]); - SU2_MPI::Irecv(&nElemTetrahedron, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 9, MPI_COMM_WORLD, &recv_req[9]); - SU2_MPI::Irecv(&nElemHexahedron, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 10, MPI_COMM_WORLD, &recv_req[10]); - SU2_MPI::Irecv(&nElemPrism, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 11, MPI_COMM_WORLD, &recv_req[11]); - SU2_MPI::Irecv(&nElemPyramid, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 12, MPI_COMM_WORLD, &recv_req[12]); - - SU2_MPI::Irecv(&nBoundLineTotal, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 13, MPI_COMM_WORLD, &recv_req[13]); - SU2_MPI::Irecv(&nBoundTriangleTotal, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 14, MPI_COMM_WORLD, &recv_req[14]); - SU2_MPI::Irecv(&nBoundQuadrilateralTotal, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 15, MPI_COMM_WORLD, &recv_req[15]); - SU2_MPI::Irecv(&nMarkerDomain, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, 16, MPI_COMM_WORLD, &recv_req[16]); - SU2_MPI::Irecv(nVertexDomain, nMarker_Max, MPI_UNSIGNED_LONG, MASTER_NODE, 17, MPI_COMM_WORLD, &recv_req[17]); - SU2_MPI::Irecv(nBoundLine, nMarker_Max, MPI_UNSIGNED_LONG, MASTER_NODE, 18, MPI_COMM_WORLD, &recv_req[18]); - SU2_MPI::Irecv(nBoundTriangle, nMarker_Max, MPI_UNSIGNED_LONG, MASTER_NODE, 19, MPI_COMM_WORLD, &recv_req[19]); - SU2_MPI::Irecv(nBoundQuadrilateral, nMarker_Max, MPI_UNSIGNED_LONG, MASTER_NODE, 20, MPI_COMM_WORLD, &recv_req[20]); - SU2_MPI::Irecv(Marker_All_SendRecv, nMarker_Max, MPI_SHORT, MASTER_NODE, 21, MPI_COMM_WORLD, &recv_req[21]); - SU2_MPI::Irecv(Marker_All_TagBound, nMarker_Max*MAX_STRING_SIZE, MPI_CHAR, MASTER_NODE, 22, MPI_COMM_WORLD, &recv_req[22]); - SU2_MPI::Irecv(&nPeriodic, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, 23, MPI_COMM_WORLD, &recv_req[23]); - - /*--- Wait for the this set of non-blocking recv's to complete ---*/ - - SU2_MPI::Waitall(22, recv_req, recv_stat); - -#endif - - /*--- Update the number of elements (local) ---*/ - - nelem_triangle = nElemTriangle; - nelem_quad = nElemQuadrilateral; - nelem_tetra = nElemTetrahedron; - nelem_hexa = nElemHexahedron; - nelem_prism = nElemPrism; - nelem_pyramid = nElemPyramid; - - /*--- Marker_All_TagBound and Marker_All_SendRecv, set the same values in the config files of all the files ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - config->SetMarker_All_SendRecv(iMarker, Marker_All_SendRecv[iMarker]); - config->SetMarker_All_TagBound(iMarker, string(&Marker_All_TagBound[iMarker*MAX_STRING_SIZE])); - } - - /*--- Periodic boundary conditions, set the values in the config files of all the files ---*/ - - Buffer_Receive_Center = new su2double[nPeriodic*3]; - Buffer_Receive_Rotation = new su2double[nPeriodic*3]; - Buffer_Receive_Translate = new su2double[nPeriodic*3]; - -#ifdef HAVE_MPI - - SU2_MPI::Irecv(Buffer_Receive_Center, nPeriodic*3, MPI_DOUBLE, MASTER_NODE, 24, MPI_COMM_WORLD, &recv_req[0]); - SU2_MPI::Irecv(Buffer_Receive_Rotation, nPeriodic*3, MPI_DOUBLE, MASTER_NODE, 25, MPI_COMM_WORLD, &recv_req[1]); - SU2_MPI::Irecv(Buffer_Receive_Translate, nPeriodic*3, MPI_DOUBLE, MASTER_NODE, 26, MPI_COMM_WORLD, &recv_req[2]); - - SU2_MPI::Irecv(&nTotalSendDomain_Periodic, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 27, MPI_COMM_WORLD, &recv_req[3]); - SU2_MPI::Irecv(&nTotalReceivedDomain_Periodic, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 28, MPI_COMM_WORLD, &recv_req[4]); - SU2_MPI::Irecv(nSendDomain_Periodic, nDomain, MPI_UNSIGNED_LONG, MASTER_NODE, 29, MPI_COMM_WORLD, &recv_req[5]); - SU2_MPI::Irecv(nReceivedDomain_Periodic, nDomain, MPI_UNSIGNED_LONG, MASTER_NODE, 30, MPI_COMM_WORLD, &recv_req[6]); - - /*--- Wait for this set of non-blocking comm. to complete ---*/ - - SU2_MPI::Waitall(7, recv_req, recv_stat); - -#endif - - config->SetnPeriodicIndex(nPeriodic); - - for (iPeriodic = 0; iPeriodic < nPeriodic; iPeriodic++) { - - su2double* center = new su2double[3]; // Do not deallocate the memory - su2double* rotation = new su2double[3]; // Do not deallocate the memory - su2double* translate = new su2double[3]; // Do not deallocate the memory - - for (iDim = 0; iDim < 3; iDim++) { - center[iDim] = Buffer_Receive_Center[iDim+iPeriodic*3]; - rotation[iDim] = Buffer_Receive_Rotation[iDim+iPeriodic*3]; - translate[iDim] = Buffer_Receive_Translate[iDim+iPeriodic*3]; - } - config->SetPeriodicCenter(iPeriodic, center); - config->SetPeriodicRotation(iPeriodic, rotation); - config->SetPeriodicTranslate(iPeriodic, translate); - } - - } - - delete [] Buffer_Receive_Center; - delete [] Buffer_Receive_Rotation; - delete [] Buffer_Receive_Translate; - - /*--- Allocate the receive buffer vector ---*/ - - Buffer_Receive_Coord = new su2double [nPointTotal*nDim]; - Buffer_Receive_Color = new unsigned long [nPointTotal]; - Buffer_Receive_GlobalPointIndex = new unsigned long [nPointTotal]; - Buffer_Receive_Triangle = new unsigned long [nElemTriangle*3]; - Buffer_Receive_Quadrilateral = new unsigned long [nElemQuadrilateral*4]; - Buffer_Receive_Tetrahedron = new unsigned long [nElemTetrahedron*4]; - Buffer_Receive_Hexahedron = new unsigned long [nElemHexahedron*8]; - Buffer_Receive_Prism = new unsigned long [nElemPrism*6]; - Buffer_Receive_Pyramid = new unsigned long [nElemPyramid*5]; - Buffer_Receive_BoundLine = new unsigned long [nBoundLineTotal*2]; - Buffer_Receive_BoundTriangle = new unsigned long [nBoundTriangleTotal*3]; - Buffer_Receive_BoundQuadrilateral = new unsigned long [nBoundQuadrilateralTotal*4]; - Buffer_Receive_Local2Global_Marker = new unsigned long [nMarkerDomain]; - - Buffer_Receive_SendDomain_Periodic = new unsigned long [nTotalSendDomain_Periodic]; - Buffer_Receive_SendDomain_PeriodicTrans = new unsigned long [nTotalSendDomain_Periodic]; - Buffer_Receive_SendDomain_PeriodicReceptor = new unsigned long [nTotalSendDomain_Periodic]; - Buffer_Receive_ReceivedDomain_Periodic = new unsigned long [nTotalReceivedDomain_Periodic]; - Buffer_Receive_ReceivedDomain_PeriodicTrans = new unsigned long [nTotalReceivedDomain_Periodic]; - Buffer_Receive_ReceivedDomain_PeriodicDonor = new unsigned long [nTotalReceivedDomain_Periodic]; - - } - - /*--- Set the value of the Send buffers ---*/ - - if (rank == MASTER_NODE) { - - /*--- Set the value of the interior geometry ---*/ - - iElemTotal = 0; - iPointDomain = 0; - iPointPeriodic = Buffer_Send_nPointDomainTotal; - iPointGhost = Buffer_Send_nPointDomainTotal + Buffer_Send_nPointPeriodic; - iElemTriangle = 0; - iElemQuadrilateral = 0; - iElemTetrahedron = 0; - iElemHexahedron = 0; - iElemPrism = 0; - iElemPyramid = 0; - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) Global2Local_Point[iPoint] = -1; - - for (jElem = 0; jElem < nElem_Color[iDomain]; jElem++) { - - iElem = Elem_Color[iDomain][jElem]; - - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { - iPoint = geometry->elem[iElem]->GetNode(iNode); - if (Global2Local_Point[iPoint] == -1) { - - if ( geometry->node[iPoint]->GetColor() == iDomain ) { - if ( iPoint > geometry->GetnPointDomain() - 1) iPointTotal = iPointPeriodic; - else iPointTotal = iPointDomain; - } - else iPointTotal = iPointGhost; - - Global2Local_Point[iPoint] = iPointTotal; - Buffer_Send_Color[iPointTotal] = geometry->node[iPoint]->GetColor(); - Buffer_Send_GlobalPointIndex[iPointTotal] = iPoint; - for (iDim = 0; iDim < Buffer_Send_nDim; iDim++) - Buffer_Send_Coord[Buffer_Send_nDim*iPointTotal+iDim] = geometry->node[iPoint]->GetCoord(iDim); - - if ( geometry->node[iPoint]->GetColor() == iDomain ) { - if ( iPoint > geometry->GetnPointDomain() - 1) iPointPeriodic++; - else iPointDomain++; - } - else iPointGhost++; - - } - - vnodes_local[iNode] = Global2Local_Point[iPoint]; - - } - - switch(geometry->elem[iElem]->GetVTK_Type()) { - case TRIANGLE: - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) - Buffer_Send_Triangle[3*iElemTriangle+iNode] = vnodes_local[iNode]; - iElemTriangle++; break; - case QUADRILATERAL: - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) - Buffer_Send_Quadrilateral[4*iElemQuadrilateral+iNode] = vnodes_local[iNode]; - iElemQuadrilateral++; break; - case TETRAHEDRON: - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) - Buffer_Send_Tetrahedron[4*iElemTetrahedron+iNode] = vnodes_local[iNode]; - iElemTetrahedron++; break; - case HEXAHEDRON: - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) - Buffer_Send_Hexahedron[8*iElemHexahedron+iNode] = vnodes_local[iNode]; - iElemHexahedron++; break; - case PRISM: - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) - Buffer_Send_Prism[6*iElemPrism+iNode] = vnodes_local[iNode]; - iElemPrism++; break; - case PYRAMID: - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) - Buffer_Send_Pyramid[5*iElemPyramid+iNode] = vnodes_local[iNode]; - iElemPyramid++; break; - } - - iElemTotal++; - - } - - /*--- Set the value of the boundary geometry ---*/ - - iMarkerDomain = 0; - iBoundLineTotal = 0; iBoundTriangleTotal = 0; iBoundQuadrilateralTotal = 0; - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - if ((config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) && (MarkerIn[iMarker])) { - for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { - - if (VertexIn[iMarker][iVertex]) { - - for (iNode = 0; iNode < geometry->bound[iMarker][iVertex]->GetnNodes(); iNode++) { - vnodes_local[iNode] = Global2Local_Point[geometry->bound[iMarker][iVertex]->GetNode(iNode)]; - } - - switch(geometry->bound[iMarker][iVertex]->GetVTK_Type()) { - case LINE: - Buffer_Send_BoundLine[2*iBoundLineTotal+0] = vnodes_local[0]; - Buffer_Send_BoundLine[2*iBoundLineTotal+1] = vnodes_local[1]; - iBoundLineTotal++; - break; - case TRIANGLE: - Buffer_Send_BoundTriangle[3*iBoundTriangleTotal+0] = vnodes_local[0]; - Buffer_Send_BoundTriangle[3*iBoundTriangleTotal+1] = vnodes_local[1]; - Buffer_Send_BoundTriangle[3*iBoundTriangleTotal+2] = vnodes_local[2]; - iBoundTriangleTotal++; - break; - case QUADRILATERAL: - Buffer_Send_BoundQuadrilateral[4*iBoundQuadrilateralTotal+0] = vnodes_local[0]; - Buffer_Send_BoundQuadrilateral[4*iBoundQuadrilateralTotal+1] = vnodes_local[1]; - Buffer_Send_BoundQuadrilateral[4*iBoundQuadrilateralTotal+2] = vnodes_local[2]; - Buffer_Send_BoundQuadrilateral[4*iBoundQuadrilateralTotal+3] = vnodes_local[3]; - iBoundQuadrilateralTotal++; - break; - } - } - } - - Buffer_Send_Local2Global_Marker[iMarkerDomain] = iMarker; - iMarkerDomain++; - - } - } - - /*--- Evaluate the number of already existing periodic boundary conditions ---*/ - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { - - for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { - - iPoint = geometry->bound[iMarker][iVertex]->GetNode(0); - Transformation = geometry->bound[iMarker][iVertex]->GetRotation_Type(); - - if (iDomain == geometry->node[iPoint]->GetColor()) { - - /*--- If the information is going to be sended, find the - domain of the receptor ---*/ - - if (config->GetMarker_All_SendRecv(iMarker) > 0) { - - /*--- Identify the color of the receptor ---*/ - - for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) { - if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker))) { - jPoint = geometry->bound[jMarker][iVertex]->GetNode(0); - ReceptorColor = geometry->node[jPoint]->GetColor(); - } - } - - /*--- For each color of the receptor we will han an extra marker (+) ---*/ - - Buffer_Send_SendDomain_Periodic[iTotalSendDomain_Periodic] = Global2Local_Point[iPoint]; - Buffer_Send_SendDomain_PeriodicTrans[iTotalSendDomain_Periodic] = Transformation; - Buffer_Send_SendDomain_PeriodicReceptor[iTotalSendDomain_Periodic] = ReceptorColor; - - iTotalSendDomain_Periodic++; - - } - - /*--- If the information is goint to be received, find the domain if the donor ---*/ - - if (config->GetMarker_All_SendRecv(iMarker) < 0) { - - /*--- Identify the color of the donor ---*/ - - for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) { - if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker) )) { - jPoint = geometry->bound[jMarker][iVertex]->GetNode(0); - DonorColor = geometry->node[jPoint]->GetColor(); - } - } - - /*--- For each color of the donor we will han an extra marker (-) ---*/ - - Buffer_Send_ReceivedDomain_Periodic[iTotalReceivedDomain_Periodic] = Global2Local_Point[iPoint]; - Buffer_Send_ReceivedDomain_PeriodicTrans[iTotalReceivedDomain_Periodic] = Transformation; - Buffer_Send_ReceivedDomain_PeriodicDonor[iTotalReceivedDomain_Periodic] = DonorColor; - - iTotalReceivedDomain_Periodic++; - - } - } - } - } - } - - /*--- Send the buffers with the geometrical information ---*/ - - if (iDomain != MASTER_NODE) { - -#ifdef HAVE_MPI - - SU2_MPI::Isend(Buffer_Send_Coord, Buffer_Send_nPointTotal*Buffer_Send_nDim, MPI_DOUBLE, iDomain, 0, MPI_COMM_WORLD, &send_req[0]); - SU2_MPI::Isend(Buffer_Send_GlobalPointIndex, Buffer_Send_nPointTotal, MPI_UNSIGNED_LONG, iDomain, 1, MPI_COMM_WORLD, &send_req[1]); - SU2_MPI::Isend(Buffer_Send_Color, Buffer_Send_nPointTotal, MPI_UNSIGNED_LONG, iDomain, 2, MPI_COMM_WORLD, &send_req[2]); - SU2_MPI::Isend(Buffer_Send_Triangle, Buffer_Send_nElemTriangle*3, MPI_UNSIGNED_LONG, iDomain, 3, MPI_COMM_WORLD, &send_req[3]); - SU2_MPI::Isend(Buffer_Send_Quadrilateral, Buffer_Send_nElemQuadrilateral*4, MPI_UNSIGNED_LONG, iDomain, 4, MPI_COMM_WORLD, &send_req[4]); - SU2_MPI::Isend(Buffer_Send_Tetrahedron, Buffer_Send_nElemTetrahedron*4, MPI_UNSIGNED_LONG, iDomain, 5, MPI_COMM_WORLD, &send_req[5]); - SU2_MPI::Isend(Buffer_Send_Hexahedron, Buffer_Send_nElemHexahedron*8, MPI_UNSIGNED_LONG, iDomain, 6, MPI_COMM_WORLD, &send_req[6]); - SU2_MPI::Isend(Buffer_Send_Prism, Buffer_Send_nElemPrism*6, MPI_UNSIGNED_LONG, iDomain, 7, MPI_COMM_WORLD, &send_req[7]); - SU2_MPI::Isend(Buffer_Send_Pyramid, Buffer_Send_nElemPyramid*5, MPI_UNSIGNED_LONG, iDomain, 8, MPI_COMM_WORLD, &send_req[8]); - SU2_MPI::Isend(Buffer_Send_BoundLine, Buffer_Send_nBoundLineTotal*2, MPI_UNSIGNED_LONG, iDomain, 9, MPI_COMM_WORLD, &send_req[9]); - SU2_MPI::Isend(Buffer_Send_BoundTriangle, Buffer_Send_nBoundTriangleTotal*3, MPI_UNSIGNED_LONG, iDomain, 10, MPI_COMM_WORLD, &send_req[10]); - SU2_MPI::Isend(Buffer_Send_BoundQuadrilateral, Buffer_Send_nBoundQuadrilateralTotal*4, MPI_UNSIGNED_LONG, iDomain, 11, MPI_COMM_WORLD, &send_req[11]); - SU2_MPI::Isend(Buffer_Send_Local2Global_Marker, Buffer_Send_nMarkerDomain, MPI_UNSIGNED_LONG, iDomain, 12, MPI_COMM_WORLD, &send_req[12]); - - SU2_MPI::Isend(Buffer_Send_SendDomain_Periodic, Buffer_Send_nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, 13, MPI_COMM_WORLD, &send_req[13]); - SU2_MPI::Isend(Buffer_Send_SendDomain_PeriodicTrans, Buffer_Send_nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, 14, MPI_COMM_WORLD, &send_req[14]); - SU2_MPI::Isend(Buffer_Send_SendDomain_PeriodicReceptor, Buffer_Send_nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, 15, MPI_COMM_WORLD, &send_req[15]); - SU2_MPI::Isend(Buffer_Send_ReceivedDomain_Periodic, Buffer_Send_nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, 16, MPI_COMM_WORLD, &send_req[16]); - SU2_MPI::Isend(Buffer_Send_ReceivedDomain_PeriodicTrans, Buffer_Send_nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, 17, MPI_COMM_WORLD, &send_req[17]); - SU2_MPI::Isend(Buffer_Send_ReceivedDomain_PeriodicDonor, Buffer_Send_nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, 18, MPI_COMM_WORLD, &send_req[18]); - - /*--- Wait for this set of non-blocking comm. to complete ---*/ - - SU2_MPI::Waitall(19, send_req, send_stat); - -#endif - - } else { - - for (iter = 0; iter < Buffer_Send_nPointTotal*Buffer_Send_nDim; iter++) - Buffer_Receive_Coord[iter] = Buffer_Send_Coord[iter]; - - for (iter = 0; iter < Buffer_Send_nPointTotal; iter++) { - Buffer_Receive_GlobalPointIndex[iter] = Buffer_Send_GlobalPointIndex[iter]; - Buffer_Receive_Color[iter] = Buffer_Send_Color[iter]; - } - - for (iter = 0; iter < Buffer_Send_nElemTriangle*3; iter++) - Buffer_Receive_Triangle[iter] = Buffer_Send_Triangle[iter]; - - for (iter = 0; iter < Buffer_Send_nElemQuadrilateral*4; iter++) - Buffer_Receive_Quadrilateral[iter] = Buffer_Send_Quadrilateral[iter]; - - for (iter = 0; iter < Buffer_Send_nElemTetrahedron*4; iter++) - Buffer_Receive_Tetrahedron[iter] = Buffer_Send_Tetrahedron[iter]; - - for (iter = 0; iter < Buffer_Send_nElemHexahedron*8; iter++) - Buffer_Receive_Hexahedron[iter] = Buffer_Send_Hexahedron[iter]; - - for (iter = 0; iter < Buffer_Send_nElemPrism*6; iter++) - Buffer_Receive_Prism[iter] = Buffer_Send_Prism[iter]; - - for (iter = 0; iter < Buffer_Send_nElemPyramid*5; iter++) - Buffer_Receive_Pyramid[iter] = Buffer_Send_Pyramid[iter]; - - for (iter = 0; iter < Buffer_Send_nBoundLineTotal*2; iter++) - Buffer_Receive_BoundLine[iter] = Buffer_Send_BoundLine[iter]; - - for (iter = 0; iter < Buffer_Send_nBoundTriangleTotal*3; iter++) - Buffer_Receive_BoundTriangle[iter] = Buffer_Send_BoundTriangle[iter]; - - for (iter = 0; iter < Buffer_Send_nBoundQuadrilateralTotal*4; iter++) - Buffer_Receive_BoundQuadrilateral[iter] = Buffer_Send_BoundQuadrilateral[iter]; - - for (iter = 0; iter < Buffer_Send_nMarkerDomain; iter++) - Buffer_Receive_Local2Global_Marker[iter] = Buffer_Send_Local2Global_Marker[iter]; - - for (iter = 0; iter < Buffer_Send_nTotalSendDomain_Periodic; iter++) { - Buffer_Receive_SendDomain_Periodic[iter] = Buffer_Send_SendDomain_Periodic[iter]; - Buffer_Receive_SendDomain_PeriodicTrans[iter] = Buffer_Send_SendDomain_PeriodicTrans[iter]; - Buffer_Receive_SendDomain_PeriodicReceptor[iter] = Buffer_Send_SendDomain_PeriodicReceptor[iter]; - } - - for (iter = 0; iter < Buffer_Send_nTotalReceivedDomain_Periodic; iter++) { - Buffer_Receive_ReceivedDomain_Periodic[iter] = Buffer_Send_ReceivedDomain_Periodic[iter]; - Buffer_Receive_ReceivedDomain_PeriodicTrans[iter] = Buffer_Send_ReceivedDomain_PeriodicTrans[iter]; - Buffer_Receive_ReceivedDomain_PeriodicDonor[iter] = Buffer_Send_ReceivedDomain_PeriodicDonor[iter]; - } - - } - - delete[] Buffer_Send_Coord; - delete[] Buffer_Send_GlobalPointIndex; - delete[] Buffer_Send_Color; - delete[] Buffer_Send_Triangle; - delete[] Buffer_Send_Quadrilateral; - delete[] Buffer_Send_Tetrahedron; - delete[] Buffer_Send_Hexahedron; - delete[] Buffer_Send_Prism; - delete[] Buffer_Send_Pyramid; - delete[] Buffer_Send_BoundLine; - delete[] Buffer_Send_BoundTriangle; - delete[] Buffer_Send_BoundQuadrilateral; - delete[] Buffer_Send_Local2Global_Marker; - - delete[] Buffer_Send_SendDomain_Periodic; - delete[] Buffer_Send_SendDomain_PeriodicTrans; - delete[] Buffer_Send_SendDomain_PeriodicReceptor; - delete[] Buffer_Send_ReceivedDomain_Periodic; - delete[] Buffer_Send_ReceivedDomain_PeriodicTrans; - delete[] Buffer_Send_ReceivedDomain_PeriodicDonor; - - } - - if (rank == iDomain) { - - if (rank != MASTER_NODE) { - - /*--- Receive the buffers with the geometrical information ---*/ - -#ifdef HAVE_MPI - - SU2_MPI::Irecv(Buffer_Receive_Coord, nPointTotal*nDim, MPI_DOUBLE, MASTER_NODE, 0, MPI_COMM_WORLD, &recv_req[0]); - SU2_MPI::Irecv(Buffer_Receive_GlobalPointIndex, nPointTotal, MPI_UNSIGNED_LONG, MASTER_NODE, 1, MPI_COMM_WORLD, &recv_req[1]); - SU2_MPI::Irecv(Buffer_Receive_Color, nPointTotal, MPI_UNSIGNED_LONG, MASTER_NODE, 2, MPI_COMM_WORLD, &recv_req[2]); - SU2_MPI::Irecv(Buffer_Receive_Triangle, nElemTriangle*3, MPI_UNSIGNED_LONG, MASTER_NODE, 3, MPI_COMM_WORLD, &recv_req[3]); - SU2_MPI::Irecv(Buffer_Receive_Quadrilateral, nElemQuadrilateral*4, MPI_UNSIGNED_LONG, MASTER_NODE, 4, MPI_COMM_WORLD, &recv_req[4]); - SU2_MPI::Irecv(Buffer_Receive_Tetrahedron, nElemTetrahedron*4, MPI_UNSIGNED_LONG, MASTER_NODE, 5, MPI_COMM_WORLD, &recv_req[5]); - SU2_MPI::Irecv(Buffer_Receive_Hexahedron, nElemHexahedron*8, MPI_UNSIGNED_LONG, MASTER_NODE, 6, MPI_COMM_WORLD, &recv_req[6]); - SU2_MPI::Irecv(Buffer_Receive_Prism, nElemPrism*6, MPI_UNSIGNED_LONG, MASTER_NODE, 7, MPI_COMM_WORLD, &recv_req[7]); - SU2_MPI::Irecv(Buffer_Receive_Pyramid, nElemPyramid*5, MPI_UNSIGNED_LONG, MASTER_NODE, 8, MPI_COMM_WORLD, &recv_req[8]); - SU2_MPI::Irecv(Buffer_Receive_BoundLine, nBoundLineTotal*2, MPI_UNSIGNED_LONG, MASTER_NODE, 9, MPI_COMM_WORLD, &recv_req[9]); - SU2_MPI::Irecv(Buffer_Receive_BoundTriangle, nBoundTriangleTotal*3, MPI_UNSIGNED_LONG, MASTER_NODE, 10, MPI_COMM_WORLD, &recv_req[10]); - SU2_MPI::Irecv(Buffer_Receive_BoundQuadrilateral, nBoundQuadrilateralTotal*4, MPI_UNSIGNED_LONG, MASTER_NODE, 11, MPI_COMM_WORLD, &recv_req[11]); - SU2_MPI::Irecv(Buffer_Receive_Local2Global_Marker, nMarkerDomain, MPI_UNSIGNED_LONG, MASTER_NODE, 12, MPI_COMM_WORLD, &recv_req[12]); - - SU2_MPI::Irecv(Buffer_Receive_SendDomain_Periodic, nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, MASTER_NODE, 13, MPI_COMM_WORLD, &recv_req[13]); - SU2_MPI::Irecv(Buffer_Receive_SendDomain_PeriodicTrans, nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, MASTER_NODE, 14, MPI_COMM_WORLD, &recv_req[14]); - SU2_MPI::Irecv(Buffer_Receive_SendDomain_PeriodicReceptor, nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, MASTER_NODE, 15, MPI_COMM_WORLD, &recv_req[15]); - SU2_MPI::Irecv(Buffer_Receive_ReceivedDomain_Periodic, nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, MASTER_NODE, 16, MPI_COMM_WORLD, &recv_req[16]); - SU2_MPI::Irecv(Buffer_Receive_ReceivedDomain_PeriodicTrans, nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, MASTER_NODE, 17, MPI_COMM_WORLD, &recv_req[17]); - SU2_MPI::Irecv(Buffer_Receive_ReceivedDomain_PeriodicDonor, nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, MASTER_NODE, 18, MPI_COMM_WORLD, &recv_req[18]); - - /*--- Wait for this set of non-blocking recv's to complete ---*/ - - SU2_MPI::Waitall(19, recv_req, recv_stat); - -#endif - - } - - /*--- Create the domain structures for the points ---*/ - - nPoint = nPointTotal; - nPointDomain = nPointDomainTotal; - node = new CPoint*[nPoint]; - Local_to_Global_Point = new long[nPoint]; - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - Local_to_Global_Point[iPoint] = Buffer_Receive_GlobalPointIndex[iPoint]; - if ( nDim == 2 ) node[iPoint] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0], Buffer_Receive_Coord[iPoint*nDim+1], Local_to_Global_Point[iPoint], config); - if ( nDim == 3 ) node[iPoint] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0], Buffer_Receive_Coord[iPoint*nDim+1], Buffer_Receive_Coord[iPoint*nDim+2], Local_to_Global_Point[iPoint], config); - node[iPoint]->SetColor(Buffer_Receive_Color[iPoint]); - } - - delete[] Buffer_Receive_Coord; - delete[] Buffer_Receive_GlobalPointIndex; - delete[] Buffer_Receive_Color; - - /*--- Create the domain structures for the elements ---*/ - - nElem = nElemTotal; iElem = 0; - elem = new CPrimalGrid*[nElem]; - - for (iElemTriangle = 0; iElemTriangle < nElemTriangle; iElemTriangle++) { - elem[iElem] = new CTriangle(Buffer_Receive_Triangle[iElemTriangle*3+0], Buffer_Receive_Triangle[iElemTriangle*3+1], Buffer_Receive_Triangle[iElemTriangle*3+2], 2); - iElem++; - } - for (iElemQuadrilateral = 0; iElemQuadrilateral < nElemQuadrilateral; iElemQuadrilateral++) { - elem[iElem] = new CQuadrilateral(Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+0], Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+1], Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+2], Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+3], 2); - iElem++; - } - for (iElemTetrahedron = 0; iElemTetrahedron < nElemTetrahedron; iElemTetrahedron++) { - elem[iElem] = new CTetrahedron(Buffer_Receive_Tetrahedron[iElemTetrahedron*4+0], Buffer_Receive_Tetrahedron[iElemTetrahedron*4+1], Buffer_Receive_Tetrahedron[iElemTetrahedron*4+2], Buffer_Receive_Tetrahedron[iElemTetrahedron*4+3]); - iElem++; - } - for (iElemHexahedron = 0; iElemHexahedron < nElemHexahedron; iElemHexahedron++) { - elem[iElem] = new CHexahedron(Buffer_Receive_Hexahedron[iElemHexahedron*8+0], Buffer_Receive_Hexahedron[iElemHexahedron*8+1], Buffer_Receive_Hexahedron[iElemHexahedron*8+2], Buffer_Receive_Hexahedron[iElemHexahedron*8+3], Buffer_Receive_Hexahedron[iElemHexahedron*8+4], Buffer_Receive_Hexahedron[iElemHexahedron*8+5], Buffer_Receive_Hexahedron[iElemHexahedron*8+6], Buffer_Receive_Hexahedron[iElemHexahedron*8+7]); - iElem++; - } - for (iElemPrism = 0; iElemPrism < nElemPrism; iElemPrism++) { - elem[iElem] = new CPrism(Buffer_Receive_Prism[iElemPrism*6+0], Buffer_Receive_Prism[iElemPrism*6+1], Buffer_Receive_Prism[iElemPrism*6+2], Buffer_Receive_Prism[iElemPrism*6+3], Buffer_Receive_Prism[iElemPrism*6+4], Buffer_Receive_Prism[iElemPrism*6+5]); - iElem++; - } - for (iElemPyramid = 0; iElemPyramid < nElemPyramid; iElemPyramid++) { - elem[iElem] = new CPyramid(Buffer_Receive_Pyramid[iElemPyramid*5+0], Buffer_Receive_Pyramid[iElemPyramid*5+1], Buffer_Receive_Pyramid[iElemPyramid*5+2], Buffer_Receive_Pyramid[iElemPyramid*5+3], Buffer_Receive_Pyramid[iElemPyramid*5+4]); - iElem++; - } - - delete[] Buffer_Receive_Triangle; - delete[] Buffer_Receive_Quadrilateral; - delete[] Buffer_Receive_Tetrahedron; - delete[] Buffer_Receive_Hexahedron; - delete[] Buffer_Receive_Prism; - delete[] Buffer_Receive_Pyramid; - - /*--- Create the domain structures for the boundaries ---*/ - - nMarker = nMarkerDomain; - - nElem_Bound = new unsigned long [nMarker_Max]; - Local_to_Global_Marker = new unsigned short [nMarker_Max]; - Tag_to_Marker = new string [nMarker_Max]; - string *TagBound_Copy = new string [nMarker_Max]; - short *SendRecv_Copy = new short [nMarker_Max]; - - for (iMarker = 0; iMarker < nMarker; iMarker++) nElem_Bound[iMarker] = nVertexDomain[iMarker]; - - bound = new CPrimalGrid**[nMarker+(overhead*nDomain)]; - for (iMarker = 0; iMarker < nMarker; iMarker++) bound[iMarker] = new CPrimalGrid* [nElem_Bound[iMarker]]; - - iBoundLineTotal = 0; iBoundTriangleTotal = 0; iBoundQuadrilateralTotal = 0; - - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - iVertexDomain = 0; - - for (iBoundLine = 0; iBoundLine < nBoundLine[iMarker]; iBoundLine++) { - bound[iMarker][iVertexDomain] = new CLine(Buffer_Receive_BoundLine[iBoundLineTotal*2+0], - Buffer_Receive_BoundLine[iBoundLineTotal*2+1], 2); - iVertexDomain++; iBoundLineTotal++; - } - for (iBoundTriangle = 0; iBoundTriangle < nBoundTriangle[iMarker]; iBoundTriangle++) { - bound[iMarker][iVertexDomain] = new CTriangle(Buffer_Receive_BoundTriangle[iBoundTriangleTotal*3+0], - Buffer_Receive_BoundTriangle[iBoundTriangleTotal*3+1], - Buffer_Receive_BoundTriangle[iBoundTriangleTotal*3+2], 3); - iVertexDomain++; iBoundTriangleTotal++; - } - for (iBoundQuadrilateral = 0; iBoundQuadrilateral < nBoundQuadrilateral[iMarker]; iBoundQuadrilateral++) { - bound[iMarker][iVertexDomain] = new CQuadrilateral(Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+0], - Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+1], - Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+2], - Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+3], 3); - iVertexDomain++; iBoundQuadrilateralTotal++; - } - - Local_to_Global_Marker[iMarker] = Buffer_Receive_Local2Global_Marker[iMarker]; - - /*--- Now each domain has the right information ---*/ - - string Grid_Marker = config->GetMarker_All_TagBound(Local_to_Global_Marker[iMarker]); - short SendRecv = config->GetMarker_All_SendRecv(Local_to_Global_Marker[iMarker]); - TagBound_Copy[iMarker] = Grid_Marker; - SendRecv_Copy[iMarker] = SendRecv; - - } - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - config->SetMarker_All_TagBound(iMarker, TagBound_Copy[iMarker]); - config->SetMarker_All_SendRecv(iMarker, SendRecv_Copy[iMarker]); - } - - /*--- Add the new periodic markers to the domain ---*/ - - iTotalSendDomain_Periodic = 0; - iTotalReceivedDomain_Periodic = 0; - - for (jDomain = 0; jDomain < nDomain; jDomain++) { - - if (nSendDomain_Periodic[jDomain] != 0) { - nVertexDomain[nMarker] = 0; - bound[nMarker] = new CPrimalGrid* [nSendDomain_Periodic[jDomain]]; - - iVertex = 0; - for (iTotalSendDomain_Periodic = 0; iTotalSendDomain_Periodic < nTotalSendDomain_Periodic; iTotalSendDomain_Periodic++) { - if (Buffer_Receive_SendDomain_PeriodicReceptor[iTotalSendDomain_Periodic] == jDomain) { - bound[nMarker][iVertex] = new CVertexMPI(Buffer_Receive_SendDomain_Periodic[iTotalSendDomain_Periodic], nDim); - bound[nMarker][iVertex]->SetRotation_Type(Buffer_Receive_SendDomain_PeriodicTrans[iTotalSendDomain_Periodic]); - nVertexDomain[nMarker]++; iVertex++; - } - } - - Marker_All_SendRecv[nMarker] = jDomain+1; - nElem_Bound[nMarker] = nVertexDomain[nMarker]; - nMarker++; - } - - if (nReceivedDomain_Periodic[jDomain] != 0) { - nVertexDomain[nMarker] = 0; - bound[nMarker] = new CPrimalGrid* [nReceivedDomain_Periodic[jDomain]]; - - iVertex = 0; - for (iTotalReceivedDomain_Periodic = 0; iTotalReceivedDomain_Periodic < nTotalReceivedDomain_Periodic; iTotalReceivedDomain_Periodic++) { - if (Buffer_Receive_ReceivedDomain_PeriodicDonor[iTotalReceivedDomain_Periodic] == jDomain) { - bound[nMarker][iVertex] = new CVertexMPI(Buffer_Receive_ReceivedDomain_Periodic[iTotalReceivedDomain_Periodic], nDim); - bound[nMarker][iVertex]->SetRotation_Type(Buffer_Receive_ReceivedDomain_PeriodicTrans[iTotalReceivedDomain_Periodic]); - nVertexDomain[nMarker]++; iVertex++; - } - } - - Marker_All_SendRecv[nMarker] = -(jDomain+1); - nElem_Bound[nMarker] = nVertexDomain[nMarker]; - nMarker++; - } - - } - - delete[] TagBound_Copy; - delete[] SendRecv_Copy; - - delete[] Buffer_Receive_BoundLine; - delete[] Buffer_Receive_BoundTriangle; - delete[] Buffer_Receive_BoundQuadrilateral; - delete[] Buffer_Receive_Local2Global_Marker; - - delete[] Buffer_Receive_SendDomain_Periodic; - delete[] Buffer_Receive_SendDomain_PeriodicTrans; - delete[] Buffer_Receive_SendDomain_PeriodicReceptor; - delete[] Buffer_Receive_ReceivedDomain_Periodic; - delete[] Buffer_Receive_ReceivedDomain_PeriodicTrans; - delete[] Buffer_Receive_ReceivedDomain_PeriodicDonor; - - } - - } - - - /*--- Set the value of Marker_All_SendRecv and Marker_All_TagBound in the config structure ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - config->SetMarker_All_SendRecv(iMarker, Marker_All_SendRecv[iMarker]); - } - - /*--- Set the value of Global_nPoint and Global_nPointDomain ---*/ - - unsigned long Local_nPoint = nPoint; - unsigned long Local_nPointDomain = nPointDomain; - -#ifdef HAVE_MPI - - SU2_MPI::Allreduce(&Local_nPoint, &Global_nPoint, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&Local_nPointDomain, &Global_nPointDomain, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - -#else - - Global_nPoint = Local_nPoint; - Global_nPointDomain = Local_nPointDomain; - -#endif - - if (rank == MASTER_NODE) { - - delete [] MarkerIn; - delete [] nElem_Color; - - delete [] Buffer_Send_Center; - delete [] Buffer_Send_Rotation; - delete [] Buffer_Send_Translate; - - delete [] Buffer_Send_nSendDomain_Periodic; - delete [] Buffer_Send_nReceivedDomain_Periodic; - - delete [] Marker_All_SendRecv_Copy; - delete [] Marker_All_TagBound_Copy; - - for (iDomain = 0; iDomain < nDomain; iDomain++) { - delete[] Elem_Color[iDomain]; - } - delete[] Elem_Color; - delete[] Global2Local_Point; - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) - delete [] VertexIn[iMarker]; - delete[] VertexIn; - - } - - delete [] nSendDomain_Periodic; - delete [] nReceivedDomain_Periodic; - - delete [] nVertexDomain; - delete [] nBoundLine; - delete [] nBoundTriangle; - delete [] nBoundQuadrilateral; - delete [] Buffer_Send_nVertexDomain; - delete [] Buffer_Send_nBoundLine; - delete [] Buffer_Send_nBoundTriangle; - delete [] Buffer_Send_nBoundQuadrilateral; - delete [] Buffer_Send_Marker_All_SendRecv; - delete [] Marker_All_TagBound; - delete [] Buffer_Send_Marker_All_TagBound; - -} - -CPhysicalGeometry::CPhysicalGeometry(CGeometry *geometry, CConfig *config, int option) { - - Global_to_Local_Point = NULL; - Local_to_Global_Point = NULL; - Local_to_Global_Marker = NULL; - Global_to_Local_Marker = NULL; - - unsigned long iter, iPoint, jPoint, iElem, iVertex; - //unsigned long nElemTotal = 0, nPointTotal = 0, nPointDomainTotal = 0, nPointGhost = 0, nPointPeriodic = 0, nElemTriangle = 0, nElemQuadrilateral = 0, nElemTetrahedron = 0, nElemHexahedron = 0, nElemPrism = 0, nElemPyramid = 0; - unsigned long iElemTotal, iPointTotal, iPointGhost, iPointDomain, iPointPeriodic, iElemTriangle, iElemQuadrilateral, iElemTetrahedron, iElemHexahedron, iElemPrism, iElemPyramid, iPointCurrent; - unsigned long nBoundLineTotal = 0, iBoundLineTotal; - unsigned long nBoundTriangleTotal = 0, iBoundTriangleTotal; - unsigned long nBoundQuadrilateralTotal = 0, iBoundQuadrilateralTotal; - unsigned long ReceptorColor = 0, DonorColor = 0, Transformation; - unsigned long nTotalSendDomain_Periodic = 0, iTotalSendDomain_Periodic, nTotalReceivedDomain_Periodic = 0, iTotalReceivedDomain_Periodic, *nSendDomain_Periodic = NULL, *nReceivedDomain_Periodic = NULL; - unsigned long Buffer_Send_nPointTotal = 0, Buffer_Send_nPointDomainTotal = 0, Buffer_Send_nPointGhost = 0, Buffer_Send_nPointPeriodic = 0; - unsigned long Buffer_Send_nElemTotal, Buffer_Send_nElemTriangle = 0, Buffer_Send_nElemQuadrilateral = 0, Buffer_Send_nElemTetrahedron = 0, Buffer_Send_nElemHexahedron = 0, Buffer_Send_nElemPrism = 0, Buffer_Send_nElemPyramid = 0; - unsigned long Buffer_Send_nTotalSendDomain_Periodic = 0, Buffer_Send_nTotalReceivedDomain_Periodic = 0, *Buffer_Send_nSendDomain_Periodic = NULL, *Buffer_Send_nReceivedDomain_Periodic = NULL; - unsigned long Buffer_Send_nBoundLineTotal = 0, Buffer_Send_nBoundTriangleTotal = 0, Buffer_Send_nBoundQuadrilateralTotal = 0; - unsigned long iVertexDomain, iBoundLine, iBoundTriangle, iBoundQuadrilateral; - - /*--- Need to su2double-check these shorts in case we go to nprocs > ~32,000 ---*/ - unsigned long iNode, iDim, iMarker, jMarker, nMarkerDomain = 0, iMarkerDomain; - unsigned long nDomain = 0, iDomain, jDomain, nPeriodic = 0, iPeriodic, overhead = 4, Buffer_Send_nMarkerDomain = 0, Buffer_Send_nDim = 0, Buffer_Send_nZone = 0, Buffer_Send_nPeriodic = 0; - - bool *MarkerIn = NULL, **VertexIn = NULL, *PointIn = NULL, *ElemIn = NULL; - long vnodes_local[8]; - - vector DomainList; - short *Marker_All_SendRecv_Copy = NULL; - string *Marker_All_TagBound_Copy = NULL; - - int rank = MASTER_NODE; - int size = SINGLE_NODE; - unsigned short nMarker_Max = config->GetnMarker_Max(); - - /*--- Some dynamic arrays so we're not allocating too much on the stack ---*/ - - unsigned long *nVertexDomain = new unsigned long[nMarker_Max]; - unsigned long *nBoundLine = new unsigned long[nMarker_Max]; - unsigned long *nBoundTriangle = new unsigned long[nMarker_Max]; - unsigned long *nBoundQuadrilateral = new unsigned long[nMarker_Max]; - - unsigned long *Buffer_Send_nVertexDomain = new unsigned long[nMarker_Max]; - unsigned long *Buffer_Send_nBoundLine = new unsigned long[nMarker_Max]; - unsigned long *Buffer_Send_nBoundTriangle = new unsigned long[nMarker_Max]; - unsigned long *Buffer_Send_nBoundQuadrilateral = new unsigned long[nMarker_Max]; - - short *Buffer_Send_Marker_All_SendRecv = new short[nMarker_Max]; - - char *Marker_All_TagBound = new char[nMarker_Max*MAX_STRING_SIZE]; - char *Buffer_Send_Marker_All_TagBound = new char[nMarker_Max*MAX_STRING_SIZE]; - - -#ifdef HAVE_MPI - - /*--- MPI initialization ---*/ - - MPI_Comm_size(MPI_COMM_WORLD, &size); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - /*--- MPI status and request arrays for non-blocking communications ---*/ - - MPI_Status status, status2; - unsigned long source; - int recv_count=0; - - int offset = 17; - MPI_Status *send_stat = new MPI_Status[offset+size]; - MPI_Status *recv_stat = new MPI_Status[offset+size]; - - MPI_Request *send_req = new MPI_Request[offset+size]; - MPI_Request *recv_req = new MPI_Request[offset+size]; - -#endif - - if (rank == MASTER_NODE && size > SINGLE_NODE) - cout << "Communicating partition data and creating halo layers." << endl; - - /*--- Define buffer vector interior domain ---*/ - - su2double *Buffer_Send_Coord = NULL; - unsigned long *Buffer_Send_Color = NULL; - unsigned long *Buffer_Send_GlobalPointIndex = NULL; - unsigned long *Buffer_Send_Triangle = NULL; - unsigned long *Buffer_Send_Quadrilateral = NULL; - unsigned long *Buffer_Send_Tetrahedron = NULL; - unsigned long *Buffer_Send_Hexahedron = NULL; - unsigned long *Buffer_Send_Prism = NULL; - unsigned long *Buffer_Send_Pyramid = NULL; - unsigned long *Buffer_Send_GlobElem = NULL; - - /*--- Define buffer vector boundary ---*/ - - unsigned long *Buffer_Send_BoundLine = NULL, *Buffer_Receive_BoundLine = NULL; - unsigned long *Buffer_Send_BoundTriangle = NULL, *Buffer_Receive_BoundTriangle = NULL; - unsigned long *Buffer_Send_BoundQuadrilateral = NULL, *Buffer_Receive_BoundQuadrilateral = NULL; - unsigned long *Buffer_Send_Local2Global_Marker = NULL, *Buffer_Receive_Local2Global_Marker = NULL; - - /*--- Define buffer vector periodic boundary conditions ---*/ - - su2double *Buffer_Send_Center = NULL, *Buffer_Receive_Center = NULL; - su2double *Buffer_Send_Rotation = NULL, *Buffer_Receive_Rotation = NULL; - su2double *Buffer_Send_Translate = NULL, *Buffer_Receive_Translate = NULL; - - /*--- Define buffer vector periodic boundary conditions ---*/ - - unsigned long *Buffer_Send_SendDomain_Periodic = NULL, *Buffer_Receive_SendDomain_Periodic = NULL; - unsigned long *Buffer_Send_SendDomain_PeriodicTrans = NULL, *Buffer_Receive_SendDomain_PeriodicTrans = NULL; - unsigned long *Buffer_Send_SendDomain_PeriodicReceptor = NULL, *Buffer_Receive_SendDomain_PeriodicReceptor = NULL; - unsigned long *Buffer_Send_ReceivedDomain_Periodic = NULL, *Buffer_Receive_ReceivedDomain_Periodic = NULL; - unsigned long *Buffer_Send_ReceivedDomain_PeriodicTrans = NULL, *Buffer_Receive_ReceivedDomain_PeriodicTrans = NULL; - unsigned long *Buffer_Send_ReceivedDomain_PeriodicDonor = NULL, *Buffer_Receive_ReceivedDomain_PeriodicDonor = NULL; - - /*--- Variables below are needed specifically for the ParMETIS version ---*/ - - unsigned long *Global_to_local_Point_recv; - unsigned long *local_colour_values; - unsigned long *local_colour_temp; - unsigned long *Local_to_global_elem; - - unsigned short *nDim_s = new unsigned short[size]; - unsigned short *nDim_r = new unsigned short[size]; - unsigned short *nZone_s = new unsigned short[size]; - unsigned short *nZone_r = new unsigned short[size]; - - unsigned long *nPointTotal_s = new unsigned long[size]; - unsigned long *nPointDomainTotal_s = new unsigned long[size]; - unsigned long *nPointGhost_s = new unsigned long[size]; - unsigned long *nPointPeriodic_s = new unsigned long[size]; - unsigned long *nElemTotal_s = new unsigned long[size]; - unsigned long *nElemTriangle_s = new unsigned long[size]; - unsigned long *nElemQuadrilateral_s = new unsigned long[size]; - unsigned long *nElemTetrahedron_s = new unsigned long[size]; - unsigned long *nElemHexahedron_s = new unsigned long[size]; - unsigned long *nElemPrism_s = new unsigned long[size]; - unsigned long *nElemPyramid_s = new unsigned long[size]; - - unsigned long *nPointTotal_r = new unsigned long[size]; - unsigned long *nPointDomainTotal_r = new unsigned long[size]; - unsigned long *nPointGhost_r = new unsigned long[size]; - unsigned long *nPointPeriodic_r = new unsigned long[size]; - unsigned long *nElemTotal_r = new unsigned long[size]; - unsigned long *nElemTriangle_r = new unsigned long[size]; - unsigned long *nElemQuadrilateral_r = new unsigned long[size]; - unsigned long *nElemTetrahedron_r = new unsigned long[size]; - unsigned long *nElemHexahedron_r = new unsigned long[size]; - unsigned long *nElemPrism_r = new unsigned long[size]; - unsigned long *nElemPyramid_r = new unsigned long[size]; - - unsigned long nPointTotal_r_tot=0; - unsigned long nPointDomainTotal_r_tot=0; - unsigned long nPointGhost_r_tot=0; - unsigned long nPointPeriodic_r_tot=0; - unsigned long nElemTotal_r_tot=0; - unsigned long nElemTriangle_r_tot=0; - unsigned long nElemQuadrilateral_r_tot=0; - unsigned long nElemTetrahedron_r_tot=0; - unsigned long nElemHexahedron_r_tot=0; - unsigned long nElemPrism_r_tot=0; - unsigned long nElemPyramid_r_tot=0; - - unsigned long Buffer_Size_Coord = 0; - unsigned long Buffer_Size_Color = 0; - unsigned long Buffer_Size_GlobalPointIndex = 0; - unsigned long Buffer_Size_Triangle = 0; - unsigned long Buffer_Size_Quadrilateral = 0; - unsigned long Buffer_Size_Tetrahedron = 0; - unsigned long Buffer_Size_Hexahedron = 0; - unsigned long Buffer_Size_Prism = 0; - unsigned long Buffer_Size_Pyramid = 0; - unsigned long Buffer_Size_GlobElem = 0; - - unsigned long ElemTotal_Counter = 0; - unsigned long PointTotal_Counter = 0; - unsigned long PointDomain_Counter = 0; - - /*--- WARNING: check the next two counters ---*/ - unsigned long PointPeriodic_Counter = 0; - unsigned long PointGhost_Counter = 0; - unsigned long ElemTriangle_Counter = 0; - unsigned long ElemQuadrilateral_Counter = 0; - unsigned long ElemTetrahedron_Counter = 0; - unsigned long ElemHexahedron_Counter = 0; - unsigned long ElemPrism_Counter = 0; - unsigned long ElemPyramid_Counter = 0; - - unsigned long *Local_to_global_Triangle; - unsigned long *Local_to_global_Quadrilateral; - unsigned long *Local_to_global_Tetrahedron; - unsigned long *Local_to_global_Hexahedron; - unsigned long *Local_to_global_Prism; - unsigned long *Local_to_global_Pyramid; - - bool *Triangle_presence; - bool *Quadrilateral_presence; - bool *Tetrahedron_presence; - bool *Hexahedron_presence; - bool *Prism_presence; - bool *Pyramid_presence; - bool *Element_presence; - - Element_presence = new bool[geometry->GetnElem()]; - Triangle_presence = new bool[geometry->GetnElem()]; - Quadrilateral_presence = new bool[geometry->GetnElem()]; - Tetrahedron_presence = new bool[geometry->GetnElem()]; - Hexahedron_presence = new bool[geometry->GetnElem()]; - Prism_presence = new bool[geometry->GetnElem()]; - Pyramid_presence = new bool[geometry->GetnElem()]; - - for (unsigned long i=0; i < geometry->GetnElem(); i++) { - Element_presence[i] = false; - Triangle_presence[i] = false; - Quadrilateral_presence[i] = false; - Tetrahedron_presence[i] = false; - Hexahedron_presence[i] = false; - Prism_presence[i] = false; - Pyramid_presence[i] = false; - } - - su2double *Buffer_Receive_Coord_loc = NULL; - - unsigned long *Buffer_Receive_Color_loc = NULL; - unsigned long *Buffer_Receive_GlobalPointIndex_loc = NULL; - unsigned long *Buffer_Receive_Triangle_loc = NULL; - unsigned long *Buffer_Receive_Quadrilateral_loc = NULL; - unsigned long *Buffer_Receive_Tetrahedron_loc = NULL; - unsigned long *Buffer_Receive_Hexahedron_loc = NULL; - unsigned long *Buffer_Receive_Prism_loc = NULL; - unsigned long *Buffer_Receive_Pyramid_loc = NULL; - - unsigned long *Buffer_Receive_GlobElem_loc = NULL; - unsigned long *Buffer_Receive_Triangle_presence_loc = NULL; - unsigned long *Buffer_Receive_Quadrilateral_presence_loc = NULL; - unsigned long *Buffer_Receive_Tetrahedron_presence_loc = NULL; - unsigned long *Buffer_Receive_Hexahedron_presence_loc = NULL; - unsigned long *Buffer_Receive_Prism_presence_loc = NULL; - unsigned long *Buffer_Receive_Pyramid_presence_loc = NULL; - - /*--- Allocate the memory that we only need if we have MPI support ---*/ - -#ifdef HAVE_MPI - - su2double *Buffer_Receive_Coord = NULL; - unsigned long *Buffer_Receive_Color = NULL; - unsigned long *Buffer_Receive_GlobalPointIndex = NULL; - unsigned long *Buffer_Receive_Triangle = NULL; - unsigned long *Buffer_Receive_Quadrilateral = NULL; - unsigned long *Buffer_Receive_Tetrahedron = NULL; - unsigned long *Buffer_Receive_Hexahedron = NULL; - unsigned long *Buffer_Receive_Prism = NULL; - unsigned long *Buffer_Receive_Pyramid = NULL; - unsigned long *Buffer_Receive_GlobElem = NULL; - - unsigned long **Buffer_Receive_Triangle_presence = new unsigned long*[size]; - unsigned long **Buffer_Receive_Quadrilateral_presence = new unsigned long*[size]; - unsigned long **Buffer_Receive_Tetrahedron_presence = new unsigned long*[size]; - unsigned long **Buffer_Receive_Hexahedron_presence = new unsigned long*[size]; - unsigned long **Buffer_Receive_Prism_presence = new unsigned long*[size]; - unsigned long **Buffer_Receive_Pyramid_presence = new unsigned long*[size]; - -#endif - - /*--- Basic dimensionalization ---*/ - - nDomain = size; - - Marker_All_SendRecv = new short[nMarker_Max]; - nSendDomain_Periodic = new unsigned long [nDomain]; - nReceivedDomain_Periodic = new unsigned long [nDomain]; - - /*--- Auxiliar vector based on the original geometry ---*/ - - ElemIn = new bool[geometry->no_of_local_elements]; - PointIn = new bool[geometry->GetnPoint()]; - - - Buffer_Send_nDim = geometry->GetnDim(); - Buffer_Send_nZone = geometry->GetnZone(); - - // DOUBLE CHECK THESE, SINCE WE DO THIS AGAIN AT BOTTOM WITH THE MASTER -// MarkerIn = new bool [geometry->GetnMarker()]; -// VertexIn = new bool* [geometry->GetnMarker()]; -// for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) -// VertexIn[iMarker] = new bool [geometry->GetnElem_Bound(iMarker)]; -// - // -// Buffer_Send_nPeriodic = config->GetnPeriodicIndex(); -// Buffer_Send_Center = new su2double[Buffer_Send_nPeriodic*3]; -// Buffer_Send_Rotation = new su2double[Buffer_Send_nPeriodic*3]; -// Buffer_Send_Translate = new su2double[Buffer_Send_nPeriodic*3]; - // -// Buffer_Send_nSendDomain_Periodic = new unsigned long [nDomain]; -// Buffer_Send_nReceivedDomain_Periodic = new unsigned long [nDomain]; - - /*--- Divide the elements in color list to speed up the grid partitioning ---*/ - - Local_to_global_elem= new unsigned long [geometry->no_of_local_elements]; - for (unsigned long i=0; iGetnElem(); i++) { - if (geometry->Global_to_local_elem[i] != -1) { - Local_to_global_elem[geometry->Global_to_local_elem[i]] = i; - } - } - - Global_to_local_Point_recv = new unsigned long[geometry->GetnPoint()]; - for (unsigned long i=0; iGetnPoint(); i++) { - Global_to_local_Point_recv[i]=-1; - } - -// unsigned long *Global_to_Local_Point_loc; -// Global_to_Local_Point_loc = new unsigned long[geometry->GetnPoint()]; -// for (iPoint=0; iPointGetnPoint(); iPoint++) { -// Global_to_Local_Point_loc[iPoint]=-1; -// } - - local_colour_values = new unsigned long[geometry->GetnPoint()]; - local_colour_temp = new unsigned long[geometry->ending_node[rank]-geometry->starting_node[rank]]; - - for (unsigned long i=0; iending_node[rank]-geometry->starting_node[rank]; i++) { - local_colour_temp[i]=geometry->node[i]->GetColor(); - local_colour_values[geometry->starting_node[rank]+i]=local_colour_temp[i]; - } - - /*--- Communicate the grid coloring to all partitions. This information - will be repeatedly used throughout the organization of the partitions - and sorting out their ghost points/elements. ---*/ - -#ifdef HAVE_MPI - - int comm_counter=0; - for (iDomain=0; iDomain < (unsigned long)size; iDomain++) { - if (iDomain != (unsigned long)rank) { - SU2_MPI::Isend(local_colour_temp, geometry->ending_node[rank]-geometry->starting_node[rank], - MPI_UNSIGNED_LONG, iDomain, iDomain, MPI_COMM_WORLD, &send_req[comm_counter]); - comm_counter++; - } - } - - for (iDomain=0; iDomain < (unsigned long)size-1; iDomain++) { - MPI_Probe(MPI_ANY_SOURCE, rank, MPI_COMM_WORLD, &status2); - source = status2.MPI_SOURCE; - MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(&local_colour_values[geometry->starting_node[source]], recv_count, - MPI_UNSIGNED_LONG, source, rank, MPI_COMM_WORLD, &status2); - } - - /*--- Wait for the sends to complete (will be true since we're using - blocking recv's above. ---*/ - - SU2_MPI::Waitall(size-1, send_req, send_stat); - -#endif - - /*--- Free temporary buffer for communicating colors. ---*/ - - delete [] local_colour_temp; - -#ifdef HAVE_MPI - MPI_Barrier(MPI_COMM_WORLD); -#endif - //cout << " ==== Rank " << rank << " starting first send " << endl; - - /*--- This loop gets the array sizes of points, elements, etc. for each - rank to send to each other rank. ---*/ - - for (iDomain = 0; iDomain < nDomain; iDomain++) { - - /*--- Interior dimensionalization. Loop over the original grid to - perform the dimensionalizaton of the domain variables ---*/ - - Buffer_Send_nElemTotal = 0; - Buffer_Send_nPointTotal = 0; - Buffer_Send_nPointGhost = 0; - Buffer_Send_nPointDomainTotal = 0; - Buffer_Send_nPointPeriodic = 0; - Buffer_Send_nElemTriangle = 0; - Buffer_Send_nElemQuadrilateral = 0; - Buffer_Send_nElemTetrahedron = 0; - Buffer_Send_nElemHexahedron = 0; - Buffer_Send_nElemPrism = 0; - Buffer_Send_nElemPyramid = 0; - - /*--- Initialize the global to local mapping ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - PointIn[iPoint] = false; - } - - /*--- Loop over all of the local elements and count the number of each - type of point and element that needs to be sent. ---*/ - - for (iElem = 0; iElem < geometry->no_of_local_elements; iElem++) { - - /*--- Check if the element belongs to the domain ---*/ - - ElemIn[iElem] = false; - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { - iPoint = geometry->elem[iElem]->GetNode(iNode); - if (local_colour_values[iPoint] == iDomain) { - ElemIn[iElem] = true; break; - } - } - - /*--- If this element is needed by iDomain, get information - about the number of points and element type. ---*/ - - if (ElemIn[iElem]) { - - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { - iPoint = geometry->elem[iElem]->GetNode(iNode); - - /*--- If we haven't already found this point... ---*/ - - if (PointIn[iPoint] == false) { - - /*--- Mark point as found and collect information ---*/ - - PointIn[iPoint] = true; - - if ((iPoint >= geometry->starting_node[rank]) && - (iPoint < geometry->ending_node[rank])) { - - Buffer_Send_nPointTotal++; - - /*--- Increment our counters ---*/ - if ( local_colour_values[iPoint] == iDomain ) { - if ( iPoint > geometry->GetnPointDomain() - 1) - Buffer_Send_nPointPeriodic++; - else - Buffer_Send_nPointDomainTotal++; - } - else Buffer_Send_nPointGhost++; - - - } - } - } - - /*--- Increment the counter for the current type of element ---*/ - - switch(geometry->elem[iElem]->GetVTK_Type()) { - case TRIANGLE: Buffer_Send_nElemTriangle++; break; - case QUADRILATERAL: Buffer_Send_nElemQuadrilateral++; break; - case TETRAHEDRON: Buffer_Send_nElemTetrahedron++; break; - case HEXAHEDRON: Buffer_Send_nElemHexahedron++; break; - case PRISM: Buffer_Send_nElemPrism++; break; - case PYRAMID: Buffer_Send_nElemPyramid++; break; - } - - /*--- Increment the total number of elements for iDomain ---*/ - - Buffer_Send_nElemTotal++; - - } - } - - /*--- Store the counts on a partition by partition basis. ---*/ - - nDim_s[iDomain] = geometry->GetnDim(); - nZone_s[iDomain] = Buffer_Send_nZone; - nPointTotal_s[iDomain] = Buffer_Send_nPointTotal; - nPointDomainTotal_s[iDomain] = Buffer_Send_nPointDomainTotal; - nPointGhost_s[iDomain] = Buffer_Send_nPointGhost; - nPointPeriodic_s[iDomain] = Buffer_Send_nPointPeriodic; - nElemTotal_s[iDomain] = Buffer_Send_nElemTotal; - nElemTriangle_s[iDomain] = Buffer_Send_nElemTriangle; - nElemQuadrilateral_s[iDomain] = Buffer_Send_nElemQuadrilateral; - nElemTetrahedron_s[iDomain] = Buffer_Send_nElemTetrahedron; - nElemHexahedron_s[iDomain] = Buffer_Send_nElemHexahedron; - nElemPrism_s[iDomain] = Buffer_Send_nElemPrism; - nElemPyramid_s[iDomain] = Buffer_Send_nElemPyramid; - - /*--- Total counts for allocating send buffers below ---*/ - - Buffer_Size_Coord += nPointTotal_s[iDomain]*nDim_s[iDomain]; - Buffer_Size_Color += nPointTotal_s[iDomain]; - Buffer_Size_GlobalPointIndex += nPointTotal_s[iDomain]; - Buffer_Size_Triangle += nElemTriangle_s[iDomain]; - Buffer_Size_Quadrilateral += nElemQuadrilateral_s[iDomain]; - Buffer_Size_Tetrahedron += nElemTetrahedron_s[iDomain]; - Buffer_Size_Hexahedron += nElemHexahedron_s[iDomain]; - Buffer_Size_Prism += nElemPrism_s[iDomain]; - Buffer_Size_Pyramid += nElemPyramid_s[iDomain]; - Buffer_Size_GlobElem += nElemTotal_s[iDomain]; - - } - - /*--- Allocate the buffer vectors in the appropiate domain (master, iDomain) ---*/ - - Buffer_Send_Coord = new su2double[Buffer_Size_Coord]; - Buffer_Send_Color = new unsigned long[Buffer_Size_Color]; - Buffer_Send_GlobalPointIndex = new unsigned long[Buffer_Size_GlobalPointIndex]; - Buffer_Send_Triangle = new unsigned long[Buffer_Size_Triangle*N_POINTS_TRIANGLE]; - Buffer_Send_Quadrilateral = new unsigned long[Buffer_Size_Quadrilateral*N_POINTS_QUADRILATERAL]; - Buffer_Send_Tetrahedron = new unsigned long[Buffer_Size_Tetrahedron*N_POINTS_TETRAHEDRON]; - Buffer_Send_Hexahedron = new unsigned long[Buffer_Size_Hexahedron*N_POINTS_HEXAHEDRON]; - Buffer_Send_Prism = new unsigned long[Buffer_Size_Prism*N_POINTS_PRISM]; - Buffer_Send_Pyramid = new unsigned long[Buffer_Size_Pyramid*N_POINTS_PYRAMID]; - Buffer_Send_GlobElem = new unsigned long[Buffer_Size_GlobElem]; - - Local_to_global_Triangle = new unsigned long[Buffer_Size_Triangle]; - Local_to_global_Quadrilateral = new unsigned long[Buffer_Size_Quadrilateral]; - Local_to_global_Tetrahedron = new unsigned long[Buffer_Size_Tetrahedron]; - Local_to_global_Hexahedron = new unsigned long[Buffer_Size_Hexahedron]; - Local_to_global_Prism = new unsigned long[Buffer_Size_Prism]; - Local_to_global_Pyramid = new unsigned long[Buffer_Size_Pyramid]; - - /*--- Initialize the counters for the larger send buffers (by domain) ---*/ - - ElemTotal_Counter = 0; - PointTotal_Counter = 0; - PointDomain_Counter = 0; - /*--- WARNING: check the next two counters ---*/ - PointPeriodic_Counter = 0; - PointGhost_Counter = 0; - ElemTriangle_Counter = 0; - ElemQuadrilateral_Counter = 0; - ElemTetrahedron_Counter = 0; - ElemHexahedron_Counter = 0; - ElemPrism_Counter = 0; - ElemPyramid_Counter = 0; - - /*--- Now that we know the sizes of the point, elem, etc. arrays, we can - allocate and send the information in large chunks to all processors. ---*/ - - for (iDomain = 0; iDomain < nDomain; iDomain++) { - - /*--- A rank does not communicate with itself through MPI ---*/ - - if ((unsigned long)rank != iDomain) { - -#ifdef HAVE_MPI - - /*--- Communicate the counts to iDomain with non-blocking sends ---*/ - - SU2_MPI::Isend(&nDim_s[iDomain], 1, MPI_UNSIGNED_SHORT, iDomain, - iDomain*13+0, MPI_COMM_WORLD, &send_req[0]); - - SU2_MPI::Isend(&nZone_s[iDomain], 1, MPI_UNSIGNED_SHORT, iDomain, - iDomain*13+1, MPI_COMM_WORLD, &send_req[1]); - - SU2_MPI::Isend(&nPointTotal_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, - iDomain*13+2, MPI_COMM_WORLD, &send_req[2]); - - SU2_MPI::Isend(&nPointDomainTotal_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, - iDomain*13+3, MPI_COMM_WORLD, &send_req[3]); - - SU2_MPI::Isend(&nPointGhost_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, - iDomain*13+4, MPI_COMM_WORLD, &send_req[4]); - - SU2_MPI::Isend(&nPointPeriodic_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, - iDomain*13+5, MPI_COMM_WORLD, &send_req[5]); - - SU2_MPI::Isend(&nElemTotal_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, - iDomain*13+6, MPI_COMM_WORLD, &send_req[6]); - - SU2_MPI::Isend(&nElemTriangle_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, - iDomain*13+7, MPI_COMM_WORLD, &send_req[7]); - - SU2_MPI::Isend(&nElemQuadrilateral_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, - iDomain*13+8, MPI_COMM_WORLD, &send_req[8]); - - SU2_MPI::Isend(&nElemTetrahedron_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, - iDomain*13+9, MPI_COMM_WORLD, &send_req[9]); - - SU2_MPI::Isend(&nElemHexahedron_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, - iDomain*13+10, MPI_COMM_WORLD, &send_req[10]); - - SU2_MPI::Isend(&nElemPrism_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, - iDomain*13+11, MPI_COMM_WORLD, &send_req[11]); - - SU2_MPI::Isend(&nElemPyramid_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, - iDomain*13+12, MPI_COMM_WORLD, &send_req[12]); - -#endif - - } else { - - /*--- If iDomain = rank, we simply copy values into place in memory ---*/ - - nDim = nDim_s[iDomain]; - nZone = nZone_s[iDomain]; -// nPointTotal = nPointTotal_s[iDomain]; -// nPointDomainTotal = nPointDomainTotal_s[iDomain]; -// nPointGhost = nPointGhost_s[iDomain]; -// nPointPeriodic = nPointPeriodic_s[iDomain]; -// nElemTotal = nElemTotal_s[iDomain]; -// nElemTriangle = nElemTriangle_s[iDomain]; -// nElemQuadrilateral = nElemQuadrilateral_s[iDomain]; -// nElemTetrahedron = nElemTetrahedron_s[iDomain]; -// nElemHexahedron = nElemHexahedron_s[iDomain]; -// nElemPrism = nElemPrism_s[iDomain]; -// nElemPyramid = nElemPyramid_s[iDomain]; - - nDim_r[iDomain] = nDim_s[iDomain]; - nZone_r[iDomain] = nZone_s[iDomain]; - nPointTotal_r[iDomain] = nPointTotal_s[iDomain]; - nPointDomainTotal_r[iDomain] = nPointDomainTotal_s[iDomain]; - nPointPeriodic_r[iDomain] = nPointPeriodic_s[iDomain]; - nElemTotal_r[iDomain] = nElemTotal_s[iDomain]; - nElemTriangle_r[iDomain] = nElemTriangle_s[iDomain]; - nElemQuadrilateral_r[iDomain] = nElemQuadrilateral_s[iDomain]; - nElemTetrahedron_r[iDomain] = nElemTetrahedron_s[iDomain]; - nElemHexahedron_r[iDomain] = nElemHexahedron_s[iDomain]; - nElemPrism_r[iDomain] = nElemPrism_s[iDomain]; - nElemPyramid_r[iDomain] = nElemPyramid_s[iDomain]; - - nPointTotal_r_tot += nPointTotal_r[iDomain]; - nPointDomainTotal_r_tot += nPointDomainTotal_r[iDomain]; - nPointGhost_r_tot += nPointGhost_r[iDomain]; - nPointPeriodic_r_tot += nPointPeriodic_r[iDomain]; - nElemTotal_r_tot += nElemTotal_r[iDomain]; - nElemTriangle_r_tot += nElemTriangle_r[iDomain]; - nElemQuadrilateral_r_tot += nElemQuadrilateral_r[iDomain]; - nElemTetrahedron_r_tot += nElemTetrahedron_r[iDomain]; - nElemHexahedron_r_tot += nElemHexahedron_r[iDomain]; - nElemPrism_r_tot += nElemPrism_r[iDomain]; - nElemPyramid_r_tot += nElemPyramid_r[iDomain]; - - } - - /*--- Receive the counts. All processors are sending their counters to - iDomain up above, so only iDomain needs to perform the recv here from - all other ranks. ---*/ - - if ((unsigned long)rank == iDomain) { - - for (jDomain = 0; jDomain < (unsigned long)size; jDomain++) { - - /*--- A rank does not communicate with itself through MPI ---*/ - - if ((unsigned long)rank != jDomain) { - -#ifdef HAVE_MPI - - /*--- Recv the data by probing for the current sender, jDomain, - first and then receiving the values from it. ---*/ - - MPI_Probe(jDomain, 13*rank+0, MPI_COMM_WORLD, &status2); - SU2_MPI::Recv(&nDim_r[jDomain], 1, MPI_UNSIGNED_SHORT, jDomain, - rank*13+0, MPI_COMM_WORLD, &status2); - - MPI_Probe(jDomain, 13*rank+1, MPI_COMM_WORLD, &status2); - SU2_MPI::Recv(&nZone_r[jDomain], 1, MPI_UNSIGNED_SHORT, jDomain, - rank*13+1, MPI_COMM_WORLD, &status2); - - MPI_Probe(jDomain, 13*rank+2, MPI_COMM_WORLD, &status2); - SU2_MPI::Recv(&nPointTotal_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, - rank*13+2, MPI_COMM_WORLD, &status2); - - MPI_Probe(jDomain, 13*rank+3, MPI_COMM_WORLD, &status2); - SU2_MPI::Recv(&nPointDomainTotal_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, - rank*13+3, MPI_COMM_WORLD, &status2); - - MPI_Probe(jDomain, 13*rank+4, MPI_COMM_WORLD, &status2); - SU2_MPI::Recv(&nPointGhost_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, - rank*13+4, MPI_COMM_WORLD, &status2); - - MPI_Probe(jDomain, 13*rank+5, MPI_COMM_WORLD, &status2); - SU2_MPI::Recv(&nPointPeriodic_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, - rank*13+5, MPI_COMM_WORLD, &status2); - - MPI_Probe(jDomain, 13*rank+6, MPI_COMM_WORLD, &status2); - SU2_MPI::Recv(&nElemTotal_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, - rank*13+6, MPI_COMM_WORLD, &status2); - - MPI_Probe(jDomain, 13*rank+7, MPI_COMM_WORLD, &status2); - SU2_MPI::Recv(&nElemTriangle_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, - rank*13+7, MPI_COMM_WORLD, &status2); - - MPI_Probe(jDomain, 13*rank+8, MPI_COMM_WORLD, &status2); - SU2_MPI::Recv(&nElemQuadrilateral_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, - rank*13+8, MPI_COMM_WORLD, &status2); - - MPI_Probe(jDomain, 13*rank+9, MPI_COMM_WORLD, &status2); - SU2_MPI::Recv(&nElemTetrahedron_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, - rank*13+9, MPI_COMM_WORLD, &status2); - - MPI_Probe(jDomain, 13*rank+10, MPI_COMM_WORLD, &status2); - SU2_MPI::Recv(&nElemHexahedron_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, - rank*13+10, MPI_COMM_WORLD, &status2); - - MPI_Probe(jDomain, 13*rank+11, MPI_COMM_WORLD, &status2); - SU2_MPI::Recv(&nElemPrism_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, - rank*13+11, MPI_COMM_WORLD, &status2); - - MPI_Probe(jDomain, 13*rank+12, MPI_COMM_WORLD, &status2); - SU2_MPI::Recv(&nElemPyramid_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, - rank*13+12, MPI_COMM_WORLD, &status2); - -#endif - - /*--- These are the cumulative totals that we will recv below. ----*/ - - nPointTotal_r_tot += nPointTotal_r[jDomain]; - nPointDomainTotal_r_tot += nPointDomainTotal_r[jDomain]; - nPointGhost_r_tot += nPointGhost_r[jDomain]; - nPointPeriodic_r_tot += nPointPeriodic_r[jDomain]; - nElemTotal_r_tot += nElemTotal_r[jDomain]; - nElemTriangle_r_tot += nElemTriangle_r[jDomain]; - nElemQuadrilateral_r_tot += nElemQuadrilateral_r[jDomain]; - nElemTetrahedron_r_tot += nElemTetrahedron_r[jDomain]; - nElemHexahedron_r_tot += nElemHexahedron_r[jDomain]; - nElemPrism_r_tot += nElemPrism_r[jDomain]; - nElemPyramid_r_tot += nElemPyramid_r[jDomain]; - - } - } - - } - } - - for (iDomain = 0; iDomain < nDomain; iDomain++) { - - /*--- Wait for the non-blocking sends to complete. ---*/ - -#ifdef HAVE_MPI - if ((unsigned long)rank != iDomain) SU2_MPI::Waitall(13, send_req, send_stat); - MPI_Barrier(MPI_COMM_WORLD); -#endif - //cout << " ==== Rank " << rank << " finished sending counts " << endl; - - - } - - for (iDomain = 0; iDomain < nDomain; iDomain++) { - - - /*--- Above was number of elements to send and receive, and here is where - we send/recv the actual elements. Here you're sending global index values, - which are later changed to local. ---*/ - - /*--- Set the value of the interior geometry. Initialize counters. ---*/ - - iElemTotal = 0; - iPointTotal = 0; - iPointDomain = 0; - iPointPeriodic = nPointDomainTotal_s[iDomain]; - iPointGhost = nPointDomainTotal_s[iDomain] + nPointPeriodic_s[iDomain]; - iElemTriangle = 0; - iElemQuadrilateral = 0; - iElemTetrahedron = 0; - iElemHexahedron = 0; - iElemPrism = 0; - iElemPyramid = 0; - - /*--- Initialize the global to local mapping ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) PointIn[iPoint] = false; - - /*--- Load up the actual elements into the buffers for sending. ---*/ - - for (iElem = 0; iElem < geometry->no_of_local_elements; iElem++) { - - /*--- Check if the element belongs to the domain ---*/ - - ElemIn[iElem] = false; - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { - iPoint = geometry->elem[iElem]->GetNode(iNode); - if (local_colour_values[iPoint] == iDomain) { - ElemIn[iElem] = true; break; - } - } - - /*--- If this element should be sent ---*/ - - if (ElemIn[iElem]) { - - /*--- We need to send this element, so add it to the send buffer. The - local to global mapping has already been done as a class data member. ---*/ - - Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal] = Local_to_global_elem[iElem]; - - /*--- Loop through the nodes of the current element ---*/ - - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { - - /*--- Get the global index for this node in the element ---*/ - iPoint = geometry->elem[iElem]->GetNode(iNode); - - /*--- Store the connectivity for this element for each node ---*/ - vnodes_local[iNode] = iPoint; - - /*--- Check if this point has been found previously ---*/ - - if (PointIn[iPoint] == false) { - - /*--- Check if this node lives on the current rank based on the - initial linear partitioning. We are only ever sending nodes that - we own in the linear partitioning (no duplicate nodes are sent) ---*/ - - if ((iPoint >= geometry->starting_node[rank]) && - (iPoint < geometry->ending_node[rank])) { - - /*--- Decide whether this is an interior, periodic, or ghost node ---*/ - - if (local_colour_values[iPoint] == iDomain) { - - /*--- If iDomain owns the point, it must be either an interior - node (iPoint < nPointDomain) or a periodic node. ---*/ - - if (iPoint > geometry->GetnPointDomain() - 1) - iPointCurrent = iPointPeriodic; - else - iPointCurrent = iPointDomain; - - } else { - - /*--- Otherwise, it must be a ghost point for iDomain ---*/ - iPointCurrent = iPointGhost; - - } - - /*--- Setting global to local, the color, and index. ---*/ - - PointIn[iPoint] = true; - - Buffer_Send_Color[PointTotal_Counter+iPointCurrent] = local_colour_values[iPoint]; - Buffer_Send_GlobalPointIndex[PointTotal_Counter+iPointCurrent] = iPoint; - - /*--- Get the coordinates for this point ---*/ - - for (iDim = 0; iDim < nDim_s[iDomain]; iDim++) { - - /*--- iPoint is the global index, but we store everything local - to this rank. So we need to subtract the starting index. All - ranks re-index their points from zero. ---*/ - Buffer_Send_Coord[nDim_s[iDomain]*(PointTotal_Counter+iPointCurrent)+iDim] = geometry->node[iPoint-geometry->starting_node[rank]]->GetCoord(iDim); - } - - /*--- Increment our counters ---*/ - if ( local_colour_values[iPoint] == iDomain ) { - if ( iPoint > geometry->GetnPointDomain() - 1) - iPointPeriodic++; - else - iPointDomain++; - } - else iPointGhost++; - - /*--- Increment the total number of points we're sending ---*/ - iPointTotal++; - - } - } - } - - /*--- Load the connectivity for the current element into the send buffer. - Also store the local to global mapping for the elements. - Note that we are using the vnode_local array we filled above to store - the connectivity. Loop through each element type. ---*/ - - switch(geometry->elem[iElem]->GetVTK_Type()) { - case TRIANGLE: - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) - Buffer_Send_Triangle[3*(ElemTriangle_Counter+iElemTriangle)+iNode] = vnodes_local[iNode]; - Local_to_global_Triangle[ElemTriangle_Counter+iElemTriangle] = Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal]; - iElemTriangle++; break; - case QUADRILATERAL: - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) - Buffer_Send_Quadrilateral[4*(ElemQuadrilateral_Counter+iElemQuadrilateral)+iNode] = vnodes_local[iNode]; - Local_to_global_Quadrilateral[ElemQuadrilateral_Counter+iElemQuadrilateral] =Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal]; - iElemQuadrilateral++; break; - case TETRAHEDRON: - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) - Buffer_Send_Tetrahedron[4*(ElemTetrahedron_Counter+iElemTetrahedron)+iNode] = vnodes_local[iNode]; - Local_to_global_Tetrahedron[ElemTetrahedron_Counter+iElemTetrahedron] =Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal]; - iElemTetrahedron++; break; - case HEXAHEDRON: - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) - Buffer_Send_Hexahedron[8*(ElemHexahedron_Counter+iElemHexahedron)+iNode] = vnodes_local[iNode]; - Local_to_global_Hexahedron[ElemHexahedron_Counter+iElemHexahedron] =Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal]; - iElemHexahedron++; break; - case PRISM: - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) - Buffer_Send_Prism[6*(ElemPrism_Counter+iElemPrism)+iNode] = vnodes_local[iNode]; - Local_to_global_Prism[ElemPrism_Counter+iElemPrism] =Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal]; - iElemPrism++; break; - case PYRAMID: - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) - Buffer_Send_Pyramid[5*(ElemPyramid_Counter+iElemPyramid)+iNode] = vnodes_local[iNode]; - Local_to_global_Pyramid[ElemPyramid_Counter+iElemPyramid] = Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal]; - iElemPyramid++; break; - } - - /*--- Regardless of the type, increment the total count ---*/ - iElemTotal++; - - } - } - - /*--- Send the buffers with the geometrical information ---*/ - - if (iDomain != (unsigned long)rank) { - -#ifdef HAVE_MPI - - /*--- Communicate the coordinates, global index, colors, and element - date to iDomain with non-blocking sends. ---*/ - - SU2_MPI::Isend(&Buffer_Send_Coord[PointTotal_Counter*nDim_s[iDomain]], - nPointTotal_s[iDomain]*nDim_s[iDomain], MPI_DOUBLE, iDomain, - iDomain*16+0, MPI_COMM_WORLD, &send_req[0]); - - SU2_MPI::Isend(&Buffer_Send_GlobalPointIndex[PointTotal_Counter], - nPointTotal_s[iDomain], MPI_UNSIGNED_LONG, iDomain, - iDomain*16+1, MPI_COMM_WORLD, &send_req[1]); - - SU2_MPI::Isend(&Buffer_Send_Color[PointTotal_Counter], - nPointTotal_s[iDomain], MPI_UNSIGNED_LONG, iDomain, - iDomain*16+2, MPI_COMM_WORLD, &send_req[2]); - - SU2_MPI::Isend(&Buffer_Send_Triangle[ElemTriangle_Counter*3], - nElemTriangle_s[iDomain]*3, MPI_UNSIGNED_LONG, iDomain, - iDomain*16+3, MPI_COMM_WORLD, &send_req[3]); - - SU2_MPI::Isend(&Buffer_Send_Quadrilateral[ElemQuadrilateral_Counter*4], - nElemQuadrilateral_s[iDomain]*4, MPI_UNSIGNED_LONG, iDomain, - iDomain*16+4, MPI_COMM_WORLD, &send_req[4]); - - SU2_MPI::Isend(&Buffer_Send_Tetrahedron[ElemTetrahedron_Counter*4], - nElemTetrahedron_s[iDomain]*4, MPI_UNSIGNED_LONG, iDomain, - iDomain*16+5, MPI_COMM_WORLD, &send_req[5]); - - SU2_MPI::Isend(&Buffer_Send_Hexahedron[ElemHexahedron_Counter*8], - nElemHexahedron_s[iDomain]*8, MPI_UNSIGNED_LONG, iDomain, - iDomain*16+6, MPI_COMM_WORLD, &send_req[6]); - - SU2_MPI::Isend(&Buffer_Send_Prism[ElemPrism_Counter*6], - nElemPrism_s[iDomain]*6, MPI_UNSIGNED_LONG, iDomain, - iDomain*16+7, MPI_COMM_WORLD, &send_req[7]); - - SU2_MPI::Isend(&Buffer_Send_Pyramid[ElemPyramid_Counter*5], - nElemPyramid_s[iDomain]*5, MPI_UNSIGNED_LONG, iDomain, - iDomain*16+8, MPI_COMM_WORLD, &send_req[8]); - - SU2_MPI::Isend(&Buffer_Send_GlobElem[ElemTotal_Counter], - nElemTotal_s[iDomain], MPI_UNSIGNED_LONG, iDomain, - iDomain*16+9, MPI_COMM_WORLD, &send_req[9]); - - SU2_MPI::Isend(&Local_to_global_Triangle[ElemTriangle_Counter], - nElemTriangle_s[iDomain], MPI_UNSIGNED_LONG, iDomain, - iDomain*16+10, MPI_COMM_WORLD, &send_req[10]); - - SU2_MPI::Isend(&Local_to_global_Quadrilateral[ElemQuadrilateral_Counter], - nElemQuadrilateral_s[iDomain], MPI_UNSIGNED_LONG, iDomain, - iDomain*16+11, MPI_COMM_WORLD, &send_req[11]); - - SU2_MPI::Isend(&Local_to_global_Tetrahedron[ElemTetrahedron_Counter], - nElemTetrahedron_s[iDomain], MPI_UNSIGNED_LONG, iDomain, - iDomain*16+12, MPI_COMM_WORLD, &send_req[12]); - - SU2_MPI::Isend(&Local_to_global_Hexahedron[ElemHexahedron_Counter], - nElemHexahedron_s[iDomain], MPI_UNSIGNED_LONG, iDomain, - iDomain*16+13, MPI_COMM_WORLD, &send_req[13]); - - SU2_MPI::Isend(&Local_to_global_Prism[ElemPrism_Counter], - nElemPrism_s[iDomain], MPI_UNSIGNED_LONG, iDomain, - iDomain*16+14, MPI_COMM_WORLD, &send_req[14]); - - SU2_MPI::Isend(&Local_to_global_Pyramid[ElemPyramid_Counter], - nElemPyramid_s[iDomain], MPI_UNSIGNED_LONG, iDomain, - iDomain*16+15, MPI_COMM_WORLD, &send_req[15]); - -#endif - - } else { - - /*--- Allocate local memory for the local recv of the elements ---*/ - - Buffer_Receive_Coord_loc = new su2double[nPointTotal_s[iDomain]*nDim_s[iDomain]]; - - Buffer_Receive_GlobalPointIndex_loc = new unsigned long[nPointTotal_s[iDomain]]; - Buffer_Receive_Color_loc = new unsigned long[nPointTotal_s[iDomain]]; - Buffer_Receive_Triangle_loc = new unsigned long[nElemTriangle_s[iDomain]*N_POINTS_TRIANGLE]; - Buffer_Receive_Quadrilateral_loc = new unsigned long[nElemQuadrilateral_s[iDomain]*N_POINTS_QUADRILATERAL]; - Buffer_Receive_Tetrahedron_loc = new unsigned long[nElemTetrahedron_s[iDomain]*N_POINTS_TETRAHEDRON]; - Buffer_Receive_Hexahedron_loc = new unsigned long[nElemHexahedron_s[iDomain]*N_POINTS_HEXAHEDRON]; - Buffer_Receive_Prism_loc = new unsigned long[nElemPrism_s[iDomain]*N_POINTS_PRISM]; - Buffer_Receive_Pyramid_loc = new unsigned long[nElemPyramid_s[iDomain]*N_POINTS_PYRAMID]; - Buffer_Receive_GlobElem_loc = new unsigned long[nElemTotal_s[iDomain]]; - - Buffer_Receive_Triangle_presence_loc = new unsigned long[nElemTriangle_s[iDomain]]; - Buffer_Receive_Quadrilateral_presence_loc = new unsigned long[nElemQuadrilateral_s[iDomain]]; - Buffer_Receive_Tetrahedron_presence_loc = new unsigned long[nElemTetrahedron_s[iDomain]]; - Buffer_Receive_Hexahedron_presence_loc = new unsigned long[nElemHexahedron_s[iDomain]]; - Buffer_Receive_Prism_presence_loc = new unsigned long[nElemPrism_s[iDomain]]; - Buffer_Receive_Pyramid_presence_loc = new unsigned long[nElemPyramid_s[iDomain]]; - - for (iter = 0; iter < nPointTotal_s[iDomain]*nDim_s[iDomain]; iter++) - Buffer_Receive_Coord_loc[iter] = Buffer_Send_Coord[PointTotal_Counter*nDim_s[iDomain]+iter]; - - for (iter = 0; iter < nPointTotal_s[iDomain]; iter++) { - Buffer_Receive_GlobalPointIndex_loc[iter] = Buffer_Send_GlobalPointIndex[PointTotal_Counter+iter]; - Buffer_Receive_Color_loc[iter] = Buffer_Send_Color[PointTotal_Counter+iter]; - } - - for (iter = 0; iter < nElemTriangle_s[iDomain]*N_POINTS_TRIANGLE; iter++) - Buffer_Receive_Triangle_loc[iter] = Buffer_Send_Triangle[ElemTriangle_Counter*N_POINTS_TRIANGLE+iter]; - - for (iter = 0; iter < nElemQuadrilateral_s[iDomain]*N_POINTS_QUADRILATERAL; iter++) - Buffer_Receive_Quadrilateral_loc[iter] = Buffer_Send_Quadrilateral[ElemQuadrilateral_Counter*N_POINTS_QUADRILATERAL+iter]; - - for (iter = 0; iter < nElemTetrahedron_s[iDomain]*N_POINTS_TETRAHEDRON; iter++) - Buffer_Receive_Tetrahedron_loc[iter] = Buffer_Send_Tetrahedron[ElemTetrahedron_Counter*N_POINTS_TETRAHEDRON+iter]; - - for (iter = 0; iter < nElemHexahedron_s[iDomain]*N_POINTS_HEXAHEDRON; iter++) - Buffer_Receive_Hexahedron_loc[iter] = Buffer_Send_Hexahedron[ElemHexahedron_Counter*N_POINTS_HEXAHEDRON+iter]; - - for (iter = 0; iter < nElemPrism_s[iDomain]*N_POINTS_PRISM; iter++) - Buffer_Receive_Prism_loc[iter] = Buffer_Send_Prism[ElemPrism_Counter*N_POINTS_PRISM+iter]; - - for (iter = 0; iter < nElemPyramid_s[iDomain]*N_POINTS_PYRAMID; iter++) - Buffer_Receive_Pyramid_loc[iter] = Buffer_Send_Pyramid[ElemPyramid_Counter*N_POINTS_PYRAMID+iter]; - - for (unsigned long i=0; i geometry->GetnPointDomain() - 1) { - - /*--- Set the starting point for the local index of the recv points. - The temp_node_count increments for the interior nodes, between 0 up - to nPointDomain-1. ---*/ - index = temp_node_count_periodic; - - /*--- Get the global index ---*/ - Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex[iPoint]; - - /*--- Allocating the Point object ---*/ - if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0], - Buffer_Receive_Coord[iPoint*nDim+1], - Local_to_Global_Point[index], config); - if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0], - Buffer_Receive_Coord[iPoint*nDim+1], - Buffer_Receive_Coord[iPoint*nDim+2], - Local_to_Global_Point[index], config); - - /*--- Set the color ---*/ - node[index]->SetColor(Buffer_Receive_Color[iPoint]); - - /*--- Increment the interior node counter ---*/ - temp_node_count_periodic++; - - - } - - else { - - - /*--- Set the starting point for the local index of the recv points. - The temp_node_count increments for the interior nodes, between 0 up - to nPointDomain-1. ---*/ - index = temp_node_count; - - /*--- Get the global index ---*/ - Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex[iPoint]; - - /*--- Allocating the Point object ---*/ - if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0], - Buffer_Receive_Coord[iPoint*nDim+1], - Local_to_Global_Point[index], config); - if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0], - Buffer_Receive_Coord[iPoint*nDim+1], - Buffer_Receive_Coord[iPoint*nDim+2], - Local_to_Global_Point[index], config); - - /*--- Set the color ---*/ - node[index]->SetColor(Buffer_Receive_Color[iPoint]); - - /*--- Increment the interior node counter ---*/ - temp_node_count++; - - - - - } - - - } else { - - /*--- Set the starting point for the local index of the recv points. - The temp_node_count_domain increments for the ghost nodes, between - nPointDomain up to nPoint. ---*/ - - index=temp_node_count_ghost; - - /*--- Get the global index ---*/ - Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex[iPoint]; - - /*--- Allocating the Point object ---*/ - if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0], - Buffer_Receive_Coord[iPoint*nDim+1], - Local_to_Global_Point[index], config); - if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0], - Buffer_Receive_Coord[iPoint*nDim+1], - Buffer_Receive_Coord[iPoint*nDim+2], - Local_to_Global_Point[index], config); - - /*--- Set the color ---*/ - node[index]->SetColor(Buffer_Receive_Color[iPoint]); - - /*--- Increment the ghost node counter ---*/ - temp_node_count_ghost++; - - } - } - - /*--- Delete memory for recv the point stuff ---*/ - delete [] Buffer_Receive_Coord; - delete [] Buffer_Receive_Color; - delete [] Buffer_Receive_GlobalPointIndex; - -#endif - - } else { - - /*--- Recv the point data from ourselves (same procedure as above) ---*/ - - unsigned long index = 0; - for (iPoint = 0; iPoint < nPointTotal_r[iDomain]; iPoint++) { - - if (Buffer_Receive_Color_loc[iPoint] == (unsigned long)rank) { - - /*--- If iDomain owns the point, it must be either an interior - node (iPoint < nPointDomain) or a periodic node. ---*/ - - if (Buffer_Receive_GlobalPointIndex_loc[iPoint] > geometry->GetnPointDomain() - 1) { - - index = temp_node_count_periodic; - - Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex_loc[iPoint]; - if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0], - Buffer_Receive_Coord_loc[iPoint*nDim+1], - Local_to_Global_Point[index], config); - if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0], - Buffer_Receive_Coord_loc[iPoint*nDim+1], - Buffer_Receive_Coord_loc[iPoint*nDim+2], - Local_to_Global_Point[index], config); - node[index]->SetColor(Buffer_Receive_Color_loc[iPoint]); - temp_node_count_periodic++; - - - - - } - else { - - index = temp_node_count; - Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex_loc[iPoint]; - if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0], - Buffer_Receive_Coord_loc[iPoint*nDim+1], - Local_to_Global_Point[index], config); - if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0], - Buffer_Receive_Coord_loc[iPoint*nDim+1], - Buffer_Receive_Coord_loc[iPoint*nDim+2], - Local_to_Global_Point[index], config); - node[index]->SetColor(Buffer_Receive_Color_loc[iPoint]); - temp_node_count++; - - - - } - - - } else{ - - index=temp_node_count_ghost; - Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex_loc[iPoint]; - if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0], - Buffer_Receive_Coord_loc[iPoint*nDim+1], - Local_to_Global_Point[index], config); - if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0], - Buffer_Receive_Coord_loc[iPoint*nDim+1], - Buffer_Receive_Coord_loc[iPoint*nDim+2], - Local_to_Global_Point[index], config); - node[index]->SetColor(Buffer_Receive_Color_loc[iPoint]); - temp_node_count_ghost++; - - } - } - - delete [] Buffer_Receive_Coord_loc; - delete [] Buffer_Receive_Color_loc; - delete [] Buffer_Receive_GlobalPointIndex_loc; - - } - } - - /*--- Get the global to local mapping ---*/ - - for (iPoint = 0; iPoint < nPointTotal_r_tot; iPoint++) { - Global_to_local_Point_recv[Local_to_Global_Point[iPoint]] = iPoint; - } - - - //cout << " ==== Rank " << rank << " recv of point data finished" << endl; -#ifdef HAVE_MPI - MPI_Barrier(MPI_COMM_WORLD); -#endif - /*--- Recv all of the element data. First decide which elements we need to own on each proc ---*/ - - iElem = 0; - for (iDomain = 0; iDomain < (unsigned long)size; iDomain++) { - - if ((unsigned long)rank != iDomain) { - -#ifdef HAVE_MPI - - /*--- Allocate memory for the element recv ---*/ - - Buffer_Receive_Triangle_presence[iDomain] = new unsigned long[nElemTriangle_r[iDomain]]; - Buffer_Receive_Quadrilateral_presence[iDomain] = new unsigned long[nElemQuadrilateral_r[iDomain]]; - Buffer_Receive_Tetrahedron_presence[iDomain] = new unsigned long[nElemTetrahedron_r[iDomain]]; - Buffer_Receive_Hexahedron_presence[iDomain] = new unsigned long[nElemHexahedron_r[iDomain]]; - Buffer_Receive_Prism_presence[iDomain] = new unsigned long[nElemPrism_r[iDomain]]; - Buffer_Receive_Pyramid_presence[iDomain] = new unsigned long[nElemPyramid_r[iDomain]]; - - /*--- Recv the element data ---*/ - - MPI_Probe(iDomain, rank*16+10, MPI_COMM_WORLD, &status2); - source = status2.MPI_SOURCE; - MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(&Buffer_Receive_Triangle_presence[iDomain][0], - recv_count, MPI_UNSIGNED_LONG, source, - rank*16+10, MPI_COMM_WORLD, &status2); - - MPI_Probe(iDomain, rank*16+11, MPI_COMM_WORLD, &status2); - source = status2.MPI_SOURCE; - MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(&Buffer_Receive_Quadrilateral_presence[iDomain][0], - recv_count, MPI_UNSIGNED_LONG, source, - rank*16+11, MPI_COMM_WORLD, &status2); - - MPI_Probe(iDomain, rank*16+12, MPI_COMM_WORLD, &status2); - source = status2.MPI_SOURCE; - MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(&Buffer_Receive_Tetrahedron_presence[iDomain][0], - recv_count, MPI_UNSIGNED_LONG, source, - rank*16+12, MPI_COMM_WORLD, &status2); - - MPI_Probe(iDomain, rank*16+13, MPI_COMM_WORLD, &status2); - source = status2.MPI_SOURCE; - MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(&Buffer_Receive_Hexahedron_presence[iDomain][0], - recv_count, MPI_UNSIGNED_LONG, source, - rank*16+13, MPI_COMM_WORLD, &status2); - - MPI_Probe(iDomain, rank*16+14, MPI_COMM_WORLD, &status2); - source = status2.MPI_SOURCE; - MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(&Buffer_Receive_Prism_presence[iDomain][0], - recv_count, MPI_UNSIGNED_LONG, source, - rank*16+14, MPI_COMM_WORLD, &status2); - - MPI_Probe(iDomain, rank*16+15, MPI_COMM_WORLD, &status2); - source = status2.MPI_SOURCE; - MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(&Buffer_Receive_Pyramid_presence[iDomain][0], - recv_count, MPI_UNSIGNED_LONG, source, - rank*16+15, MPI_COMM_WORLD, &status2); - - /*--- Wait to complete the above sends ---*/ - - //if (rank!=iDomain) SU2_MPI::Waitall(6, &send_req[10], &send_stat[10]); - - /*--- Allocating the elements after the recv ---*/ - - for (iElemTriangle = 0; iElemTriangle < nElemTriangle_r[iDomain]; iElemTriangle++) { - if (Triangle_presence[Buffer_Receive_Triangle_presence[iDomain][iElemTriangle]] == false) { - Triangle_presence[Buffer_Receive_Triangle_presence[iDomain][iElemTriangle]] = true; - iElem++; - } - } - - for (iElemQuadrilateral = 0; iElemQuadrilateral < nElemQuadrilateral_r[iDomain]; iElemQuadrilateral++) { - if (Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence[iDomain][iElemQuadrilateral]] == false) { - Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence[iDomain][iElemQuadrilateral]] = true; - iElem++; - } - } - - for (iElemTetrahedron = 0; iElemTetrahedron < nElemTetrahedron_r[iDomain]; iElemTetrahedron++) { - if (Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence[iDomain][iElemTetrahedron]] == false) { - Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence[iDomain][iElemTetrahedron]] = true; - iElem++; - } - } - - for (iElemHexahedron = 0; iElemHexahedron < nElemHexahedron_r[iDomain]; iElemHexahedron++) { - if (Hexahedron_presence[Buffer_Receive_Hexahedron_presence[iDomain][iElemHexahedron]] == false) { - Hexahedron_presence[Buffer_Receive_Hexahedron_presence[iDomain][iElemHexahedron]] = true; - iElem++; - } - } - - for (iElemPrism = 0; iElemPrism < nElemPrism_r[iDomain]; iElemPrism++) { - if (Prism_presence[Buffer_Receive_Prism_presence[iDomain][iElemPrism]] == false) { - Prism_presence[Buffer_Receive_Prism_presence[iDomain][iElemPrism]] = true; - iElem++; - } - } - - for (iElemPyramid = 0; iElemPyramid < nElemPyramid_r[iDomain]; iElemPyramid++) { - if (Pyramid_presence[Buffer_Receive_Pyramid_presence[iDomain][iElemPyramid]] == false) { - Pyramid_presence[Buffer_Receive_Pyramid_presence[iDomain][iElemPyramid]] = true; - iElem++; - } - } - -#endif - - } else { - - /*--- Store the element data from our own local rank info ---*/ - - for (iElemTriangle = 0; iElemTriangle < nElemTriangle_r[iDomain]; iElemTriangle++) { - if (Triangle_presence[Buffer_Receive_Triangle_presence_loc[iElemTriangle]] == false) { - Triangle_presence[Buffer_Receive_Triangle_presence_loc[iElemTriangle]] = true; - iElem++; - } - } - - for (iElemQuadrilateral = 0; iElemQuadrilateral < nElemQuadrilateral_r[iDomain]; iElemQuadrilateral++) { - if (Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence_loc[iElemQuadrilateral]] == false) { - Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence_loc[iElemQuadrilateral]] = true; - iElem++; - } - } - - for (iElemTetrahedron = 0; iElemTetrahedron < nElemTetrahedron_r[iDomain]; iElemTetrahedron++) { - if (Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence_loc[iElemTetrahedron]] == false) { - Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence_loc[iElemTetrahedron]] = true; - iElem++; - } - } - - for (iElemHexahedron = 0; iElemHexahedron < nElemHexahedron_r[iDomain]; iElemHexahedron++) { - if (Hexahedron_presence[Buffer_Receive_Hexahedron_presence_loc[iElemHexahedron]] == false) { - Hexahedron_presence[Buffer_Receive_Hexahedron_presence_loc[iElemHexahedron]] = true; - iElem++; - } - } - - for (iElemPrism = 0; iElemPrism < nElemPrism_r[iDomain]; iElemPrism++) { - if (Prism_presence[Buffer_Receive_Prism_presence_loc[iElemPrism]] == false) { - Prism_presence[Buffer_Receive_Prism_presence_loc[iElemPrism]] = true; - iElem++; - } - } - - for (iElemPyramid = 0; iElemPyramid < nElemPyramid_r[iDomain]; iElemPyramid++) { - if (Pyramid_presence[Buffer_Receive_Pyramid_presence_loc[iElemPyramid]] == false) { - Pyramid_presence[Buffer_Receive_Pyramid_presence_loc[iElemPyramid]] = true; - iElem++; - } - } - - } - } - -#ifdef HAVE_MPI - MPI_Barrier(MPI_COMM_WORLD); -#endif - - /*--- iElem now contains the number of elements that this processor needs in - total. Now we can complete the recv of the element connectivity and only - store the elements that we need on this particular rank. Initialize space - for the elements on this rank. ---*/ - - nElem = iElem; iElem = 0; - elem = new CPrimalGrid*[nElem]; - unsigned long iElemTria = 0; - unsigned long iElemRect = 0; - unsigned long iElemTetr = 0; - unsigned long iElemHexa = 0; - unsigned long iElemPris = 0; - unsigned long iElemPyra = 0; - - /*--- Reset presence before storing elems now that we know nElem ---*/ - - for (unsigned long i = 0; i < geometry->GetnElem(); i++) { - Element_presence[i] = false; - Triangle_presence[i] = false; - Quadrilateral_presence[i] = false; - Tetrahedron_presence[i] = false; - Hexahedron_presence[i] = false; - Prism_presence[i] = false; - Pyramid_presence[i] = false; - } - - /*--- Now recv all of the element connectivity data ---*/ - - for (iDomain = 0; iDomain < (unsigned long)size; iDomain++) { - - if ((unsigned long)rank != iDomain) { - -#ifdef HAVE_MPI - - /*--- Allocate memory for the element recv ---*/ - - Buffer_Receive_Triangle = new unsigned long[nElemTriangle_r[iDomain]*N_POINTS_TRIANGLE]; - Buffer_Receive_Quadrilateral = new unsigned long[nElemQuadrilateral_r[iDomain]*N_POINTS_QUADRILATERAL]; - Buffer_Receive_Tetrahedron = new unsigned long[nElemTetrahedron_r[iDomain]*N_POINTS_TETRAHEDRON]; - Buffer_Receive_Hexahedron = new unsigned long[nElemHexahedron_r[iDomain]*N_POINTS_HEXAHEDRON]; - Buffer_Receive_Prism = new unsigned long[nElemPrism_r[iDomain]*N_POINTS_PRISM]; - Buffer_Receive_Pyramid = new unsigned long[nElemPyramid_r[iDomain]*N_POINTS_PYRAMID]; - Buffer_Receive_GlobElem = new unsigned long[nElemTotal_r[iDomain]]; - - /*--- Recv the element data ---*/ - - MPI_Probe(iDomain, rank*16+3, MPI_COMM_WORLD, &status2); - source = status2.MPI_SOURCE; - MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(Buffer_Receive_Triangle, recv_count, MPI_UNSIGNED_LONG, - source, rank*16+3, MPI_COMM_WORLD, &status2); - - MPI_Probe(iDomain, rank*16+4, MPI_COMM_WORLD, &status2); - source = status2.MPI_SOURCE; - MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(Buffer_Receive_Quadrilateral, recv_count, MPI_UNSIGNED_LONG, - source, rank*16+4, MPI_COMM_WORLD, &status2); - - MPI_Probe(iDomain, rank*16+5, MPI_COMM_WORLD, &status2); - source = status2.MPI_SOURCE; - MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(Buffer_Receive_Tetrahedron, recv_count, MPI_UNSIGNED_LONG, - source, rank*16+5, MPI_COMM_WORLD, &status2); - - MPI_Probe(iDomain, rank*16+6, MPI_COMM_WORLD, &status2); - source = status2.MPI_SOURCE; - MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(Buffer_Receive_Hexahedron, recv_count, MPI_UNSIGNED_LONG, - source, rank*16+6, MPI_COMM_WORLD, &status2); - - MPI_Probe(iDomain, rank*16+7, MPI_COMM_WORLD, &status2); - source = status2.MPI_SOURCE; - MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(Buffer_Receive_Prism, recv_count, MPI_UNSIGNED_LONG, - source, rank*16+7, MPI_COMM_WORLD, &status2); - - MPI_Probe(iDomain, rank*16+8, MPI_COMM_WORLD, &status2); - source = status2.MPI_SOURCE; - MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(Buffer_Receive_Pyramid, recv_count, MPI_UNSIGNED_LONG, - source, rank*16+8, MPI_COMM_WORLD, &status2); - - MPI_Probe(iDomain, rank*16+9, MPI_COMM_WORLD, &status2); - source = status2.MPI_SOURCE; - MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(Buffer_Receive_GlobElem, recv_count, MPI_UNSIGNED_LONG, - source, rank*16+9, MPI_COMM_WORLD, &status2); - - /*--- Wait to complete the above sends ---*/ - - //if (rank!=iDomain) SU2_MPI::Waitall(7, &send_req[3], &send_stat[3]); - //cout << " ==== Rank " << rank << " recv from " << iDomain << " would be waiting here... " << endl; - - /*--- Allocating the elements after the recv. Note that here we are - reusing the presence arrays to make sure that we find the exact same - set of elements that were counted above to get nElem. ---*/ - - for (iElemTriangle = 0; iElemTriangle < nElemTriangle_r[iDomain]; iElemTriangle++) { - if (Triangle_presence[Buffer_Receive_Triangle_presence[iDomain][iElemTriangle]] == false) { - Triangle_presence[Buffer_Receive_Triangle_presence[iDomain][iElemTriangle]] = true; - elem[iElem] = new CTriangle(Global_to_local_Point_recv[Buffer_Receive_Triangle[iElemTriangle*3+0]], - Global_to_local_Point_recv[Buffer_Receive_Triangle[iElemTriangle*3+1]], - Global_to_local_Point_recv[Buffer_Receive_Triangle[iElemTriangle*3+2]], 2); - iElem++; iElemTria++; - } - } - - for (iElemQuadrilateral = 0; iElemQuadrilateral < nElemQuadrilateral_r[iDomain]; iElemQuadrilateral++) { - if (Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence[iDomain][iElemQuadrilateral]] == false) { - Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence[iDomain][iElemQuadrilateral]] = true; - elem[iElem] = new CQuadrilateral(Global_to_local_Point_recv[Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+0]], - Global_to_local_Point_recv[Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+1]], - Global_to_local_Point_recv[Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+2]], - Global_to_local_Point_recv[Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+3]], 2); - iElem++; iElemRect++; - } - } - - for (iElemTetrahedron = 0; iElemTetrahedron < nElemTetrahedron_r[iDomain]; iElemTetrahedron++) { - if (Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence[iDomain][iElemTetrahedron]] == false) { - Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence[iDomain][iElemTetrahedron]] = true; - elem[iElem] = new CTetrahedron(Global_to_local_Point_recv[Buffer_Receive_Tetrahedron[iElemTetrahedron*4+0]], - Global_to_local_Point_recv[Buffer_Receive_Tetrahedron[iElemTetrahedron*4+1]], - Global_to_local_Point_recv[Buffer_Receive_Tetrahedron[iElemTetrahedron*4+2]], - Global_to_local_Point_recv[Buffer_Receive_Tetrahedron[iElemTetrahedron*4+3]]); - iElem++; iElemTetr++; - } - } - - for (iElemHexahedron = 0; iElemHexahedron < nElemHexahedron_r[iDomain]; iElemHexahedron++) { - if (Hexahedron_presence[Buffer_Receive_Hexahedron_presence[iDomain][iElemHexahedron]] == false) { - Hexahedron_presence[Buffer_Receive_Hexahedron_presence[iDomain][iElemHexahedron]] = true; - elem[iElem] = new CHexahedron(Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+0]], - Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+1]], - Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+2]], - Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+3]], - Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+4]], - Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+5]], - Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+6]], - Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+7]]); - iElem++; iElemHexa++; - } - } - - for (iElemPrism = 0; iElemPrism < nElemPrism_r[iDomain]; iElemPrism++) { - if (Prism_presence[Buffer_Receive_Prism_presence[iDomain][iElemPrism]] == false) { - Prism_presence[Buffer_Receive_Prism_presence[iDomain][iElemPrism]] = true; - elem[iElem] = new CPrism(Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+0]], - Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+1]], - Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+2]], - Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+3]], - Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+4]], - Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+5]]); - iElem++; iElemPris++; - } - } - - for (iElemPyramid = 0; iElemPyramid < nElemPyramid_r[iDomain]; iElemPyramid++) { - if (Pyramid_presence[Buffer_Receive_Pyramid_presence[iDomain][iElemPyramid]] == false ) { - Pyramid_presence[Buffer_Receive_Pyramid_presence[iDomain][iElemPyramid]] = true; - elem[iElem] = new CPyramid(Global_to_local_Point_recv[Buffer_Receive_Pyramid[iElemPyramid*5+0]], - Global_to_local_Point_recv[Buffer_Receive_Pyramid[iElemPyramid*5+1]], - Global_to_local_Point_recv[Buffer_Receive_Pyramid[iElemPyramid*5+2]], - Global_to_local_Point_recv[Buffer_Receive_Pyramid[iElemPyramid*5+3]], - Global_to_local_Point_recv[Buffer_Receive_Pyramid[iElemPyramid*5+4]]); - iElem++; iElemPyra++; - } - } - - /*--- Free memory for the element data --*/ - - delete[] Buffer_Receive_Triangle; - delete[] Buffer_Receive_Quadrilateral; - delete[] Buffer_Receive_Tetrahedron; - delete[] Buffer_Receive_Hexahedron; - delete[] Buffer_Receive_Prism; - delete[] Buffer_Receive_Pyramid; - - delete[] Buffer_Receive_Triangle_presence[iDomain]; - delete[] Buffer_Receive_Quadrilateral_presence[iDomain]; - delete[] Buffer_Receive_Tetrahedron_presence[iDomain]; - delete[] Buffer_Receive_Hexahedron_presence[iDomain]; - delete[] Buffer_Receive_Prism_presence[iDomain]; - delete[] Buffer_Receive_Pyramid_presence[iDomain]; - -#endif - - } else { - - /*--- Store the element data from our local rank ---*/ - - for (iElemTriangle = 0; iElemTriangle < nElemTriangle_r[iDomain]; iElemTriangle++) { - if (Triangle_presence[Buffer_Receive_Triangle_presence_loc[iElemTriangle]] == false ) { - Triangle_presence[Buffer_Receive_Triangle_presence_loc[iElemTriangle]] = true; - elem[iElem] = new CTriangle(Global_to_local_Point_recv[Buffer_Receive_Triangle_loc[iElemTriangle*3+0]], - Global_to_local_Point_recv[Buffer_Receive_Triangle_loc[iElemTriangle*3+1]], - Global_to_local_Point_recv[Buffer_Receive_Triangle_loc[iElemTriangle*3+2]], 2); - iElem++; iElemTria++; - } - } - - for (iElemQuadrilateral = 0; iElemQuadrilateral < nElemQuadrilateral_r[iDomain]; iElemQuadrilateral++) { - if (Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence_loc[iElemQuadrilateral]] == false) { - Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence_loc[iElemQuadrilateral]] = true; - elem[iElem] = new CQuadrilateral(Global_to_local_Point_recv[Buffer_Receive_Quadrilateral_loc[iElemQuadrilateral*4+0]], - Global_to_local_Point_recv[Buffer_Receive_Quadrilateral_loc[iElemQuadrilateral*4+1]], - Global_to_local_Point_recv[Buffer_Receive_Quadrilateral_loc[iElemQuadrilateral*4+2]], - Global_to_local_Point_recv[Buffer_Receive_Quadrilateral_loc[iElemQuadrilateral*4+3]], 2); - iElem++; iElemRect++; - } - } - - for (iElemTetrahedron = 0; iElemTetrahedron < nElemTetrahedron_r[iDomain]; iElemTetrahedron++) { - if (Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence_loc[iElemTetrahedron]] == false) { - Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence_loc[iElemTetrahedron]] = true; - elem[iElem] = new CTetrahedron(Global_to_local_Point_recv[Buffer_Receive_Tetrahedron_loc[iElemTetrahedron*4+0]], - Global_to_local_Point_recv[Buffer_Receive_Tetrahedron_loc[iElemTetrahedron*4+1]], - Global_to_local_Point_recv[Buffer_Receive_Tetrahedron_loc[iElemTetrahedron*4+2]], - Global_to_local_Point_recv[Buffer_Receive_Tetrahedron_loc[iElemTetrahedron*4+3]]); - iElem++; iElemTetr++; - } - } - - for (iElemHexahedron = 0; iElemHexahedron < nElemHexahedron_r[iDomain]; iElemHexahedron++) { - if (Hexahedron_presence[Buffer_Receive_Hexahedron_presence_loc[iElemHexahedron]] == false) { - Hexahedron_presence[Buffer_Receive_Hexahedron_presence_loc[iElemHexahedron]] = true; - elem[iElem] = new CHexahedron(Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+0]], - Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+1]], - Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+2]], - Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+3]], - Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+4]], - Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+5]], - Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+6]], - Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+7]]); - iElem++; iElemHexa++; - } - } - - for (iElemPrism = 0; iElemPrism < nElemPrism_r[iDomain]; iElemPrism++) { - if (Prism_presence[Buffer_Receive_Prism_presence_loc[iElemPrism]] == false) { - Prism_presence[Buffer_Receive_Prism_presence_loc[iElemPrism]] = true; - elem[iElem] = new CPrism(Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+0]], - Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+1]], - Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+2]], - Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+3]], - Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+4]], - Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+5]]); - iElem++; iElemPris++; - } - } - - for (iElemPyramid = 0; iElemPyramid < nElemPyramid_r[iDomain]; iElemPyramid++) { - if (Pyramid_presence[Buffer_Receive_Pyramid_presence_loc[iElemPyramid]] == false) { - Pyramid_presence[Buffer_Receive_Pyramid_presence_loc[iElemPyramid]] = true; - elem[iElem] = new CPyramid(Global_to_local_Point_recv[Buffer_Receive_Pyramid_loc[iElemPyramid*5+0]], - Global_to_local_Point_recv[Buffer_Receive_Pyramid_loc[iElemPyramid*5+1]], - Global_to_local_Point_recv[Buffer_Receive_Pyramid_loc[iElemPyramid*5+2]], - Global_to_local_Point_recv[Buffer_Receive_Pyramid_loc[iElemPyramid*5+3]], - Global_to_local_Point_recv[Buffer_Receive_Pyramid_loc[iElemPyramid*5+4]]); - iElem++; iElemPyra++; - } - } - - /*--- Free memory for element data ---*/ - - delete[] Buffer_Receive_Triangle_loc; - delete[] Buffer_Receive_Quadrilateral_loc; - delete[] Buffer_Receive_Tetrahedron_loc; - delete[] Buffer_Receive_Hexahedron_loc; - delete[] Buffer_Receive_Prism_loc; - delete[] Buffer_Receive_Pyramid_loc; - - delete[] Buffer_Receive_Triangle_presence_loc; - delete[] Buffer_Receive_Quadrilateral_presence_loc; - delete[] Buffer_Receive_Tetrahedron_presence_loc; - delete[] Buffer_Receive_Hexahedron_presence_loc; - delete[] Buffer_Receive_Prism_presence_loc; - delete[] Buffer_Receive_Pyramid_presence_loc; - - } - } - -#ifdef HAVE_MPI - for (iDomain = 0; iDomain < (unsigned long)size; iDomain++) { - if ((unsigned long)rank != iDomain) SU2_MPI::Waitall(16, send_req, send_stat); - } - MPI_Barrier(MPI_COMM_WORLD); -#endif - - /*--- Free all of the memory used for communicating points and elements ---*/ - - delete[] Buffer_Send_Coord; - delete[] Buffer_Send_GlobalPointIndex; - delete[] Buffer_Send_Color; - delete[] Buffer_Send_Triangle; - delete[] Buffer_Send_Quadrilateral; - delete[] Buffer_Send_Tetrahedron; - delete[] Buffer_Send_Hexahedron; - delete[] Buffer_Send_Prism; - delete[] Buffer_Send_Pyramid; - delete[] Buffer_Send_BoundLine; - delete[] Buffer_Send_BoundTriangle; - delete[] Buffer_Send_BoundQuadrilateral; - delete[] Buffer_Send_Local2Global_Marker; - - delete[] Buffer_Send_SendDomain_Periodic; - delete[] Buffer_Send_SendDomain_PeriodicTrans; - delete[] Buffer_Send_SendDomain_PeriodicReceptor; - delete[] Buffer_Send_ReceivedDomain_Periodic; - delete[] Buffer_Send_ReceivedDomain_PeriodicTrans; - delete[] Buffer_Send_ReceivedDomain_PeriodicDonor; - - delete[] Local_to_global_Triangle; - delete[] Local_to_global_Quadrilateral; - delete[] Local_to_global_Tetrahedron; - delete[] Local_to_global_Hexahedron; - delete[] Local_to_global_Prism; - delete[] Local_to_global_Pyramid; - - - /*--- Communicate the number of each element type to all processors. These - values are important for merging and writing output later. ---*/ - -#ifdef HAVE_MPI - unsigned long Local_nElem = nElem; - SU2_MPI::Allreduce(&Local_nElem, &Global_nElem, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#else - Global_nElem = nElem; -#endif - - if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) - cout << Global_nElem << " interior elements including halo cells. " << endl; - - /*--- Store total number of each element type after incrementing the - counters in the recv loop above (to make sure there aren't repeats). ---*/ - - nelem_triangle = iElemTria; - nelem_quad = iElemRect; - nelem_tetra = iElemTetr; - nelem_hexa = iElemHexa; - nelem_prism = iElemPris; - nelem_pyramid = iElemPyra; - -#ifdef HAVE_MPI - unsigned long Local_nElemTri = nelem_triangle; - unsigned long Local_nElemQuad = nelem_quad; - unsigned long Local_nElemTet = nelem_tetra; - unsigned long Local_nElemHex = nelem_hexa; - unsigned long Local_nElemPrism = nelem_prism; - unsigned long Local_nElemPyramid = nelem_pyramid; - SU2_MPI::Allreduce(&Local_nElemTri, &Global_nelem_triangle, 1, - MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&Local_nElemQuad, &Global_nelem_quad, 1, - MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&Local_nElemTet, &Global_nelem_tetra, 1, - MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&Local_nElemHex, &Global_nelem_hexa, 1, - MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&Local_nElemPrism, &Global_nelem_prism, 1, - MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&Local_nElemPyramid, &Global_nelem_pyramid, 1, - MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#else - Global_nelem_triangle = nelem_triangle; - Global_nelem_quad = nelem_quad; - Global_nelem_tetra = nelem_tetra; - Global_nelem_hexa = nelem_hexa; - Global_nelem_prism = nelem_prism; - Global_nelem_pyramid = nelem_pyramid; -#endif - - /*--- Print information about the elements to the console ---*/ - - if (rank == MASTER_NODE) { - if (Global_nelem_triangle > 0) cout << Global_nelem_triangle << " triangles." << endl; - if (Global_nelem_quad > 0) cout << Global_nelem_quad << " quadrilaterals." << endl; - if (Global_nelem_tetra > 0) cout << Global_nelem_tetra << " tetrahedra." << endl; - if (Global_nelem_hexa > 0) cout << Global_nelem_hexa << " hexahedra." << endl; - if (Global_nelem_prism > 0) cout << Global_nelem_prism << " prisms." << endl; - if (Global_nelem_pyramid > 0) cout << Global_nelem_pyramid << " pyramids." << endl; - } - - delete [] Triangle_presence; - delete [] Quadrilateral_presence; - delete [] Tetrahedron_presence; - delete [] Hexahedron_presence; - delete [] Prism_presence; - delete [] Pyramid_presence; - - /*--- Now partition the boundary elements on the markers. Note that, for - now, we are still performing the boundary partitioning using the master - node alone. The boundaries should make up a much smaller portion of the - mesh, so this is ok for now, but we will transition to a parallel version - of this soon that follows the same procedure above for the interior. ---*/ - - if (rank == MASTER_NODE) { - - /*--- Create auxiliary vectors based on the original geometry ---*/ - - MarkerIn = new bool[geometry->GetnMarker()]; - VertexIn = new bool*[geometry->GetnMarker()]; - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) - VertexIn[iMarker] = new bool[geometry->GetnElem_Bound(iMarker)]; - - Buffer_Send_nDim = geometry->GetnDim(); - Buffer_Send_nZone = geometry->GetnZone(); - Buffer_Send_nPeriodic = config->GetnPeriodicIndex(); - Buffer_Send_Center = new su2double[Buffer_Send_nPeriodic*3]; - Buffer_Send_Rotation = new su2double[Buffer_Send_nPeriodic*3]; - Buffer_Send_Translate = new su2double[Buffer_Send_nPeriodic*3]; - - Buffer_Send_nSendDomain_Periodic = new unsigned long[nDomain]; - Buffer_Send_nReceivedDomain_Periodic = new unsigned long[nDomain]; - - /*--- Create a local copy of config->GetMarker_All_SendRecv and - config->GetMarker_All_TagBound in the master node ---*/ - - Marker_All_SendRecv_Copy = new short[geometry->GetnMarker()]; - Marker_All_TagBound_Copy = new string[geometry->GetnMarker()]; - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - Marker_All_SendRecv_Copy[iMarker] = config->GetMarker_All_SendRecv(iMarker); - Marker_All_TagBound_Copy[iMarker] = config->GetMarker_All_TagBound(iMarker); - } - - } - - for (iDomain = 0; iDomain < nDomain; iDomain++) { - - if (rank == MASTER_NODE) { - - /*--- Interior dimensionalization. Loop over the original grid - to perform the dimensionalizaton of the domain variables ---*/ - -// Buffer_Send_nElemTotal = 0; -// Buffer_Send_nPointTotal = 0; -// Buffer_Send_nPointGhost = 0; -// Buffer_Send_nPointDomainTotal = 0; -// Buffer_Send_nPointPeriodic = 0; -// Buffer_Send_nElemTriangle = 0; -// Buffer_Send_nElemQuadrilateral = 0; -// Buffer_Send_nElemTetrahedron = 0; -// Buffer_Send_nElemHexahedron = 0; -// Buffer_Send_nElemPrism = 0; -// Buffer_Send_nElemPyramid = 0; - - /*--- Boundary dimensionalization. Dimensionalization with physical - boundaries, compute Buffer_Send_nMarkerDomain, - Buffer_Send_nVertexDomain[nMarkerDomain] ---*/ - - Buffer_Send_nMarkerDomain = 0; - Buffer_Send_nBoundLineTotal = 0; - Buffer_Send_nBoundTriangleTotal = 0; - Buffer_Send_nBoundQuadrilateralTotal = 0; - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - Buffer_Send_nVertexDomain[iMarker] = 0; - Buffer_Send_nBoundLine[iMarker] = 0; - Buffer_Send_nBoundTriangle[iMarker] = 0; - Buffer_Send_nBoundQuadrilateral[iMarker] = 0; - Buffer_Send_Marker_All_SendRecv[iMarker] = Marker_All_SendRecv_Copy[iMarker]; - SPRINTF(&Buffer_Send_Marker_All_TagBound[iMarker*MAX_STRING_SIZE], "%s", - Marker_All_TagBound_Copy[iMarker].c_str()); - } - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { - - MarkerIn[iMarker] = false; - Buffer_Send_nVertexDomain[Buffer_Send_nMarkerDomain] = 0; - - for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { - VertexIn[iMarker][iVertex] = false; - for (iNode = 0; iNode < geometry->bound[iMarker][iVertex]->GetnNodes(); iNode++) { - iPoint = geometry->bound[iMarker][iVertex]->GetNode(iNode); - if (local_colour_values[iPoint] == iDomain) VertexIn[iMarker][iVertex] = true; - } - - /*--- If this vertex should be sent, increment the element type ---*/ - if (VertexIn[iMarker][iVertex]) { - switch(geometry->bound[iMarker][iVertex]->GetVTK_Type()) { - case LINE: - Buffer_Send_nBoundLine[Buffer_Send_nMarkerDomain]++; - Buffer_Send_nBoundLineTotal++; - break; - case TRIANGLE: - Buffer_Send_nBoundTriangle[Buffer_Send_nMarkerDomain]++; - Buffer_Send_nBoundTriangleTotal++; - break; - case QUADRILATERAL: - Buffer_Send_nBoundQuadrilateral[Buffer_Send_nMarkerDomain]++; - Buffer_Send_nBoundQuadrilateralTotal++; - break; - } - - /*--- Increment the total number of vertices to be sent ---*/ - Buffer_Send_nVertexDomain[Buffer_Send_nMarkerDomain]++; - MarkerIn[iMarker] = true; - - } - } - - /*--- Increment the number of markers to be sent ---*/ - if (MarkerIn[iMarker]) { Buffer_Send_nMarkerDomain++; } - - } - } - - /*--- Copy periodic information from the config file ---*/ - - for (iPeriodic = 0; iPeriodic < Buffer_Send_nPeriodic; iPeriodic++) { - for (iDim = 0; iDim < 3; iDim++) { - Buffer_Send_Center[iDim+iPeriodic*3] = config->GetPeriodicCenter(iPeriodic)[iDim]; - Buffer_Send_Rotation[iDim+iPeriodic*3] = config->GetPeriodicRotation(iPeriodic)[iDim]; - Buffer_Send_Translate[iDim+iPeriodic*3] = config->GetPeriodicTranslate(iPeriodic)[iDim]; - } - } - - /*--- Dimensionalization of the periodic auxiliary vectors ---*/ - - for (jDomain = 0; jDomain < nDomain; jDomain++) { - Buffer_Send_nSendDomain_Periodic[jDomain] = 0; - Buffer_Send_nReceivedDomain_Periodic[jDomain] = 0; - } - Buffer_Send_nTotalSendDomain_Periodic = 0; - Buffer_Send_nTotalReceivedDomain_Periodic = 0; - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { - for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { - iPoint = geometry->bound[iMarker][iVertex]->GetNode(0); - if (iDomain == local_colour_values[iPoint]) { - - if (config->GetMarker_All_SendRecv(iMarker) > 0) { - - /*--- Identify the color of the receptor ---*/ - - for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) { - if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker))) { - jPoint = geometry->bound[jMarker][iVertex]->GetNode(0); - ReceptorColor = local_colour_values[jPoint]; - } - } - - Buffer_Send_nSendDomain_Periodic[ReceptorColor]++; - Buffer_Send_nTotalSendDomain_Periodic++; - - } - if (config->GetMarker_All_SendRecv(iMarker) < 0) { - - /*--- Identify the color of the donor ---*/ - - for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) { - if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker))) { - jPoint = geometry->bound[jMarker][iVertex]->GetNode(0); - DonorColor = local_colour_values[jPoint]; - } - } - - Buffer_Send_nReceivedDomain_Periodic[DonorColor]++; - Buffer_Send_nTotalReceivedDomain_Periodic++; - - } - } - } - } - } - - /*--- Allocate the buffer vectors in the appropiate domain (master, iDomain) ---*/ - - Buffer_Send_BoundLine = new unsigned long[Buffer_Send_nBoundLineTotal*N_POINTS_LINE]; - Buffer_Send_BoundTriangle = new unsigned long[Buffer_Send_nBoundTriangleTotal*N_POINTS_TRIANGLE]; - Buffer_Send_BoundQuadrilateral = new unsigned long[Buffer_Send_nBoundQuadrilateralTotal*N_POINTS_QUADRILATERAL]; - Buffer_Send_Local2Global_Marker = new unsigned long[Buffer_Send_nMarkerDomain]; - - Buffer_Send_SendDomain_Periodic = new unsigned long[Buffer_Send_nTotalSendDomain_Periodic]; - Buffer_Send_SendDomain_PeriodicTrans = new unsigned long[Buffer_Send_nTotalSendDomain_Periodic]; - Buffer_Send_SendDomain_PeriodicReceptor = new unsigned long[Buffer_Send_nTotalSendDomain_Periodic]; - Buffer_Send_ReceivedDomain_Periodic = new unsigned long[Buffer_Send_nTotalReceivedDomain_Periodic]; - Buffer_Send_ReceivedDomain_PeriodicTrans = new unsigned long[Buffer_Send_nTotalReceivedDomain_Periodic]; - Buffer_Send_ReceivedDomain_PeriodicDonor = new unsigned long[Buffer_Send_nTotalReceivedDomain_Periodic]; - - if (iDomain != MASTER_NODE) { - - //cout << " Rank " << rank << " iDomain " << iDomain << endl; - -#ifdef HAVE_MPI - - SU2_MPI::Isend(&Buffer_Send_nBoundLineTotal, 1, - MPI_UNSIGNED_LONG, iDomain, - 0, MPI_COMM_WORLD, &send_req[0]); - - SU2_MPI::Isend(&Buffer_Send_nBoundTriangleTotal, 1, - MPI_UNSIGNED_LONG, iDomain, - 1, MPI_COMM_WORLD, &send_req[1]); - - SU2_MPI::Isend(&Buffer_Send_nBoundQuadrilateralTotal, 1, - MPI_UNSIGNED_LONG, iDomain, - 2, MPI_COMM_WORLD, &send_req[2]); - - SU2_MPI::Isend(&Buffer_Send_nMarkerDomain, 1, - MPI_UNSIGNED_SHORT, iDomain, - 3, MPI_COMM_WORLD, &send_req[3]); - - SU2_MPI::Isend(Buffer_Send_nVertexDomain, - nMarker_Max, MPI_UNSIGNED_LONG, iDomain, - 4, MPI_COMM_WORLD, &send_req[4]); - - SU2_MPI::Isend(Buffer_Send_nBoundLine, - nMarker_Max, MPI_UNSIGNED_LONG, iDomain, - 5, MPI_COMM_WORLD, &send_req[5]); - - SU2_MPI::Isend(Buffer_Send_nBoundTriangle, - nMarker_Max, MPI_UNSIGNED_LONG, iDomain, - 6, MPI_COMM_WORLD, &send_req[6]); - - SU2_MPI::Isend(Buffer_Send_nBoundQuadrilateral, - nMarker_Max, MPI_UNSIGNED_LONG, iDomain, - 7, MPI_COMM_WORLD, &send_req[7]); - - SU2_MPI::Isend(Buffer_Send_Marker_All_SendRecv, - nMarker_Max, MPI_SHORT, iDomain, - 8, MPI_COMM_WORLD, &send_req[8]); - - SU2_MPI::Isend(Buffer_Send_Marker_All_TagBound, - nMarker_Max*MAX_STRING_SIZE, MPI_CHAR, iDomain, - 9, MPI_COMM_WORLD, &send_req[9]); - - SU2_MPI::Isend(&Buffer_Send_nPeriodic, - 1, MPI_UNSIGNED_SHORT, iDomain, - 10, MPI_COMM_WORLD, &send_req[10]); - - SU2_MPI::Isend(Buffer_Send_Center, - nPeriodic*3, MPI_DOUBLE, iDomain, - 11, MPI_COMM_WORLD, &send_req[11]); - - SU2_MPI::Isend(Buffer_Send_Rotation, - nPeriodic*3, MPI_DOUBLE, iDomain, - 12, MPI_COMM_WORLD, &send_req[12]); - - SU2_MPI::Isend(Buffer_Send_Translate, - nPeriodic*3, MPI_DOUBLE, iDomain, - 13, MPI_COMM_WORLD, &send_req[13]); - - SU2_MPI::Isend(&Buffer_Send_nTotalSendDomain_Periodic, - 1, MPI_UNSIGNED_LONG, iDomain, - 14, MPI_COMM_WORLD, &send_req[14]); - - SU2_MPI::Isend(&Buffer_Send_nTotalReceivedDomain_Periodic, - 1, MPI_UNSIGNED_LONG, iDomain, - 15, MPI_COMM_WORLD, &send_req[15]); - - SU2_MPI::Isend(Buffer_Send_nSendDomain_Periodic, - nDomain, MPI_UNSIGNED_LONG, iDomain, - 16, MPI_COMM_WORLD, &send_req[16]); - - SU2_MPI::Isend(Buffer_Send_nReceivedDomain_Periodic, - nDomain, MPI_UNSIGNED_LONG, iDomain, - 17, MPI_COMM_WORLD, &send_req[17]); - - /*--- Wait for this set of non-blocking comm. to complete ---*/ - - SU2_MPI::Waitall(18, send_req, send_stat); - //cout << " Rank " << rank << " iDomain " << iDomain << " just waited for first sends" << endl; - -#endif - - } else { - - /*--- We are the master node, so simply copy values into place ---*/ - - nDim = Buffer_Send_nDim; - nZone = Buffer_Send_nZone; - - nPeriodic = Buffer_Send_nPeriodic; -// nPointGhost = Buffer_Send_nPointGhost; -// nPointPeriodic = Buffer_Send_nPointPeriodic; - - nBoundLineTotal = Buffer_Send_nBoundLineTotal; - nBoundTriangleTotal = Buffer_Send_nBoundTriangleTotal; - nBoundQuadrilateralTotal = Buffer_Send_nBoundQuadrilateralTotal; - nMarkerDomain = Buffer_Send_nMarkerDomain; - - for (iMarker = 0; iMarker < nMarker_Max; iMarker++) { - nVertexDomain[iMarker] = Buffer_Send_nVertexDomain[iMarker]; - nBoundLine[iMarker] = Buffer_Send_nBoundLine[iMarker]; - nBoundTriangle[iMarker] = Buffer_Send_nBoundTriangle[iMarker]; - nBoundQuadrilateral[iMarker] = Buffer_Send_nBoundQuadrilateral[iMarker]; - Marker_All_SendRecv[iMarker] = Buffer_Send_Marker_All_SendRecv[iMarker]; - for (iter = 0; iter < MAX_STRING_SIZE; iter++) - Marker_All_TagBound[iMarker*MAX_STRING_SIZE+iter] = Buffer_Send_Marker_All_TagBound[iMarker*MAX_STRING_SIZE+iter]; - } - - Buffer_Receive_Center = new su2double[nPeriodic*3]; - Buffer_Receive_Rotation = new su2double[nPeriodic*3]; - Buffer_Receive_Translate = new su2double[nPeriodic*3]; - - for (iter = 0; iter < nPeriodic*3; iter++) { - Buffer_Receive_Center[iter] = Buffer_Send_Center[iter]; - Buffer_Receive_Rotation[iter] = Buffer_Send_Rotation[iter]; - Buffer_Receive_Translate[iter] = Buffer_Send_Translate[iter]; - } - - nTotalSendDomain_Periodic = Buffer_Send_nTotalSendDomain_Periodic; - nTotalReceivedDomain_Periodic = Buffer_Send_nTotalReceivedDomain_Periodic; - - for (iter = 0; iter < nDomain; iter++) { - nSendDomain_Periodic[iter] = Buffer_Send_nSendDomain_Periodic[iter]; - nReceivedDomain_Periodic[iter] = Buffer_Send_nReceivedDomain_Periodic[iter]; - } - - } - } - - /*--- Each rank now begins to receive information from the master ---*/ - - if ((unsigned long)rank == iDomain) { - - /*--- First, receive the size of buffers before receiving the data ---*/ - - if (rank != MASTER_NODE) { - -#ifdef HAVE_MPI - - MPI_Probe(MASTER_NODE, 0, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(&nBoundLineTotal, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 0, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 1, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(&nBoundTriangleTotal, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 1, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 2, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(&nBoundQuadrilateralTotal, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 2, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 3, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_SHORT, &recv_count); - SU2_MPI::Recv(&nMarkerDomain, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 3, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 4, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(nVertexDomain, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 4, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 5, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(nBoundLine, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 5, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 6, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(nBoundTriangle, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 6, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 7, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(nBoundQuadrilateral, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 7, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 8, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_SHORT, &recv_count); - SU2_MPI::Recv(Marker_All_SendRecv, recv_count, MPI_SHORT, - MASTER_NODE, 8, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 9, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_CHAR, &recv_count); - SU2_MPI::Recv(Marker_All_TagBound, recv_count, MPI_CHAR, - MASTER_NODE, 9, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 10, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_SHORT, &recv_count); - SU2_MPI::Recv(&nPeriodic, recv_count, MPI_UNSIGNED_SHORT, - MASTER_NODE, 10, MPI_COMM_WORLD, &status); - -#endif - - /*--- Marker_All_TagBound and Marker_All_SendRecv, set the same - values in the config files of all the files ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - config->SetMarker_All_SendRecv(iMarker, - Marker_All_SendRecv[iMarker]); - config->SetMarker_All_TagBound(iMarker, - string(&Marker_All_TagBound[iMarker*MAX_STRING_SIZE])); - } - - - /*--- Periodic boundary conditions ---*/ - - Buffer_Receive_Center = new su2double[nPeriodic*3]; - Buffer_Receive_Rotation = new su2double[nPeriodic*3]; - Buffer_Receive_Translate = new su2double[nPeriodic*3]; - -#ifdef HAVE_MPI - - MPI_Probe(MASTER_NODE, 11, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_DOUBLE, &recv_count); - SU2_MPI::Recv(Buffer_Receive_Center, recv_count, MPI_DOUBLE, - MASTER_NODE, 11, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 12, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_DOUBLE, &recv_count); - SU2_MPI::Recv(Buffer_Receive_Rotation, recv_count, MPI_DOUBLE, - MASTER_NODE, 12, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 13, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_DOUBLE, &recv_count); - SU2_MPI::Recv(Buffer_Receive_Translate, recv_count, MPI_DOUBLE, - MASTER_NODE, 13, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 14, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(&nTotalSendDomain_Periodic, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 14, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 15, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(&nTotalReceivedDomain_Periodic, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 15, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 16, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(nSendDomain_Periodic, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 16, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 17, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(nReceivedDomain_Periodic, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 17, MPI_COMM_WORLD, &status); - -#endif - - config->SetnPeriodicIndex(nPeriodic); - - for (iPeriodic = 0; iPeriodic < nPeriodic; iPeriodic++) { - - su2double* center = new su2double[3]; // Do not deallocate the memory - su2double* rotation = new su2double[3]; // Do not deallocate the memory - su2double* translate = new su2double[3]; // Do not deallocate the memory - - for (iDim = 0; iDim < 3; iDim++) { - center[iDim] = Buffer_Receive_Center[iDim+iPeriodic*3]; - rotation[iDim] = Buffer_Receive_Rotation[iDim+iPeriodic*3]; - translate[iDim] = Buffer_Receive_Translate[iDim+iPeriodic*3]; - } - config->SetPeriodicCenter(iPeriodic, center); - config->SetPeriodicRotation(iPeriodic, rotation); - config->SetPeriodicTranslate(iPeriodic, translate); - } - - } - - delete [] Buffer_Receive_Center; - delete [] Buffer_Receive_Rotation; - delete [] Buffer_Receive_Translate; - - /*--- Allocate the receive buffer vector ---*/ - - Buffer_Receive_BoundLine = new unsigned long[nBoundLineTotal*2]; - Buffer_Receive_BoundTriangle = new unsigned long[nBoundTriangleTotal*3]; - Buffer_Receive_BoundQuadrilateral = new unsigned long[nBoundQuadrilateralTotal*4]; - Buffer_Receive_Local2Global_Marker = new unsigned long[nMarkerDomain]; - - Buffer_Receive_SendDomain_Periodic = new unsigned long[nTotalSendDomain_Periodic]; - Buffer_Receive_SendDomain_PeriodicTrans = new unsigned long[nTotalSendDomain_Periodic]; - Buffer_Receive_SendDomain_PeriodicReceptor = new unsigned long[nTotalSendDomain_Periodic]; - Buffer_Receive_ReceivedDomain_Periodic = new unsigned long[nTotalReceivedDomain_Periodic]; - Buffer_Receive_ReceivedDomain_PeriodicTrans = new unsigned long[nTotalReceivedDomain_Periodic]; - Buffer_Receive_ReceivedDomain_PeriodicDonor = new unsigned long[nTotalReceivedDomain_Periodic]; - - } - - - //cout << " &&&& Rank " << rank << " about to start bound elems " << endl; - - /*--- Set the value of the Send buffers ---*/ - - if (rank == MASTER_NODE) { - - /*--- Set the value of the boundary geometry ---*/ - - iMarkerDomain = 0; - iBoundLineTotal = 0; iBoundTriangleTotal = 0; iBoundQuadrilateralTotal = 0; - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - if ((config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) && (MarkerIn[iMarker])) { - for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { - - if (VertexIn[iMarker][iVertex]) { - - /*--- Send global index here and then convert to local on the recv ---*/ - - for (iNode = 0; iNode < geometry->bound[iMarker][iVertex]->GetnNodes(); iNode++) { - vnodes_local[iNode] = geometry->bound[iMarker][iVertex]->GetNode(iNode); - } - - switch(geometry->bound[iMarker][iVertex]->GetVTK_Type()) { - case LINE: - Buffer_Send_BoundLine[N_POINTS_LINE*iBoundLineTotal+0] = vnodes_local[0]; - Buffer_Send_BoundLine[N_POINTS_LINE*iBoundLineTotal+1] = vnodes_local[1]; - iBoundLineTotal++; - break; - case TRIANGLE: - Buffer_Send_BoundTriangle[N_POINTS_TRIANGLE*iBoundTriangleTotal+0] = vnodes_local[0]; - Buffer_Send_BoundTriangle[N_POINTS_TRIANGLE*iBoundTriangleTotal+1] = vnodes_local[1]; - Buffer_Send_BoundTriangle[N_POINTS_TRIANGLE*iBoundTriangleTotal+2] = vnodes_local[2]; - iBoundTriangleTotal++; - break; - case QUADRILATERAL: - Buffer_Send_BoundQuadrilateral[N_POINTS_QUADRILATERAL*iBoundQuadrilateralTotal+0] = vnodes_local[0]; - Buffer_Send_BoundQuadrilateral[N_POINTS_QUADRILATERAL*iBoundQuadrilateralTotal+1] = vnodes_local[1]; - Buffer_Send_BoundQuadrilateral[N_POINTS_QUADRILATERAL*iBoundQuadrilateralTotal+2] = vnodes_local[2]; - Buffer_Send_BoundQuadrilateral[N_POINTS_QUADRILATERAL*iBoundQuadrilateralTotal+3] = vnodes_local[3]; - iBoundQuadrilateralTotal++; - break; - } - } - } - - Buffer_Send_Local2Global_Marker[iMarkerDomain] = iMarker; - iMarkerDomain++; - - } - } - - /*--- Evaluate the number of already existing periodic boundary conditions ---*/ - - iTotalSendDomain_Periodic = 0; - iTotalReceivedDomain_Periodic = 0; - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { - - for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { - - iPoint = geometry->bound[iMarker][iVertex]->GetNode(0); - Transformation = geometry->bound[iMarker][iVertex]->GetRotation_Type(); - - if (iDomain == local_colour_values[iPoint]) { - - /*--- If the information is going to be sended, find the - domain of the receptor ---*/ - - if (config->GetMarker_All_SendRecv(iMarker) > 0) { - - /*--- Identify the color of the receptor ---*/ - - for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) { - if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker))) { - jPoint = geometry->bound[jMarker][iVertex]->GetNode(0); - ReceptorColor = local_colour_values[jPoint]; - } - } - - /*--- For each color of the receptor we will han an extra marker (+) ---*/ - - Buffer_Send_SendDomain_Periodic[iTotalSendDomain_Periodic] = iPoint; - Buffer_Send_SendDomain_PeriodicTrans[iTotalSendDomain_Periodic] = Transformation; - Buffer_Send_SendDomain_PeriodicReceptor[iTotalSendDomain_Periodic] = ReceptorColor; - - iTotalSendDomain_Periodic++; - - } - - /*--- If the information is goint to be received, find the domain if the donor ---*/ - - if (config->GetMarker_All_SendRecv(iMarker) < 0) { - - /*--- Identify the color of the donor ---*/ - - for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) { - if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker) )) { - jPoint = geometry->bound[jMarker][iVertex]->GetNode(0); - DonorColor = local_colour_values[jPoint]; - } - } - - /*--- For each color of the donor we will han an extra marker (-) ---*/ - - Buffer_Send_ReceivedDomain_Periodic[iTotalReceivedDomain_Periodic] = iPoint; - Buffer_Send_ReceivedDomain_PeriodicTrans[iTotalReceivedDomain_Periodic] = Transformation; - Buffer_Send_ReceivedDomain_PeriodicDonor[iTotalReceivedDomain_Periodic] = DonorColor; - - iTotalReceivedDomain_Periodic++; - - } - } - } - } - } - - /*--- Send the buffers with the geometrical information ---*/ - - if (iDomain != MASTER_NODE) { - -#ifdef HAVE_MPI - - SU2_MPI::Isend(Buffer_Send_BoundLine, - Buffer_Send_nBoundLineTotal*N_POINTS_LINE, MPI_UNSIGNED_LONG, iDomain, - 0, MPI_COMM_WORLD, &send_req[0]); - - SU2_MPI::Isend(Buffer_Send_BoundTriangle, - Buffer_Send_nBoundTriangleTotal*N_POINTS_TRIANGLE, MPI_UNSIGNED_LONG, iDomain, - 1, MPI_COMM_WORLD, &send_req[1]); - - SU2_MPI::Isend(Buffer_Send_BoundQuadrilateral, - Buffer_Send_nBoundQuadrilateralTotal*N_POINTS_QUADRILATERAL, MPI_UNSIGNED_LONG, iDomain, - 2, MPI_COMM_WORLD, &send_req[2]); - - SU2_MPI::Isend(Buffer_Send_Local2Global_Marker, - Buffer_Send_nMarkerDomain, MPI_UNSIGNED_LONG, iDomain, - 3, MPI_COMM_WORLD, &send_req[3]); - - SU2_MPI::Isend(Buffer_Send_SendDomain_Periodic, - Buffer_Send_nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, - 4, MPI_COMM_WORLD, &send_req[4]); - - SU2_MPI::Isend(Buffer_Send_SendDomain_PeriodicTrans, - Buffer_Send_nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, - 5, MPI_COMM_WORLD, &send_req[5]); - - SU2_MPI::Isend(Buffer_Send_SendDomain_PeriodicReceptor, - Buffer_Send_nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, - 6, MPI_COMM_WORLD, &send_req[6]); - - SU2_MPI::Isend(Buffer_Send_ReceivedDomain_Periodic, - Buffer_Send_nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, - 7, MPI_COMM_WORLD, &send_req[7]); - - SU2_MPI::Isend(Buffer_Send_ReceivedDomain_PeriodicTrans, - Buffer_Send_nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, - 8, MPI_COMM_WORLD, &send_req[8]); - - SU2_MPI::Isend(Buffer_Send_ReceivedDomain_PeriodicDonor, - Buffer_Send_nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, - 9, MPI_COMM_WORLD, &send_req[9]); - - /*--- Wait for this set of non-blocking comm. to complete ---*/ - - SU2_MPI::Waitall(10, send_req, send_stat); - -#endif - - } else { - - /*--- Copy the data directly from our own rank ---*/ - - for (iter = 0; iter < Buffer_Send_nBoundLineTotal*N_POINTS_LINE; iter++) - Buffer_Receive_BoundLine[iter] = Buffer_Send_BoundLine[iter]; - - for (iter = 0; iter < Buffer_Send_nBoundTriangleTotal*N_POINTS_TRIANGLE; iter++) - Buffer_Receive_BoundTriangle[iter] = Buffer_Send_BoundTriangle[iter]; - - for (iter = 0; iter < Buffer_Send_nBoundQuadrilateralTotal*N_POINTS_QUADRILATERAL; iter++) - Buffer_Receive_BoundQuadrilateral[iter] = Buffer_Send_BoundQuadrilateral[iter]; - - for (iter = 0; iter < Buffer_Send_nMarkerDomain; iter++) - Buffer_Receive_Local2Global_Marker[iter] = Buffer_Send_Local2Global_Marker[iter]; - - for (iter = 0; iter < Buffer_Send_nTotalSendDomain_Periodic; iter++) { - Buffer_Receive_SendDomain_Periodic[iter] = Buffer_Send_SendDomain_Periodic[iter]; - Buffer_Receive_SendDomain_PeriodicTrans[iter] = Buffer_Send_SendDomain_PeriodicTrans[iter]; - Buffer_Receive_SendDomain_PeriodicReceptor[iter] = Buffer_Send_SendDomain_PeriodicReceptor[iter]; - } - - for (iter = 0; iter < Buffer_Send_nTotalReceivedDomain_Periodic; iter++) { - Buffer_Receive_ReceivedDomain_Periodic[iter] = Buffer_Send_ReceivedDomain_Periodic[iter]; - Buffer_Receive_ReceivedDomain_PeriodicTrans[iter] = Buffer_Send_ReceivedDomain_PeriodicTrans[iter]; - Buffer_Receive_ReceivedDomain_PeriodicDonor[iter] = Buffer_Send_ReceivedDomain_PeriodicDonor[iter]; - } - - } - - delete[] Buffer_Send_BoundLine; - delete[] Buffer_Send_BoundTriangle; - delete[] Buffer_Send_BoundQuadrilateral; - delete[] Buffer_Send_Local2Global_Marker; - - delete[] Buffer_Send_SendDomain_Periodic; - delete[] Buffer_Send_SendDomain_PeriodicTrans; - delete[] Buffer_Send_SendDomain_PeriodicReceptor; - delete[] Buffer_Send_ReceivedDomain_Periodic; - delete[] Buffer_Send_ReceivedDomain_PeriodicTrans; - delete[] Buffer_Send_ReceivedDomain_PeriodicDonor; - - } - - //cout << " Rank " << rank << " about to recv of bound elems " << endl; - - if ((unsigned long)rank == iDomain) { - - if (rank != MASTER_NODE) { - - /*--- Receive the buffers with the geometrical information ---*/ - -#ifdef HAVE_MPI - - MPI_Probe(MASTER_NODE, 0, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(Buffer_Receive_BoundLine, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 0, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 1, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(Buffer_Receive_BoundTriangle, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 1, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 2, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(Buffer_Receive_BoundQuadrilateral, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 2, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 3, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(Buffer_Receive_Local2Global_Marker, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 3, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 4, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(Buffer_Receive_SendDomain_Periodic, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 4, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 5, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(Buffer_Receive_SendDomain_PeriodicTrans, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 5, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 6, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(Buffer_Receive_SendDomain_PeriodicReceptor, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 6, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 7, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(Buffer_Receive_ReceivedDomain_Periodic, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 7, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 8, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(Buffer_Receive_ReceivedDomain_PeriodicTrans, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 8, MPI_COMM_WORLD, &status); - - MPI_Probe(MASTER_NODE, 9, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); - SU2_MPI::Recv(Buffer_Receive_ReceivedDomain_PeriodicDonor, recv_count, MPI_UNSIGNED_LONG, - MASTER_NODE, 9, MPI_COMM_WORLD, &status); - -#endif - - } - - /*--- Create the domain structures for the boundaries ---*/ - - nMarker = nMarkerDomain; - nElem_Bound = new unsigned long[nMarker_Max]; - Local_to_Global_Marker = new unsigned short[nMarker_Max]; - Tag_to_Marker = new string[nMarker_Max]; - string *TagBound_Copy = new string[nMarker_Max]; - short *SendRecv_Copy = new short[nMarker_Max]; - - for (iMarker = 0; iMarker < nMarker; iMarker++) - nElem_Bound[iMarker] = nVertexDomain[iMarker]; - - bound = new CPrimalGrid**[nMarker+(overhead*nDomain)]; - for (iMarker = 0; iMarker < nMarker; iMarker++) - bound[iMarker] = new CPrimalGrid*[nElem_Bound[iMarker]]; - - /*--- Initialize boundary element counters ---*/ - iBoundLineTotal = 0; - iBoundTriangleTotal = 0; - iBoundQuadrilateralTotal = 0; - - /*--- Store the boundary element connectivity. Note here that we have - communicated the global index values for the elements, so we need to - convert this to the local index when instantiating the element. ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - iVertexDomain = 0; - - for (iBoundLine = 0; iBoundLine < nBoundLine[iMarker]; iBoundLine++) { - bound[iMarker][iVertexDomain] = new CLine(Global_to_local_Point_recv[Buffer_Receive_BoundLine[iBoundLineTotal*2+0]], - Global_to_local_Point_recv[Buffer_Receive_BoundLine[iBoundLineTotal*2+1]], 2); - iVertexDomain++; iBoundLineTotal++; - } - for (iBoundTriangle = 0; iBoundTriangle < nBoundTriangle[iMarker]; iBoundTriangle++) { - bound[iMarker][iVertexDomain] = new CTriangle(Global_to_local_Point_recv[Buffer_Receive_BoundTriangle[iBoundTriangleTotal*3+0]], - Global_to_local_Point_recv[Buffer_Receive_BoundTriangle[iBoundTriangleTotal*3+1]], - Global_to_local_Point_recv[Buffer_Receive_BoundTriangle[iBoundTriangleTotal*3+2]], 3); - iVertexDomain++; iBoundTriangleTotal++; - } - for (iBoundQuadrilateral = 0; iBoundQuadrilateral < nBoundQuadrilateral[iMarker]; iBoundQuadrilateral++) { - bound[iMarker][iVertexDomain] = new CQuadrilateral(Global_to_local_Point_recv[Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+0]], - Global_to_local_Point_recv[Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+1]], - Global_to_local_Point_recv[Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+2]], - Global_to_local_Point_recv[Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+3]], 3); - iVertexDomain++; iBoundQuadrilateralTotal++; - } - - Local_to_Global_Marker[iMarker] = Buffer_Receive_Local2Global_Marker[iMarker]; - - /*--- Now each domain has the right information ---*/ - - string Grid_Marker = config->GetMarker_All_TagBound(Local_to_Global_Marker[iMarker]); - short SendRecv = config->GetMarker_All_SendRecv(Local_to_Global_Marker[iMarker]); - TagBound_Copy[iMarker] = Grid_Marker; - SendRecv_Copy[iMarker] = SendRecv; - - } - - /*--- Store total number of each boundary element type ---*/ - - nelem_edge_bound = iBoundLineTotal; - nelem_triangle_bound = iBoundTriangleTotal; - nelem_quad_bound = iBoundQuadrilateralTotal; - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - config->SetMarker_All_TagBound(iMarker, TagBound_Copy[iMarker]); - config->SetMarker_All_SendRecv(iMarker, SendRecv_Copy[iMarker]); - } - - /*--- Add the new periodic markers to the domain ---*/ - -// iTotalSendDomain_Periodic = 0; -// iTotalReceivedDomain_Periodic = 0; - - for (jDomain = 0; jDomain < nDomain; jDomain++) { - - if (nSendDomain_Periodic[jDomain] != 0) { - nVertexDomain[nMarker] = 0; - bound[nMarker] = new CPrimalGrid* [nSendDomain_Periodic[jDomain]]; - - iVertex = 0; - for (iTotalSendDomain_Periodic = 0; iTotalSendDomain_Periodic < nTotalSendDomain_Periodic; iTotalSendDomain_Periodic++) { - if (Buffer_Receive_SendDomain_PeriodicReceptor[iTotalSendDomain_Periodic] == jDomain) { - bound[nMarker][iVertex] = new CVertexMPI(Global_to_local_Point_recv[Buffer_Receive_SendDomain_Periodic[iTotalSendDomain_Periodic]], nDim); - bound[nMarker][iVertex]->SetRotation_Type(Buffer_Receive_SendDomain_PeriodicTrans[iTotalSendDomain_Periodic]); - nVertexDomain[nMarker]++; iVertex++; - } - } - - Marker_All_SendRecv[nMarker] = jDomain+1; - nElem_Bound[nMarker] = nVertexDomain[nMarker]; - nMarker++; - } - - if (nReceivedDomain_Periodic[jDomain] != 0) { - nVertexDomain[nMarker] = 0; - bound[nMarker] = new CPrimalGrid* [nReceivedDomain_Periodic[jDomain]]; - - iVertex = 0; - for (iTotalReceivedDomain_Periodic = 0; iTotalReceivedDomain_Periodic < nTotalReceivedDomain_Periodic; iTotalReceivedDomain_Periodic++) { - if (Buffer_Receive_ReceivedDomain_PeriodicDonor[iTotalReceivedDomain_Periodic] == jDomain) { - bound[nMarker][iVertex] = new CVertexMPI(Global_to_local_Point_recv[Buffer_Receive_ReceivedDomain_Periodic[iTotalReceivedDomain_Periodic]], nDim); - bound[nMarker][iVertex]->SetRotation_Type(Buffer_Receive_ReceivedDomain_PeriodicTrans[iTotalReceivedDomain_Periodic]); - nVertexDomain[nMarker]++; iVertex++; - } - } - - Marker_All_SendRecv[nMarker] = -(jDomain+1); - nElem_Bound[nMarker] = nVertexDomain[nMarker]; - nMarker++; - } - - } - - delete[] TagBound_Copy; - delete[] SendRecv_Copy; - - delete[] Buffer_Receive_BoundLine; - delete[] Buffer_Receive_BoundTriangle; - delete[] Buffer_Receive_BoundQuadrilateral; - delete[] Buffer_Receive_Local2Global_Marker; - - delete[] Buffer_Receive_SendDomain_Periodic; - delete[] Buffer_Receive_SendDomain_PeriodicTrans; - delete[] Buffer_Receive_SendDomain_PeriodicReceptor; - delete[] Buffer_Receive_ReceivedDomain_Periodic; - delete[] Buffer_Receive_ReceivedDomain_PeriodicTrans; - delete[] Buffer_Receive_ReceivedDomain_PeriodicDonor; - - } - - - } - - /*--- The MASTER should wait for the sends above to complete ---*/ - -#ifdef HAVE_MPI - MPI_Barrier(MPI_COMM_WORLD); -#endif - - /*--- Set the value of Marker_All_SendRecv and Marker_All_TagBound in the config structure ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - config->SetMarker_All_SendRecv(iMarker, Marker_All_SendRecv[iMarker]); - } - - /*--- Set the value of Global_nPoint and Global_nPointDomain ---*/ - - unsigned long Local_nPoint = nPoint; - unsigned long Local_nPointDomain = nPointDomain; - -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&Local_nPoint, &Global_nPoint, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&Local_nPointDomain, &Global_nPointDomain, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#else - Global_nPoint = Local_nPoint; - Global_nPointDomain = Local_nPointDomain; -#endif - - if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) - cout << Global_nPoint << " vertices including ghost points. " << endl; - - /*--- Release all of the temporary memory ---*/ - - delete [] nDim_s; - delete [] nDim_r; - - delete [] nPointTotal_s; - delete [] nPointDomainTotal_s; - delete [] nPointGhost_s; - delete [] nPointPeriodic_s; - delete [] nElemTotal_s; - delete [] nElemTriangle_s; - delete [] nElemQuadrilateral_s; - delete [] nElemTetrahedron_s; - delete [] nElemHexahedron_s; - delete [] nElemPrism_s; - delete [] nElemPyramid_s; - delete [] nZone_s; - - delete [] nPointTotal_r; - delete [] nPointDomainTotal_r; - delete [] nPointGhost_r; - delete [] nPointPeriodic_r; - delete [] nElemTotal_r; - delete [] nElemTriangle_r; - delete [] nElemQuadrilateral_r; - delete [] nElemTetrahedron_r; - delete [] nElemHexahedron_r; - delete [] nElemPrism_r; - delete [] nElemPyramid_r; - delete [] nZone_r; - - if (rank == MASTER_NODE) { - delete [] MarkerIn; - delete [] Buffer_Send_Center; - delete [] Buffer_Send_Rotation; - delete [] Buffer_Send_Translate; - delete [] Buffer_Send_nSendDomain_Periodic; - delete [] Buffer_Send_nReceivedDomain_Periodic; - delete [] Marker_All_SendRecv_Copy; - delete [] Marker_All_TagBound_Copy; - delete [] PointIn; - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) - delete [] VertexIn[iMarker]; - delete[] VertexIn; - } - - delete [] Marker_All_TagBound; - delete [] Buffer_Send_Marker_All_TagBound; - - delete [] nSendDomain_Periodic; - delete [] nReceivedDomain_Periodic; - delete [] nVertexDomain; - delete [] nBoundLine; - delete [] nBoundTriangle; - delete [] nBoundQuadrilateral; - delete [] Buffer_Send_nVertexDomain; - delete [] Buffer_Send_nBoundLine; - delete [] Buffer_Send_nBoundTriangle; - delete [] Buffer_Send_nBoundQuadrilateral; - delete [] Buffer_Send_Marker_All_SendRecv; - -#ifdef HAVE_MPI - delete [] send_stat; - delete [] recv_stat; - delete [] send_req; - delete [] recv_req; -#endif - -} - - -CPhysicalGeometry::~CPhysicalGeometry(void) { - - if (Global_to_Local_Point != NULL) delete [] Global_to_Local_Point; - if (Local_to_Global_Point != NULL) delete [] Local_to_Global_Point; - if (Global_to_Local_Marker != NULL) delete [] Global_to_Local_Marker; - if (Local_to_Global_Marker != NULL) delete [] Local_to_Global_Marker; - -} - - - -void CPhysicalGeometry::SetSendReceive(CConfig *config) { - - unsigned short Counter_Send, Counter_Receive, iMarkerSend, iMarkerReceive; - unsigned long iVertex, LocalNode; - unsigned short nMarker_Max = config->GetnMarker_Max(); - unsigned long iPoint, jPoint, iElem; - unsigned long *nVertexDomain = new unsigned long[nMarker_Max]; - unsigned short nDomain, iNode, iDomain, jDomain, jNode; - vector::iterator it; - - vector > SendTransfLocal; /*!< \brief Vector to store the type of transformation for this send point. */ - vector > ReceivedTransfLocal; /*!< \brief Vector to store the type of transformation for this received point. */ - vector > SendDomainLocal; /*!< \brief SendDomain[from domain][to domain] and return the point index of the node that must me sended. */ - vector > ReceivedDomainLocal; /*!< \brief SendDomain[from domain][to domain] and return the point index of the node that must me sended. */ - - int rank = MASTER_NODE; - int size = SINGLE_NODE; - -#ifdef HAVE_MPI - /*--- MPI initialization ---*/ - MPI_Comm_size(MPI_COMM_WORLD, &size); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - if (rank == MASTER_NODE && size > SINGLE_NODE) - cout << "Establishing MPI communication patterns." << endl; - - nDomain = size; - - SendTransfLocal.resize(nDomain); - ReceivedTransfLocal.resize(nDomain); - SendDomainLocal.resize(nDomain); - ReceivedDomainLocal.resize(nDomain); - - /*--- Loop over the all the points of the element - to find the points with different colours, and create the send/received list ---*/ - for (iElem = 0; iElem < nElem; iElem++) { - for (iNode = 0; iNode < elem[iElem]->GetnNodes(); iNode++) { - iPoint = elem[iElem]->GetNode(iNode); - iDomain = node[iPoint]->GetColor(); - - if (iDomain == rank) { - for (jNode = 0; jNode < elem[iElem]->GetnNodes(); jNode++) { - jPoint = elem[iElem]->GetNode(jNode); - jDomain = node[jPoint]->GetColor(); - - /*--- If different color and connected by an edge, then we add them to the list ---*/ - if (iDomain != jDomain) { - - /*--- We send from iDomain to jDomain the value of iPoint, we save the - global value becuase we need to sort the lists ---*/ - SendDomainLocal[jDomain].push_back(Local_to_Global_Point[iPoint]); - /*--- We send from jDomain to iDomain the value of jPoint, we save the - global value becuase we need to sort the lists ---*/ - ReceivedDomainLocal[jDomain].push_back(Local_to_Global_Point[jPoint]); - - } - } - } - } - } - - /*--- Sort the points that must be sended and delete repeated points, note - that the sorting should be done with the global point (not the local) ---*/ - for (iDomain = 0; iDomain < nDomain; iDomain++) { - sort( SendDomainLocal[iDomain].begin(), SendDomainLocal[iDomain].end()); - it = unique( SendDomainLocal[iDomain].begin(), SendDomainLocal[iDomain].end()); - SendDomainLocal[iDomain].resize( it - SendDomainLocal[iDomain].begin() ); - } - - /*--- Sort the points that must be received and delete repeated points, note - that the sorting should be done with the global point (not the local) ---*/ - for (iDomain = 0; iDomain < nDomain; iDomain++) { - sort( ReceivedDomainLocal[iDomain].begin(), ReceivedDomainLocal[iDomain].end()); - it = unique( ReceivedDomainLocal[iDomain].begin(), ReceivedDomainLocal[iDomain].end()); - ReceivedDomainLocal[iDomain].resize( it - ReceivedDomainLocal[iDomain].begin() ); - } - - /*--- Create Global to Local Point array, note that the array is smaller (Max_GlobalPoint) than the total - number of points in the simulation ---*/ - Max_GlobalPoint = 0; - for (iPoint = 0; iPoint < nPoint; iPoint++) { - if (Local_to_Global_Point[iPoint] > (long)Max_GlobalPoint) - Max_GlobalPoint = Local_to_Global_Point[iPoint]; - } - Global_to_Local_Point = new long[Max_GlobalPoint+1]; // +1 to include the bigger point. - - /*--- Initialization of the array with -1 this is important for the FFD ---*/ - for (iPoint = 0; iPoint < Max_GlobalPoint+1; iPoint++) - Global_to_Local_Point[iPoint] = -1; - - /*--- Set the value of some of the points ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint++) - Global_to_Local_Point[Local_to_Global_Point[iPoint]] = iPoint; - - /*--- Add the new MPI send receive boundaries, reset the transformation, and save the local value ---*/ - for (iDomain = 0; iDomain < nDomain; iDomain++) { - if (SendDomainLocal[iDomain].size() != 0) { - nVertexDomain[nMarker] = SendDomainLocal[iDomain].size(); - for (iVertex = 0; iVertex < nVertexDomain[nMarker]; iVertex++) { - SendDomainLocal[iDomain][iVertex] = Global_to_Local_Point[SendDomainLocal[iDomain][iVertex]]; - SendTransfLocal[iDomain].push_back(0); - } - nElem_Bound[nMarker] = nVertexDomain[nMarker]; - bound[nMarker] = new CPrimalGrid*[nElem_Bound[nMarker]]; - nMarker++; - } - } - - /*--- Add the new MPI receive boundaries, reset the transformation, and save the local value ---*/ - for (iDomain = 0; iDomain < nDomain; iDomain++) { - if (ReceivedDomainLocal[iDomain].size() != 0) { - nVertexDomain[nMarker] = ReceivedDomainLocal[iDomain].size(); - for (iVertex = 0; iVertex < nVertexDomain[nMarker]; iVertex++) { - ReceivedDomainLocal[iDomain][iVertex] = Global_to_Local_Point[ReceivedDomainLocal[iDomain][iVertex]]; - ReceivedTransfLocal[iDomain].push_back(0); - } - nElem_Bound[nMarker] = nVertexDomain[nMarker]; - bound[nMarker] = new CPrimalGrid*[nElem_Bound[nMarker]]; - nMarker++; - } - } - - /*--- First compute the Send/Receive boundaries ---*/ - Counter_Send = 0; Counter_Receive = 0; - for (iDomain = 0; iDomain < nDomain; iDomain++) - if (SendDomainLocal[iDomain].size() != 0) Counter_Send++; - - for (iDomain = 0; iDomain < nDomain; iDomain++) - if (ReceivedDomainLocal[iDomain].size() != 0) Counter_Receive++; - - iMarkerSend = nMarker - Counter_Send - Counter_Receive; - iMarkerReceive = nMarker - Counter_Receive; - - /*--- First we do the send ---*/ - for (iDomain = 0; iDomain < nDomain; iDomain++) { - if (SendDomainLocal[iDomain].size() != 0) { - for (iVertex = 0; iVertex < GetnElem_Bound(iMarkerSend); iVertex++) { - LocalNode = SendDomainLocal[iDomain][iVertex]; - bound[iMarkerSend][iVertex] = new CVertexMPI(LocalNode, nDim); - bound[iMarkerSend][iVertex]->SetRotation_Type(SendTransfLocal[iDomain][iVertex]); - } - Marker_All_SendRecv[iMarkerSend] = iDomain+1; - iMarkerSend++; - } - } - - /*--- Second we do the receive ---*/ - for (iDomain = 0; iDomain < nDomain; iDomain++) { - if (ReceivedDomainLocal[iDomain].size() != 0) { - for (iVertex = 0; iVertex < GetnElem_Bound(iMarkerReceive); iVertex++) { - LocalNode = ReceivedDomainLocal[iDomain][iVertex]; - bound[iMarkerReceive][iVertex] = new CVertexMPI(LocalNode, nDim); - bound[iMarkerReceive][iVertex]->SetRotation_Type(ReceivedTransfLocal[iDomain][iVertex]); - } - Marker_All_SendRecv[iMarkerReceive] = -(iDomain+1); - iMarkerReceive++; - } - } - - /*--- Free memory ---*/ - delete [] nVertexDomain; -} - - -void CPhysicalGeometry::SetBoundaries(CConfig *config) { - - unsigned long iElem_Bound, TotalElem, *nElem_Bound_Copy, iVertex_; - string Grid_Marker; - unsigned short iDomain, nDomain, iMarkersDomain, iLoop, *DomainCount, nMarker_Physical, Duplicate_SendReceive, *DomainSendCount, **DomainSendMarkers, *DomainReceiveCount, **DomainReceiveMarkers, nMarker_SendRecv, iMarker, iMarker_; - CPrimalGrid*** bound_Copy; - short *Marker_All_SendRecv_Copy; - bool CheckStart; - - int size = SINGLE_NODE; - -#ifdef HAVE_MPI - /*--- MPI initialization ---*/ - MPI_Comm_size(MPI_COMM_WORLD, &size); -#endif - - nDomain = size+1; - - /*--- Count the number of physical markers - in the boundaries ---*/ - - nMarker_Physical = 0; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (bound[iMarker][0]->GetVTK_Type() != VERTEX) { - nMarker_Physical++; - } - } - - /*--- Identify if there are markers that send/received with the same domain, - they should be together---*/ - - Duplicate_SendReceive = 0; - for (iLoop = 0; iLoop < 2; iLoop++) { - - DomainCount = new unsigned short [nDomain]; - - for (iDomain = 0; iDomain < nDomain; iDomain++) - DomainCount[iDomain] = 0; - - if (iLoop == 0) { - for (iDomain = 0; iDomain < nDomain; iDomain++) - for (iMarker = 0; iMarker < nMarker; iMarker++) - if (bound[iMarker][0]->GetVTK_Type() == VERTEX) - if (Marker_All_SendRecv[iMarker] == iDomain) DomainCount[iDomain]++; - } - else { - for (iDomain = 0; iDomain < nDomain; iDomain++) - for (iMarker = 0; iMarker < nMarker; iMarker++) - if (bound[iMarker][0]->GetVTK_Type() == VERTEX) - if (Marker_All_SendRecv[iMarker] == -iDomain) DomainCount[iDomain]++; - } - - for (iDomain = 0; iDomain < nDomain; iDomain++) - if (DomainCount[iDomain] > 1) Duplicate_SendReceive++; - - delete [] DomainCount; - - } - - DomainSendCount = new unsigned short [nDomain]; - DomainSendMarkers = new unsigned short *[nDomain]; - DomainReceiveCount = new unsigned short [nDomain]; - DomainReceiveMarkers = new unsigned short *[nDomain]; - - for (iDomain = 0; iDomain < nDomain; iDomain++) { - DomainSendCount[iDomain] = 0; - DomainSendMarkers[iDomain] = new unsigned short [nMarker]; - - DomainReceiveCount[iDomain] = 0; - DomainReceiveMarkers[iDomain] = new unsigned short [nMarker]; - } - - for (iDomain = 0; iDomain < nDomain; iDomain++) { - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (bound[iMarker][0]->GetVTK_Type() == VERTEX) { - if (Marker_All_SendRecv[iMarker] == iDomain) { - DomainSendMarkers[iDomain][DomainSendCount[iDomain]] = iMarker; - DomainSendCount[iDomain]++; - } - if (Marker_All_SendRecv[iMarker] == -iDomain) { - DomainReceiveMarkers[iDomain][DomainReceiveCount[iDomain]] = iMarker; - DomainReceiveCount[iDomain]++; - } - } - } - } - - /*--- Create an structure to store the Send/Receive - boundaries, because they require some reorganization ---*/ - - nMarker_SendRecv = nMarker - nMarker_Physical - Duplicate_SendReceive; - bound_Copy = new CPrimalGrid**[nMarker_Physical + nMarker_SendRecv]; - nElem_Bound_Copy = new unsigned long [nMarker_Physical + nMarker_SendRecv]; - Marker_All_SendRecv_Copy = new short [nMarker_Physical + nMarker_SendRecv]; - iMarker_ = nMarker_Physical; - iVertex_ = 0; - CheckStart = false; - - /*--- Copy and allocate the physical markers in the data structure ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (bound[iMarker][0]->GetVTK_Type() != VERTEX) { - - nElem_Bound_Copy[iMarker] = nElem_Bound[iMarker]; - bound_Copy[iMarker] = new CPrimalGrid* [nElem_Bound[iMarker]]; - - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - if (bound[iMarker][iElem_Bound]->GetVTK_Type() == LINE) - bound_Copy[iMarker][iElem_Bound] = new CLine(bound[iMarker][iElem_Bound]->GetNode(0), - bound[iMarker][iElem_Bound]->GetNode(1), 2); - if (bound[iMarker][iElem_Bound]->GetVTK_Type() == TRIANGLE) - - bound_Copy[iMarker][iElem_Bound] = new CTriangle(bound[iMarker][iElem_Bound]->GetNode(0), - bound[iMarker][iElem_Bound]->GetNode(1), - bound[iMarker][iElem_Bound]->GetNode(2), 3); - if (bound[iMarker][iElem_Bound]->GetVTK_Type() == QUADRILATERAL) - bound_Copy[iMarker][iElem_Bound] = new CQuadrilateral(bound[iMarker][iElem_Bound]->GetNode(0), - bound[iMarker][iElem_Bound]->GetNode(1), - bound[iMarker][iElem_Bound]->GetNode(2), - bound[iMarker][iElem_Bound]->GetNode(3), 3); - } - } - } - - - for (iDomain = 0; iDomain < nDomain; iDomain++) { - - /*--- Compute the total number of elements (adding all the - boundaries with the same Send/Receive ---*/ - - if (DomainSendCount[iDomain] != 0) { - TotalElem = 0; - for (iMarkersDomain = 0; iMarkersDomain < DomainSendCount[iDomain]; iMarkersDomain++) { - iMarker = DomainSendMarkers[iDomain][iMarkersDomain]; - TotalElem += nElem_Bound[iMarker]; - } - if (CheckStart) iMarker_++; - CheckStart = true; - iVertex_ = 0; - nElem_Bound_Copy[iMarker_] = TotalElem; - bound_Copy[iMarker_] = new CPrimalGrid*[TotalElem]; - } - - for (iMarkersDomain = 0; iMarkersDomain < DomainSendCount[iDomain]; iMarkersDomain++) { - iMarker = DomainSendMarkers[iDomain][iMarkersDomain]; - Marker_All_SendRecv_Copy[iMarker_] = Marker_All_SendRecv[iMarker]; - - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - bound_Copy[iMarker_][iVertex_] = new CVertexMPI(bound[iMarker][iElem_Bound]->GetNode(0), nDim); - bound_Copy[iMarker_][iVertex_]->SetRotation_Type(bound[iMarker][iElem_Bound]->GetRotation_Type()); - iVertex_++; - } - - } - - /*--- Compute the total number of elements (adding all the - boundaries with the same Send/Receive ---*/ - - if (DomainReceiveCount[iDomain] != 0) { - TotalElem = 0; - for (iMarkersDomain = 0; iMarkersDomain < DomainReceiveCount[iDomain]; iMarkersDomain++) { - iMarker = DomainReceiveMarkers[iDomain][iMarkersDomain]; - TotalElem += nElem_Bound[iMarker]; - } - if (CheckStart) iMarker_++; - CheckStart = true; - iVertex_ = 0; - nElem_Bound_Copy[iMarker_] = TotalElem; - bound_Copy[iMarker_] = new CPrimalGrid*[TotalElem]; - - } - - for (iMarkersDomain = 0; iMarkersDomain < DomainReceiveCount[iDomain]; iMarkersDomain++) { - iMarker = DomainReceiveMarkers[iDomain][iMarkersDomain]; - Marker_All_SendRecv_Copy[iMarker_] = Marker_All_SendRecv[iMarker]; - - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - bound_Copy[iMarker_][iVertex_] = new CVertexMPI(bound[iMarker][iElem_Bound]->GetNode(0), nDim); - bound_Copy[iMarker_][iVertex_]->SetRotation_Type(bound[iMarker][iElem_Bound]->GetRotation_Type()); - iVertex_++; - } - - } - - } - - delete [] DomainSendCount; - for (iDomain = 0; iDomain < nDomain; iDomain++) - delete [] DomainSendMarkers[iDomain]; - delete[] DomainSendMarkers; - - delete [] DomainReceiveCount; - for (iDomain = 0; iDomain < nDomain; iDomain++) - delete [] DomainReceiveMarkers[iDomain]; - delete[] DomainReceiveMarkers; - - /*--- Deallocate the bound variables ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) - delete [] bound[iMarker]; - delete [] bound; - - /*--- Allocate the new bound variables, and set the number of markers ---*/ - - bound = bound_Copy; - nMarker = nMarker_Physical + nMarker_SendRecv; - - config->SetnMarker_All(nMarker); - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - nElem_Bound[iMarker] = nElem_Bound_Copy[iMarker]; - } - for (iMarker = nMarker_Physical; iMarker < nMarker; iMarker++) { - Marker_All_SendRecv[iMarker] = Marker_All_SendRecv_Copy[iMarker]; - config->SetMarker_All_SendRecv(iMarker, Marker_All_SendRecv[iMarker]); - config->SetMarker_All_TagBound(iMarker, "SEND_RECEIVE"); - } - - /*--- Update config information storing the boundary information in the right place ---*/ - - for (iMarker = 0 ; iMarker < nMarker; iMarker++) { - - string Marker_Tag = config->GetMarker_All_TagBound(iMarker); - - if (Marker_Tag != "SEND_RECEIVE") { - - /*--- Update config information storing the boundary information in the right place ---*/ - - Tag_to_Marker[config->GetMarker_CfgFile_TagBound(Marker_Tag)] = Marker_Tag; - config->SetMarker_All_KindBC(iMarker, config->GetMarker_CfgFile_KindBC(Marker_Tag)); - config->SetMarker_All_Monitoring(iMarker, config->GetMarker_CfgFile_Monitoring(Marker_Tag)); - config->SetMarker_All_GeoEval(iMarker, config->GetMarker_CfgFile_GeoEval(Marker_Tag)); - config->SetMarker_All_Designing(iMarker, config->GetMarker_CfgFile_Designing(Marker_Tag)); - config->SetMarker_All_Plotting(iMarker, config->GetMarker_CfgFile_Plotting(Marker_Tag)); - config->SetMarker_All_FSIinterface(iMarker, config->GetMarker_CfgFile_FSIinterface(Marker_Tag)); - config->SetMarker_All_DV(iMarker, config->GetMarker_CfgFile_DV(Marker_Tag)); - config->SetMarker_All_Moving(iMarker, config->GetMarker_CfgFile_Moving(Marker_Tag)); - config->SetMarker_All_PerBound(iMarker, config->GetMarker_CfgFile_PerBound(Marker_Tag)); - config->SetMarker_All_Out_1D(iMarker, config->GetMarker_CfgFile_Out_1D(Marker_Tag)); - - } - - /*--- Send-Receive boundaries definition ---*/ - - else { - - config->SetMarker_All_KindBC(iMarker, SEND_RECEIVE); - config->SetMarker_All_Monitoring(iMarker, NO); - config->SetMarker_All_GeoEval(iMarker, NO); - config->SetMarker_All_Designing(iMarker, NO); - config->SetMarker_All_Plotting(iMarker, NO); - config->SetMarker_All_FSIinterface(iMarker, NO); - config->SetMarker_All_DV(iMarker, NO); - config->SetMarker_All_Moving(iMarker, NO); - config->SetMarker_All_PerBound(iMarker, NO); - config->SetMarker_All_Out_1D(iMarker, NO); - - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - if (config->GetMarker_All_SendRecv(iMarker) < 0) - node[bound[iMarker][iElem_Bound]->GetNode(0)]->SetDomain(false); - } - - } - - /*--- Loop over the surface element to set the boundaries ---*/ - - unsigned long Point_Surface, iElem_Surface; - unsigned short iNode_Surface; - - for (iElem_Surface = 0; iElem_Surface < nElem_Bound[iMarker]; iElem_Surface++) { - for (iNode_Surface = 0; iNode_Surface < bound[iMarker][iElem_Surface]->GetnNodes(); iNode_Surface++) { - Point_Surface = bound[iMarker][iElem_Surface]->GetNode(iNode_Surface); - node[Point_Surface]->SetBoundary(nMarker); - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE && - config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY && - config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY && - config->GetMarker_All_KindBC(iMarker) != PERIODIC_BOUNDARY) - node[Point_Surface]->SetPhysicalBoundary(true); - - if (config->GetMarker_All_KindBC(iMarker) == EULER_WALL && - config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX && - config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) - node[Point_Surface]->SetSolidBoundary(true); - } - } - - } - -} - -void CPhysicalGeometry::Read_SU2_Format_Parallel(CConfig *config, string val_mesh_filename, unsigned short val_iZone, unsigned short val_nZone) { - - string text_line, Marker_Tag; - ifstream mesh_file; - unsigned short nMarker_Max = config->GetnMarker_Max(); - unsigned long VTK_Type, iMarker, iChar; - unsigned long iCount = 0; - unsigned long iElem_Bound = 0, iPoint = 0, ielem_div = 0, ielem = 0; - unsigned long vnodes_edge[2], vnodes_triangle[3], vnodes_quad[4]; - unsigned long vnodes_tetra[4], vnodes_hexa[8], vnodes_prism[6], - vnodes_pyramid[5], dummyLong, GlobalIndex; - unsigned long i, j; - char cstr[200]; - su2double Coord_2D[2], Coord_3D[3]; - string::size_type position; - int rank = MASTER_NODE, size = SINGLE_NODE; - bool domain_flag = false; - bool found_transform = false; - bool time_spectral = config->GetUnsteady_Simulation() == TIME_SPECTRAL; - nZone = val_nZone; - - /*--- Initialize some additional counters for the parallel partitioning ---*/ - - unsigned long total_pt_accounted = 0; - unsigned long rem_points = 0; - unsigned long element_count = 0; - unsigned long boundary_marker_count = 0; - unsigned long node_count = 0; - unsigned long loc_element_count = 0; - bool elem_reqd = false; - - /*--- Initialize counters for local/global points & elements ---*/ -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); - unsigned long LocalIndex; -#endif - Global_nPoint = 0; Global_nPointDomain = 0; Global_nElem = 0; - nelem_edge = 0; Global_nelem_edge = 0; - nelem_triangle = 0; Global_nelem_triangle = 0; - nelem_quad = 0; Global_nelem_quad = 0; - nelem_tetra = 0; Global_nelem_tetra = 0; - nelem_hexa = 0; Global_nelem_hexa = 0; - nelem_prism = 0; Global_nelem_prism = 0; - nelem_pyramid = 0; Global_nelem_pyramid = 0; - - /*--- Allocate memory for the linear partition of the mesh. These - arrays are the size of the number of ranks. ---*/ - - starting_node = new unsigned long[size]; - ending_node = new unsigned long[size]; - npoint_procs = new unsigned long[size]; - - /*--- Open grid file ---*/ - - strcpy (cstr, val_mesh_filename.c_str()); - mesh_file.open(cstr, ios::in); - - /*--- Check the grid ---*/ - - if (mesh_file.fail()) { - cout << "There is no mesh file (CPhysicalGeometry)!! " << cstr << endl; -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - } - - /*--- If more than one, find the zone in the mesh file ---*/ - - if (val_nZone > 1 || time_spectral) { - if (time_spectral) { - if (rank == MASTER_NODE) cout << "Reading time spectral instance " << val_iZone+1 << ":" << endl; - } else { - while (getline (mesh_file,text_line)) { - /*--- Search for the current domain ---*/ - position = text_line.find ("IZONE=",0); - if (position != string::npos) { - text_line.erase (0,6); - unsigned short jDomain = atoi(text_line.c_str()); - if (jDomain == val_iZone+1) { - if (rank == MASTER_NODE) cout << "Reading zone " << val_iZone+1 << " points:" << endl; - break; - } - } - } - } - } - - /*--- Read grid file with format SU2 ---*/ - - while (getline (mesh_file, text_line)) { - - /*--- Read the dimension of the problem ---*/ - - position = text_line.find ("NDIME=",0); - if (position != string::npos) { - if (domain_flag == false) { - text_line.erase (0,6); nDim = atoi(text_line.c_str()); - if (rank == MASTER_NODE) { - if (nDim == 2) cout << "Two dimensional problem." << endl; - if (nDim == 3) cout << "Three dimensional problem." << endl; - } - domain_flag = true; - } else { break; } - } - - /*--- Read number of points ---*/ - - position = text_line.find ("NPOIN=",0); - if (position != string::npos) { - text_line.erase (0,6); - - /*--- Check for ghost points. ---*/ - stringstream test_line(text_line); - while (test_line >> dummyLong) - iCount++; - - /*--- Now read and store the number of points and possible ghost points. ---*/ - - stringstream stream_line(text_line); - if (iCount == 2) { - stream_line >> nPoint; - stream_line >> nPointDomain; - - /*--- Set some important point information for parallel simulations. ---*/ - - Global_nPoint = nPoint; - Global_nPointDomain = nPointDomain; - if (rank == MASTER_NODE && size > SINGLE_NODE) { - cout << Global_nPointDomain << " points and " << Global_nPoint-Global_nPointDomain; - cout << " ghost points before parallel partitioning." << endl; - } else if (rank == MASTER_NODE) { - cout << Global_nPointDomain << " points and " << Global_nPoint-Global_nPointDomain; - cout << " ghost points." << endl; - } - - } else if (iCount == 1) { - stream_line >> nPoint; - nPointDomain = nPoint; - Global_nPointDomain = nPoint; - Global_nPoint = nPoint; - if (rank == MASTER_NODE && size > SINGLE_NODE) { - cout << nPoint << " points before parallel partitioning." << endl; - } else if (rank == MASTER_NODE) { - cout << nPoint << " points." << endl; - } - } - else { - cout << "NPOIN improperly specified!!" << endl; -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - } - - if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) - cout << "Performing linear partitioning of the grid nodes." << endl; - - /*--- Compute the number of points that will be on each processor. - This is a linear partitioning with the addition of a simple load - balancing for any remainder points. ---*/ - - total_pt_accounted = 0; - for (i = 0; i < (unsigned long)size; i++) { - npoint_procs[i] = nPoint/size; - total_pt_accounted = total_pt_accounted + npoint_procs[i]; - } - - /*--- Get the number of remainder points after the even division ---*/ - rem_points = nPoint-total_pt_accounted; - for (i = 0; i= starting_node[rank]) && (node_count < ending_node[rank])) { - switch(nDim) { - case 2: - GlobalIndex = node_count; -#ifndef HAVE_MPI - point_line >> Coord_2D[0]; point_line >> Coord_2D[1]; -#else - if (size > SINGLE_NODE) { point_line >> Coord_2D[0]; point_line >> Coord_2D[1]; point_line >> LocalIndex; point_line >> GlobalIndex; } - else { point_line >> Coord_2D[0]; point_line >> Coord_2D[1]; LocalIndex = iPoint; GlobalIndex = node_count; } -#endif - node[iPoint] = new CPoint(Coord_2D[0], Coord_2D[1], GlobalIndex, config); - iPoint++; break; - case 3: - GlobalIndex = node_count; -#ifndef HAVE_MPI - point_line >> Coord_3D[0]; point_line >> Coord_3D[1]; point_line >> Coord_3D[2]; -#else - if (size > SINGLE_NODE) { point_line >> Coord_3D[0]; point_line >> Coord_3D[1]; point_line >> Coord_3D[2]; point_line >> LocalIndex; point_line >> GlobalIndex; } - else { point_line >> Coord_3D[0]; point_line >> Coord_3D[1]; point_line >> Coord_3D[2]; LocalIndex = iPoint; GlobalIndex = node_count; } -#endif - node[iPoint] = new CPoint(Coord_3D[0], Coord_3D[1], Coord_3D[2], GlobalIndex, config); - iPoint++; break; - } - } - node_count++; - } - } - } - - mesh_file.close(); - strcpy (cstr, val_mesh_filename.c_str()); - - /*--- Initialize some arrays for the adjacency information (ParMETIS). ---*/ - -// unsigned long *adj_counter = new unsigned long[local_node]; -// unsigned long **adjacent_elem = new unsigned long*[local_node]; - - adj_counter = new unsigned long[local_node]; - adjacent_elem = new unsigned long*[local_node]; - - for (iPoint = 0; iPoint < local_node; iPoint++) { - adjacent_elem[iPoint] = new unsigned long[2000]; - adj_counter[iPoint] = 0; - } - - mesh_file.open(cstr, ios::in); - - /*--- If more than one, find the zone in the mesh file ---*/ - - if (val_nZone > 1 && !time_spectral) { - while (getline (mesh_file,text_line)) { - /*--- Search for the current domain ---*/ - position = text_line.find ("IZONE=",0); - if (position != string::npos) { - text_line.erase (0,6); - unsigned short jDomain = atoi(text_line.c_str()); - if (jDomain == val_iZone+1) { - if (rank == MASTER_NODE) cout << "Reading zone " << val_iZone+1 << " elements:" << endl; - break; - } - } - } - } - - while (getline (mesh_file, text_line)) { - - /*--- Read the information about inner elements ---*/ - - position = text_line.find ("NELEM=",0); - if (position != string::npos) { - text_line.erase (0,6); nElem = atoi(text_line.c_str()); - - /*--- Store total number of elements in the original mesh ---*/ - - Global_nElem = nElem; - if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) - cout << Global_nElem << " interior elements before parallel partitioning." << endl; - - /*--- Allocate space for elements ---*/ - - elem = new CPrimalGrid*[nElem]; - for (unsigned long iElem = 0; iElem < nElem; iElem++) elem[iElem] = NULL; - - - /*--- Set up the global to local element mapping. ---*/ - Global_to_local_elem = new long[nElem]; - for (i = 0; i SINGLE_NODE)) - cout << "Distributing elements across all ranks." << endl; - - /*--- Loop over all the volumetric elements and store any element that - contains at least one of an owned node for this rank (i.e., there will - be element redundancy, since multiple ranks will store the same elems - on the boundaries of the initial linear partitioning. ---*/ - - // TO DO: remove redundant edges (quads have extra diagonals for instance) - - element_count=0; loc_element_count=0; ielem_div=0; - while (ielem_div < nElem) { - getline(mesh_file, text_line); - istringstream elem_line(text_line); - - elem_line >> VTK_Type; - elem_reqd = false; - - /*--- Decide whether this rank needs each element. If so, build the - adjacency arrays needed by ParMETIS and store the element connectivity. - Note that every proc starts it's node indexing from zero. ---*/ - - switch(VTK_Type) { - - case TRIANGLE: - - elem_line >> vnodes_triangle[0]; elem_line >> vnodes_triangle[1]; elem_line >> vnodes_triangle[2]; - for (i = 0; i < N_POINTS_TRIANGLE; i++) { - if ((vnodes_triangle[i]>=starting_node[rank])&&(vnodes_triangle[i]> vnodes_quad[0]; elem_line >> vnodes_quad[1]; elem_line >> vnodes_quad[2]; elem_line >> vnodes_quad[3]; - for (i = 0; i < N_POINTS_QUADRILATERAL; i++) { - if ((vnodes_quad[i]>=starting_node[rank])&&(vnodes_quad[i]> vnodes_tetra[0]; elem_line >> vnodes_tetra[1]; elem_line >> vnodes_tetra[2]; elem_line >> vnodes_tetra[3]; - for (i = 0; i < N_POINTS_TETRAHEDRON; i++) { - if ((vnodes_tetra[i]>=starting_node[rank])&&(vnodes_tetra[i]> vnodes_hexa[0]; elem_line >> vnodes_hexa[1]; elem_line >> vnodes_hexa[2]; - elem_line >> vnodes_hexa[3]; elem_line >> vnodes_hexa[4]; elem_line >> vnodes_hexa[5]; - elem_line >> vnodes_hexa[6]; elem_line >> vnodes_hexa[7]; - for (i = 0; i < N_POINTS_HEXAHEDRON; i++) { - if ((vnodes_hexa[i]>=starting_node[rank])&&(vnodes_hexa[i]> vnodes_prism[0]; elem_line >> vnodes_prism[1]; elem_line >> vnodes_prism[2]; - elem_line >> vnodes_prism[3]; elem_line >> vnodes_prism[4]; elem_line >> vnodes_prism[5]; - for (i = 0; i < N_POINTS_PRISM; i++) { - if ((vnodes_prism[i]>=starting_node[rank])&&(vnodes_prism[i]> vnodes_pyramid[0]; elem_line >> vnodes_pyramid[1]; elem_line >> vnodes_pyramid[2]; - elem_line >> vnodes_pyramid[3]; elem_line >> vnodes_pyramid[4]; - for (i = 0; i < N_POINTS_PYRAMID; i++) { - if ((vnodes_pyramid[i]>=starting_node[rank])&&(vnodes_pyramid[i] SINGLE_NODE)) - cout << "Calling the partitioning functions." << endl; - - /*--- Store the number of local elements on each rank after determining - which elements must be kept in the loop above. ---*/ - - no_of_local_elements = loc_element_count; - - /*--- Post process the adjacency information in order to get it into the - proper format before sending the data to ParMETIS. We need to remove - repeats and adjust the size of the array for each local node. ---*/ - - if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) - cout << "Building the graph adjacency structure." << endl; - - unsigned long loc_adjc_size=0; - vector adjac_vec; - unsigned long adj_elem_size; - vector::iterator it; - local_elem=loc_element_count; - - xadj = new unsigned long [npoint_procs[rank]+1]; - xadj[0]=0; - vector temp_adjacency; - unsigned long local_count=0; - - for (unsigned long i = 0; i < local_node; i++) { - - for (j = 0; j 1 && !time_spectral) { - while (getline (mesh_file,text_line)) { - /*--- Search for the current domain ---*/ - position = text_line.find ("IZONE=",0); - if (position != string::npos) { - text_line.erase (0,6); - unsigned short jDomain = atoi(text_line.c_str()); - if (jDomain == val_iZone+1) { - if (rank == MASTER_NODE) cout << "Reading zone " << val_iZone+1 << " markers:" << endl; - break; - } - } - } - } - - if (rank == MASTER_NODE) { - - while (getline (mesh_file, text_line)) { - /*--- Read number of markers ---*/ - position = text_line.find ("NMARK=",0); - boundary_marker_count = 0; - if (position != string::npos) { - text_line.erase (0,6); nMarker = atoi(text_line.c_str()); - if (rank == MASTER_NODE) cout << nMarker << " surface markers." << endl; - config->SetnMarker_All(nMarker); - bound = new CPrimalGrid**[nMarker]; - nElem_Bound = new unsigned long [nMarker]; - Tag_to_Marker = new string [nMarker_Max]; - - for (iMarker = 0 ; iMarker < nMarker; iMarker++) { - getline (mesh_file, text_line); - text_line.erase (0,11); - string::size_type position; - for (iChar = 0; iChar < 20; iChar++) { - position = text_line.find( " ", 0 ); - if (position != string::npos) text_line.erase (position,1); - position = text_line.find( "\r", 0 ); - if (position != string::npos) text_line.erase (position,1); - position = text_line.find( "\n", 0 ); - if (position != string::npos) text_line.erase (position,1); - } - Marker_Tag = text_line.c_str(); - - /*--- Physical boundaries definition ---*/ - if (Marker_Tag != "SEND_RECEIVE") { - getline (mesh_file, text_line); - text_line.erase (0,13); nElem_Bound[iMarker] = atoi(text_line.c_str()); - if (rank == MASTER_NODE) - cout << nElem_Bound[iMarker] << " boundary elements in index "<< iMarker <<" (Marker = " <> VTK_Type; - switch(VTK_Type) { - case LINE: - - if (nDim == 3) { - cout << "Please remove line boundary conditions from the mesh file!" << endl; -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - } - - bound_line >> vnodes_edge[0]; bound_line >> vnodes_edge[1]; - bound[iMarker][ielem] = new CLine(vnodes_edge[0], vnodes_edge[1],2); - ielem++; nelem_edge_bound++; break; - - case TRIANGLE: - bound_line >> vnodes_triangle[0]; bound_line >> vnodes_triangle[1]; bound_line >> vnodes_triangle[2]; - bound[iMarker][ielem] = new CTriangle(vnodes_triangle[0], vnodes_triangle[1], vnodes_triangle[2],3); - ielem++; nelem_triangle_bound++; break; - - case QUADRILATERAL: - - bound_line >> vnodes_quad[0]; bound_line >> vnodes_quad[1]; bound_line >> vnodes_quad[2]; bound_line >> vnodes_quad[3]; - - bound[iMarker][ielem] = new CQuadrilateral(vnodes_quad[0], vnodes_quad[1], vnodes_quad[2], vnodes_quad[3],3); - ielem++; nelem_quad_bound++; - - break; - - - } - } - - /*--- Update config information storing the boundary information in the right place ---*/ - - Tag_to_Marker[config->GetMarker_CfgFile_TagBound(Marker_Tag)] = Marker_Tag; - config->SetMarker_All_TagBound(iMarker, Marker_Tag); - config->SetMarker_All_KindBC(iMarker, config->GetMarker_CfgFile_KindBC(Marker_Tag)); - config->SetMarker_All_Monitoring(iMarker, config->GetMarker_CfgFile_Monitoring(Marker_Tag)); - config->SetMarker_All_GeoEval(iMarker, config->GetMarker_CfgFile_GeoEval(Marker_Tag)); - config->SetMarker_All_Designing(iMarker, config->GetMarker_CfgFile_Designing(Marker_Tag)); - config->SetMarker_All_Plotting(iMarker, config->GetMarker_CfgFile_Plotting(Marker_Tag)); - config->SetMarker_All_FSIinterface(iMarker, config->GetMarker_CfgFile_FSIinterface(Marker_Tag)); - config->SetMarker_All_DV(iMarker, config->GetMarker_CfgFile_DV(Marker_Tag)); - config->SetMarker_All_Moving(iMarker, config->GetMarker_CfgFile_Moving(Marker_Tag)); - config->SetMarker_All_PerBound(iMarker, config->GetMarker_CfgFile_PerBound(Marker_Tag)); - config->SetMarker_All_SendRecv(iMarker, NONE); - config->SetMarker_All_Out_1D(iMarker, config->GetMarker_CfgFile_Out_1D(Marker_Tag)); - - } - - /*--- Send-Receive boundaries definition ---*/ - - else { - unsigned long nelem_vertex = 0, vnodes_vertex; - unsigned short transform; - getline (mesh_file, text_line); - text_line.erase (0,13); nElem_Bound[iMarker] = atoi(text_line.c_str()); - bound[iMarker] = new CPrimalGrid* [nElem_Bound[iMarker]]; - - nelem_vertex = 0; ielem = 0; - getline (mesh_file, text_line); text_line.erase (0,8); - config->SetMarker_All_KindBC(iMarker, SEND_RECEIVE); - config->SetMarker_All_SendRecv(iMarker, atoi(text_line.c_str())); - - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - getline(mesh_file, text_line); - istringstream bound_line(text_line); - bound_line >> VTK_Type; bound_line >> vnodes_vertex; bound_line >> transform; - - bound[iMarker][ielem] = new CVertexMPI(vnodes_vertex, nDim); - bound[iMarker][ielem]->SetRotation_Type(transform); - ielem++; nelem_vertex++; - } - - } - boundary_marker_count++; - } - if (boundary_marker_count == nMarker) break; - } - } - - while (getline (mesh_file, text_line)) { - - /*--- Read periodic transformation info (center, rotation, translation) ---*/ - - position = text_line.find ("NPERIODIC=",0); - if (position != string::npos) { - unsigned short nPeriodic, iPeriodic, iIndex; - - /*--- Set bool signifying that periodic transormations were found ---*/ - found_transform = true; - - /*--- Read and store the number of transformations. ---*/ - text_line.erase (0,10); nPeriodic = atoi(text_line.c_str()); - if (rank == MASTER_NODE) { - if (nPeriodic - 1 != 0) - cout << nPeriodic - 1 << " periodic transformations." << endl; - } - config->SetnPeriodicIndex(nPeriodic); - - /*--- Store center, rotation, & translation in that order for each. ---*/ - for (iPeriodic = 0; iPeriodic < nPeriodic; iPeriodic++) { - getline (mesh_file, text_line); - position = text_line.find ("PERIODIC_INDEX=",0); - if (position != string::npos) { - text_line.erase (0,15); iIndex = atoi(text_line.c_str()); - if (iIndex != iPeriodic) { - cout << "PERIODIC_INDEX out of order in SU2 file!!" << endl; -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - } - } - su2double* center = new su2double[3]; - su2double* rotation = new su2double[3]; - su2double* translate = new su2double[3]; - getline (mesh_file, text_line); - istringstream cent(text_line); - cent >> center[0]; cent >> center[1]; cent >> center[2]; - config->SetPeriodicCenter(iPeriodic, center); - getline (mesh_file, text_line); - istringstream rot(text_line); - rot >> rotation[0]; rot >> rotation[1]; rot >> rotation[2]; - config->SetPeriodicRotation(iPeriodic, rotation); - getline (mesh_file, text_line); - istringstream tran(text_line); - tran >> translate[0]; tran >> translate[1]; tran >> translate[2]; - config->SetPeriodicTranslate(iPeriodic, translate); - - } - } - } - - /*--- If no periodic transormations were found, store default zeros ---*/ - - if (!found_transform) { - unsigned short nPeriodic = 1, iPeriodic = 0; - config->SetnPeriodicIndex(nPeriodic); - su2double* center = new su2double[3]; - su2double* rotation = new su2double[3]; - su2double* translate = new su2double[3]; - for (unsigned short iDim = 0; iDim < 3; iDim++) { - center[iDim] = 0.0; rotation[iDim] = 0.0; translate[iDim] = 0.0; - } - config->SetPeriodicCenter(iPeriodic, center); - config->SetPeriodicRotation(iPeriodic, rotation); - config->SetPeriodicTranslate(iPeriodic, translate); - } - } - - /*--- Close the input file ---*/ - - mesh_file.close(); - - -} - -void CPhysicalGeometry::Read_CGNS_Format_Parallel(CConfig *config, string val_mesh_filename, unsigned short val_iZone, unsigned short val_nZone) { - - /*--- Original CGNS reader implementation by Thomas D. Economon, - Francisco Palacios. Improvements for mixed-element meshes generated - by ICEM added by Martin Spel (3D) & Shlomy Shitrit (2D), April 2014. - Parallel version by Thomas D. Economon, February 2015. ---*/ - -#ifdef HAVE_CGNS - - string text_line, Marker_Tag; - ifstream mesh_file; - unsigned short VTK_Type = 0, iMarker = 0; - unsigned short nMarker_Max = config->GetnMarker_Max(); - unsigned long iPoint = 0, iProcessor = 0, ielem = 0, GlobalIndex = 0; - unsigned long globalOffset = 0; - int rank = MASTER_NODE, size = SINGLE_NODE; - nZone = val_nZone; - - /*--- Local variables needed when calling the CGNS mid-level API. ---*/ - - unsigned long vnodes_cgns[8] = {0,0,0,0,0,0,0,0}; - su2double Coord_cgns[3] = {0.0,0.0,0.0}; - int fn, nbases = 0, nzones = 0, ngrids = 0, ncoords = 0, nsections = 0; - int *vertices = NULL, *cells = NULL, nMarkers = 0, *boundVerts = NULL, npe; - int interiorElems = 0, totalVerts = 0; - int cell_dim = 0, phys_dim = 0, nbndry, parent_flag, file_type; - char basename[CGNS_STRING_SIZE], zonename[CGNS_STRING_SIZE]; - char coordname[CGNS_STRING_SIZE]; - cgsize_t* cgsize; cgsize = new cgsize_t[3]; - ZoneType_t zonetype; - DataType_t datatype; - su2double** coordArray = NULL; - su2double*** gridCoords = NULL; - ElementType_t elemType; - cgsize_t range_min, range_max, startE, endE; - range_min = 1; - string currentElem; - int** elemTypeVTK = NULL; - int** elemIndex = NULL; - int** elemBegin = NULL; - int** elemEnd = NULL; - int** nElems = NULL; - cgsize_t**** connElems = NULL; - cgsize_t* connElemCGNS = NULL; - cgsize_t* connElemTemp = NULL; - cgsize_t ElementDataSize = 0; - cgsize_t* parentData = NULL; - int** dataSize = NULL; - bool** isInternal = NULL; - char*** sectionNames = NULL; - //int indexMax; // check memory issue - - /*--- Initialize counters for local/global points & elements ---*/ - -#ifdef HAVE_MPI - unsigned long Local_nElem; - unsigned long Local_nElemTri, Local_nElemQuad, Local_nElemTet; - unsigned long Local_nElemHex, Local_nElemPrism, Local_nElemPyramid; - - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); - - MPI_Request *send_req, *recv_req; - MPI_Status status; - int ind; -#endif - - /*--- Initialize counters for local/global points & elements ---*/ - - Global_nPoint = 0; Global_nPointDomain = 0; Global_nElem = 0; - nelem_edge = 0; Global_nelem_edge = 0; - nelem_triangle = 0; Global_nelem_triangle = 0; - nelem_quad = 0; Global_nelem_quad = 0; - nelem_tetra = 0; Global_nelem_tetra = 0; - nelem_hexa = 0; Global_nelem_hexa = 0; - nelem_prism = 0; Global_nelem_prism = 0; - nelem_pyramid = 0; Global_nelem_pyramid = 0; - - /*--- Initialize some additional counters for the parallel partitioning ---*/ - - unsigned long total_pt_accounted = 0; - unsigned long rem_points = 0; - unsigned long element_count = 0; - unsigned long element_remainder = 0; - unsigned long total_elems = 0; - - /*--- Allocate memory for the linear partitioning of the mesh. These - arrays are the size of the number of ranks. ---*/ - - starting_node = new unsigned long[size]; - ending_node = new unsigned long[size]; - npoint_procs = new unsigned long[size]; - - unsigned long *nPoint_Linear = new unsigned long[size+1]; - unsigned long *nElem_Linear = new unsigned long[size]; - - unsigned long *elemB = new unsigned long[size]; - unsigned long *elemE = new unsigned long[size]; - - unsigned long *elemGlobalID = NULL; - - unsigned short *nPoinPerElem = NULL; - unsigned short *elemTypes = NULL; - - bool *isMixed = NULL; - - unsigned short connSize = 10; - - /*--- Check whether the supplied file is truly a CGNS file. ---*/ - if (cg_is_cgns(val_mesh_filename.c_str(), &file_type) != CG_OK) { - if (rank == MASTER_NODE) { - printf( "\n\n !!! Error !!!\n" ); - printf( " %s is not a CGNS file.\n", val_mesh_filename.c_str()); - printf( " Now exiting...\n\n"); - } -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - } - - /*--- Open the CGNS file for reading. The value of fn returned - is the specific index number for this file and will be - repeatedly used in the function calls. ---*/ - - if (cg_open(val_mesh_filename.c_str(), CG_MODE_READ, &fn)) cg_error_exit(); - if (rank == MASTER_NODE) { - cout << "Reading the CGNS file: "; - cout << val_mesh_filename.c_str() << "." << endl; - } - - /*--- Get the number of databases. This is the highest node - in the CGNS heirarchy. ---*/ - - if ( cg_nbases(fn, &nbases) ) cg_error_exit(); - if (rank == MASTER_NODE) - cout << "CGNS file contains " << nbases << " database(s)." << endl; - - /*--- Check if there is more than one database. Throw an - error if there is because this reader can currently - only handle one database. ---*/ - - if ( nbases > 1 ) { - if (rank == MASTER_NODE) { - printf("\n\n !!! Error !!!\n" ); - printf("CGNS reader currently incapable of handling more than 1 database."); - printf("Now exiting...\n\n"); - } -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - } - - /*--- Read the databases. Note that the CGNS indexing starts at 1. ---*/ - - for (int i = 1; i <= nbases; i++) { - - if (cg_base_read(fn, i, basename, &cell_dim, &phys_dim)) cg_error_exit(); - - /*--- Get the number of zones for this base. ---*/ - - if ( cg_nzones(fn, i, &nzones) ) cg_error_exit(); - if (rank == MASTER_NODE) { - cout << "Database " << i << ", " << basename << ": " << nzones; - cout << " zone(s), cell dimension of " << cell_dim << ", physical "; - cout << "dimension of " << phys_dim << "." << endl; - } - - /*--- Check if there is more than one zone. Throw an - error if there is, because this reader can currently - only handle one zone. This could be extended in the future. ---*/ - - if ( nzones > 1 ) { - if (rank == MASTER_NODE) { - printf("\n\n !!! Error !!!\n" ); - printf("CGNS reader currently incapable of handling more than 1 zone."); - printf("Now exiting...\n\n"); - } -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - } - - /*--- Initialize some data structures for all zones. ---*/ - - vertices = new int[nzones]; - cells = new int[nzones]; - boundVerts = new int[nzones]; - coordArray = new su2double*[nzones]; - gridCoords = new su2double**[nzones]; - elemTypeVTK = new int*[nzones]; - elemIndex = new int*[nzones]; - elemBegin = new int*[nzones]; - elemEnd = new int*[nzones]; - nElems = new int*[nzones]; - dataSize = new int*[nzones]; - isInternal = new bool*[nzones]; - nMarkers = 0; - sectionNames = new char**[nzones]; - connElems = new cgsize_t***[nzones]; - - /*--- Loop over all zones in this base. Again, indexing starts at 1. ---*/ - - for (int j = 1; j <= nzones; j++) { - - /*--- Read the basic information for this zone, including - the name and the number of vertices, cells, and - boundary cells which are stored in the cgsize variable. ---*/ - - if (cg_zone_read(fn, i, j, zonename, cgsize)) cg_error_exit(); - - /*--- Rename the zone size information for clarity. - NOTE: The number of cells here may be only the number of - interior elements or it may be the total. This needs to - be counted explicitly later. ---*/ - - vertices[j-1] = cgsize[0]; - cells[j-1] = cgsize[1]; - boundVerts[j-1] = cgsize[2]; - - /*--- Increment the total number of vertices from all zones. ---*/ - - nPoint = vertices[j-1]; - nPointDomain = vertices[j-1]; - - Global_nPoint = vertices[j-1]; - Global_nPointDomain = vertices[j-1]; - - totalVerts += vertices[j-1]; - - /*--- Print some information about the current zone. ---*/ - - if (cg_zone_type(fn, i, j, &zonetype)) cg_error_exit(); - if (rank == MASTER_NODE) { - cout << "Zone " << j << ", " << zonename << ": " << vertices[j-1]; - cout << " vertices, " << cells[j-1] << " cells, " << boundVerts[j-1]; - cout << " boundary vertices." << endl; - } - - /*--- Retrieve the number of grids in this zone. For now, we know - this is one, but to be more general, this will need to check and - allow for a loop over all grids. ---*/ - - if (cg_ngrids(fn, i, j, &ngrids)) cg_error_exit(); - if (ngrids > 1) { - if (rank == MASTER_NODE) { - printf("\n\n !!! Error !!!\n" ); - printf("CGNS reader currently handles only 1 grid per zone."); - printf("Now exiting...\n\n"); - } -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - } - - /*--- Check the number of coordinate arrays stored in this zone. - Should be 2 for 2-D grids and 3 for 3-D grids. ---*/ - - if (cg_ncoords( fn, i, j, &ncoords)) cg_error_exit(); - if (rank == MASTER_NODE) { - cout << "Reading grid coordinates." << endl; - cout << "Number of coordinate dimensions is " << ncoords << "." << endl; - } - - /*--- Compute the number of points that will be on each processor. - This is a linear partitioning with the addition of a simple load - balancing for any remainder points. ---*/ - - total_pt_accounted = 0; - for (int ii = 0; ii < size; ii++) { - npoint_procs[ii] = vertices[j-1]/size; - total_pt_accounted = total_pt_accounted + npoint_procs[ii]; - } - - /*--- Get the number of remainder points after the even division ---*/ - - rem_points = vertices[j-1]-total_pt_accounted; - for (unsigned long ii = 0; ii < rem_points; ii++) { - npoint_procs[ii]++; - } - - /*--- Store the local number of nodes and the beginning/end index ---*/ - - local_node = npoint_procs[rank]; - starting_node[0] = 0; - ending_node[0] = starting_node[0] + npoint_procs[0]; - nPoint_Linear[0] = 0; - for (int ii = 1; ii < size; ii++) { - starting_node[ii] = ending_node[ii-1]; - ending_node[ii] = starting_node[ii] + npoint_procs[ii]; - nPoint_Linear[ii] = nPoint_Linear[ii-1] + npoint_procs[ii-1]; - } - nPoint_Linear[size] = vertices[j-1]; - - /*--- Set the value of range_max to the total number of nodes in - the unstructured mesh. Also allocate memory for the temporary array - that will hold the grid coordinates as they are extracted. Note the - +1 for CGNS convention. ---*/ - - range_min = (cgsize_t)starting_node[rank]+1; - range_max = (cgsize_t)ending_node[rank]; - coordArray[j-1] = new su2double[local_node]; - - /*--- Allocate memory for the 2-D array that will store the x, y, - & z (if required) coordinates for writing into the SU2 mesh. ---*/ - - gridCoords[j-1] = new su2double*[ncoords]; - for (int ii = 0; ii < ncoords; ii++) { - *(gridCoords[j-1]+ii) = new su2double[local_node]; - } - - /*--- Loop over each set of coordinates. Note again - that the indexing starts at 1. ---*/ - - for (int k = 1; k <= ncoords; k++) { - - /*--- Read the coordinate info. This will retrieve the - data type (either RealSingle or RealDouble) as - well as the coordname which will specifiy the - type of data that it is based in the SIDS convention. - This might be "CoordinateX," for instance. ---*/ - - if (cg_coord_info(fn, i, j, k, &datatype, coordname)) - cg_error_exit(); - if (rank == MASTER_NODE) { - cout << "Loading " << coordname; - cout << " values into linear partitions." << endl; - } - - /*--- Always retrieve the grid coords in su2double precision. ---*/ - - if (datatype != RealDouble) { - printf("\n\n !!! Error !!!\n" ); - printf(" CGNS coordinates are not su2double precision.\n"); - printf(" Now exiting...\n\n"); -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - } - if ( cg_coord_read(fn, i, j, coordname, datatype, &range_min, - &range_max, coordArray[j-1]) ) cg_error_exit(); - - /*--- Copy these coords into the array for storage until - writing the SU2 mesh. ---*/ - - for (unsigned long m = 0; m < local_node; m++ ) { - gridCoords[j-1][k-1][m] = coordArray[j-1][m]; - } - - } - - /*--- Begin section for retrieving the connectivity info. ---*/ - - if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) - cout << "Distributing connectivity across all ranks." << endl; - - /*--- First check the number of sections. ---*/ - - if ( cg_nsections(fn, i, j, &nsections) ) cg_error_exit(); - if (rank == MASTER_NODE) { - cout << "Number of connectivity sections is "; - cout << nsections << "." << endl; - } - - /*--- Allocate several data structures to hold the various - pieces of information describing each section. It is - stored in this manner so that it can be written to - SU2 memory later. ---*/ - - elemTypeVTK[j-1] = new int[nsections]; - elemIndex[j-1] = new int[nsections]; - elemBegin[j-1] = new int[nsections]; - elemEnd[j-1] = new int[nsections]; - nElems[j-1] = new int[nsections]; - dataSize[j-1] = new int[nsections]; - isInternal[j-1] = new bool[nsections]; - - sectionNames[j-1] = new char*[nsections]; - for (int ii = 0; ii < nsections; ii++) { - sectionNames[j-1][ii]= new char[CGNS_STRING_SIZE]; - } - - connElems[j-1] = new cgsize_t**[nsections]; - - /*--- Loop over each section. This will include the main - connectivity information for the grid cells, as well - as any boundaries which were labeled before export. ---*/ - - for (int s = 1; s <= nsections; s++) { - - /*--- Read the connectivity details for this section. - Store the total number of elements in this section - to be used later for memory allocation. ---*/ - - if (cg_section_read(fn, i, j, s, sectionNames[j-1][s-1], - &elemType, &startE, &endE, &nbndry, - &parent_flag)) cg_error_exit(); - - /*--- Store the beginning and ending index for this section. ---*/ - - elemBegin[j-1][s-1] = (int)startE; - elemEnd[j-1][s-1] = (int)endE; - - /*--- Compute element linear partitioning ---*/ - - element_count = (int) (endE-startE+1); - total_elems = 0; - for (int ii = 0; ii < size; ii++) { - nElem_Linear[ii] = element_count/size; - total_elems += nElem_Linear[ii]; - } - - /*--- Get the number of remainder elements after even division ---*/ - - element_remainder = element_count-total_elems; - for (unsigned long ii = 0; ii < element_remainder; ii++) { - nElem_Linear[ii]++; - } - - /*--- Store the number of elements that this rank is responsible for - in the current section. ---*/ - - nElems[j-1][s-1] = (int)nElem_Linear[rank]; - - /*--- Get starting and end element index for my rank. ---*/ - - elemB[0] = startE; - elemE[0] = startE + nElem_Linear[0] - 1; - for (unsigned long ii = 1; ii < (unsigned long)size; ii++) { - elemB[ii] = elemE[ii-1]+1; - elemE[ii] = elemB[ii] + nElem_Linear[ii] - 1; - } - - /*--- Allocate some memory for the handling the connectivity - and auxiliary data that we are need to communicate. ---*/ - - connElemCGNS = new cgsize_t[nElems[j-1][s-1]*connSize]; - nPoinPerElem = new unsigned short[nElems[j-1][s-1]]; - elemGlobalID = new unsigned long[nElems[j-1][s-1]]; - elemTypes = new unsigned short[nElems[j-1][s-1]]; - - isMixed = new bool[nElems[j-1][s-1]]; - for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) isMixed[ii] = false; - - /*--- Retrieve the connectivity information and store. Note that - we are only accessing our rank's piece of the data here in the - partial read function in the CGNS API. ---*/ - - if (cg_elements_partial_read(fn, i, j, s, (cgsize_t)elemB[rank], - (cgsize_t)elemE[rank], connElemCGNS, - parentData) != CG_OK) cg_error_exit(); - - /*--- Find the number of nodes required to represent - this type of element. ---*/ - - ElementType_t elmt_type; - if (cg_npe(elemType, &npe)) cg_error_exit(); - - /*--- Loop through all of the elements in this section to get more - information and to decide whether it has internal elements. ---*/ - - int counter = 0; - for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) { - - /*--- If we have a mixed element section, we need to check the elem - type one by one. Set the flag to true if mixed. ---*/ - - if (elemType == MIXED) { - elmt_type = ElementType_t(connElemCGNS[counter]); - cg_npe(elmt_type, &npe); - counter++; for ( int jj = 0; jj < npe; jj++ ) counter++; - isMixed[ii] = true; - } else { - elmt_type = elemType; - } - - /*--- Store the number of verts per elem for the current elem. ---*/ - - nPoinPerElem[ii] = npe; - - /*--- Store the global ID for this element. Note the -1 to move - from CGNS convention to SU2 convention. We also subtract off - an additional offset in case we have found boundary sections - prior to this one, in order to keep the internal element global - IDs indexed starting from zero. ---*/ - - elemGlobalID[ii] = elemB[rank] + ii - 1 - globalOffset; - - /*--- Need to check the element type and correctly specify the - VTK identifier for that element. SU2 recognizes elements by - their VTK number. ---*/ - - switch (elmt_type) { - case NODE: - currentElem = "Vertex"; - elemTypes[ii] = 1; - break; - case BAR_2: - currentElem = "Line"; - elemTypes[ii] = 3; - break; - case BAR_3: - currentElem = "Line"; - elemTypes[ii] = 3; - break; - case TRI_3: - currentElem = "Triangle"; - elemTypes[ii] = 5; - break; - case QUAD_4: - currentElem = "Quadrilateral"; - elemTypes[ii] = 9; - break; - case TETRA_4: - currentElem = "Tetrahedron"; - elemTypes[ii] = 10; - break; - case HEXA_8: - currentElem = "Hexahedron"; - elemTypes[ii] = 12; - break; - case PENTA_6: - currentElem = "Prism"; - elemTypes[ii] = 13; - break; - case PYRA_5: - currentElem = "Pyramid"; - elemTypes[ii] = 14; - break; - case HEXA_20: - if (rank == MASTER_NODE) { - printf("\n\n !!! Error !!!\n" ); - printf(" HEXA-20 element type not supported\n"); - printf(" Section %d, npe=%d\n", s, npe); - printf(" startE %d, endE %d\n", startE, endE); - printf(" Now exiting...\n\n"); - } -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - break; - default: - if (rank == MASTER_NODE) { - printf("\n\n !!! Error !!!\n" ); - printf(" Unknown elem: (type %d, npe=%d)\n", elemType, npe); - printf(" Section %d\n", s); - printf(" startE %d, endE %d\n", startE, endE); - printf(" Now exiting...\n\n"); - } -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - break; - } - - /*--- Check if the elements in this section are part - of the internal domain or are part of the boundary - surfaces. This will be used to separate the - internal connectivity from the boundary connectivity. - We will check for quad and tri elements for 3-D meshes - because these will be the boundaries. Similarly, line - elements will be boundaries to 2-D problems. ---*/ - - if ( cell_dim == 2 ) { - - /*--- In 2-D check for line elements, VTK type 3. ---*/ - - if (elemTypes[ii] == 3) { - isInternal[j-1][s-1] = false; - } else { - isInternal[j-1][s-1] = true; - interiorElems++; - } - - } else if (cell_dim == 3) { - - /*--- In 3-D check for tri/quad elements, VTK types 5 or 9. ---*/ - - switch (elemTypes[ii]) { - case 5: - case 9: - isInternal[j-1][s-1] = false; - break; - default: - isInternal[j-1][s-1] = true; - interiorElems++; - break; - } - - } - } - - /*--- Print some information to the console. ---*/ - - if (rank == MASTER_NODE) { - for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) - if (isMixed[ii]) {currentElem = "Mixed"; break;} - cout << "Loading section " << sectionNames[j-1][s-1]; - cout << " of element type " << currentElem << "." << endl; - } - - /*--- If we have found that this is a boundary section (we assume - that internal cells and boundary cells do not exist in the same - section together), the master node read the boundary section. - Otherwise, we have all ranks read and communicate the internals. ---*/ - - if (!isInternal[j-1][s-1]) { - - /*--- Master node should read this entire marker section. Free - the memory for the conn. from the CGNS file since we are going - to read the section again with the master. ---*/ - - delete [] connElemCGNS; - delete [] nPoinPerElem; - delete [] elemTypes; - delete [] elemGlobalID; - delete [] isMixed; - - /*--- Since we found an internal section, we should adjust the - element global ID offset by the total size of the section. ---*/ - - globalOffset += element_count; - - if (rank == MASTER_NODE) { - - /*--- First increment the markers ---*/ - - nMarkers++; - - /*--- Read the section info again ---*/ - - if ( cg_section_read(fn, i, j, s, sectionNames[j-1][s-1], - &elemType, &startE, &endE, &nbndry, - &parent_flag) ) cg_error_exit(); - - /*--- Store the number of elems (all on the master). ---*/ - - nElems[j-1][s-1] = (int) (endE-startE+1); - - /*--- Read and store the total amount of data that will be - listed when reading this section. ---*/ - - if (cg_ElementDataSize(fn, i, j, s, &ElementDataSize)) - cg_error_exit(); - dataSize[j-1][s-1] = ElementDataSize; - - /*--- Find the number of nodes required to represent - this type of element. ---*/ - - if (cg_npe(elemType, &npe)) cg_error_exit(); - elemIndex[j-1][s-1] = npe; - - /*--- Need to check the element type and correctly - specify the VTK identifier for that element. - SU2 recognizes elements by their VTK number. ---*/ - - switch (elemType) { - case NODE: - elemTypeVTK[j-1][s-1] = 1; - break; - case BAR_2: - elemTypeVTK[j-1][s-1] = 3; - break; - case BAR_3: - elemTypeVTK[j-1][s-1] = 3; - break; - case TRI_3: - elemTypeVTK[j-1][s-1] = 5; - break; - case QUAD_4: - elemTypeVTK[j-1][s-1] = 9; - break; - case TETRA_4: - elemTypeVTK[j-1][s-1] = 10; - break; - case HEXA_8: - elemTypeVTK[j-1][s-1] = 12; - break; - case PENTA_6: - elemTypeVTK[j-1][s-1] = 13; - break; - case PYRA_5: - elemTypeVTK[j-1][s-1] = 14; - break; - case HEXA_20: - printf( "\n\n !!! Error !!!\n" ); - printf( " HEXA-20 element type not supported\n"); - printf(" Section %d, npe=%d\n", s, npe); - printf(" startE %d, endE %d\n", startE, endE); - printf( " Now exiting...\n\n"); -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - break; - case MIXED: - currentElem = "Mixed"; - elemTypeVTK[j-1][s-1] = -1; - break; - default: - printf( "\n\n !!! Error !!!\n" ); - printf( " Unknown elem: (type %d, npe=%d)\n", elemType, npe); - printf(" Section %d\n", s); - printf(" startE %d, endE %d\n", startE, endE); - printf( " Now exiting...\n\n"); -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - break; - } - - /*--- In case of mixed data type, allocate place for 8 nodes - maximum (hex), plus element type. ---*/ - - if (elemTypeVTK[j-1][s-1] == -1) elemIndex[j-1][s-1] = 9; - - /*--- Allocate memory for accessing the connectivity and to - store it in the proper data structure for post-processing. ---*/ - - connElemTemp = new cgsize_t[dataSize[j-1][s-1]]; - - connElems[j-1][s-1] = new cgsize_t*[elemIndex[j-1][s-1]]; - for (int jj = 0; jj < elemIndex[j-1][s-1]; jj++) { - connElems[j-1][s-1][jj] = new cgsize_t[nElems[j-1][s-1]]; - } - - /*--- Retrieve the connectivity information and store. ---*/ - - if (cg_elements_read(fn, i, j, s, connElemTemp, parentData)) - cg_error_exit(); - - /*--- Copy these values into the larger array for - storage until writing the SU2 file. ---*/ - - if (elemTypeVTK[j-1][s-1] == -1) { - int counter = 0; - for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) { - ElementType_t elmt_type = ElementType_t(connElemTemp[counter]); - cg_npe( elmt_type, &npe); - counter++; - connElems[j-1][s-1][0][ii] = elmt_type; - for ( int jj = 0; jj < npe; jj++ ) { - connElems[j-1][s-1][jj+1][ii] = connElemTemp[counter] - 1; - counter++; - } - } - } else { - int counter = 0; - for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) { - for ( int jj = 0; jj < elemIndex[j-1][s-1]; jj++ ) { - connElems[j-1][s-1][jj][ii] = connElemTemp[counter] - 1; - counter++; - } - } - } - delete[] connElemTemp; - - } // end master - - } else { - - /*--- These are internal elems. Allocate memory on each proc. ---*/ - - connElemTemp = new cgsize_t[nElems[j-1][s-1]*connSize]; - - /*--- Copy these values into the larger array for - storage until writing the SU2 file. ---*/ - - int counterTemp = 0, counterCGNS = 0; - for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) { - - /*--- Store the conn in chunks of connSize for simplicity. ---*/ - - counterTemp = ii*connSize; - - /*--- Store the connectivity values. Note we subtract one from - the CGNS 1-based convention. We may also need to remove the first - entry is this is a mixed element section. ---*/ - - if (isMixed[ii]) counterCGNS++; - for ( int jj = 0; jj < nPoinPerElem[ii]; jj++) { - connElemTemp[counterTemp] = connElemCGNS[counterCGNS + jj] - 1; - counterTemp++; - } - counterCGNS += nPoinPerElem[ii]; - - } - - /*--- Free the memory for the conn. from the CGNS file. ---*/ - - delete [] connElemCGNS; - delete [] isMixed; - - /*--- We now have the connectivity stored in linearly partitioned - chunks. We need to loop through and decide how many elements we - must send to each rank in order to have all elements that - surround a particular "owned" node on each rank (i.e., elements - will appear on multiple ranks). First, initialize a counter - and flag. ---*/ - - int *nElem_Send = new int[size+1]; nElem_Send[0] = 0; - int *nElem_Recv = new int[size+1]; nElem_Recv[0] = 0; - int *nElem_Flag = new int[size]; - - for (int ii=0; ii < size; ii++) { - nElem_Send[ii] = 0; - nElem_Recv[ii] = 0; - nElem_Flag[ii]= -1; - } - nElem_Send[size] = 0; nElem_Recv[size] = 0; - - for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) { - for ( int jj = 0; jj < nPoinPerElem[ii]; jj++ ) { - - /*--- Get the index of the current point. ---*/ - - iPoint = connElemTemp[ii*connSize + jj]; - - /*--- Search for the processor that owns this point ---*/ - - iProcessor = iPoint/npoint_procs[0]; - if (iProcessor >= (unsigned long)size) iProcessor = (unsigned long)size-1; - if (iPoint >= nPoint_Linear[iProcessor]) - while(iPoint >= nPoint_Linear[iProcessor+1]) iProcessor++; - else - while(iPoint < nPoint_Linear[iProcessor]) iProcessor--; - - /*--- If we have not visted this element yet, increment our - number of elements that must be sent to a particular proc. ---*/ - - if (nElem_Flag[iProcessor] != ii) { - nElem_Flag[iProcessor] = ii; - nElem_Send[iProcessor+1]++; - } - - } - } - - /*--- Communicate the number of cells to be sent/recv'd amongst - all processors. After this communication, each proc knows how - many cells it will receive from each other processor. ---*/ - -#ifdef HAVE_MPI - MPI_Alltoall(&(nElem_Send[1]), 1, MPI_INT, - &(nElem_Recv[1]), 1, MPI_INT, MPI_COMM_WORLD); -#else - nElem_Recv[1] = nElem_Send[1]; -#endif - - /*--- Prepare to send connectivities. First check how many - messages we will be sending and receiving. Here we also put - the counters into cumulative storage format to make the - communications simpler. ---*/ - - int nSends = 0, nRecvs = 0; - for (int ii=0; ii < size; ii++) nElem_Flag[ii] = -1; - - for (int ii = 0; ii < size; ii++) { - - if ((ii != rank) && (nElem_Send[ii+1] > 0)) nSends++; - if ((ii != rank) && (nElem_Recv[ii+1] > 0)) nRecvs++; - - nElem_Send[ii+1] += nElem_Send[ii]; - nElem_Recv[ii+1] += nElem_Recv[ii]; - } - - /*--- Allocate memory to hold the connectivity that we are - sending. Note that we are also sending the VTK element type - in the first position and also the global ID. We have assumed - a constant message size of a hex element + 2 extra vals. ---*/ - - unsigned long *connSend = NULL; - connSend = new unsigned long[connSize*nElem_Send[size]]; - for (int ii = 0; ii < connSize*nElem_Send[size]; ii++) - connSend[ii] = 0; - - /*--- Create an index variable to keep track of our index - position as we load up the send buffer. ---*/ - - unsigned long *index = new unsigned long[size]; - for (int ii=0; ii < size; ii++) index[ii] = connSize*nElem_Send[ii]; - - /*--- Loop through our elements and load the elems and their - additional data that we will send to the other procs. ---*/ - - for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) { - for ( int jj = 0; jj < nPoinPerElem[ii]; jj++ ) { - - /*--- Get the index of the current point. ---*/ - - iPoint = connElemTemp[ii*connSize + jj]; - - /*--- Search for the processor that owns this point ---*/ - - iProcessor = iPoint/npoint_procs[0]; - if (iProcessor >= (unsigned long)size) iProcessor = (unsigned long)size-1; - if (iPoint >= nPoint_Linear[iProcessor]) - while(iPoint >= nPoint_Linear[iProcessor+1]) iProcessor++; - else - while(iPoint < nPoint_Linear[iProcessor]) iProcessor--; - - /*--- Load connectivity into the buffer for sending ---*/ - - if (nElem_Flag[iProcessor] != ii) { - - nElem_Flag[iProcessor] = ii; - unsigned long nn = index[iProcessor]; - - /*--- Load the VTK type first into the conn array, - then the connectivity vals, and last, the global ID. ---*/ - - connSend[nn] = elemTypes[ii]; nn++; - for ( int kk = 0; kk < nPoinPerElem[ii]; kk++ ) { - connSend[nn] = connElemTemp[ii*connSize + kk]; nn++; - } - connSend[nn] = (cgsize_t)elemGlobalID[ii]; - - /*--- Increment the index by the message length ---*/ - - index[iProcessor] += connSize; - - } - } - } - - /*--- Free memory after loading up the send buffer. ---*/ - - delete [] connElemTemp; - delete [] elemTypes; - delete [] nPoinPerElem; - delete [] elemGlobalID; - delete [] index; - - /*--- Allocate the memory that we need for receiving the conn - values and then cue up the non-blocking receives. Note that - we do not include our own rank in the communications. We will - directly copy our own data later. ---*/ - - unsigned long *connRecv = NULL; - connRecv = new unsigned long[connSize*nElem_Recv[size]]; - for (int ii = 0; ii < connSize*nElem_Recv[size]; ii++) - connRecv[ii] = 0; - -#ifdef HAVE_MPI - send_req = new MPI_Request[nSends]; - recv_req = new MPI_Request[nRecvs]; - unsigned long iMessage = 0; - for (int ii=0; ii nElem_Recv[ii])) { - int ll = connSize*nElem_Recv[ii]; - int kk = nElem_Recv[ii+1] - nElem_Recv[ii]; - int count = connSize*kk; - int source = ii; - int tag = ii + 1; - SU2_MPI::Irecv(&(connRecv[ll]), count, MPI_UNSIGNED_LONG, source, tag, - MPI_COMM_WORLD, &(recv_req[iMessage])); - iMessage++; - } - } - - /*--- Launch the non-blocking sends of the connectivity. ---*/ - - iMessage = 0; - for (int ii=0; ii nElem_Send[ii])) { - int ll = connSize*nElem_Send[ii]; - int kk = nElem_Send[ii+1] - nElem_Send[ii]; - int count = connSize*kk; - int dest = ii; - int tag = rank + 1; - SU2_MPI::Isend(&(connSend[ll]), count, MPI_UNSIGNED_LONG, dest, tag, - MPI_COMM_WORLD, &(send_req[iMessage])); - iMessage++; - } - } -#endif - - /*--- Copy my own rank's data into the recv buffer directly. ---*/ - - int mm = connSize*nElem_Recv[rank]; - int ll = connSize*nElem_Send[rank]; - int kk = connSize*nElem_Send[rank+1]; - - for (int nn=ll; nn SINGLE_NODE)) { - cout << nElem << " interior elements before linear partitioning." << endl; - } else if (rank == MASTER_NODE) { - cout << nElem << " interior elements." << endl; - } - - /*--- Set up the global to local element mapping. ---*/ - - Global_to_local_elem = new long[nElem]; - for (unsigned long i = 0; i < nElem; i++) { - Global_to_local_elem[i] = -1; - } - - /*--- Allocate space for elements. We allocate enough for all interior - elements globally, but we will only instantiate our local set. ---*/ - - elem = new CPrimalGrid*[nElem]; - for (unsigned long iElem = 0; iElem < nElem; iElem++) elem[iElem] = NULL; - ielem = 0; - unsigned long global_id = 0; - - /*--- Loop over all the internal, local volumetric elements. ---*/ - - for (int k = 0; k < nzones; k++) { - for (int s = 0; s < nsections; s++) { - if (isInternal[k][s]) { - for ( int i = 0; i < nElems[k][s]; i++) { - - /*--- Get the VTK type for this element. This is stored in the - first entry of the connectivity structure. ---*/ - - VTK_Type = connElems[k][s][0][i]; - - /*--- Instantiate this element and build adjacency structure. ---*/ - - switch(VTK_Type) { - case TRIANGLE: - for ( int j = 0; j < N_POINTS_TRIANGLE; j++ ) { - vnodes_cgns[j] = connElems[k][s][j+1][i]; - } - global_id = connElems[k][s][N_POINTS_TRIANGLE+1][i]; - for (unsigned short ii=0; ii=starting_node[rank])&&(vnodes_cgns[ii]=starting_node[rank])&&(vnodes_cgns[ii]=starting_node[rank])&&(vnodes_cgns[ii]=starting_node[rank])&&(vnodes_cgns[ii]=starting_node[rank])&&(vnodes_cgns[ii]=starting_node[rank])&&(vnodes_cgns[ii] SINGLE_NODE)) - cout << "Building the graph adjacency structure." << endl; - - unsigned long loc_adjc_size=0; - vector adjac_vec; - unsigned long adj_elem_size; - vector::iterator it; - local_elem=ielem; - - xadj = new unsigned long [npoint_procs[rank]+1]; - xadj[0]=0; - vector temp_adjacency; - unsigned long local_count=0; - - for (unsigned long i = 0; i < local_node; i++) { - - for (unsigned long j=0; j SINGLE_NODE)) { - cout << nPoint << " grid points before linear partitioning." << endl; - } else if (rank == MASTER_NODE) { - cout << nPoint << " grid points." << endl; - } - - iPoint = 0; - node = new CPoint*[local_node]; - GlobalIndex = starting_node[rank]; - for (int k = 0; k < nzones; k++ ) { - for (unsigned long i = 0; i < local_node; i++ ) { - for (int j = 0; j < cell_dim; j++ ) Coord_cgns[j] = gridCoords[k][j][i]; - switch(nDim) { - case 2: - node[iPoint] = new CPoint(Coord_cgns[0], Coord_cgns[1], GlobalIndex, config); - iPoint++; break; - case 3: - node[iPoint] = new CPoint(Coord_cgns[0], Coord_cgns[1], Coord_cgns[2], GlobalIndex, config); - iPoint++; break; - } - GlobalIndex++; - } - } - - /*--- For now, the master node takes care of all markers. ---*/ - - if (rank == MASTER_NODE) { - - /*--- Read number of markers ---*/ - - nMarker = nMarkers; - cout << nMarker << " surface markers." << endl; - config->SetnMarker_All(nMarker); - bound = new CPrimalGrid**[nMarker]; - nElem_Bound = new unsigned long [nMarker]; - Tag_to_Marker = new string [nMarker_Max]; - - iMarker = 0; - for ( int k = 0; k < nzones; k ++ ) { - for ( int s = 0; s < nsections; s++ ) { - if ( !isInternal[k][s] ) { - - /*--- Initialize some counter variables ---*/ - - nelem_edge_bound = 0; nelem_triangle_bound = 0; - nelem_quad_bound = 0; ielem = 0; - - Marker_Tag = sectionNames[k][s]; - - /*--- Remove whitespaces from the marker names ---*/ - Marker_Tag.erase(remove(Marker_Tag.begin(), Marker_Tag.end(),' '), Marker_Tag.end()); - - if (Marker_Tag != "SEND_RECEIVE") { - nElem_Bound[iMarker] = nElems[k][s]; - if (rank == MASTER_NODE) { - cout << nElem_Bound[iMarker] << " boundary elements in index "; - cout << iMarker <<" (Marker = " <GetMarker_CfgFile_TagBound(Marker_Tag)] = Marker_Tag; - config->SetMarker_All_TagBound(iMarker, Marker_Tag); - config->SetMarker_All_KindBC(iMarker, config->GetMarker_CfgFile_KindBC(Marker_Tag)); - config->SetMarker_All_Monitoring(iMarker, config->GetMarker_CfgFile_Monitoring(Marker_Tag)); - config->SetMarker_All_GeoEval(iMarker, config->GetMarker_CfgFile_GeoEval(Marker_Tag)); - config->SetMarker_All_Designing(iMarker, config->GetMarker_CfgFile_Designing(Marker_Tag)); - config->SetMarker_All_Plotting(iMarker, config->GetMarker_CfgFile_Plotting(Marker_Tag)); - config->SetMarker_All_FSIinterface(iMarker, config->GetMarker_CfgFile_FSIinterface(Marker_Tag)); - config->SetMarker_All_DV(iMarker, config->GetMarker_CfgFile_DV(Marker_Tag)); - config->SetMarker_All_Moving(iMarker, config->GetMarker_CfgFile_Moving(Marker_Tag)); - config->SetMarker_All_PerBound(iMarker, config->GetMarker_CfgFile_PerBound(Marker_Tag)); - config->SetMarker_All_Out_1D(iMarker, config->GetMarker_CfgFile_Out_1D(Marker_Tag)); - config->SetMarker_All_SendRecv(iMarker, NONE); - - } - iMarker++; - } - } - } - - /*--- Periodic transormations is not implement, store default zeros ---*/ - unsigned short nPeriodic = 1, iPeriodic = 0; - config->SetnPeriodicIndex(nPeriodic); - su2double* center = new su2double[3]; - su2double* rotation = new su2double[3]; - su2double* translate = new su2double[3]; - for (unsigned short iDim = 0; iDim < 3; iDim++) { - center[iDim] = 0.0; rotation[iDim] = 0.0; translate[iDim] = 0.0; - } - config->SetPeriodicCenter(iPeriodic, center); - config->SetPeriodicRotation(iPeriodic, rotation); - config->SetPeriodicTranslate(iPeriodic, translate); - - } - - /*--- Deallocate temporary memory. ---*/ - - delete[] vertices; - delete[] cells; - delete[] boundVerts; - - for ( int j = 0; j < nzones; j++) { - delete[] coordArray[j]; - delete[] elemTypeVTK[j]; - delete[] elemIndex[j]; - delete[] nElems[j]; - delete[] dataSize[j]; - delete[] isInternal[j]; - delete[] sectionNames[j]; - } - delete[] coordArray; - delete[] elemTypeVTK; - delete[] elemIndex; - delete[] nElems; - delete[] dataSize; - delete[] isInternal; - delete[] sectionNames; - - for ( int j = 0; j < nzones; j++) { - for ( int i = 0; i < ncoords; i++ ) { - delete[] gridCoords[j][i]; - } - delete[] gridCoords[j]; - } - delete[] gridCoords; - - // for ( int kk = 0; kk < nzones; kk++) { - // for (int ii = 0; ii < nsections; ii++) { - // for (int jj = 0; jj < indexMax; jj++) { - // delete[] connElems[kk][ii][jj]; - // } - // delete connElems[kk][ii]; - // } - // delete connElems[kk]; - // } - // delete[] connElems; - - delete [] nPoint_Linear; - delete [] nElem_Linear; - - delete [] elemB; - delete [] elemE; - -#else - cout << "SU2 built without CGNS support!!" << endl; - cout << "To use CGNS, remove the -DNO_CGNS directive "; - cout << "from the makefile and supply the correct path"; - cout << " to the CGNS library." << endl; - exit(EXIT_FAILURE); -#endif - -} - -void CPhysicalGeometry::Check_IntElem_Orientation(CConfig *config) { - - unsigned long Point_1, Point_2, Point_3, Point_4, Point_5, Point_6, - iElem; - su2double test_1, test_2, test_3, test_4, *Coord_1, *Coord_2, *Coord_3, *Coord_4, - *Coord_5, *Coord_6, a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}, c[3] = {0.0,0.0,0.0}, n[3] = {0.0,0.0,0.0}, test; - unsigned short iDim; - - /*--- Loop over all the elements ---*/ - - for (iElem = 0; iElem < nElem; iElem++) { - - /*--- 2D grid, triangle case ---*/ - - if (elem[iElem]->GetVTK_Type() == TRIANGLE) { - - Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); - Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); - Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); - b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); } - test = a[0]*b[1]-b[0]*a[1]; - - if (test < 0.0) elem[iElem]->Change_Orientation(); - } - - /*--- 2D grid, quadrilateral case ---*/ - - if (elem[iElem]->GetVTK_Type() == QUADRILATERAL) { - - Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); - Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); - Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); - Point_4 = elem[iElem]->GetNode(3); Coord_4 = node[Point_4]->GetCoord(); - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); - b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); } - test_1 = a[0]*b[1]-b[0]*a[1]; - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_3[iDim]-Coord_2[iDim]); - b[iDim] = 0.5*(Coord_4[iDim]-Coord_2[iDim]); } - test_2 = a[0]*b[1]-b[0]*a[1]; - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_4[iDim]-Coord_3[iDim]); - b[iDim] = 0.5*(Coord_1[iDim]-Coord_3[iDim]); } - test_3 = a[0]*b[1]-b[0]*a[1]; - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_1[iDim]-Coord_4[iDim]); - b[iDim] = 0.5*(Coord_3[iDim]-Coord_4[iDim]); } - test_4 = a[0]*b[1]-b[0]*a[1]; - - if ((test_1 < 0.0) && (test_2 < 0.0) && (test_3 < 0.0) && (test_4 < 0.0)) - elem[iElem]->Change_Orientation(); - } - - /*--- 3D grid, tetrahedron case ---*/ - - if (elem[iElem]->GetVTK_Type() == TETRAHEDRON) { - - Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); - Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); - Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); - Point_4 = elem[iElem]->GetNode(3); Coord_4 = node[Point_4]->GetCoord(); - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); - b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); - c[iDim] = Coord_4[iDim]-Coord_1[iDim]; } - n[0] = a[1]*b[2]-b[1]*a[2]; - n[1] = -(a[0]*b[2]-b[0]*a[2]); - n[2] = a[0]*b[1]-b[0]*a[1]; - - test = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - if (test < 0.0) elem[iElem]->Change_Orientation(); - - } - - /*--- 3D grid, prism case ---*/ - - if (elem[iElem]->GetVTK_Type() == PRISM) { - - Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); - Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); - Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); - Point_4 = elem[iElem]->GetNode(3); Coord_4 = node[Point_4]->GetCoord(); - Point_5 = elem[iElem]->GetNode(4); Coord_5 = node[Point_5]->GetCoord(); - Point_6 = elem[iElem]->GetNode(5); Coord_6 = node[Point_6]->GetCoord(); - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); - b[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); - c[iDim] = (Coord_4[iDim]-Coord_1[iDim])+ - (Coord_5[iDim]-Coord_2[iDim])+ - (Coord_6[iDim]-Coord_3[iDim]); } - - /*--- The normal vector should point to the interior of the element ---*/ - - n[0] = a[1]*b[2]-b[1]*a[2]; - n[1] = -(a[0]*b[2]-b[0]*a[2]); - n[2] = a[0]*b[1]-b[0]*a[1]; - - test_1 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_5[iDim]-Coord_4[iDim]); - b[iDim] = 0.5*(Coord_6[iDim]-Coord_4[iDim]); - c[iDim] = (Coord_1[iDim]-Coord_4[iDim])+ - (Coord_2[iDim]-Coord_5[iDim])+ - (Coord_3[iDim]-Coord_6[iDim]); } - - /*--- The normal vector should point to the interior of the element ---*/ - - n[0] = a[1]*b[2]-b[1]*a[2]; - n[1] = -(a[0]*b[2]-b[0]*a[2]); - n[2] = a[0]*b[1]-b[0]*a[1]; - - test_2 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - - if ((test_1 < 0.0) || (test_2 < 0.0)) - elem[iElem]->Change_Orientation(); - - } - - if (elem[iElem]->GetVTK_Type() == HEXAHEDRON) { - - Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); - Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); - Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); - Point_4 = elem[iElem]->GetNode(5); Coord_4 = node[Point_4]->GetCoord(); - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); - b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); - c[iDim] = Coord_4[iDim]-Coord_1[iDim]; } - n[0] = a[1]*b[2]-b[1]*a[2]; - n[1] = -(a[0]*b[2]-b[0]*a[2]); - n[2] = a[0]*b[1]-b[0]*a[1]; - - test_1 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - - Point_1 = elem[iElem]->GetNode(2); Coord_1 = node[Point_1]->GetCoord(); - Point_2 = elem[iElem]->GetNode(3); Coord_2 = node[Point_2]->GetCoord(); - Point_3 = elem[iElem]->GetNode(0); Coord_3 = node[Point_3]->GetCoord(); - Point_4 = elem[iElem]->GetNode(7); Coord_4 = node[Point_4]->GetCoord(); - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); - b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); - c[iDim] = Coord_4[iDim]-Coord_1[iDim]; } - n[0] = a[1]*b[2]-b[1]*a[2]; - n[1] = -(a[0]*b[2]-b[0]*a[2]); - n[2] = a[0]*b[1]-b[0]*a[1]; - - test_2 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - - Point_1 = elem[iElem]->GetNode(1); Coord_1 = node[Point_1]->GetCoord(); - Point_2 = elem[iElem]->GetNode(2); Coord_2 = node[Point_2]->GetCoord(); - Point_3 = elem[iElem]->GetNode(3); Coord_3 = node[Point_3]->GetCoord(); - Point_4 = elem[iElem]->GetNode(6); Coord_4 = node[Point_4]->GetCoord(); - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); - b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); - c[iDim] = Coord_4[iDim]-Coord_1[iDim]; } - n[0] = a[1]*b[2]-b[1]*a[2]; - n[1] = -(a[0]*b[2]-b[0]*a[2]); - n[2] = a[0]*b[1]-b[0]*a[1]; - - test_3 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - - Point_1 = elem[iElem]->GetNode(3); Coord_1 = node[Point_1]->GetCoord(); - Point_2 = elem[iElem]->GetNode(0); Coord_2 = node[Point_2]->GetCoord(); - Point_3 = elem[iElem]->GetNode(1); Coord_3 = node[Point_3]->GetCoord(); - Point_4 = elem[iElem]->GetNode(4); Coord_4 = node[Point_4]->GetCoord(); - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); - b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); - c[iDim] = Coord_4[iDim]-Coord_1[iDim]; } - n[0] = a[1]*b[2]-b[1]*a[2]; - n[1] = -(a[0]*b[2]-b[0]*a[2]); - n[2] = a[0]*b[1]-b[0]*a[1]; - - test_4 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - - if ((test_1 < 0.0) || (test_2 < 0.0) || (test_3 < 0.0) - || (test_4 < 0.0)) elem[iElem]->Change_Orientation(); - - } - - if (elem[iElem]->GetVTK_Type() == PYRAMID) { - - Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); - Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); - Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); - Point_4 = elem[iElem]->GetNode(4); Coord_4 = node[Point_4]->GetCoord(); - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); - b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); - c[iDim] = Coord_4[iDim]-Coord_1[iDim]; } - n[0] = a[1]*b[2]-b[1]*a[2]; - n[1] = -(a[0]*b[2]-b[0]*a[2]); - n[2] = a[0]*b[1]-b[0]*a[1]; - - test_1 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - - Point_1 = elem[iElem]->GetNode(2); Coord_1 = node[Point_1]->GetCoord(); - Point_2 = elem[iElem]->GetNode(3); Coord_2 = node[Point_2]->GetCoord(); - Point_3 = elem[iElem]->GetNode(0); Coord_3 = node[Point_3]->GetCoord(); - Point_4 = elem[iElem]->GetNode(4); Coord_4 = node[Point_4]->GetCoord(); - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); - b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); - c[iDim] = Coord_4[iDim]-Coord_1[iDim]; } - n[0] = a[1]*b[2]-b[1]*a[2]; - n[1] = -(a[0]*b[2]-b[0]*a[2]); - n[2] = a[0]*b[1]-b[0]*a[1]; - - test_2 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - - if ((test_1 < 0.0) || (test_2 < 0.0)) - elem[iElem]->Change_Orientation(); - - } - - } - -} - -void CPhysicalGeometry::Check_BoundElem_Orientation(CConfig *config) { - - unsigned long Point_1_Surface, Point_2_Surface, Point_3_Surface, Point_4_Surface, - iElem_Domain, Point_Domain = 0, Point_Surface, iElem_Surface; - su2double test_1, test_2, test_3, test_4, *Coord_1, *Coord_2, *Coord_3, *Coord_4, - *Coord_5, a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}, c[3] = {0.0,0.0,0.0}, n[3] = {0.0,0.0,0.0}, test; - unsigned short iDim, iMarker, iNode_Domain, iNode_Surface; - bool find; - - /*--- Surface elements ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) - for (iElem_Surface = 0; iElem_Surface < nElem_Bound[iMarker]; iElem_Surface++) { - - iElem_Domain = bound[iMarker][iElem_Surface]->GetDomainElement(); - for (iNode_Domain = 0; iNode_Domain < elem[iElem_Domain]->GetnNodes(); iNode_Domain++) { - Point_Domain = elem[iElem_Domain]->GetNode(iNode_Domain); - find = false; - for (iNode_Surface = 0; iNode_Surface < bound[iMarker][iElem_Surface]->GetnNodes(); iNode_Surface++) { - Point_Surface = bound[iMarker][iElem_Surface]->GetNode(iNode_Surface); - if (Point_Surface == Point_Domain) {find = true; break;} - } - if (!find) break; - } - - /*--- 2D grid, line case ---*/ - - if (bound[iMarker][iElem_Surface]->GetVTK_Type() == LINE) { - - Point_1_Surface = bound[iMarker][iElem_Surface]->GetNode(0); Coord_1 = node[Point_1_Surface]->GetCoord(); - Point_2_Surface = bound[iMarker][iElem_Surface]->GetNode(1); Coord_2 = node[Point_2_Surface]->GetCoord(); - Coord_3 = node[Point_Domain]->GetCoord(); - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); - b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); } - test = a[0]*b[1]-b[0]*a[1]; - - if (test < 0.0) { - bound[iMarker][iElem_Surface]->Change_Orientation(); - node[Point_1_Surface]->SetFlip_Orientation(); - node[Point_2_Surface]->SetFlip_Orientation(); - } - - } - - /*--- 3D grid, triangle case ---*/ - if (bound[iMarker][iElem_Surface]->GetVTK_Type() == TRIANGLE) { - - Point_1_Surface = bound[iMarker][iElem_Surface]->GetNode(0); Coord_1 = node[Point_1_Surface]->GetCoord(); - Point_2_Surface = bound[iMarker][iElem_Surface]->GetNode(1); Coord_2 = node[Point_2_Surface]->GetCoord(); - Point_3_Surface = bound[iMarker][iElem_Surface]->GetNode(2); Coord_3 = node[Point_3_Surface]->GetCoord(); - Coord_4 = node[Point_Domain]->GetCoord(); - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); - b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); - c[iDim] = Coord_4[iDim]-Coord_1[iDim]; } - n[0] = a[1]*b[2]-b[1]*a[2]; - n[1] = -(a[0]*b[2]-b[0]*a[2]); - n[2] = a[0]*b[1]-b[0]*a[1]; - - test = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - if (test < 0.0) { - bound[iMarker][iElem_Surface]->Change_Orientation(); - node[Point_1_Surface]->SetFlip_Orientation(); - node[Point_2_Surface]->SetFlip_Orientation(); - node[Point_3_Surface]->SetFlip_Orientation(); - } - - } - - if (bound[iMarker][iElem_Surface]->GetVTK_Type() == QUADRILATERAL) { - - Point_1_Surface = bound[iMarker][iElem_Surface]->GetNode(0); Coord_1 = node[Point_1_Surface]->GetCoord(); - Point_2_Surface = bound[iMarker][iElem_Surface]->GetNode(1); Coord_2 = node[Point_2_Surface]->GetCoord(); - Point_3_Surface = bound[iMarker][iElem_Surface]->GetNode(2); Coord_3 = node[Point_3_Surface]->GetCoord(); - Point_4_Surface = bound[iMarker][iElem_Surface]->GetNode(3); Coord_4 = node[Point_4_Surface]->GetCoord(); - Coord_5 = node[Point_Domain]->GetCoord(); - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); - b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); - c[iDim] = Coord_5[iDim]-Coord_1[iDim]; } - n[0] = a[1]*b[2]-b[1]*a[2]; - n[1] = -(a[0]*b[2]-b[0]*a[2]); - n[2] = a[0]*b[1]-b[0]*a[1]; - test_1 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_3[iDim]-Coord_2[iDim]); - b[iDim] = 0.5*(Coord_4[iDim]-Coord_2[iDim]); - c[iDim] = Coord_5[iDim]-Coord_2[iDim]; } - n[0] = a[1]*b[2]-b[1]*a[2]; - n[1] = -(a[0]*b[2]-b[0]*a[2]); - n[2] = a[0]*b[1]-b[0]*a[1]; - test_2 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_4[iDim]-Coord_3[iDim]); - b[iDim] = 0.5*(Coord_1[iDim]-Coord_3[iDim]); - c[iDim] = Coord_5[iDim]-Coord_3[iDim]; } - n[0] = a[1]*b[2]-b[1]*a[2]; - n[1] = -(a[0]*b[2]-b[0]*a[2]); - n[2] = a[0]*b[1]-b[0]*a[1]; - test_3 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = 0.5*(Coord_1[iDim]-Coord_4[iDim]); - b[iDim] = 0.5*(Coord_3[iDim]-Coord_4[iDim]); - c[iDim] = Coord_5[iDim]-Coord_4[iDim]; } - n[0] = a[1]*b[2]-b[1]*a[2]; - n[1] = -(a[0]*b[2]-b[0]*a[2]); - n[2] = a[0]*b[1]-b[0]*a[1]; - test_4 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - - if ((test_1 < 0.0) && (test_2 < 0.0) && (test_3 < 0.0) && (test_4 < 0.0)) { - bound[iMarker][iElem_Surface]->Change_Orientation(); - node[Point_1_Surface]->SetFlip_Orientation(); - node[Point_2_Surface]->SetFlip_Orientation(); - node[Point_3_Surface]->SetFlip_Orientation(); - node[Point_4_Surface]->SetFlip_Orientation(); - } - - } - } -} - -void CPhysicalGeometry::ComputeWall_Distance(CConfig *config) { - - su2double *coord, dist; - passivedouble dist2, diff; - unsigned short iDim, iMarker; - unsigned long iPoint, iVertex, nVertex_SolidWall, iVertex_nearestWall = 0; - - -#ifndef HAVE_MPI - - /*--- Compute the total number of nodes on no-slip boundaries ---*/ - - nVertex_SolidWall = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) ) - nVertex_SolidWall += GetnVertex(iMarker); - - /*--- Allocate an array to hold boundary node coordinates ---*/ - - su2double **Coord_bound; - Coord_bound = new su2double* [nVertex_SolidWall]; - for (iVertex = 0; iVertex < nVertex_SolidWall; iVertex++) - Coord_bound[iVertex] = new su2double [nDim]; - - /*--- Retrieve and store the coordinates of the no-slip boundary nodes ---*/ - - nVertex_SolidWall = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) ) - for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - for (iDim = 0; iDim < nDim; iDim++) - Coord_bound[nVertex_SolidWall][iDim] = node[iPoint]->GetCoord(iDim); - nVertex_SolidWall++; - } - } - - /*--- Loop over all interior mesh nodes and compute the distances to each - of the no-slip boundary nodes. Store the minimum distance to the wall for - each interior mesh node. ---*/ - - su2double dist1 = 0.0; - if (nVertex_SolidWall != 0) { - for (iPoint = 0; iPoint < GetnPoint(); iPoint++) { - coord = node[iPoint]->GetCoord(); - dist1 = 1E20; - for (iVertex = 0; iVertex < nVertex_SolidWall; iVertex++) { - dist2 = 0.0; - - /*--- The wall distance computation is done using the plain su2double datatype to just - * determine the index of the closest vertex. Otherwise we are storing a lot of - * unnecessary derivative information when using AD.---*/ - - for (iDim = 0; iDim < nDim; iDim++){ - diff = (SU2_TYPE::GetValue(coord[iDim]) - -SU2_TYPE::GetValue(Coord_bound[iVertex][iDim])); - dist2 += diff*diff; - } - if (dist2 < dist1) { - iVertex_nearestWall = iVertex; - dist1 = dist2; - } - } - dist = 0.0; - - /*--- Now we do the computation of the wall distance again using the general datatype.---*/ - - for (iDim = 0; iDim < nDim; iDim++){ - dist += (coord[iDim] - Coord_bound[iVertex_nearestWall][iDim])* - (coord[iDim] - Coord_bound[iVertex_nearestWall][iDim]); - } - node[iPoint]->SetWall_Distance(sqrt(dist)); - } - } - else { - for (iPoint = 0; iPoint < GetnPoint(); iPoint++) - node[iPoint]->SetWall_Distance(0.0); - } - - /*--- Deallocate the vector of boundary coordinates. ---*/ - - for (iVertex = 0; iVertex < nVertex_SolidWall; iVertex++) - delete[] Coord_bound[iVertex]; - delete[] Coord_bound; - - -#else - - /*--- Variables and buffers needed for MPI ---*/ - - int iProcessor, nProcessor; - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); - - unsigned long nLocalVertex_NS = 0, nGlobalVertex_NS = 0, MaxLocalVertex_NS = 0; - unsigned long *Buffer_Send_nVertex = new unsigned long [1]; - unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor]; - - /*--- Count the total number of nodes on no-slip boundaries within the - local partition. ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) ) - nLocalVertex_NS += GetnVertex(iMarker); - - /*--- Communicate to all processors the total number of no-slip boundary - nodes, the maximum number of no-slip boundary nodes on any single single - partition, and the number of no-slip nodes on each partition. ---*/ - - Buffer_Send_nVertex[0] = nLocalVertex_NS; - SU2_MPI::Allreduce(&nLocalVertex_NS, &nGlobalVertex_NS, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalVertex_NS, &MaxLocalVertex_NS, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - - /*--- Create and initialize to zero some buffers to hold the coordinates - of the boundary nodes that are communicated from each partition (all-to-all). ---*/ - - su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_NS*nDim]; - su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_NS*nDim]; - unsigned long nBuffer = MaxLocalVertex_NS*nDim; - - for (iVertex = 0; iVertex < MaxLocalVertex_NS; iVertex++) - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; - - /*--- Retrieve and store the coordinates of the no-slip boundary nodes on - the local partition and broadcast them to all partitions. ---*/ - - nVertex_SolidWall = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) ) - for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[nVertex_SolidWall*nDim+iDim] = node[iPoint]->GetCoord(iDim); - nVertex_SolidWall++; - } - - SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer, MPI_DOUBLE, MPI_COMM_WORLD); - - /*--- Loop over all interior mesh nodes on the local partition and compute - the distances to each of the no-slip boundary nodes in the entire mesh. - Store the minimum distance to the wall for each interior mesh node. ---*/ - - nVertex_SolidWall = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - nVertex_SolidWall += Buffer_Receive_nVertex[iProcessor]; - } - - if (nVertex_SolidWall != 0) { - for (iPoint = 0; iPoint < GetnPoint(); iPoint++) { - coord = node[iPoint]->GetCoord(); - dist = 1E20; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) - for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { - dist2 = 0.0; - - /*--- The wall distance computation is done using the plain su2double datatype to just - * determine the index of the closest vertex. Otherwise we are storing a lot of - * unnecessary derivative information when using AD.---*/ - - for (iDim = 0; iDim < nDim; iDim++){ - diff = SU2_TYPE::GetValue(coord[iDim]) - - SU2_TYPE::GetValue(Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_NS+iVertex)*nDim+iDim]); - dist2 += diff*diff; - } - if (dist2 < dist) { - iVertex_nearestWall = iProcessor*MaxLocalVertex_NS+iVertex; - dist = dist2; - } - } - - /*--- Now we do the computation of the wall distance again using the general datatype.---*/ - - dist = 0.0; - for (iDim = 0; iDim < nDim; iDim++){ - dist += (coord[iDim] - Buffer_Receive_Coord[iVertex_nearestWall*nDim+iDim])* - (coord[iDim] - Buffer_Receive_Coord[iVertex_nearestWall*nDim+iDim]); - } - node[iPoint]->SetWall_Distance(sqrt(dist)); - } - } - else { - for (iPoint = 0; iPoint < GetnPoint(); iPoint++) - node[iPoint]->SetWall_Distance(0.0); - } - - /*--- Deallocate the buffers needed for the MPI communication. ---*/ - - delete[] Buffer_Send_Coord; - delete[] Buffer_Receive_Coord; - delete[] Buffer_Send_nVertex; - delete[] Buffer_Receive_nVertex; - -#endif - -} - -void CPhysicalGeometry::SetPositive_ZArea(CConfig *config) { - unsigned short iMarker, Boundary, Monitoring; - unsigned long iVertex, iPoint; - su2double *Normal, PositiveZArea; - int rank = MASTER_NODE; - -#ifndef HAVE_MPI - - PositiveZArea = 0.0; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - Boundary = config->GetMarker_All_KindBC(iMarker); - Monitoring = config->GetMarker_All_Monitoring(iMarker); - - if (((Boundary == EULER_WALL) || - (Boundary == HEAT_FLUX) || - (Boundary == ISOTHERMAL) || - (Boundary == LOAD_BOUNDARY) || - (Boundary == DISPLACEMENT_BOUNDARY)) && (Monitoring == YES)) - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - Normal = vertex[iMarker][iVertex]->GetNormal(); - if (Normal[nDim-1] < 0) PositiveZArea -= Normal[nDim-1]; - } - } - } - -#else - - su2double TotalPositiveZArea; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - PositiveZArea = 0.0; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - Boundary = config->GetMarker_All_KindBC(iMarker); - Monitoring = config->GetMarker_All_Monitoring(iMarker); - - if (((Boundary == EULER_WALL) || - (Boundary == HEAT_FLUX) || - (Boundary == ISOTHERMAL) || - (Boundary == LOAD_BOUNDARY) || - (Boundary == DISPLACEMENT_BOUNDARY)) && (Monitoring == YES)) - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - Normal = vertex[iMarker][iVertex]->GetNormal(); - if (Normal[nDim-1] < 0) PositiveZArea -= Normal[nDim-1]; - } - } - } - SU2_MPI::Reduce(&PositiveZArea, &TotalPositiveZArea, 1, MPI_DOUBLE, MPI_SUM, MASTER_NODE, MPI_COMM_WORLD); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if (rank == MASTER_NODE) PositiveZArea = TotalPositiveZArea; - SU2_MPI::Bcast(&PositiveZArea, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - -#endif - - if (config->GetRefAreaCoeff() == 0.0) - config->SetRefAreaCoeff(PositiveZArea); - - if (rank == MASTER_NODE) { - if (nDim == 2) cout << "Area projection in the y-plane = "<< PositiveZArea << "." << endl; - else cout << "Area projection in the z-plane = "<< PositiveZArea << "." << endl; - } - -} - -void CPhysicalGeometry::SetPoint_Connectivity(void) { - - unsigned short Node_Neighbor, iNode, iNeighbor; - unsigned long jElem, Point_Neighbor, iPoint, iElem; - - /*--- Loop over all the elements ---*/ - - for (iElem = 0; iElem < nElem; iElem++) - - /*--- Loop over all the nodes of an element ---*/ - - for (iNode = 0; iNode < elem[iElem]->GetnNodes(); iNode++) { - iPoint = elem[iElem]->GetNode(iNode); - - /*--- Store the element into the point ---*/ - - node[iPoint]->SetElem(iElem); - } - - /*--- Loop over all the points ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) - - /*--- Loop over all elements shared by the point ---*/ - - for (iElem = 0; iElem < node[iPoint]->GetnElem(); iElem++) { - - jElem = node[iPoint]->GetElem(iElem); - - /*--- If we find the point iPoint in the surronding element ---*/ - - for (iNode = 0; iNode < elem[jElem]->GetnNodes(); iNode++) - - if (elem[jElem]->GetNode(iNode) == iPoint) - - /*--- Localize the local index of the neighbor of iPoint in the element ---*/ - - for (iNeighbor = 0; iNeighbor < elem[jElem]->GetnNeighbor_Nodes(iNode); iNeighbor++) { - Node_Neighbor = elem[jElem]->GetNeighbor_Nodes(iNode, iNeighbor); - Point_Neighbor = elem[jElem]->GetNode(Node_Neighbor); - - /*--- Store the point into the point ---*/ - - node[iPoint]->SetPoint(Point_Neighbor); - } - } - - /*--- Set the number of neighbors variable, this is - important for JST and multigrid in parallel ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) - node[iPoint]->SetnNeighbor(node[iPoint]->GetnPoint()); - -} - -void CPhysicalGeometry::SetRCM_Ordering(CConfig *config) { - unsigned long iPoint, AdjPoint, AuxPoint, AddPoint, iElem, iNode, jNode; - vector Queue, AuxQueue, Result; - unsigned short Degree, MinDegree, iDim, iMarker; - bool *inQueue; - - inQueue = new bool [nPoint]; - - for (iPoint = 0; iPoint < nPoint; iPoint++) - inQueue[iPoint] = false; - - /*--- Select the node with the lowest degree in the grid. ---*/ - - MinDegree = node[0]->GetnNeighbor(); AddPoint = 0; - for (iPoint = 1; iPoint < nPointDomain; iPoint++) { - Degree = node[iPoint]->GetnPoint(); - if (Degree < MinDegree) { MinDegree = Degree; AddPoint = iPoint; } - } - - /*--- Add the node in the first free position. ---*/ - - Result.push_back(AddPoint); inQueue[AddPoint] = true; - - /*--- Loop until reorganize all the nodes ---*/ - - do { - - /*--- Add to the queue all the nodes adjacent in the increasing - order of their degree, checking if the element is already - in the Queue. ---*/ - - AuxQueue.clear(); - for (iNode = 0; iNode < node[AddPoint]->GetnPoint(); iNode++) { - AdjPoint = node[AddPoint]->GetPoint(iNode); - if ((!inQueue[AdjPoint]) && (AdjPoint < nPointDomain)) { - AuxQueue.push_back(AdjPoint); - } - } - - if (AuxQueue.size() != 0) { - - /*--- Sort the auxiliar queue based on the number of neighbors ---*/ - - for (iNode = 0; iNode < AuxQueue.size(); iNode++) { - for (jNode = 0; jNode < AuxQueue.size() - 1 - iNode; jNode++) { - if (node[AuxQueue[jNode]]->GetnPoint() > node[AuxQueue[jNode+1]]->GetnPoint()) { - AuxPoint = AuxQueue[jNode]; - AuxQueue[jNode] = AuxQueue[jNode+1]; - AuxQueue[jNode+1] = AuxPoint; - } - } - } - - Queue.insert(Queue.end(), AuxQueue.begin(), AuxQueue.end()); - for (iNode = 0; iNode < AuxQueue.size(); iNode++) { - inQueue[AuxQueue[iNode]] = true; - } - - } - - /*--- Extract the first node from the queue and add it in the first free - position. ---*/ - - if (Queue.size() != 0) { - AddPoint = Queue[0]; - Result.push_back(Queue[0]); - Queue.erase (Queue.begin(), Queue.begin()+1); - } - - /*--- Add to the queue all the nodes adjacent in the increasing - order of their degree, checking if the element is already - in the Queue. ---*/ - - } while (Queue.size() != 0); - - /*--- Check that all the points have been added ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - if (inQueue[iPoint] == false) Result.push_back(iPoint); - } - - delete[] inQueue; - - reverse(Result.begin(), Result.end()); - - /*--- Add the MPI points ---*/ - - for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { - Result.push_back(iPoint); - } - - /*--- Reset old data structures ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - node[iPoint]->ResetElem(); - node[iPoint]->ResetPoint(); - node[iPoint]->ResetBoundary(); - node[iPoint]->SetPhysicalBoundary(false); - node[iPoint]->SetSolidBoundary(false); - node[iPoint]->SetDomain(true); - } - - /*--- Set the new coordinates ---*/ - - su2double **AuxCoord; - unsigned long *AuxGlobalIndex; - - AuxGlobalIndex = new unsigned long [nPoint]; - AuxCoord = new su2double* [nPoint]; - for (iPoint = 0; iPoint < nPoint; iPoint++) - AuxCoord[iPoint] = new su2double [nDim]; - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - AuxGlobalIndex[iPoint] = node[iPoint]->GetGlobalIndex(); - for (iDim = 0; iDim < nDim; iDim++) { - AuxCoord[iPoint][iDim] = node[iPoint]->GetCoord(iDim); - } - } - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - node[iPoint]->SetGlobalIndex(AuxGlobalIndex[Result[iPoint]]); - for (iDim = 0; iDim < nDim; iDim++) - node[iPoint]->SetCoord(iDim, AuxCoord[Result[iPoint]][iDim]); - } - - for (iPoint = 0; iPoint < nPoint; iPoint++) - delete[] AuxCoord[iPoint]; - delete[] AuxCoord; - delete[] AuxGlobalIndex; - - /*--- Set the new conectivities ---*/ - - unsigned long *InvResult; - InvResult = new unsigned long [nPoint]; - for (iPoint = 0; iPoint < nPoint; iPoint++) - InvResult[Result[iPoint]] = iPoint; - - for (iElem = 0; iElem < nElem; iElem++) { - for (iNode = 0; iNode < elem[iElem]->GetnNodes(); iNode++) { - iPoint = elem[iElem]->GetNode(iNode); - elem[iElem]->SetNode(iNode, InvResult[iPoint]); - } - } - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) { - - string Marker_Tag = config->GetMarker_All_TagBound(iMarker); - if (Marker_Tag == "SEND_RECEIVE") { - for (unsigned long iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - if (config->GetMarker_All_SendRecv(iMarker) < 0) - node[bound[iMarker][iElem_Bound]->GetNode(0)]->SetDomain(false); - } - } - - for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { - iPoint = bound[iMarker][iElem]->GetNode(iNode); - bound[iMarker][iElem]->SetNode(iNode, InvResult[iPoint]); - node[InvResult[iPoint]]->SetBoundary(nMarker); - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE && - config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY && - config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY && - config->GetMarker_All_KindBC(iMarker) != PERIODIC_BOUNDARY) - node[InvResult[iPoint]]->SetPhysicalBoundary(true); - - if (config->GetMarker_All_KindBC(iMarker) == EULER_WALL || - config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX || - config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) - node[InvResult[iPoint]]->SetSolidBoundary(true); - } - } - } - - - delete[] InvResult; - -} - -void CPhysicalGeometry::SetElement_Connectivity(void) { - unsigned short first_elem_face, second_elem_face, iFace, iNode, jElem; - unsigned long face_point, Test_Elem, iElem; - - /*--- Loop over all the elements, faces and nodes ---*/ - - for (iElem = 0; iElem < nElem; iElem++) - for (iFace = 0; iFace < elem[iElem]->GetnFaces(); iFace++) - for (iNode = 0; iNode < elem[iElem]->GetnNodesFace(iFace); iNode++) { - face_point = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iNode)); - - /*--- Loop over all elements sharing the face point ---*/ - - for (jElem = 0; jElem < node[face_point]->GetnElem(); jElem++) { - Test_Elem = node[face_point]->GetElem(jElem); - - /*--- If it is a new element in this face ---*/ - - if ((elem[iElem]->GetNeighbor_Elements(iFace) == -1) && (iElem < Test_Elem) && - (FindFace(iElem, Test_Elem, first_elem_face, second_elem_face))) { - - /*--- Localice which faces are sharing both elements ---*/ - - elem[iElem]->SetNeighbor_Elements(Test_Elem, first_elem_face); - - /*--- Store the element for both elements ---*/ - - elem[Test_Elem]->SetNeighbor_Elements(iElem, second_elem_face); - - } - } - } -} - -void CPhysicalGeometry::SetBoundVolume(void) { - unsigned short cont, iMarker, iElem, iNode_Domain, iNode_Surface; - unsigned long Point_Domain, Point_Surface, Point, iElem_Surface, iElem_Domain; - bool CheckVol; - - for (iMarker = 0; iMarker < nMarker; iMarker++) - for (iElem_Surface = 0; iElem_Surface < nElem_Bound[iMarker]; iElem_Surface++) { - - /*--- Choose and arbitrary point from the surface --*/ - Point = bound[iMarker][iElem_Surface]->GetNode(0); - CheckVol = false; - - for (iElem = 0; iElem < node[Point]->GetnElem(); iElem++) { - /*--- Look for elements surronding that point --*/ - cont = 0; iElem_Domain = node[Point]->GetElem(iElem); - for (iNode_Domain = 0; iNode_Domain < elem[iElem_Domain]->GetnNodes(); iNode_Domain++) { - Point_Domain = elem[iElem_Domain]->GetNode(iNode_Domain); - for (iNode_Surface = 0; iNode_Surface < bound[iMarker][iElem_Surface]->GetnNodes(); iNode_Surface++) { - Point_Surface = bound[iMarker][iElem_Surface]->GetNode(iNode_Surface); - if (Point_Surface == Point_Domain) cont++; - if (cont == bound[iMarker][iElem_Surface]->GetnNodes()) break; - } - if (cont == bound[iMarker][iElem_Surface]->GetnNodes()) break; - } - - if (cont == bound[iMarker][iElem_Surface]->GetnNodes()) { - bound[iMarker][iElem_Surface]->SetDomainElement(iElem_Domain); - CheckVol = true; - break; - } - } - if (!CheckVol) { - cout << "The surface element ("<< iMarker <<", "<< iElem_Surface << ") doesn't have an associated volume element." << endl; - exit(EXIT_FAILURE); - } - } -} - -void CPhysicalGeometry::SetVertex(CConfig *config) { - unsigned long iPoint, iVertex, iElem; - unsigned short iMarker, iNode; - - /*--- Initialize the Vertex vector for each node of the grid ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) - for (iMarker = 0; iMarker < nMarker; iMarker++) - node[iPoint]->SetVertex(-1, iMarker); - - /*--- Create and compute the vector with the number of vertex per marker ---*/ - - nVertex = new unsigned long [nMarker]; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - /*--- Initialize the number of Bound Vertex for each Marker ---*/ - - nVertex[iMarker] = 0; - for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) - for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { - iPoint = bound[iMarker][iElem]->GetNode(iNode); - - /*--- Set the vertex in the node information ---*/ - - if ((node[iPoint]->GetVertex(iMarker) == -1) || (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE)) { - node[iPoint]->SetVertex(nVertex[iMarker], iMarker); - nVertex[iMarker]++; - } - } - } - - /*--- Initialize the Vertex vector for each node, the previous result is deleted ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) - for (iMarker = 0; iMarker < nMarker; iMarker++) - node[iPoint]->SetVertex(-1, iMarker); - - /*--- Create the bound vertex structure, note that the order - is the same as in the input file, this is important for Send/Receive part ---*/ - - vertex = new CVertex**[nMarker]; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - vertex[iMarker] = new CVertex* [nVertex[iMarker]]; - nVertex[iMarker] = 0; - - /*--- Initialize the number of Bound Vertex for each Marker ---*/ - - for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) - for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { - iPoint = bound[iMarker][iElem]->GetNode(iNode); - - /*--- Set the vertex in the node information ---*/ - - if ((node[iPoint]->GetVertex(iMarker) == -1) || (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE)) { - iVertex = nVertex[iMarker]; - vertex[iMarker][iVertex] = new CVertex(iPoint, nDim); - - if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { - vertex[iMarker][iVertex]->SetRotation_Type(bound[iMarker][iElem]->GetRotation_Type()); - } - node[iPoint]->SetVertex(nVertex[iMarker], iMarker); - nVertex[iMarker]++; - } - } - } -} - -void CPhysicalGeometry::SetCoord_CG(void) { - unsigned short nNode, iDim, iMarker, iNode; - unsigned long elem_poin, edge_poin, iElem, iEdge; - su2double **Coord; - - /*--- Compute the center of gravity for elements ---*/ - - for (iElem = 0; iElemGetnNodes(); - Coord = new su2double* [nNode]; - - /*--- Store the coordinates for all the element nodes ---*/ - - for (iNode = 0; iNode < nNode; iNode++) { - elem_poin = elem[iElem]->GetNode(iNode); - Coord[iNode] = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Coord[iNode][iDim]=node[elem_poin]->GetCoord(iDim); - } - - /*--- Compute the element CG coordinates ---*/ - - elem[iElem]->SetCoord_CG(Coord); - - for (iNode = 0; iNode < nNode; iNode++) - if (Coord[iNode] != NULL) delete[] Coord[iNode]; - if (Coord != NULL) delete[] Coord; - } - - /*--- Center of gravity for face elements ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) - for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) { - nNode = bound[iMarker][iElem]->GetnNodes(); - Coord = new su2double* [nNode]; - - /*--- Store the coordinates for all the element nodes ---*/ - - for (iNode = 0; iNode < nNode; iNode++) { - elem_poin = bound[iMarker][iElem]->GetNode(iNode); - Coord[iNode] = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Coord[iNode][iDim]=node[elem_poin]->GetCoord(iDim); - } - /*--- Compute the element CG coordinates ---*/ - - bound[iMarker][iElem]->SetCoord_CG(Coord); - for (iNode = 0; iNode < nNode; iNode++) - if (Coord[iNode] != NULL) delete[] Coord[iNode]; - if (Coord != NULL) delete[] Coord; - } - - /*--- Center of gravity for edges ---*/ - - for (iEdge = 0; iEdge < nEdge; iEdge++) { - nNode = edge[iEdge]->GetnNodes(); - Coord = new su2double* [nNode]; - - /*--- Store the coordinates for all the element nodes ---*/ - - for (iNode = 0; iNode < nNode; iNode++) { - edge_poin=edge[iEdge]->GetNode(iNode); - Coord[iNode] = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Coord[iNode][iDim]=node[edge_poin]->GetCoord(iDim); - } - - /*--- Compute the edge CG coordinates ---*/ - - edge[iEdge]->SetCoord_CG(Coord); - - for (iNode = 0; iNode < nNode; iNode++) - if (Coord[iNode] != NULL) delete[] Coord[iNode]; - if (Coord != NULL) delete[] Coord; - } -} - -void CPhysicalGeometry::SetBoundControlVolume(CConfig *config, unsigned short action) { - unsigned short Neighbor_Node, iMarker, iNode, iNeighbor_Nodes, iDim; - unsigned long Neighbor_Point, iVertex, iPoint, iElem; - long iEdge; - su2double Area, *NormalFace = NULL; - - /*--- Update values of faces of the edge ---*/ - - if (action != ALLOCATE) - for (iMarker = 0; iMarker < nMarker; iMarker++) - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) - vertex[iMarker][iVertex]->SetZeroValues(); - - su2double *Coord_Edge_CG = new su2double [nDim]; - su2double *Coord_Elem_CG = new su2double [nDim]; - su2double *Coord_Vertex = new su2double [nDim]; - - /*--- Loop over all the markers ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) - - /*--- Loop over all the boundary elements ---*/ - - for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) - - /*--- Loop over all the nodes of the boundary ---*/ - - for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { - iPoint = bound[iMarker][iElem]->GetNode(iNode); - iVertex = node[iPoint]->GetVertex(iMarker); - - /*--- Loop over the neighbor nodes, there is a face for each one ---*/ - - for (iNeighbor_Nodes = 0; iNeighbor_Nodes < bound[iMarker][iElem]->GetnNeighbor_Nodes(iNode); iNeighbor_Nodes++) { - Neighbor_Node = bound[iMarker][iElem]->GetNeighbor_Nodes(iNode, iNeighbor_Nodes); - Neighbor_Point = bound[iMarker][iElem]->GetNode(Neighbor_Node); - - /*--- Shared edge by the Neighbor Point and the point ---*/ - - iEdge = FindEdge(iPoint, Neighbor_Point); - for (iDim = 0; iDim < nDim; iDim++) { - Coord_Edge_CG[iDim] = edge[iEdge]->GetCG(iDim); - Coord_Elem_CG[iDim] = bound[iMarker][iElem]->GetCG(iDim); - Coord_Vertex[iDim] = node[iPoint]->GetCoord(iDim); - } - switch (nDim) { - case 2: - - /*--- Store the 2D face ---*/ - - if (iNode == 0) vertex[iMarker][iVertex]->SetNodes_Coord(Coord_Elem_CG, Coord_Vertex); - if (iNode == 1) vertex[iMarker][iVertex]->SetNodes_Coord(Coord_Vertex, Coord_Elem_CG); - break; - case 3: - - /*--- Store the 3D face ---*/ - - if (iNeighbor_Nodes == 0) vertex[iMarker][iVertex]->SetNodes_Coord(Coord_Elem_CG, Coord_Edge_CG, Coord_Vertex); - if (iNeighbor_Nodes == 1) vertex[iMarker][iVertex]->SetNodes_Coord(Coord_Edge_CG, Coord_Elem_CG, Coord_Vertex); - break; - } - } - } - - delete[] Coord_Edge_CG; - delete[] Coord_Elem_CG; - delete[] Coord_Vertex; - - /*--- Check if there is a normal with null area ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker ++) - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - NormalFace = vertex[iMarker][iVertex]->GetNormal(); - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += NormalFace[iDim]*NormalFace[iDim]; - Area = sqrt(Area); - if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS; - } - -} - -void CPhysicalGeometry::MatchInterface(CConfig *config) { - su2double epsilon = 1.5e-1; - - unsigned short nMarker_InterfaceBound = config->GetnMarker_InterfaceBound(); - - if (nMarker_InterfaceBound != 0) { -#ifndef HAVE_MPI - - unsigned short iMarker, jMarker; - unsigned long iVertex, iPoint, jVertex, jPoint = 0, pPoint = 0; - su2double *Coord_i, *Coord_j, dist = 0.0, mindist, maxdist; - - cout << "Set Interface boundary conditions." << endl; - - maxdist = 0.0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - Coord_i = node[iPoint]->GetCoord(); - - mindist = 1E6; - for (jMarker = 0; jMarker < config->GetnMarker_All(); jMarker++) - if ((config->GetMarker_All_KindBC(jMarker) == INTERFACE_BOUNDARY) && (iMarker != jMarker)) - for (jVertex = 0; jVertex < nVertex[jMarker]; jVertex++) { - jPoint = vertex[jMarker][jVertex]->GetNode(); - Coord_j = node[jPoint]->GetCoord(); - if (nDim == 2) dist = sqrt(pow(Coord_j[0]-Coord_i[0],2.0) + pow(Coord_j[1]-Coord_i[1],2.0)); - if (nDim == 3) dist = sqrt(pow(Coord_j[0]-Coord_i[0],2.0) + pow(Coord_j[1]-Coord_i[1],2.0) + pow(Coord_j[2]-Coord_i[2],2.0)); - if (dist < mindist) {mindist = dist; pPoint = jPoint;} - } - maxdist = max(maxdist, mindist); - vertex[iMarker][iVertex]->SetDonorPoint(pPoint, MASTER_NODE); - - if (mindist > epsilon) { - cout.precision(10); - cout << endl; - cout << " Bad match for point " << iPoint << ".\tNearest"; - cout << " donor distance: " << scientific << mindist << "."; - vertex[iMarker][iVertex]->SetDonorPoint(iPoint, MASTER_NODE); - maxdist = min(maxdist, 0.0); - } - - } - cout <<"The max distance between points is: " << maxdist <<"."<< endl; - } - -#else - - unsigned short iMarker, iDim; - unsigned long iVertex, iPoint, pPoint = 0, jVertex, jPoint; - su2double *Coord_i, Coord_j[3], dist = 0.0, mindist, maxdist_local, maxdist_global; - int iProcessor, pProcessor = 0; - unsigned long nLocalVertex_Interface = 0, nGlobalVertex_Interface = 0, MaxLocalVertex_Interface = 0; - int rank, nProcessor; - - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); - - unsigned long *Buffer_Send_nVertex = new unsigned long [1]; - unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor]; - - if (rank == MASTER_NODE) cout << "Set Interface boundary conditions (if any)." << endl; - - /*--- Compute the number of vertex that have interfase boundary condition - without including the ghost nodes ---*/ - - nLocalVertex_Interface = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) - for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) nLocalVertex_Interface ++; - } - - Buffer_Send_nVertex[0] = nLocalVertex_Interface; - - /*--- Send Interface vertex information --*/ - - SU2_MPI::Allreduce(&nLocalVertex_Interface, &nGlobalVertex_Interface, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalVertex_Interface, &MaxLocalVertex_Interface, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - - su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_Interface*nDim]; - unsigned long *Buffer_Send_Point = new unsigned long [MaxLocalVertex_Interface]; - - su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_Interface*nDim]; - unsigned long *Buffer_Receive_Point = new unsigned long [nProcessor*MaxLocalVertex_Interface]; - - unsigned long nBuffer_Coord = MaxLocalVertex_Interface*nDim; - unsigned long nBuffer_Point = MaxLocalVertex_Interface; - - for (iVertex = 0; iVertex < MaxLocalVertex_Interface; iVertex++) { - Buffer_Send_Point[iVertex] = 0; - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; - } - - /*--- Copy coordinates and point to the auxiliar vector --*/ - - nLocalVertex_Interface = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) - for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - Buffer_Send_Point[nLocalVertex_Interface] = iPoint; - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[nLocalVertex_Interface*nDim+iDim] = node[iPoint]->GetCoord(iDim); - nLocalVertex_Interface++; - } - } - - SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_Point, nBuffer_Point, MPI_UNSIGNED_LONG, Buffer_Receive_Point, nBuffer_Point, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - - /*--- Compute the closest point to a Near-Field boundary point ---*/ - - maxdist_local = 0.0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - - /*--- Coordinates of the boundary point ---*/ - - Coord_i = node[iPoint]->GetCoord(); mindist = 1E6; pProcessor = 0; pPoint = 0; - - /*--- Loop over all the boundaries to find the pair ---*/ - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) - for (jVertex = 0; jVertex < Buffer_Receive_nVertex[iProcessor]; jVertex++) { - jPoint = Buffer_Receive_Point[iProcessor*MaxLocalVertex_Interface+jVertex]; - - /*--- Compute the distance ---*/ - - dist = 0.0; for (iDim = 0; iDim < nDim; iDim++) { - Coord_j[iDim] = Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_Interface+jVertex)*nDim+iDim]; - dist += pow(Coord_j[iDim]-Coord_i[iDim],2.0); - } dist = sqrt(dist); - - if (((dist < mindist) && (iProcessor != rank)) || - ((dist < mindist) && (iProcessor == rank) && (jPoint != iPoint))) { - mindist = dist; pProcessor = iProcessor; pPoint = jPoint; - } - } - - /*--- Store the value of the pair ---*/ - - maxdist_local = max(maxdist_local, mindist); - vertex[iMarker][iVertex]->SetDonorPoint(pPoint, pProcessor); - - if (mindist > epsilon) { - cout.precision(10); - cout << endl; - cout << " Bad match for point " << iPoint << ".\tNearest"; - cout << " donor distance: " << scientific << mindist << "."; - vertex[iMarker][iVertex]->SetDonorPoint(iPoint, pProcessor); - maxdist_local = min(maxdist_local, 0.0); - } - - } - } - } - } - - SU2_MPI::Reduce(&maxdist_local, &maxdist_global, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, MPI_COMM_WORLD); - - if (rank == MASTER_NODE) cout <<"The max distance between points is: " << maxdist_global <<"."<< endl; - - delete[] Buffer_Send_Coord; - delete[] Buffer_Send_Point; - - delete[] Buffer_Receive_Coord; - delete[] Buffer_Receive_Point; - - delete[] Buffer_Send_nVertex; - delete[] Buffer_Receive_nVertex; - -#endif - - } - -} - -void CPhysicalGeometry::MatchNearField(CConfig *config) { - su2double epsilon = 1e-1; - - unsigned short nMarker_NearfieldBound = config->GetnMarker_NearFieldBound(); - - if (nMarker_NearfieldBound != 0) { - -#ifndef HAVE_MPI - - unsigned short iMarker, jMarker; - unsigned long iVertex, iPoint, jVertex, jPoint = 0, pPoint = 0; - su2double *Coord_i, *Coord_j, dist = 0.0, mindist, maxdist; - - cout << "Set Near-Field boundary conditions. " << endl; - - maxdist = 0.0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - Coord_i = node[iPoint]->GetCoord(); - - mindist = 1e10; - for (jMarker = 0; jMarker < config->GetnMarker_All(); jMarker++) - if ((config->GetMarker_All_KindBC(jMarker) == NEARFIELD_BOUNDARY) && (iMarker != jMarker)) - for (jVertex = 0; jVertex < nVertex[jMarker]; jVertex++) { - jPoint = vertex[jMarker][jVertex]->GetNode(); - Coord_j = node[jPoint]->GetCoord(); - if (nDim == 2) dist = sqrt(pow(Coord_j[0]-Coord_i[0],2.0) + pow(Coord_j[1]-Coord_i[1],2.0)); - if (nDim == 3) dist = sqrt(pow(Coord_j[0]-Coord_i[0],2.0) + pow(Coord_j[1]-Coord_i[1],2.0) + pow(Coord_j[2]-Coord_i[2],2.0)); - if (dist < mindist) { mindist = dist; pPoint = jPoint; } - } - maxdist = max(maxdist, mindist); - vertex[iMarker][iVertex]->SetDonorPoint(pPoint, MASTER_NODE); - - if (mindist > epsilon) { - cout.precision(10); - cout << endl; - cout << " Bad match for point " << iPoint << ".\tNearest"; - cout << " donor distance: " << scientific << mindist << "."; - vertex[iMarker][iVertex]->SetDonorPoint(iPoint, MASTER_NODE); - maxdist = min(maxdist, 0.0); - } - } - cout <<"The max distance between points is: " << maxdist <<"."<< endl; - } - -#else - - unsigned short iMarker, iDim; - unsigned long iVertex, iPoint, pPoint = 0, jVertex, jPoint; - su2double *Coord_i, Coord_j[3], dist = 0.0, mindist, maxdist_local, maxdist_global; - int iProcessor, pProcessor = 0; - unsigned long nLocalVertex_NearField = 0, nGlobalVertex_NearField = 0, MaxLocalVertex_NearField = 0; - int rank, nProcessor; - - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); - - unsigned long *Buffer_Send_nVertex = new unsigned long [1]; - unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor]; - - if (rank == MASTER_NODE) cout << "Set Near-Field boundary conditions." << endl; - - /*--- Compute the number of vertex that have nearfield boundary condition - without including the ghost nodes ---*/ - - nLocalVertex_NearField = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) - for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) nLocalVertex_NearField ++; - } - - Buffer_Send_nVertex[0] = nLocalVertex_NearField; - - /*--- Send Near-Field vertex information --*/ - - SU2_MPI::Allreduce(&nLocalVertex_NearField, &nGlobalVertex_NearField, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalVertex_NearField, &MaxLocalVertex_NearField, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - - su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_NearField*nDim]; - unsigned long *Buffer_Send_Point = new unsigned long [MaxLocalVertex_NearField]; - - su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_NearField*nDim]; - unsigned long *Buffer_Receive_Point = new unsigned long [nProcessor*MaxLocalVertex_NearField]; - - unsigned long nBuffer_Coord = MaxLocalVertex_NearField*nDim; - unsigned long nBuffer_Point = MaxLocalVertex_NearField; - - for (iVertex = 0; iVertex < MaxLocalVertex_NearField; iVertex++) { - Buffer_Send_Point[iVertex] = 0; - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; - } - - /*--- Copy coordinates and point to the auxiliar vector --*/ - - nLocalVertex_NearField = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) - for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - Buffer_Send_Point[nLocalVertex_NearField] = iPoint; - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[nLocalVertex_NearField*nDim+iDim] = node[iPoint]->GetCoord(iDim); - nLocalVertex_NearField++; - } - } - - SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_Point, nBuffer_Point, MPI_UNSIGNED_LONG, Buffer_Receive_Point, nBuffer_Point, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - - /*--- Compute the closest point to a Near-Field boundary point ---*/ - - maxdist_local = 0.0; - maxdist_global = 0.0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { - - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - - /*--- Coordinates of the boundary point ---*/ - - Coord_i = node[iPoint]->GetCoord(); mindist = 1E6; pProcessor = 0; pPoint = 0; - - /*--- Loop over all the boundaries to find the pair ---*/ - - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) - for (jVertex = 0; jVertex < Buffer_Receive_nVertex[iProcessor]; jVertex++) { - jPoint = Buffer_Receive_Point[iProcessor*MaxLocalVertex_NearField+jVertex]; - - /*--- Compute the distance ---*/ - - dist = 0.0; for (iDim = 0; iDim < nDim; iDim++) { - Coord_j[iDim] = Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_NearField+jVertex)*nDim+iDim]; - dist += pow(Coord_j[iDim]-Coord_i[iDim],2.0); - } dist = sqrt(dist); - - if (((dist < mindist) && (iProcessor != rank)) || - ((dist < mindist) && (iProcessor == rank) && (jPoint != iPoint))) { - mindist = dist; pProcessor = iProcessor; pPoint = jPoint; - } - } - - /*--- Store the value of the pair ---*/ - - maxdist_local = max(maxdist_local, mindist); - vertex[iMarker][iVertex]->SetDonorPoint(pPoint, pProcessor); - - if (mindist > epsilon) { - cout.precision(10); - cout << endl; - cout << " Bad match for point " << iPoint << ".\tNearest"; - cout << " donor distance: " << scientific << mindist << "."; - vertex[iMarker][iVertex]->SetDonorPoint(iPoint, pProcessor); - maxdist_local = min(maxdist_local, 0.0); - } - - } - } - - } - } - - SU2_MPI::Reduce(&maxdist_local, &maxdist_global, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, MPI_COMM_WORLD); - - if (rank == MASTER_NODE) cout <<"The max distance between points is: " << maxdist_global <<"."<< endl; - - delete[] Buffer_Send_Coord; - delete[] Buffer_Send_Point; - - delete[] Buffer_Receive_Coord; - delete[] Buffer_Receive_Point; - - delete[] Buffer_Send_nVertex; - delete[] Buffer_Receive_nVertex; - -#endif - - } - -} - -void CPhysicalGeometry::MatchActuator_Disk(CConfig *config) { - su2double epsilon = 1e-1; - unsigned short iMarker, iDim; - unsigned long iVertex, iPoint, pPoint = 0, jVertex, jPoint; - su2double *Coord_i, Coord_j[3], dist = 0.0, mindist, maxdist_local = 0.0, maxdist_global = 0.0; - int iProcessor, pProcessor = 0; - unsigned long nLocalVertex_ActDisk = 0, MaxLocalVertex_ActDisk = 0; - int rank, nProcessor; - unsigned short Beneficiary = 0, Donor = 0, iBC; - - unsigned short nMarker_ActDisk_Inlet = config->GetnMarker_ActDisk_Inlet(); - - if (nMarker_ActDisk_Inlet != 0) { - - for (iBC = 0; iBC < 2; iBC++) { - - if (iBC == 0) { Beneficiary = ACTDISK_INLET; Donor = ACTDISK_OUTLET; } - if (iBC == 1) { Beneficiary = ACTDISK_OUTLET; Donor = ACTDISK_INLET; } - -#ifndef HAVE_MPI - rank = MASTER_NODE; - nProcessor = SINGLE_NODE; -#else - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); -#endif - - unsigned long *Buffer_Send_nVertex = new unsigned long [1]; - unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor]; - - if ((iBC == 0) && (rank == MASTER_NODE)) cout << "Set Actuator Disk inlet boundary conditions." << endl; - if ((iBC == 1) && (rank == MASTER_NODE)) cout << "Set Actuator Disk outlet boundary conditions." << endl; - - /*--- Compute the number of vertex that have an actuator disk outlet boundary condition - without including the ghost nodes ---*/ - - nLocalVertex_ActDisk = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == Donor) { - for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) nLocalVertex_ActDisk ++; - } - } - } - - Buffer_Send_nVertex[0] = nLocalVertex_ActDisk; - - /*--- Send actuator disk vertex information --*/ - -#ifndef HAVE_MPI - MaxLocalVertex_ActDisk = nLocalVertex_ActDisk; - Buffer_Receive_nVertex[0] = Buffer_Send_nVertex[0]; -#else - SU2_MPI::Allreduce(&nLocalVertex_ActDisk, &MaxLocalVertex_ActDisk, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#endif - - /*--- Array dimensionalization --*/ - - su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_ActDisk*nDim]; - unsigned long *Buffer_Send_Point = new unsigned long [MaxLocalVertex_ActDisk]; - - su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_ActDisk*nDim]; - unsigned long *Buffer_Receive_Point = new unsigned long [nProcessor*MaxLocalVertex_ActDisk]; - - unsigned long nBuffer_Coord = MaxLocalVertex_ActDisk*nDim; - unsigned long nBuffer_Point = MaxLocalVertex_ActDisk; - - for (iVertex = 0; iVertex < MaxLocalVertex_ActDisk; iVertex++) { - Buffer_Send_Point[iVertex] = 0; - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; - } - - /*--- Copy coordinates and point to the auxiliar vector --*/ - - nLocalVertex_ActDisk = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == Donor) { - for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - Buffer_Send_Point[nLocalVertex_ActDisk] = iPoint; - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[nLocalVertex_ActDisk*nDim+iDim] = node[iPoint]->GetCoord(iDim); - nLocalVertex_ActDisk++; - } - } - } - } - -#ifndef HAVE_MPI - for (unsigned long iBuffer_Coord = 0; iBuffer_Coord < nBuffer_Coord; iBuffer_Coord++) - Buffer_Receive_Coord[iBuffer_Coord] = Buffer_Send_Coord[iBuffer_Coord]; - for (unsigned long iBuffer_Point = 0; iBuffer_Point < nBuffer_Point; iBuffer_Point++) - Buffer_Receive_Point[iBuffer_Point] = Buffer_Send_Point[iBuffer_Point]; -#else - SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_Point, nBuffer_Point, MPI_UNSIGNED_LONG, Buffer_Receive_Point, nBuffer_Point, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#endif - - /*--- Compute the closest point to an actuator disk inlet point ---*/ - - maxdist_local = 0.0; - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == Beneficiary) { - - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - - /*--- Coordinates of the boundary point ---*/ - - Coord_i = node[iPoint]->GetCoord(); mindist = 1E6; pProcessor = 0; pPoint = 0; - - /*--- Loop over all the boundaries to find the pair ---*/ - - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (jVertex = 0; jVertex < Buffer_Receive_nVertex[iProcessor]; jVertex++) { - jPoint = Buffer_Receive_Point[iProcessor*MaxLocalVertex_ActDisk+jVertex]; - - /*--- Compute the distance ---*/ - - dist = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Coord_j[iDim] = Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_ActDisk+jVertex)*nDim+iDim]; - dist += pow(Coord_j[iDim]-Coord_i[iDim], 2.0); - } - dist = sqrt(dist); - - if (dist < mindist) { - mindist = dist; pProcessor = iProcessor; pPoint = jPoint; - if (dist == 0.0) break; - } - - } - } - - /*--- Store the value of the pair ---*/ - - maxdist_local = max(maxdist_local, mindist); - vertex[iMarker][iVertex]->SetDonorPoint(pPoint, pProcessor); - - if (mindist > epsilon) { - cout.precision(10); - cout << endl; - cout << " Bad match for point " << iPoint << ".\tNearest"; - cout << " donor distance: " << scientific << mindist << "."; - vertex[iMarker][iVertex]->SetDonorPoint(iPoint, pProcessor); - maxdist_local = min(maxdist_local, 0.0); - } - - } - } - - } - } - -#ifndef HAVE_MPI - maxdist_global = maxdist_local; -#else - SU2_MPI::Reduce(&maxdist_local, &maxdist_global, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, MPI_COMM_WORLD); -#endif - - if (rank == MASTER_NODE) cout <<"The max distance between points is: " << maxdist_global <<"."<< endl; - - delete[] Buffer_Send_Coord; - delete[] Buffer_Send_Point; - - delete[] Buffer_Receive_Coord; - delete[] Buffer_Receive_Point; - - delete[] Buffer_Send_nVertex; - delete[] Buffer_Receive_nVertex; - - } - } - -} - -void CPhysicalGeometry::MatchZone(CConfig *config, CGeometry *geometry_donor, CConfig *config_donor, - unsigned short val_iZone, unsigned short val_nZone) { - -#ifndef HAVE_MPI - - unsigned short iMarker, jMarker; - unsigned long iVertex, iPoint, jVertex, jPoint = 0, pPoint = 0; - su2double *Coord_i, *Coord_j, dist = 0.0, mindist, maxdist; - - if (val_iZone == ZONE_0) cout << "Set zone boundary conditions (if any)." << endl; - - maxdist = 0.0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - Coord_i = node[iPoint]->GetCoord(); - - mindist = 1E6; - for (jMarker = 0; jMarker < config_donor->GetnMarker_All(); jMarker++) - for (jVertex = 0; jVertex < geometry_donor->GetnVertex(jMarker); jVertex++) { - jPoint = geometry_donor->vertex[jMarker][jVertex]->GetNode(); - Coord_j = geometry_donor->node[jPoint]->GetCoord(); - if (nDim == 2) dist = sqrt(pow(Coord_j[0]-Coord_i[0],2.0) + pow(Coord_j[1]-Coord_i[1],2.0)); - if (nDim == 3) dist = sqrt(pow(Coord_j[0]-Coord_i[0],2.0) + pow(Coord_j[1]-Coord_i[1],2.0) + pow(Coord_j[2]-Coord_i[2],2.0)); - if (dist < mindist) { mindist = dist; pPoint = jPoint; } - } - - maxdist = max(maxdist, mindist); - vertex[iMarker][iVertex]->SetDonorPoint(pPoint, MASTER_NODE); - - } - } - -#else - - unsigned short iMarker, iDim; - unsigned long iVertex, iPoint, pPoint = 0, jVertex, jPoint; - su2double *Coord_i, Coord_j[3], dist = 0.0, mindist, maxdist; - int iProcessor, pProcessor = 0; - unsigned long nLocalVertex_Zone = 0, nGlobalVertex_Zone = 0, MaxLocalVertex_Zone = 0; - int rank, nProcessor; - - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); - - unsigned long *Buffer_Send_nVertex = new unsigned long [1]; - unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor]; - - if (val_iZone == ZONE_0) cout << "Set zone boundary conditions (if any)." << endl; - - nLocalVertex_Zone = 0; - for (iMarker = 0; iMarker < config_donor->GetnMarker_All(); iMarker++) - for (iVertex = 0; iVertex < geometry_donor->GetnVertex(iMarker); iVertex++) { - iPoint = geometry_donor->vertex[iMarker][iVertex]->GetNode(); - if (geometry_donor->node[iPoint]->GetDomain()) nLocalVertex_Zone ++; - } - - Buffer_Send_nVertex[0] = nLocalVertex_Zone; - - /*--- Send Interface vertex information --*/ - - SU2_MPI::Allreduce(&nLocalVertex_Zone, &nGlobalVertex_Zone, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalVertex_Zone, &MaxLocalVertex_Zone, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - - su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_Zone*nDim]; - unsigned long *Buffer_Send_Point = new unsigned long [MaxLocalVertex_Zone]; - - su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_Zone*nDim]; - unsigned long *Buffer_Receive_Point = new unsigned long [nProcessor*MaxLocalVertex_Zone]; - - unsigned long nBuffer_Coord = MaxLocalVertex_Zone*nDim; - unsigned long nBuffer_Point = MaxLocalVertex_Zone; - - for (iVertex = 0; iVertex < MaxLocalVertex_Zone; iVertex++) { - Buffer_Send_Point[iVertex] = 0; - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; - } - - /*--- Copy coordinates and point to the auxiliar vector --*/ - nLocalVertex_Zone = 0; - for (iMarker = 0; iMarker < config_donor->GetnMarker_All(); iMarker++) - for (iVertex = 0; iVertex < geometry_donor->GetnVertex(iMarker); iVertex++) { - iPoint = geometry_donor->vertex[iMarker][iVertex]->GetNode(); - if (geometry_donor->node[iPoint]->GetDomain()) { - Buffer_Send_Point[nLocalVertex_Zone] = iPoint; - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[nLocalVertex_Zone*nDim+iDim] = geometry_donor->node[iPoint]->GetCoord(iDim); - nLocalVertex_Zone++; - } - } - - SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_Point, nBuffer_Point, MPI_UNSIGNED_LONG, Buffer_Receive_Point, nBuffer_Point, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - - /*--- Compute the closest point to a Near-Field boundary point ---*/ - maxdist = 0.0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - - if (node[iPoint]->GetDomain()) { - - /*--- Coordinates of the boundary point ---*/ - Coord_i = node[iPoint]->GetCoord(); mindist = 1E6; pProcessor = 0; pPoint = 0; - - /*--- Loop over all the boundaries to find the pair ---*/ - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) - for (jVertex = 0; jVertex < Buffer_Receive_nVertex[iProcessor]; jVertex++) { - jPoint = Buffer_Receive_Point[iProcessor*MaxLocalVertex_Zone+jVertex]; - - /*--- Compute the distance ---*/ - dist = 0.0; for (iDim = 0; iDim < nDim; iDim++) { - Coord_j[iDim] = Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_Zone+jVertex)*nDim+iDim]; - dist += pow(Coord_j[iDim]-Coord_i[iDim],2.0); - } dist = sqrt(dist); - - if (((dist < mindist) && (iProcessor != rank)) || - ((dist < mindist) && (iProcessor == rank) && (jPoint != iPoint))) { - mindist = dist; pProcessor = iProcessor; pPoint = jPoint; - } - } - - /*--- Store the value of the pair ---*/ - maxdist = max(maxdist, mindist); - vertex[iMarker][iVertex]->SetDonorPoint(pPoint, pProcessor); - - - } - } - } - - delete[] Buffer_Send_Coord; - delete[] Buffer_Send_Point; - - delete[] Buffer_Receive_Coord; - delete[] Buffer_Receive_Point; - - delete[] Buffer_Send_nVertex; - delete[] Buffer_Receive_nVertex; - -#endif - -} - - -void CPhysicalGeometry::SetControlVolume(CConfig *config, unsigned short action) { - unsigned long face_iPoint = 0, face_jPoint = 0, iPoint, iElem; - long iEdge; - unsigned short nEdgesFace = 1, iFace, iEdgesFace, iDim; - su2double *Coord_Edge_CG, *Coord_FaceElem_CG, *Coord_Elem_CG, *Coord_FaceiPoint, *Coord_FacejPoint, Area, - Volume, DomainVolume, my_DomainVolume, *NormalFace = NULL; - bool change_face_orientation; - int rank; - -#ifndef HAVE_MPI - rank = MASTER_NODE; -#else - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Update values of faces of the edge ---*/ - if (action != ALLOCATE) { - for (iEdge = 0; iEdge < (long)nEdge; iEdge++) - edge[iEdge]->SetZeroValues(); - for (iPoint = 0; iPoint < nPoint; iPoint++) - node[iPoint]->SetVolume (0.0); - } - - Coord_Edge_CG = new su2double [nDim]; - Coord_FaceElem_CG = new su2double [nDim]; - Coord_Elem_CG = new su2double [nDim]; - Coord_FaceiPoint = new su2double [nDim]; - Coord_FacejPoint = new su2double [nDim]; - - my_DomainVolume = 0.0; - for (iElem = 0; iElem < nElem; iElem++) - for (iFace = 0; iFace < elem[iElem]->GetnFaces(); iFace++) { - - /*--- In 2D all the faces have only one edge ---*/ - if (nDim == 2) nEdgesFace = 1; - /*--- In 3D the number of edges per face is the same as the number of point per face ---*/ - if (nDim == 3) nEdgesFace = elem[iElem]->GetnNodesFace(iFace); - - /*-- Loop over the edges of a face ---*/ - for (iEdgesFace = 0; iEdgesFace < nEdgesFace; iEdgesFace++) { - - /*--- In 2D only one edge (two points) per edge ---*/ - if (nDim == 2) { - face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0)); - face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,1)); - } - - /*--- In 3D there are several edges in each face ---*/ - if (nDim == 3) { - face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iEdgesFace)); - if (iEdgesFace != nEdgesFace-1) - face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iEdgesFace+1)); - else - face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0)); - } - - /*--- We define a direction (from the smalest index to the greatest) --*/ - change_face_orientation = false; - if (face_iPoint > face_jPoint) change_face_orientation = true; - iEdge = FindEdge(face_iPoint, face_jPoint); - - for (iDim = 0; iDim < nDim; iDim++) { - Coord_Edge_CG[iDim] = edge[iEdge]->GetCG(iDim); - Coord_Elem_CG[iDim] = elem[iElem]->GetCG(iDim); - Coord_FaceElem_CG[iDim] = elem[iElem]->GetFaceCG(iFace, iDim); - Coord_FaceiPoint[iDim] = node[face_iPoint]->GetCoord(iDim); - Coord_FacejPoint[iDim] = node[face_jPoint]->GetCoord(iDim); - } - - switch (nDim) { - case 2: - /*--- Two dimensional problem ---*/ - if (change_face_orientation) edge[iEdge]->SetNodes_Coord(Coord_Elem_CG, Coord_Edge_CG); - else edge[iEdge]->SetNodes_Coord(Coord_Edge_CG, Coord_Elem_CG); - Area = edge[iEdge]->GetVolume(Coord_FaceiPoint, Coord_Edge_CG, Coord_Elem_CG); - node[face_iPoint]->AddVolume(Area); my_DomainVolume +=Area; - Area = edge[iEdge]->GetVolume(Coord_FacejPoint, Coord_Edge_CG, Coord_Elem_CG); - node[face_jPoint]->AddVolume(Area); my_DomainVolume +=Area; - break; - case 3: - /*--- Three dimensional problem ---*/ - if (change_face_orientation) edge[iEdge]->SetNodes_Coord(Coord_FaceElem_CG, Coord_Edge_CG, Coord_Elem_CG); - else edge[iEdge]->SetNodes_Coord(Coord_Edge_CG, Coord_FaceElem_CG, Coord_Elem_CG); - Volume = edge[iEdge]->GetVolume(Coord_FaceiPoint, Coord_Edge_CG, Coord_FaceElem_CG, Coord_Elem_CG); - node[face_iPoint]->AddVolume(Volume); my_DomainVolume +=Volume; - Volume = edge[iEdge]->GetVolume(Coord_FacejPoint, Coord_Edge_CG, Coord_FaceElem_CG, Coord_Elem_CG); - node[face_jPoint]->AddVolume(Volume); my_DomainVolume +=Volume; - break; - } - } - } - - /*--- Check if there is a normal with null area ---*/ - for (iEdge = 0; iEdge < (long)nEdge; iEdge++) { - NormalFace = edge[iEdge]->GetNormal(); - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += NormalFace[iDim]*NormalFace[iDim]; - Area = sqrt(Area); - if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS; - } - - -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&my_DomainVolume, &DomainVolume, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); -#else - DomainVolume = my_DomainVolume; -#endif - - if ((rank == MASTER_NODE) && (action == ALLOCATE)) { - if (nDim == 2) cout <<"Area of the computational grid: "<< DomainVolume <<"."<< endl; - if (nDim == 3) cout <<"Volume of the computational grid: "<< DomainVolume <<"."<< endl; - } - - config->SetDomainVolume(DomainVolume); - - delete[] Coord_Edge_CG; - delete[] Coord_FaceElem_CG; - delete[] Coord_Elem_CG; - delete[] Coord_FaceiPoint; - delete[] Coord_FacejPoint; -} - -void CPhysicalGeometry::VisualizeControlVolume(CConfig *config, unsigned short action) { - - /*--- This routine is only meant for visualization in serial currently ---*/ -#ifndef HAVE_MPI - - unsigned long face_iPoint = 0, face_jPoint = 0, iElem, iPoint_Viz; - long iEdge; - unsigned short nEdgesFace = 1, iFace, iEdgesFace, iDim; - su2double *Coord_Edge_CG, *Coord_FaceElem_CG, *Coord_Elem_CG, *Coord_FaceiPoint, - *Coord_FacejPoint; - int counter = 0; - char cstr[MAX_STRING_SIZE], buffer[50]; - ofstream Tecplot_File; - string mesh_filename; - vector X, Y, Z, X_n, Y_n, Z_n; - su2double r1[3], r2[3], CrossProduct[3]; - - /*--- Access the point number for control volume we want to vizualize ---*/ - - iPoint_Viz = config->GetVisualize_CV(); - - /*--- Allocate some structures for building the dual CVs ---*/ - - Coord_Edge_CG = new su2double [nDim]; - Coord_FaceElem_CG = new su2double [nDim]; - Coord_Elem_CG = new su2double [nDim]; - Coord_FaceiPoint = new su2double [nDim]; - Coord_FacejPoint = new su2double [nDim]; - - /*--- Loop over each face of each element ---*/ - - CrossProduct[0] = 0.0; CrossProduct[1] = 0.0; CrossProduct[2] = 0.0; - - for (iElem = 0; iElem < nElem; iElem++) { - - for (iFace = 0; iFace < elem[iElem]->GetnFaces(); iFace++) { - - /*--- In 2D all the faces have only one edge ---*/ - if (nDim == 2) nEdgesFace = 1; - /*--- In 3D the number of edges per face is the same as the number of point per face ---*/ - if (nDim == 3) nEdgesFace = elem[iElem]->GetnNodesFace(iFace); - - /*-- Loop over the edges of a face ---*/ - for (iEdgesFace = 0; iEdgesFace < nEdgesFace; iEdgesFace++) { - - /*--- In 2D only one edge (two points) per edge ---*/ - if (nDim == 2) { - face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0)); - face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,1)); - } - - /*--- In 3D there are several edges in each face ---*/ - if (nDim == 3) { - face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iEdgesFace)); - if (iEdgesFace != nEdgesFace-1) - face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iEdgesFace+1)); - else - face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0)); - } - - /*--- We define a direction (from the smallest index to the greatest) --*/ - iEdge = FindEdge(face_iPoint, face_jPoint); - - for (iDim = 0; iDim < nDim; iDim++) { - Coord_Edge_CG[iDim] = edge[iEdge]->GetCG(iDim); - Coord_Elem_CG[iDim] = elem[iElem]->GetCG(iDim); - Coord_FaceElem_CG[iDim] = elem[iElem]->GetFaceCG(iFace, iDim); - Coord_FaceiPoint[iDim] = node[face_iPoint]->GetCoord(iDim); - Coord_FacejPoint[iDim] = node[face_jPoint]->GetCoord(iDim); - } - - /*--- Print out the coordinates for a set of triangles making - up a single dual control volume for visualization. ---*/ - - if (face_iPoint == iPoint_Viz || face_jPoint == iPoint_Viz) { - - if (nDim == 2) { - X.push_back(Coord_Elem_CG[0]); X.push_back(Coord_Edge_CG[0]); - Y.push_back(Coord_Elem_CG[1]); Y.push_back(Coord_Edge_CG[1]); - } else if (nDim == 3) { - X.push_back(Coord_FaceElem_CG[0]); X.push_back(Coord_Edge_CG[0]); X.push_back(Coord_Elem_CG[0]); - Y.push_back(Coord_FaceElem_CG[1]); Y.push_back(Coord_Edge_CG[1]); Y.push_back(Coord_Elem_CG[1]); - Z.push_back(Coord_FaceElem_CG[2]); Z.push_back(Coord_Edge_CG[2]); Z.push_back(Coord_Elem_CG[2]); - - for (iDim = 0; iDim < nDim; iDim++) { - r1[iDim] = Coord_FaceElem_CG[iDim]-Coord_Elem_CG[iDim]; - r2[iDim] = Coord_Edge_CG[iDim]-Coord_Elem_CG[iDim]; - } - CrossProduct[0] += 0.5*(r1[1]*r2[2] - r1[2]*r2[1]); - CrossProduct[1] += 0.5*(r1[2]*r2[0] - r1[0]*r2[2]); - CrossProduct[2] += 0.5*(r1[0]*r2[1] - r1[1]*r2[0]); - } - counter++; - } - } - } - } - - /*--- Write a Tecplot file to visualize the CV ---*/ - - strcpy(cstr,"dual_cv"); - SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(iPoint_Viz)); - strcat(cstr, buffer); - - Tecplot_File.open(cstr, ios::out); - Tecplot_File << "TITLE= \"Visualization of the control volume\"" << endl; - - if (nDim == 2) { - Tecplot_File << "VARIABLES = \"x\",\"y\" " << endl; - Tecplot_File << "ZONE NODES= "<< counter*2 <<", ELEMENTS= "; - Tecplot_File << counter <<", DATAPACKING=POINT, ZONETYPE=FEQUADRILATERAL"<< endl; - } if (nDim == 3) { - Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\" " << endl; - Tecplot_File << "ZONE NODES= "<< counter*3 <<", ELEMENTS= "; - Tecplot_File << counter <<", DATAPACKING=POINT, ZONETYPE=FEBRICK"<< endl; - } - - /*--- Write coordinates for the nodes in the order that they were found - for each of the edges/triangles making up a dual control volume. ---*/ - - for (vector::size_type i = 0; i != X.size(); i++) { - Tecplot_File << X[i] << "\t" << Y[i]; - if (nDim == 3) Tecplot_File << "\t" << Z[i]; - Tecplot_File << "\n"; - } - - /*--- Create a new connectivity table in the order the faces were found ---*/ - - int j; - for (int i= 0; i < counter; i++) { - if (nDim == 2) { - j = i*2; - Tecplot_File << j+1 <<"\t"<GetNode(iNodes); - output_file << "\t"<GetCoord(iDim) ; -#ifndef HAVE_MPI - output_file << "\t" << iPoint << endl; -#else - output_file << "\t" << iPoint << "\t" << node[iPoint]->GetGlobalIndex() << endl; -#endif - - } - - /*--- Loop through and write the boundary info ---*/ - - output_file << "NMARK= " << nMarker << endl; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - /*--- Ignore SEND_RECEIVE for the moment ---*/ - if (bound[iMarker][0]->GetVTK_Type() != VERTEX) { - - Grid_Marker = config->GetMarker_All_TagBound(iMarker); - output_file << "MARKER_TAG= " << Grid_Marker << endl; - output_file << "MARKER_ELEMS= " << nElem_Bound[iMarker]<< endl; - - if (nDim == 2) { - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ; - for (iNodes = 0; iNodes < bound[iMarker][iElem_Bound]->GetnNodes(); iNodes++) - output_file << bound[iMarker][iElem_Bound]->GetNode(iNodes) << "\t" ; - output_file << iElem_Bound << endl; - } - } - - if (nDim == 3) { - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ; - for (iNodes = 0; iNodes < bound[iMarker][iElem_Bound]->GetnNodes(); iNodes++) - output_file << bound[iMarker][iElem_Bound]->GetNode(iNodes) << "\t" ; - output_file << iElem_Bound << endl; - } - } - - } else if (bound[iMarker][0]->GetVTK_Type() == VERTEX) { - output_file << "MARKER_TAG= SEND_RECEIVE" << endl; - output_file << "MARKER_ELEMS= " << nElem_Bound[iMarker]<< endl; - if (config->GetMarker_All_SendRecv(iMarker) > 0) output_file << "SEND_TO= " << config->GetMarker_All_SendRecv(iMarker) << endl; - if (config->GetMarker_All_SendRecv(iMarker) < 0) output_file << "SEND_TO= " << config->GetMarker_All_SendRecv(iMarker) << endl; - - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" << - bound[iMarker][iElem_Bound]->GetNode(0) << "\t" << - bound[iMarker][iElem_Bound]->GetRotation_Type() << endl; - } - - } - } - - /*--- Get the total number of periodic transformations ---*/ - - nPeriodic = config->GetnPeriodicIndex(); - output_file << "NPERIODIC= " << nPeriodic << endl; - - /*--- From iPeriodic obtain the iMarker ---*/ - - for (iPeriodic = 0; iPeriodic < nPeriodic; iPeriodic++) { - - /*--- Retrieve the supplied periodic information. ---*/ - - center = config->GetPeriodicCenter(iPeriodic); - angles = config->GetPeriodicRotation(iPeriodic); - transl = config->GetPeriodicTranslate(iPeriodic); - - output_file << "PERIODIC_INDEX= " << iPeriodic << endl; - output_file << center[0] << "\t" << center[1] << "\t" << center[2] << endl; - output_file << angles[0] << "\t" << angles[1] << "\t" << angles[2] << endl; - output_file << transl[0] << "\t" << transl[1] << "\t" << transl[2] << endl; - - } - - - output_file.close(); -} - -void CPhysicalGeometry::SetCoord_Smoothing (unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config) { - unsigned short iSmooth, nneigh, iMarker; - su2double *Coord_Old, *Coord_Sum, *Coord, *Coord_i, *Coord_j, Position_Plane = 0.0; - unsigned long iEdge, iPoint, jPoint, iVertex; - su2double eps = 1E-6; - bool NearField = false; - - Coord = new su2double [nDim]; - - for (iPoint = 0; iPoint < GetnPoint(); iPoint++) { - su2double *Coord = node[iPoint]->GetCoord(); - node[iPoint]->SetCoord_Old(Coord); - } - - /*--- Jacobi iterations ---*/ - for (iSmooth = 0; iSmooth < val_nSmooth; iSmooth++) { - - for (iPoint = 0; iPoint < nPoint; iPoint++) - node[iPoint]->SetCoord_SumZero(); - - - /*--- Loop over Interior edges ---*/ - for (iEdge = 0; iEdge < nEdge; iEdge++) { - iPoint = edge[iEdge]->GetNode(0); - Coord_i = node[iPoint]->GetCoord(); - - jPoint = edge[iEdge]->GetNode(1); - Coord_j = node[jPoint]->GetCoord(); - - /*--- Accumulate nearest neighbor Coord to Res_sum for each variable ---*/ - node[iPoint]->AddCoord_Sum(Coord_j); - node[jPoint]->AddCoord_Sum(Coord_i); - - } - - /*--- Loop over all mesh points (Update Coords with averaged sum) ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint++) { - nneigh = node[iPoint]->GetnPoint(); - Coord_Sum = node[iPoint]->GetCoord_Sum(); - Coord_Old = node[iPoint]->GetCoord_Old(); - - if (nDim == 2) { - Coord[0] =(Coord_Old[0] + val_smooth_coeff*Coord_Sum[0]) /(1.0 + val_smooth_coeff*su2double(nneigh)); - Coord[1] =(Coord_Old[1] + val_smooth_coeff*Coord_Sum[1]) /(1.0 + val_smooth_coeff*su2double(nneigh)); - if ((NearField) && ((Coord_Old[1] > Position_Plane-eps) && (Coord_Old[1] < Position_Plane+eps))) - Coord[1] = Coord_Old[1]; - } - - if (nDim == 3) { - Coord[0] =(Coord_Old[0] + val_smooth_coeff*Coord_Sum[0]) /(1.0 + val_smooth_coeff*su2double(nneigh)); - Coord[1] =(Coord_Old[1] + val_smooth_coeff*Coord_Sum[1]) /(1.0 + val_smooth_coeff*su2double(nneigh)); - Coord[2] =(Coord_Old[2] + val_smooth_coeff*Coord_Sum[2]) /(1.0 + val_smooth_coeff*su2double(nneigh)); - if ((NearField) && ((Coord_Old[2] > Position_Plane-eps) && (Coord_Old[2] < Position_Plane+eps))) - Coord[2] = Coord_Old[2]; - } - - node[iPoint]->SetCoord(Coord); - } - - /*--- Copy boundary values ---*/ - for (iMarker = 0; iMarker < nMarker; iMarker++) - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - Coord_Old = node[iPoint]->GetCoord_Old(); - node[iPoint]->SetCoord(Coord_Old); - } - } - - delete[] Coord; -} - -bool CPhysicalGeometry::FindFace(unsigned long first_elem, unsigned long second_elem, unsigned short &face_first_elem, - unsigned short &face_second_elem) { - - /*--- Find repeated nodes between two elements to identify the common face ---*/ - unsigned long iPoint = 0, jPoint = 0; - unsigned short face_node, iFace, iNode, jNode, nNodesFace; - vector CommonPoints, PointFaceFirst, PointFaceSecond; - vector::iterator IterPoint; - pair::iterator, vector ::iterator> mypair; - bool face_first_found = false, face_second_found =false; - - if (first_elem == second_elem) return false; - - for (iNode = 0; iNode < elem[first_elem]->GetnNodes(); iNode++) { - iPoint = elem[first_elem]->GetNode(iNode); - for (jNode = 0; jNode < elem[second_elem]->GetnNodes(); jNode++) { - jPoint = elem[second_elem]->GetNode(jNode); - if (iPoint == jPoint) { - CommonPoints.push_back(iPoint); - break; - } - } - } - - /*--- Sort point in face and check that the list is unique ---*/ - sort( CommonPoints.begin(), CommonPoints.end()); - IterPoint = unique( CommonPoints.begin(), CommonPoints.end()); - CommonPoints.resize( distance(CommonPoints.begin(), IterPoint) ); - - /*--- In 2D, the two elements must share two points that make up - an edge, as all "faces" are edges in 2D. In 3D, we need to find - exactly 3 (tri) or 4 (quad) common points. Return immediately to - avoid a memory issue due to vectors of different lengths below. ---*/ - - if ((nDim == 2) && (CommonPoints.size() != 2)) return false; - if ((nDim == 3) && ((CommonPoints.size() != 3) && - (CommonPoints.size() != 4))) return false; - - /*--- Search the sequence in the first element ---*/ - for (iFace = 0; iFace < elem[first_elem]->GetnFaces(); iFace++) { - nNodesFace = elem[first_elem]->GetnNodesFace(iFace); - - if (nNodesFace == CommonPoints.size()) { - for (iNode = 0; iNode < nNodesFace; iNode++) { - face_node = elem[first_elem]->GetFaces(iFace, iNode); - PointFaceFirst.push_back(elem[first_elem]->GetNode(face_node)); - } - - /*--- Sort face_poin to perform comparison ---*/ - sort( PointFaceFirst.begin(), PointFaceFirst.end()); - - /*--- List comparison ---*/ - mypair = mismatch (PointFaceFirst.begin(), PointFaceFirst.end(), CommonPoints.begin()); - if (mypair.first == PointFaceFirst.end()) { - face_first_elem = iFace; - face_first_found = true; - break; - } - - PointFaceFirst.erase (PointFaceFirst.begin(), PointFaceFirst.end()); - } - } - - /*--- Search the secuence in the second element ---*/ - for (iFace = 0; iFace < elem[second_elem]->GetnFaces(); iFace++) { - nNodesFace = elem[second_elem]->GetnNodesFace(iFace); - - if (nNodesFace == CommonPoints.size()) { - for (iNode = 0; iNode < nNodesFace; iNode++) { - face_node = elem[second_elem]->GetFaces(iFace, iNode); - PointFaceSecond.push_back(elem[second_elem]->GetNode(face_node)); - } - - /*--- Sort face_poin to perform comparison ---*/ - sort( PointFaceSecond.begin(), PointFaceSecond.end()); - - /*--- List comparison ---*/ - mypair = mismatch (PointFaceSecond.begin(), PointFaceSecond.end(), CommonPoints.begin()); - if (mypair.first == PointFaceSecond.end()) { - face_second_elem = iFace; - face_second_found = true; - break; - } - - PointFaceSecond.erase (PointFaceSecond.begin(), PointFaceSecond.end()); - } - } - - if (face_first_found && face_second_found) return true; - else return false; - -} - -void CPhysicalGeometry::SetTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file) { - - unsigned long iElem, iPoint; - unsigned short iDim; - ofstream Tecplot_File; - - /*--- Open the tecplot file and write the header ---*/ - - if (new_file) { - Tecplot_File.open(mesh_filename, ios::out); - Tecplot_File << "TITLE= \"Visualization of the volumetric grid\"" << endl; - if (nDim == 2) Tecplot_File << "VARIABLES = \"x\",\"y\" " << endl; - if (nDim == 3) Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\" " << endl; - } - else Tecplot_File.open(mesh_filename, ios::out | ios::app); - - Tecplot_File << "ZONE T= "; - if (new_file) Tecplot_File << "\"Original grid\", C=BLACK, "; - else Tecplot_File << "\"Deformed grid\", C=RED, "; - Tecplot_File << "NODES= "<< nPoint <<", ELEMENTS= "<< nElem <<", DATAPACKING= POINT"; - if (nDim == 2) Tecplot_File << ", ZONETYPE= FEQUADRILATERAL"<< endl; - if (nDim == 3) Tecplot_File << ", ZONETYPE= FEBRICK"<< endl; - - /*--- Adding coordinates ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - for (iDim = 0; iDim < nDim; iDim++) - Tecplot_File << scientific << node[iPoint]->GetCoord(iDim) << "\t"; - Tecplot_File << "\n"; - } - - /*--- Adding conectivity ---*/ - - for (iElem = 0; iElem < nElem; iElem++) { - if (elem[iElem]->GetVTK_Type() == TRIANGLE) { - Tecplot_File << - elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< - elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(2)+1 << endl; - } - if (elem[iElem]->GetVTK_Type() == QUADRILATERAL) { - Tecplot_File << - elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< - elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 << endl; - } - if (elem[iElem]->GetVTK_Type() == TETRAHEDRON) { - Tecplot_File << - elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< - elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(2)+1 <<" "<< - elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<< - elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(3)+1 << endl; - } - if (elem[iElem]->GetVTK_Type() == HEXAHEDRON) { - Tecplot_File << - elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< - elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<< - elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(5)+1 <<" "<< - elem[iElem]->GetNode(6)+1 <<" "<< elem[iElem]->GetNode(7)+1 << endl; - } - if (elem[iElem]->GetVTK_Type() == PYRAMID) { - Tecplot_File << - elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< - elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<< - elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(4)+1 <<" "<< - elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(4)+1 << endl; - } - if (elem[iElem]->GetVTK_Type() == PRISM) { - Tecplot_File << - elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< - elem[iElem]->GetNode(1)+1 <<" "<< elem[iElem]->GetNode(2)+1 <<" "<< - elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(4)+1 <<" "<< - elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(5)+1 << endl; - } - } - - Tecplot_File.close(); -} - -void CPhysicalGeometry::SetBoundTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file, CConfig *config) { - - ofstream Tecplot_File; - unsigned long iPoint, Total_nElem_Bound, iElem, *PointSurface = NULL, nPointSurface = 0; - unsigned short Coord_i, iMarker; - - /*--- It is important to do a renumbering to don't add points - that do not belong to the surfaces ---*/ - - PointSurface = new unsigned long[nPoint]; - for (iPoint = 0; iPoint < nPoint; iPoint++) - if (node[iPoint]->GetBoundary()) { - PointSurface[iPoint] = nPointSurface; - nPointSurface++; - } - - /*--- Compute the total number of elements ---*/ - - Total_nElem_Bound = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_Plotting(iMarker) == YES) { - Total_nElem_Bound += nElem_Bound[iMarker]; - } - } - - /*--- Open the tecplot file and write the header ---*/ - - if (new_file) { - Tecplot_File.open(mesh_filename, ios::out); - Tecplot_File << "TITLE= \"Visualization of the surface grid\"" << endl; - if (nDim == 2) Tecplot_File << "VARIABLES = \"x\",\"y\" " << endl; - if (nDim == 3) Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\" " << endl; - } - else Tecplot_File.open(mesh_filename, ios::out | ios::app); - - if (Total_nElem_Bound != 0) { - - /*--- Write the header of the file ---*/ - - Tecplot_File << "ZONE T= "; - if (new_file) Tecplot_File << "\"Original grid\", C=BLACK, "; - else Tecplot_File << "\"Deformed grid\", C=RED, "; - Tecplot_File << "NODES= "<< nPointSurface <<", ELEMENTS= "<< Total_nElem_Bound <<", DATAPACKING= POINT"; - if (nDim == 2) Tecplot_File << ", ZONETYPE= FELINESEG"<< endl; - if (nDim == 3) Tecplot_File << ", ZONETYPE= FEQUADRILATERAL"<< endl; - - /*--- Only write the coordiantes of the points that are on the surfaces ---*/ - - if (nDim == 3) { - for (iPoint = 0; iPoint < nPoint; iPoint++) - if (node[iPoint]->GetBoundary()) { - for (Coord_i = 0; Coord_i < nDim-1; Coord_i++) - Tecplot_File << node[iPoint]->GetCoord(Coord_i) << " "; - Tecplot_File << node[iPoint]->GetCoord(nDim-1) << "\n"; - } - } - else { - for (iPoint = 0; iPoint < nPoint; iPoint++) - if (node[iPoint]->GetBoundary()) { - for (Coord_i = 0; Coord_i < nDim; Coord_i++) - Tecplot_File << node[iPoint]->GetCoord(Coord_i) << " "; - Tecplot_File << "\n"; - } - } - - /*--- Write the cells using the new numbering ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_Plotting(iMarker) == YES) - for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) { - if (nDim == 2) { - Tecplot_File << PointSurface[bound[iMarker][iElem]->GetNode(0)]+1 << " " - << PointSurface[bound[iMarker][iElem]->GetNode(1)]+1 << endl; - } - if (nDim == 3) { - if (bound[iMarker][iElem]->GetnNodes() == 3) { - Tecplot_File << PointSurface[bound[iMarker][iElem]->GetNode(0)]+1 << " " - << PointSurface[bound[iMarker][iElem]->GetNode(1)]+1 << " " - << PointSurface[bound[iMarker][iElem]->GetNode(2)]+1 << " " - << PointSurface[bound[iMarker][iElem]->GetNode(2)]+1 << endl; - } - if (bound[iMarker][iElem]->GetnNodes() == 4) { - Tecplot_File << PointSurface[bound[iMarker][iElem]->GetNode(0)]+1 << " " - << PointSurface[bound[iMarker][iElem]->GetNode(1)]+1 << " " - << PointSurface[bound[iMarker][iElem]->GetNode(2)]+1 << " " - << PointSurface[bound[iMarker][iElem]->GetNode(3)]+1 << endl; - } - } - } - } - else { - - /*--- No elements in the surface ---*/ - - if (nDim == 2) { - Tecplot_File << "ZONE NODES= 1, ELEMENTS= 1, DATAPACKING=POINT, ZONETYPE=FELINESEG"<< endl; - Tecplot_File << "0.0 0.0"<< endl; - Tecplot_File << "1 1"<< endl; - } - if (nDim == 3) { - Tecplot_File << "ZONE NODES= 1, ELEMENTS= 1, DATAPACKING=POINT, ZONETYPE=FEQUADRILATERAL"<< endl; - Tecplot_File << "0.0 0.0 0.0"<< endl; - Tecplot_File << "1 1 1 1"<< endl; - } - } - - /*--- Dealocate memory and close the file ---*/ - - delete[] PointSurface; - Tecplot_File.close(); - -} - -void CPhysicalGeometry::SetBoundSTL(char mesh_filename[MAX_STRING_SIZE], bool new_file, CConfig *config) { - - ofstream STL_File; - unsigned long this_node, iNode, nNode, iElem; - unsigned short iDim, iMarker; - su2double p[3] = {0.0,0.0,0.0}, u[3] = {0.0,0.0,0.0}, v[3] = {0.0,0.0,0.0}, n[3] = {0.0,0.0,0.0}, a; - - /*--- STL format: - solid NAME - ... - facet normal 0.00 0.00 1.00 - outer loop - vertex 2.00 2.00 0.00 - vertex -1.00 1.00 0.00 - vertex 0.00 -1.00 0.00 - endloop - endfacet - ... - end solid - ---*/ - - /*--- Open the STL file ---*/ - - if (new_file) STL_File.open(mesh_filename, ios::out); - else STL_File.open(mesh_filename, ios::out | ios::app); - - /*--- Write the header of the file ---*/ - - STL_File << "solid surface_mesh" << endl; - - /*--- Write facets of surface markers ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_Plotting(iMarker) == YES) - for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) { - - /*--- number of nodes for this elemnt ---*/ - - nNode = bound[iMarker][iElem]->GetnNodes(); - - /*--- Calculate Normal Vector ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - p[0] = node[bound[iMarker][iElem]->GetNode(0)] ->GetCoord(iDim); - p[1] = node[bound[iMarker][iElem]->GetNode(1)] ->GetCoord(iDim); - p[2] = node[bound[iMarker][iElem]->GetNode(nNode-1)]->GetCoord(iDim); - u[iDim] = p[1]-p[0]; - v[iDim] = p[2]-p[0]; - } - - n[0] = u[1]*v[2]-u[2]*v[1]; - n[1] = u[2]*v[0]-u[0]*v[2]; - n[2] = u[0]*v[1]-u[1]*v[0]; - a = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]); - - /*--- Print normal vector ---*/ - - STL_File << " facet normal "; - for (iDim = 0; iDim < nDim; iDim++) { - STL_File << n[iDim]/a << " "; - } - STL_File << endl; - - /*--- STL Facet Loop --*/ - - STL_File << " outer loop" << endl; - - /*--- Print Nodes for Facet ---*/ - - for (iNode = 0; iNode < nNode; iNode++) { - this_node = bound[iMarker][iElem]->GetNode(iNode); - STL_File << " vertex "; - for (iDim = 0; iDim < nDim; iDim++) - STL_File << node[this_node]->GetCoord(iDim) << " "; - if (nDim==2) - STL_File << 0.0 << " "; - STL_File << endl; - } - STL_File << " endloop" << endl; - STL_File << " endfacet" << endl; - } - - /*--- Done with Surface Mesh ---*/ - - STL_File << "endsolid" << endl; - - /*--- Close the file ---*/ - - STL_File.close(); - -} - -void CPhysicalGeometry::SetColorGrid(CConfig *config) { - -#ifdef HAVE_MPI -#ifdef HAVE_METIS - - unsigned long iPoint, iElem, iElem_Triangle, iElem_Tetrahedron, nElem_Triangle, - nElem_Tetrahedron; - idx_t ne = 0, nn, *elmnts = NULL, *epart = NULL, *npart = NULL, nparts, edgecut, *eptr; - int rank, size; - - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); - - if (size != SINGLE_ZONE) - cout << endl <<"---------------------------- Grid partitioning --------------------------" << endl; - - unsigned short nDomain = size; - - nElem_Triangle = 0; - nElem_Tetrahedron = 0; - for (iElem = 0; iElem < GetnElem(); iElem++) { - if (elem[iElem]->GetVTK_Type() == TRIANGLE) nElem_Triangle = nElem_Triangle + 1; - if (elem[iElem]->GetVTK_Type() == QUADRILATERAL) nElem_Triangle = nElem_Triangle + 2; - if (elem[iElem]->GetVTK_Type() == TETRAHEDRON) nElem_Tetrahedron = nElem_Tetrahedron + 1; - if (elem[iElem]->GetVTK_Type() == HEXAHEDRON) nElem_Tetrahedron = nElem_Tetrahedron + 5; - if (elem[iElem]->GetVTK_Type() == PYRAMID) nElem_Tetrahedron = nElem_Tetrahedron + 2; - if (elem[iElem]->GetVTK_Type() == PRISM) nElem_Tetrahedron = nElem_Tetrahedron + 3; - } - - if (GetnDim() == 2) { - ne = nElem_Triangle; - elmnts = new idx_t [ne*3]; - } - if (GetnDim() == 3) { - ne = nElem_Tetrahedron; - elmnts = new idx_t [ne*4]; - } - - nn = nPoint; - nparts = nDomain; - epart = new idx_t [ne]; - npart = new idx_t [nn]; - eptr = new idx_t[ne+1]; - - /*--- Initialize the color vector ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) - node[iPoint]->SetColor(0); - - if (nparts > 1) { - - iElem_Triangle = 0; iElem_Tetrahedron = 0; - for (iElem = 0; iElem < GetnElem(); iElem++) { - if (elem[iElem]->GetVTK_Type() == TRIANGLE) { - elmnts[3*iElem_Triangle+0]= elem[iElem]->GetNode(0); - elmnts[3*iElem_Triangle+1]= elem[iElem]->GetNode(1); - elmnts[3*iElem_Triangle+2]= elem[iElem]->GetNode(2); - eptr[iElem_Triangle] = 3*iElem_Triangle; - iElem_Triangle++; - } - if (elem[iElem]->GetVTK_Type() == QUADRILATERAL) { - elmnts[3*iElem_Triangle+0]= elem[iElem]->GetNode(0); - elmnts[3*iElem_Triangle+1]= elem[iElem]->GetNode(1); - elmnts[3*iElem_Triangle+2]= elem[iElem]->GetNode(2); - eptr[iElem_Triangle] = 3*iElem_Triangle; - iElem_Triangle++; - elmnts[3*iElem_Triangle+0]= elem[iElem]->GetNode(0); - elmnts[3*iElem_Triangle+1]= elem[iElem]->GetNode(2); - elmnts[3*iElem_Triangle+2]= elem[iElem]->GetNode(3); - eptr[iElem_Triangle] = 3*iElem_Triangle; - iElem_Triangle++; - } - if (elem[iElem]->GetVTK_Type() == TETRAHEDRON) { - elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); - elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(1); - elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(2); - elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(3); - eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; - iElem_Tetrahedron++; - } - if (elem[iElem]->GetVTK_Type() == HEXAHEDRON) { - elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); - elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(1); - elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(2); - elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(5); - eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; - iElem_Tetrahedron++; - elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); - elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(2); - elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(3); - elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(7); - eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; - iElem_Tetrahedron++; - elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); - elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(5); - elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(7); - elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(4); - eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; - iElem_Tetrahedron++; - elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(2); - elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(7); - elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(5); - elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(6); - eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; - iElem_Tetrahedron++; - elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); - elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(2); - elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(7); - elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(5); - eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; - iElem_Tetrahedron++; - } - if (elem[iElem]->GetVTK_Type() == PYRAMID) { - elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); - elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(1); - elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(2); - elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(4); - eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; - iElem_Tetrahedron++; - elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); - elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(2); - elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(3); - elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(4); - eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; - iElem_Tetrahedron++; - } - if (elem[iElem]->GetVTK_Type() == PRISM) { - elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); - elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(1); - elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(4); - elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(2); - eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; - iElem_Tetrahedron++; - elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); - elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(2); - elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(3); - elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(4); - eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; - iElem_Tetrahedron++; - elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(3); - elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(4); - elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(5); - elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(2); - eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; - iElem_Tetrahedron++; - } - } - - /*--- Add final value to element pointer array ---*/ - - if (GetnDim() == 2) eptr[ne] = 3*ne; - else eptr[ne] = 4*ne; - - METIS_PartMeshNodal(&ne, &nn, eptr, elmnts, NULL, NULL, &nparts, NULL, NULL, &edgecut, epart, npart); - - cout << "Finished partitioning using METIS. (" << edgecut << " edge cuts)." << endl; - - for (iPoint = 0; iPoint < nPoint; iPoint++) - node[iPoint]->SetColor(npart[iPoint]); - } - - delete[] epart; - delete[] npart; - delete[] elmnts; - delete[] eptr; - -#endif - -#endif - -} - -void CPhysicalGeometry::SetColorGrid_Parallel(CConfig *config) { - - /*--- Initialize the color vector ---*/ - - for (unsigned long iPoint = 0; iPoint < local_node; iPoint++) - node[iPoint]->SetColor(0); - - /*--- This routine should only ever be called if we have parallel support - with MPI and have the ParMETIS library compiled and linked. ---*/ - -#ifdef HAVE_MPI -#ifdef HAVE_PARMETIS - - unsigned long iPoint; - int rank, size; - MPI_Comm comm = MPI_COMM_WORLD; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); - - /*--- Only call ParMETIS if we have more than one rank to avoid errors ---*/ - - if (size > SINGLE_NODE) { - - /*--- Create some structures that ParMETIS needs for partitioning. ---*/ - - idx_t numflag, nparts, edgecut, wgtflag, ncon; - idx_t *vtxdist = new idx_t[size+1]; - idx_t *xadj_l = new idx_t[xadj_size]; - idx_t *adjacency_l = new idx_t[adjacency_size]; - idx_t *elmwgt = new idx_t[local_node]; - idx_t *part = new idx_t[local_node]; - - real_t ubvec; - real_t *tpwgts = new real_t[size]; - - /*--- Some recommended defaults for the various ParMETIS options. ---*/ - - wgtflag = 0; - numflag = 0; - ncon = 1; - ubvec = 1.05; - nparts = (idx_t)size; - idx_t options[METIS_NOPTIONS]; - METIS_SetDefaultOptions(options); - options[1] = 0; - - /*--- Fill the necessary ParMETIS data arrays. Note that xadj_size and - adjacency_size are class data members that have been defined and set - earlier in the partitioning process. ---*/ - - for (int i = 0; i < size; i++) { - tpwgts[i] = 1.0/((real_t)size); - } - - vtxdist[0] = 0; - for (int i = 0; i < size; i++) { - vtxdist[i+1] = (idx_t)ending_node[i]; - } - - for (unsigned long i = 0; i < xadj_size; i++) { - xadj_l[i] = (idx_t)xadj[i]; - } - - for (unsigned long i = 0; i < adjacency_size; i++) { - adjacency_l[i] = (idx_t)adjacency[i]; - } - - /*--- Calling ParMETIS ---*/ - if (rank == MASTER_NODE) cout << "Calling ParMETIS..." << endl; - ParMETIS_V3_PartKway(vtxdist,xadj_l, adjacency_l, NULL, NULL, &wgtflag, - &numflag, &ncon, &nparts, tpwgts, &ubvec, options, - &edgecut, part, &comm); - if (rank == MASTER_NODE) { - cout << "Finished partitioning using ParMETIS ("; - cout << edgecut << " edge cuts)." << endl; - } - - /*--- Store the results of the partitioning (note that this is local - since each processor is calling ParMETIS in parallel and storing the - results for its initial piece of the grid. ---*/ - - for (iPoint = 0; iPoint < local_node; iPoint++) { - node[iPoint]->SetColor(part[iPoint]); - } - - /*--- Free all memory needed for the ParMETIS structures ---*/ - - delete [] vtxdist; - delete [] xadj_l; - delete [] adjacency_l; - delete [] elmwgt; - delete [] part; - delete [] tpwgts; - - } - - /*--- Delete the memory from the geometry class that carried the - adjacency structure. ---*/ - - delete [] xadj; - delete [] adjacency; - -#endif -#endif - -} - -void CPhysicalGeometry::GetQualityStatistics(su2double *statistics) { - unsigned long jPoint, Point_2, Point_3, iElem; - su2double *Coord_j, *Coord_2, *Coord_3; - unsigned short iDim; - - statistics[0] = 1e06; - statistics[1] = 0; - - /*--- Loop interior edges ---*/ - for (iElem = 0; iElem < this->GetnElem(); iElem++) { - - if ((this->GetnDim() == 2) && (elem[iElem]->GetVTK_Type() == TRIANGLE)) { - - jPoint = elem[iElem]->GetNode(0); Coord_j = node[jPoint]->GetCoord(); - Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); - Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); - - /*--- Compute sides of the triangle ---*/ - su2double a = 0, b = 0, c = 0; - for (iDim = 0; iDim < nDim; iDim++) { - a += (Coord_2[iDim]-Coord_j[iDim])*(Coord_2[iDim]-Coord_j[iDim]); - b += (Coord_3[iDim]-Coord_j[iDim])*(Coord_3[iDim]-Coord_j[iDim]); - c += (Coord_3[iDim]-Coord_2[iDim])*(Coord_3[iDim]-Coord_2[iDim]); - } - a = sqrt(a); b = sqrt(b); c = sqrt(c); - - /*--- Compute semiperimeter (s) and area ---*/ - su2double s = 0.5*(a + b + c); - su2double Area = sqrt(s*(s-a)*(s-b)*(s-c)); - - /*--- Compute radius of the circumcircle (R) and of the incircle (r) ---*/ - su2double R = (a*b*c) / (4.0*Area); - su2double r = Area / s; - su2double roR = r / R; - - /*--- Update statistics ---*/ - if (roR < statistics[0]) - statistics[0] = roR; - statistics[1] += roR; - - } - } - statistics[1] /= this->GetnElem(); - -} - -void CPhysicalGeometry::SetRotationalVelocity(CConfig *config, unsigned short val_iZone) { - - unsigned long iPoint; - su2double RotVel[3], Distance[3], *Coord, Center[3], Omega[3], L_Ref; - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Center of rotation & angular velocity vector from config ---*/ - - Center[0] = config->GetMotion_Origin_X(val_iZone); - Center[1] = config->GetMotion_Origin_Y(val_iZone); - Center[2] = config->GetMotion_Origin_Z(val_iZone); - Omega[0] = config->GetRotation_Rate_X(val_iZone)/config->GetOmega_Ref(); - Omega[1] = config->GetRotation_Rate_Y(val_iZone)/config->GetOmega_Ref(); - Omega[2] = config->GetRotation_Rate_Z(val_iZone)/config->GetOmega_Ref(); - L_Ref = config->GetLength_Ref(); - - /*--- Print some information to the console ---*/ - - if (rank == MASTER_NODE) { - cout << " Rotational origin (x, y, z): ( " << Center[0] << ", " << Center[1]; - cout << ", " << Center[2] << " )" << endl; - cout << " Angular velocity about x, y, z axes: ( " << Omega[0] << ", "; - cout << Omega[1] << ", " << Omega[2] << " ) rad/s" << endl; - } - - /*--- Loop over all nodes and set the rotational velocity ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - - /*--- Get the coordinates of the current node ---*/ - - Coord = node[iPoint]->GetCoord(); - - /*--- Calculate the non-dim. distance from the rotation center ---*/ - - Distance[0] = (Coord[0]-Center[0])/L_Ref; - Distance[1] = (Coord[1]-Center[1])/L_Ref; - Distance[2] = (Coord[2]-Center[2])/L_Ref; - - /*--- Calculate the angular velocity as omega X r ---*/ - - RotVel[0] = Omega[1]*(Distance[2]) - Omega[2]*(Distance[1]); - RotVel[1] = Omega[2]*(Distance[0]) - Omega[0]*(Distance[2]); - RotVel[2] = Omega[0]*(Distance[1]) - Omega[1]*(Distance[0]); - - /*--- Store the grid velocity at this node ---*/ - - node[iPoint]->SetGridVel(RotVel); - - } - -} - -void CPhysicalGeometry::SetTranslationalVelocity(CConfig *config) { - - unsigned short iDim; - unsigned long iPoint; - su2double xDot[3] = {0.0,0.0,0.0}; - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Get the translational velocity vector from config ---*/ - - xDot[0] = config->GetTranslation_Rate_X(ZONE_0)/config->GetVelocity_Ref(); - xDot[1] = config->GetTranslation_Rate_Y(ZONE_0)/config->GetVelocity_Ref(); - xDot[2] = config->GetTranslation_Rate_Z(ZONE_0)/config->GetVelocity_Ref(); - - /*--- Print some information to the console ---*/ - - if (rank == MASTER_NODE) { - cout << " Non-dim. translational velocity: (" << xDot[0] << ", " << xDot[1]; - cout << ", " << xDot[2] << ")." << endl; - } - - /*--- Loop over all nodes and set the translational velocity ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - - /*--- Store the grid velocity at this node ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - node[iPoint]->SetGridVel(iDim,xDot[iDim]); - } - - } - -} - -void CPhysicalGeometry::SetGridVelocity(CConfig *config, unsigned long iter) { - - /*--- Local variables ---*/ - - su2double *Coord_nP1 = NULL, *Coord_n = NULL, *Coord_nM1 = NULL; - su2double TimeStep, GridVel = 0.0; - unsigned long iPoint; - unsigned short iDim; - - /*--- Compute the velocity of each node in the volume mesh ---*/ - - for (iPoint = 0; iPoint < GetnPoint(); iPoint++) { - - /*--- Coordinates of the current point at n+1, n, & n-1 time levels ---*/ - - Coord_nM1 = node[iPoint]->GetCoord_n1(); - Coord_n = node[iPoint]->GetCoord_n(); - Coord_nP1 = node[iPoint]->GetCoord(); - - /*--- Unsteady time step ---*/ - - TimeStep = config->GetDelta_UnstTimeND(); - - /*--- Compute mesh velocity with 1st or 2nd-order approximation ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - GridVel = ( Coord_nP1[iDim] - Coord_n[iDim] ) / TimeStep; - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - GridVel = ( 3.0*Coord_nP1[iDim] - 4.0*Coord_n[iDim] - + 1.0*Coord_nM1[iDim] ) / (2.0*TimeStep); - - /*--- Store grid velocity for this point ---*/ - - node[iPoint]->SetGridVel(iDim, GridVel); - } - } - -} - -void CPhysicalGeometry::Set_MPI_Coord(CConfig *config) { - - unsigned short iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, *Buffer_Receive_Coord = NULL, *Buffer_Send_Coord = NULL, *Coord = NULL, *newCoord = NULL; - - newCoord = new su2double[nDim]; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = nVertex[MarkerS]; nVertexR = nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nDim; nBufferR_Vector = nVertexR*nDim; - - /*--- Allocate Receive and send buffers ---*/ - - Buffer_Receive_Coord = new su2double [nBufferR_Vector]; - Buffer_Send_Coord = new su2double[nBufferS_Vector]; - - /*--- Copy the coordinates that should be sended ---*/ - - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = vertex[MarkerS][iVertex]->GetNode(); - Coord = node[iPoint]->GetCoord(); - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[iDim*nVertexS+iVertex] = Coord[iDim]; - } - -#ifdef HAVE_MPI - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Coord, nBufferS_Vector, MPI_DOUBLE, send_to,0, - Buffer_Receive_Coord, nBufferR_Vector, MPI_DOUBLE, receive_from,0, MPI_COMM_WORLD, &status); -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Receive_Coord[iDim*nVertexR+iVertex] = Buffer_Send_Coord[iDim*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - - delete [] Buffer_Send_Coord; - - /*--- Do the coordinate transformation ---*/ - - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - - iPoint = vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy coordinates before performing transformation. ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - newCoord[iDim] = Buffer_Receive_Coord[iDim*nVertexR+iVertex]; - - /*--- Rotate the coordinates. ---*/ - - if (nDim == 2) { - newCoord[0] = (rotMatrix[0][0]*Buffer_Receive_Coord[0*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_Coord[1*nVertexR+iVertex]); - newCoord[1] = (rotMatrix[1][0]*Buffer_Receive_Coord[0*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_Coord[1*nVertexR+iVertex]); - } - else { - newCoord[0] = (rotMatrix[0][0]*Buffer_Receive_Coord[0*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_Coord[1*nVertexR+iVertex] + - rotMatrix[0][2]*Buffer_Receive_Coord[2*nVertexR+iVertex]); - newCoord[1] = (rotMatrix[1][0]*Buffer_Receive_Coord[0*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_Coord[1*nVertexR+iVertex] + - rotMatrix[1][2]*Buffer_Receive_Coord[2*nVertexR+iVertex]); - newCoord[2] = (rotMatrix[2][0]*Buffer_Receive_Coord[0*nVertexR+iVertex] + - rotMatrix[2][1]*Buffer_Receive_Coord[1*nVertexR+iVertex] + - rotMatrix[2][2]*Buffer_Receive_Coord[2*nVertexR+iVertex]); - } - - /*--- Copy transformed coordinates back into buffer. ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - node[iPoint]->SetCoord(iDim, newCoord[iDim]); - - } - - /*--- Deallocate receive buffer. ---*/ - - delete [] Buffer_Receive_Coord; - - } - - } - - delete [] newCoord; - -} - -void CPhysicalGeometry::Set_MPI_GridVel(CConfig *config) { - - unsigned short iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, *Buffer_Receive_GridVel = NULL, *Buffer_Send_GridVel = NULL, *GridVel = NULL, *newGridVel = NULL; - - newGridVel = new su2double[nDim]; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = nVertex[MarkerS]; nVertexR = nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nDim; nBufferR_Vector = nVertexR*nDim; - - /*--- Allocate Receive and send buffers ---*/ - - Buffer_Receive_GridVel = new su2double [nBufferR_Vector]; - Buffer_Send_GridVel = new su2double[nBufferS_Vector]; - - /*--- Copy the grid velocity that should be sended ---*/ - - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = vertex[MarkerS][iVertex]->GetNode(); - GridVel = node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_GridVel[iDim*nVertexS+iVertex] = GridVel[iDim]; - } - -#ifdef HAVE_MPI - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_GridVel, nBufferS_Vector, MPI_DOUBLE, send_to,0, - Buffer_Receive_GridVel, nBufferR_Vector, MPI_DOUBLE, receive_from,0, MPI_COMM_WORLD, &status); -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Receive_GridVel[iDim*nVertexR+iVertex] = Buffer_Send_GridVel[iDim*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - - delete [] Buffer_Send_GridVel; - - /*--- Do the coordinate transformation ---*/ - - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - - iPoint = vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy grid velocity before performing transformation. ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - newGridVel[iDim] = Buffer_Receive_GridVel[iDim*nVertexR+iVertex]; - - if (nDim == 2) { - newGridVel[0] = (rotMatrix[0][0]*Buffer_Receive_GridVel[0*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_GridVel[1*nVertexR+iVertex]); - newGridVel[1] = (rotMatrix[1][0]*Buffer_Receive_GridVel[0*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_GridVel[1*nVertexR+iVertex]); - } - else { - newGridVel[0] = (rotMatrix[0][0]*Buffer_Receive_GridVel[0*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_GridVel[1*nVertexR+iVertex] + - rotMatrix[0][2]*Buffer_Receive_GridVel[2*nVertexR+iVertex]); - newGridVel[1] = (rotMatrix[1][0]*Buffer_Receive_GridVel[0*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_GridVel[1*nVertexR+iVertex] + - rotMatrix[1][2]*Buffer_Receive_GridVel[2*nVertexR+iVertex]); - newGridVel[2] = (rotMatrix[2][0]*Buffer_Receive_GridVel[0*nVertexR+iVertex] + - rotMatrix[2][1]*Buffer_Receive_GridVel[1*nVertexR+iVertex] + - rotMatrix[2][2]*Buffer_Receive_GridVel[2*nVertexR+iVertex]); - } - - /*--- Copy transformed grid velocity back into buffer. ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - node[iPoint]->SetGridVel(iDim, newGridVel[iDim]); - - } - - /*--- Deallocate receive buffer ---*/ - - delete [] Buffer_Receive_GridVel; - - } - - } - - delete [] newGridVel; - -} - -void CPhysicalGeometry::SetPeriodicBoundary(CConfig *config) { - - unsigned short iMarker, jMarker, kMarker = 0, iPeriodic, iDim, nPeriodic = 0, VTK_Type; - unsigned long iNode, iIndex, iVertex, iPoint, iElem, kElem; - unsigned long jElem, kPoint = 0, jVertex = 0, jPoint = 0, pPoint = 0, nPointPeriodic, newNodes[4] = {0,0,0,0}; - vector::iterator IterElem, IterPoint[MAX_NUMBER_PERIODIC][2]; - su2double *center, *angles, rotMatrix[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}, - translation[3], *trans, theta, phi, psi, cosTheta, sinTheta, cosPhi, sinPhi, cosPsi, sinPsi, - dx, dy, dz, rotCoord[3], epsilon = 1e-10, mindist = 1e6, *Coord_i, *Coord_j, dist = 0.0; - bool isBadMatch = false; - - /*--- Check this dimensionalization ---*/ - - vector OldBoundaryElems[100]; - vector::iterator IterNewElem[100]; - - /*--- We only create the mirror structure for the second boundary ---*/ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) { - /*--- Evaluate the number of periodic boundary conditions ---*/ - nPeriodic++; - } - } - bool *CreateMirror = new bool[nPeriodic+1]; - CreateMirror[0] = false; - for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { - if (iPeriodic <= nPeriodic/2) CreateMirror[iPeriodic] = false; - else CreateMirror[iPeriodic] = true; - } - - /*--- Send an initial message to the console. ---*/ - cout << "Setting the periodic boundary conditions." << endl; - - /*--- Loop through each marker to find any periodic boundaries. ---*/ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) { - - /*--- Get marker index of the periodic donor boundary. ---*/ - jMarker = config->GetMarker_Periodic_Donor(config->GetMarker_All_TagBound(iMarker)); - - /*--- Write some info to the console. ---*/ - cout << "Checking " << config->GetMarker_All_TagBound(iMarker); - cout << " boundary against periodic donor, " << config->GetMarker_All_TagBound(jMarker) << ". "; - - /*--- Retrieve the supplied periodic information. ---*/ - center = config->GetPeriodicRotCenter(config->GetMarker_All_TagBound(iMarker)); - angles = config->GetPeriodicRotAngles(config->GetMarker_All_TagBound(iMarker)); - trans = config->GetPeriodicTranslation(config->GetMarker_All_TagBound(iMarker)); - - /*--- Store (center+trans) as it is constant and will be added on. ---*/ - translation[0] = center[0] + trans[0]; - translation[1] = center[1] + trans[1]; - translation[2] = center[2] + trans[2]; - - /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ - theta = angles[0]; - phi = angles[1]; - psi = angles[2]; - - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; - rotMatrix[1][0] = cosPhi*sinPsi; - rotMatrix[2][0] = -sinPhi; - - rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; - rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; - rotMatrix[2][1] = sinTheta*cosPhi; - - rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Loop through all vertices and find/set the periodic point. ---*/ - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - - /*--- Retrieve node information for this boundary point. ---*/ - iPoint = vertex[iMarker][iVertex]->GetNode(); - Coord_i = node[iPoint]->GetCoord(); - - /*--- Get the position vector from rot center to point. ---*/ - dx = Coord_i[0] - center[0]; - dy = Coord_i[1] - center[1]; - if (nDim == 3) { - dz = Coord_i[2] - center[2]; - } else { - dz = 0.0; - } - - /*--- Compute transformed point coordinates. ---*/ - rotCoord[0] = rotMatrix[0][0]*dx - + rotMatrix[0][1]*dy - + rotMatrix[0][2]*dz + translation[0]; - - rotCoord[1] = rotMatrix[1][0]*dx - + rotMatrix[1][1]*dy - + rotMatrix[1][2]*dz + translation[1]; - - rotCoord[2] = rotMatrix[2][0]*dx - + rotMatrix[2][1]*dy - + rotMatrix[2][2]*dz + translation[2]; - - /*--- Perform a search to find the closest donor point. ---*/ - mindist = 1e10; - for (jVertex = 0; jVertex < nVertex[jMarker]; jVertex++) { - - /*--- Retrieve information for this jPoint. ---*/ - jPoint = vertex[jMarker][jVertex]->GetNode(); - Coord_j = node[jPoint]->GetCoord(); - - /*--- Check the distance between the computed periodic - location and this jPoint. ---*/ - dist = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - dist += (Coord_j[iDim]-rotCoord[iDim])*(Coord_j[iDim]-rotCoord[iDim]); - } - dist = sqrt(dist); - - /*--- Store vertex information if this is the closest - point found thus far. ---*/ - if (dist < mindist) { mindist = dist; pPoint = jPoint; } - } - - /*--- Set the periodic point for this iPoint. ---*/ - vertex[iMarker][iVertex]->SetDonorPoint(pPoint, MASTER_NODE); - - /*--- Print warning if the nearest point was not within - the specified tolerance. Computation will continue. ---*/ - if (mindist > epsilon) { - isBadMatch = true; - cout.precision(10); - cout << endl; - cout << " Bad match for point " << iPoint << ".\tNearest"; - cout << " donor distance: " << scientific << mindist << "."; - } - } - - /*--- Print final warning when finding bad matches. ---*/ - if (isBadMatch) { - cout << endl; - cout << "\n !!! Warning !!!" << endl; - cout << "Bad matches found. Computation will continue, but be cautious.\n"; - } - cout << endl; - isBadMatch = false; - - } - - /*--- Create a vector to identify the points that belong to each periodic boundary condition ---*/ - bool *PeriodicBC = new bool [nPoint]; - for (iPoint = 0; iPoint < nPoint; iPoint++) PeriodicBC[iPoint] = false; - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - PeriodicBC[iPoint] = true; - } - - /*--- Determine the new points that must be added to each periodic boundary, - note that only one of the boundaries require the extra data ---*/ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) { - iPeriodic = config->GetMarker_All_PerBound(iMarker); - - /*--- An integer identify the periodic boundary condition --*/ - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - - /*--- iPoint is the original point on the surface and jPoint is the - equivalent point in the other periodic surface ---*/ - iPoint = vertex[iMarker][iVertex]->GetNode(); - jPoint = vertex[iMarker][iVertex]->GetDonorPoint(); - - /*--- First the case in which it is necessary to create a mirror set of elements ---*/ - if (CreateMirror[iPeriodic]) { - /*--- Now we must determine the neighbor points (including indirect ones) to the periodic points - and store all the information (in this list we do not include the points - that already belong to the periodic boundary), we also add the elements that - share a point with the periodic boundary condition ---*/ - for (iIndex = 0; iIndex < node[jPoint]->GetnElem(); iIndex++) { - iElem = node[jPoint]->GetElem(iIndex); - PeriodicElem[iPeriodic].push_back(iElem); - for (unsigned short iNode = 0; iNode < elem[iElem]->GetnNodes(); iNode ++) { - kPoint = elem[iElem]->GetNode(iNode); - if (!PeriodicBC[kPoint]) PeriodicPoint[iPeriodic][0].push_back(kPoint); - } - } - } - /*--- Second the case where no new element is added, neither points ---*/ - else { - PeriodicPoint[iPeriodic][0].push_back(jPoint); - PeriodicPoint[iPeriodic][1].push_back(iPoint); - } - } - } - } - - /*--- Sort the points that must be sended and delete repeated points ---*/ - for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { - if (CreateMirror[iPeriodic]) { - sort( PeriodicPoint[iPeriodic][0].begin(), PeriodicPoint[iPeriodic][0].end()); - IterPoint[iPeriodic][0] = unique( PeriodicPoint[iPeriodic][0].begin(), PeriodicPoint[iPeriodic][0].end()); - PeriodicPoint[iPeriodic][0].resize( IterPoint[iPeriodic][0] - PeriodicPoint[iPeriodic][0].begin() ); - } - } - - /*--- Create a list of the points that receive the values (only the new points) ---*/ - nPointPeriodic = nPoint; - for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { - if (CreateMirror[iPeriodic]) { - for (iPoint = 0; iPoint < PeriodicPoint[iPeriodic][0].size(); iPoint++) { - PeriodicPoint[iPeriodic][1].push_back(nPointPeriodic); - nPointPeriodic++; - } - } - } - - /*--- Sort the elements that must be replicated in the periodic boundary - and delete the repeated elements ---*/ - for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { - if (CreateMirror[iPeriodic]) { - sort( PeriodicElem[iPeriodic].begin(), PeriodicElem[iPeriodic].end()); - IterElem = unique( PeriodicElem[iPeriodic].begin(), PeriodicElem[iPeriodic].end()); - PeriodicElem[iPeriodic].resize( IterElem - PeriodicElem[iPeriodic].begin() ); - } - } - - /*--- Check all SEND points to see if they also lie on another boundary. ---*/ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - - /*--- iPoint is a node that lies on the current marker. ---*/ - iPoint = vertex[iMarker][iVertex]->GetNode(); - - /*--- Search through SEND points to check for iPoint. ---*/ - for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { - if (CreateMirror[iPeriodic]) { - - /*--- jPoint is the SEND point. ---*/ - for (iElem = 0; iElem < PeriodicPoint[iPeriodic][0].size(); iElem++) { - jPoint = PeriodicPoint[iPeriodic][0][iElem]; - - /*--- If the two match, then jPoint lies on this boundary. - However, we are concerned with the new points, so we - will store kPoint instead. ---*/ - if (iPoint == jPoint) { -// kPoint = PeriodicPoint[iPeriodic][1][iElem]; - - /*--- We also want the type of boundary element that this point - was within, so that we know what type of element to add - built from the new points. ---*/ - bool isJPoint, isPeriodic; - for (jElem = 0; jElem < nElem_Bound[iMarker]; jElem++) { - isJPoint = false; isPeriodic = false; - for (iNode = 0; iNode < bound[iMarker][jElem]->GetnNodes(); iNode++) { - if (bound[iMarker][jElem]->GetNode(iNode) == jPoint) isJPoint = true; - if (PeriodicBC[bound[iMarker][jElem]->GetNode(iNode)]) isPeriodic = true; - } - - /*--- If both points were found, store this element. ---*/ - if (isJPoint && isPeriodic) { - OldBoundaryElems[iMarker].push_back(jElem); - } - - } - - } - } - } - } - } - } - - /*--- Sort the elements that must be added and remove duplicates. ---*/ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - sort( OldBoundaryElems[iMarker].begin(), OldBoundaryElems[iMarker].end()); - IterNewElem[iMarker] = unique( OldBoundaryElems[iMarker].begin(), OldBoundaryElems[iMarker].end()); - OldBoundaryElems[iMarker].resize( IterNewElem[iMarker] - OldBoundaryElems[iMarker].begin() ); - } - - /*--- Create the new boundary elements. Points making up these new - elements must either be SEND/RECEIVE or periodic points. ---*/ - nNewElem_Bound = new unsigned long[nMarker]; - newBound = new CPrimalGrid**[nMarker]; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - nNewElem_Bound[iMarker] = OldBoundaryElems[iMarker].size(); - newBound[iMarker] = new CPrimalGrid*[nNewElem_Bound[iMarker]]; - - /*--- Loop through all new elements to be added. ---*/ - for (iElem = 0; iElem < nNewElem_Bound[iMarker]; iElem++) { - jElem = OldBoundaryElems[iMarker][iElem]; - - /*--- Loop through all nodes of this element. ---*/ - for (iNode = 0; iNode < bound[iMarker][jElem]->GetnNodes(); iNode++) { - pPoint = bound[iMarker][jElem]->GetNode(iNode); - - /*--- Check if this node is a send point. If so, the corresponding - receive point will be used in making the new boundary element. ---*/ - for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { - for (kElem = 0; kElem < PeriodicPoint[iPeriodic][0].size(); kElem++) { - if (pPoint == PeriodicPoint[iPeriodic][0][kElem]) newNodes[iNode] = PeriodicPoint[iPeriodic][1][kElem]; - } - } - - /*--- Check if this node is a periodic point. If so, the corresponding - periodic point will be used in making the new boundary element. ---*/ - if (PeriodicBC[pPoint]) { - - /*--- Find the corresponding periodic point. ---*/ - for (jMarker = 0; jMarker < config->GetnMarker_All(); jMarker++) { - if (config->GetMarker_All_KindBC(jMarker) == PERIODIC_BOUNDARY) { - for (iVertex = 0; iVertex < nVertex[jMarker]; iVertex++) { - if (pPoint == vertex[jMarker][iVertex]->GetNode()) {kMarker = jMarker; jVertex = iVertex;} - } - } - } - newNodes[iNode] = vertex[kMarker][jVertex]->GetDonorPoint(); - } - } - - /*--- Now instantiate the new element. ---*/ - VTK_Type = bound[iMarker][jElem]->GetVTK_Type(); - switch(VTK_Type) { - case LINE: - newBound[iMarker][iElem] = new CLine(newNodes[0], newNodes[1],2); - break; - case TRIANGLE: - newBound[iMarker][iElem] = new CTriangle(newNodes[0], newNodes[1], newNodes[2],3); - break; - case QUADRILATERAL: - newBound[iMarker][iElem] = new CQuadrilateral(newNodes[0], newNodes[1], newNodes[2], newNodes[3],3); - break; - } - - } - } - - delete [] PeriodicBC; - delete [] CreateMirror; - -} - -void CPhysicalGeometry::FindNormal_Neighbor(CConfig *config) { - su2double cos_max, scalar_prod, norm_vect, norm_Normal, cos_alpha, diff_coord, *Normal; - unsigned long Point_Normal, jPoint; - unsigned short iNeigh, iMarker, iDim; - unsigned long iPoint, iVertex; - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE && - config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY && - config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY ) { - - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - - iPoint = vertex[iMarker][iVertex]->GetNode(); - Normal = vertex[iMarker][iVertex]->GetNormal(); - - /*--- Compute closest normal neighbor, note that the normal are oriented inwards ---*/ - Point_Normal = 0; cos_max = -1.0; - for (iNeigh = 0; iNeigh < node[iPoint]->GetnPoint(); iNeigh++) { - jPoint = node[iPoint]->GetPoint(iNeigh); - scalar_prod = 0.0; norm_vect = 0.0; norm_Normal = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - diff_coord = node[jPoint]->GetCoord(iDim)-node[iPoint]->GetCoord(iDim); - scalar_prod += diff_coord*Normal[iDim]; - norm_vect += diff_coord*diff_coord; - norm_Normal += Normal[iDim]*Normal[iDim]; - } - norm_vect = sqrt(norm_vect); - norm_Normal = sqrt(norm_Normal); - cos_alpha = scalar_prod/(norm_vect*norm_Normal); - - /*--- Get maximum cosine ---*/ - if (cos_alpha >= cos_max) { - Point_Normal = jPoint; - cos_max = cos_alpha; - } - } - vertex[iMarker][iVertex]->SetNormal_Neighbor(Point_Normal); - } - } - } -} - -void CPhysicalGeometry::SetGeometryPlanes(CConfig *config) { - - bool loop_on; - unsigned short iMarker = 0; - su2double auxXCoord, auxYCoord, auxZCoord, *Face_Normal = NULL, auxArea, *Xcoord = NULL, *Ycoord = NULL, *Zcoord = NULL, *FaceArea = NULL; - unsigned long jVertex, iVertex, ixCoord, iPoint, iVertex_Wall, nVertex_Wall = 0; - - /*--- Compute the total number of points on the near-field ---*/ - nVertex_Wall = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) || - (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ) - nVertex_Wall += nVertex[iMarker]; - - - /*--- Create an array with all the coordinates, points, pressures, face area, - equivalent area, and nearfield weight ---*/ - Xcoord = new su2double[nVertex_Wall]; - Ycoord = new su2double[nVertex_Wall]; - if (nDim == 3) Zcoord = new su2double[nVertex_Wall]; - FaceArea = new su2double[nVertex_Wall]; - - /*--- Copy the boundary information to an array ---*/ - iVertex_Wall = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) || - (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ) - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - Xcoord[iVertex_Wall] = node[iPoint]->GetCoord(0); - Ycoord[iVertex_Wall] = node[iPoint]->GetCoord(1); - if (nDim==3) Zcoord[iVertex_Wall] = node[iPoint]->GetCoord(2); - Face_Normal = vertex[iMarker][iVertex]->GetNormal(); - FaceArea[iVertex_Wall] = fabs(Face_Normal[nDim-1]); - iVertex_Wall ++; - } - - - //vector XCoordList; - vector::iterator IterXCoordList; - - for (iVertex = 0; iVertex < nVertex_Wall; iVertex++) - XCoordList.push_back(Xcoord[iVertex]); - - sort( XCoordList.begin(), XCoordList.end()); - IterXCoordList = unique( XCoordList.begin(), XCoordList.end()); - XCoordList.resize( IterXCoordList - XCoordList.begin() ); - - /*--- Create vectors and distribute the values among the different PhiAngle queues ---*/ - Xcoord_plane.resize(XCoordList.size()); - Ycoord_plane.resize(XCoordList.size()); - if (nDim==3) Zcoord_plane.resize(XCoordList.size()); - FaceArea_plane.resize(XCoordList.size()); - Plane_points.resize(XCoordList.size()); - - - su2double dist_ratio; - unsigned long iCoord; - - /*--- Distribute the values among the different PhiAngles ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint++) { - if (node[iPoint]->GetDomain()) { - loop_on = true; - for (ixCoord = 0; ixCoord < XCoordList.size()-1 && loop_on; ixCoord++) { - dist_ratio = (node[iPoint]->GetCoord(0) - XCoordList[ixCoord])/(XCoordList[ixCoord+1]- XCoordList[ixCoord]); - if (dist_ratio >= 0 && dist_ratio <= 1.0) { - if (dist_ratio <= 0.5) iCoord = ixCoord; - else iCoord = ixCoord+1; - Xcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(0) ); - Ycoord_plane[iCoord].push_back(node[iPoint]->GetCoord(1) ); - if (nDim==3) Zcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(2) ); - FaceArea_plane[iCoord].push_back(node[iPoint]->GetVolume()); ///// CHECK AREA CALCULATION - Plane_points[iCoord].push_back(iPoint ); - loop_on = false; - } - } - } - } - - unsigned long auxPoint; - /*--- Order the arrays in ascending values of y ---*/ - for (ixCoord = 0; ixCoord < XCoordList.size(); ixCoord++) - for (iVertex = 0; iVertex < Xcoord_plane[ixCoord].size(); iVertex++) - for (jVertex = 0; jVertex < Xcoord_plane[ixCoord].size() - 1 - iVertex; jVertex++) - if (Ycoord_plane[ixCoord][jVertex] > Ycoord_plane[ixCoord][jVertex+1]) { - auxXCoord = Xcoord_plane[ixCoord][jVertex]; Xcoord_plane[ixCoord][jVertex] = Xcoord_plane[ixCoord][jVertex+1]; Xcoord_plane[ixCoord][jVertex+1] = auxXCoord; - auxYCoord = Ycoord_plane[ixCoord][jVertex]; Ycoord_plane[ixCoord][jVertex] = Ycoord_plane[ixCoord][jVertex+1]; Ycoord_plane[ixCoord][jVertex+1] = auxYCoord; - auxPoint = Plane_points[ixCoord][jVertex]; Plane_points[ixCoord][jVertex] = Plane_points[ixCoord][jVertex+1]; Plane_points[ixCoord][jVertex+1] = auxPoint; - if (nDim==3) { - auxZCoord = Zcoord_plane[ixCoord][jVertex]; Zcoord_plane[ixCoord][jVertex] = Zcoord_plane[ixCoord][jVertex+1]; Zcoord_plane[ixCoord][jVertex+1] = auxZCoord; - } - auxArea = FaceArea_plane[ixCoord][jVertex]; FaceArea_plane[ixCoord][jVertex] = FaceArea_plane[ixCoord][jVertex+1]; FaceArea_plane[ixCoord][jVertex+1] = auxArea; - } - - /*--- Delete structures ---*/ - delete[] Xcoord; delete[] Ycoord; - if (nDim==3) delete[] Zcoord; - delete[] FaceArea; -} - -void CPhysicalGeometry::SetBoundSensitivity(CConfig *config) { - unsigned short iMarker, icommas; - unsigned long iVertex, iPoint, (*Point2Vertex)[2], nPointLocal = 0, nPointGlobal = 0; - su2double Sensitivity; - bool *PointInDomain; - -#ifdef HAVE_MPI - int rank = MASTER_NODE; - int size = SINGLE_NODE; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); -#endif - - nPointLocal = nPoint; -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&nPointLocal, &nPointGlobal, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#else - nPointGlobal = nPointLocal; -#endif - - Point2Vertex = new unsigned long[nPointGlobal][2]; - PointInDomain = new bool[nPointGlobal]; - - for (iPoint = 0; iPoint < nPointGlobal; iPoint ++) - PointInDomain[iPoint] = false; - - for (iMarker = 0; iMarker < nMarker; iMarker++) - if (config->GetMarker_All_DV(iMarker) == YES) - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - - /*--- The sensitivity file uses the global numbering ---*/ - iPoint = node[vertex[iMarker][iVertex]->GetNode()]->GetGlobalIndex(); - - if (vertex[iMarker][iVertex]->GetNode() < GetnPointDomain()) { - Point2Vertex[iPoint][0] = iMarker; - Point2Vertex[iPoint][1] = iVertex; - PointInDomain[iPoint] = true; - vertex[iMarker][iVertex]->SetAuxVar(0.0); - } - } - - /*--- Time-average any unsteady surface sensitivities ---*/ - - unsigned long iExtIter, nExtIter; - su2double delta_T, total_T; - if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { - nExtIter = config->GetUnst_AdjointIter(); - delta_T = config->GetDelta_UnstTimeND(); - total_T = (su2double)nExtIter*delta_T; - } else if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { - - /*--- Compute period of oscillation & compute time interval using nTimeInstances ---*/ - - su2double period = config->GetTimeSpectral_Period(); - nExtIter = config->GetnTimeInstances(); - delta_T = period/(su2double)nExtIter; - total_T = period; - - } else { - nExtIter = 1; - delta_T = 1.0; - total_T = 1.0; - } - - for (iExtIter = 0; iExtIter < nExtIter; iExtIter++) { - - /*--- Prepare to read surface sensitivity files (CSV) ---*/ - - string text_line; - ifstream Surface_file; - char buffer[50]; - char cstr[MAX_STRING_SIZE]; - string surfadj_filename = config->GetSurfAdjCoeff_FileName(); - strcpy (cstr, surfadj_filename.c_str()); - - /*--- Write file name with extension if unsteady or steady ---*/ - - if ((config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) || - (config->GetUnsteady_Simulation() == TIME_SPECTRAL)) { - if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(iExtIter)); - if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(iExtIter)); - } - else - SPRINTF (buffer, ".csv"); - - strcat (cstr, buffer); - - /*--- Read the sensitivity file ---*/ - - string::size_type position; - - Surface_file.open(cstr, ios::in); - getline(Surface_file, text_line); - - while (getline(Surface_file, text_line)) { - for (icommas = 0; icommas < 50; icommas++) { - position = text_line.find( ",", 0 ); - if (position!=string::npos) text_line.erase (position,1); - } - stringstream point_line(text_line); - point_line >> iPoint >> Sensitivity; - - if (PointInDomain[iPoint]) { - - /*--- Find the vertex for the Point and Marker ---*/ - - iMarker = Point2Vertex[iPoint][0]; - iVertex = Point2Vertex[iPoint][1]; - - /*--- Increment the auxiliary variable with the contribution of - this unsteady timestep. For steady problems, this reduces to - a single sensitivity value multiplied by 1.0. ---*/ - - vertex[iMarker][iVertex]->AddAuxVar(Sensitivity*(delta_T/total_T)); - } - - } - Surface_file.close(); - } - - delete[] Point2Vertex; -} - -void CPhysicalGeometry::SetSensitivity(CConfig *config){ - - ifstream restart_file; - string filename = config->GetSolution_AdjFileName(); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool sst = config->GetKind_Turb_Model() == SST; - bool sa = config->GetKind_Turb_Model() == SA; - bool grid_movement = config->GetGrid_Movement(); - su2double Sens, dull_val; - //su2double delta_T, total_T; - unsigned short nExtIter, iDim, iExtIter; - unsigned long iPoint, index; - - Sensitivity = new su2double[nPoint*nDim]; - - if (config->GetUnsteady_Simulation()){ - nExtIter = config->GetUnst_AdjointIter(); - // delta_T = config->GetDelta_UnstTimeND(); - // delta_T = 1.0; - //total_T = (su2double)nExtIter*delta_T; - }else{ - //total_T = 1.0; - nExtIter = 1; - } - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - #endif - - unsigned short skipVar = nDim; - - if (incompressible) { skipVar += nDim+1; } - if (freesurface) { skipVar += nDim+2; } - if (compressible) { skipVar += nDim+2; } - if (sst) { skipVar += 2;} - if (sa) { skipVar += 1;} - - if (grid_movement) {skipVar += nDim;} - - /*--- Sensitivity in normal direction ---*/ - - skipVar += 1; - - /*--- In case this is a parallel simulation, we need to perform the - Global2Local index transformation first. ---*/ - long *Global2Local = new long[Global_nPointDomain]; - - /*--- First, set all indices to a negative value by default ---*/ - for(iPoint = 0; iPoint < Global_nPointDomain; iPoint++) - Global2Local[iPoint] = -1; - - /*--- Now fill array with the transform values only for local points ---*/ - for(iPoint = 0; iPoint < nPointDomain; iPoint++) - Global2Local[node[iPoint]->GetGlobalIndex()] = iPoint; - - /*--- Read all lines in the restart file ---*/ - long iPoint_Local; unsigned long iPoint_Global = 0; string text_line; - - - for (iPoint = 0; iPoint < nPoint; iPoint++){ - for (iDim = 0; iDim < nDim; iDim++){ - Sensitivity[iPoint*nDim+iDim] = 0.0; - } - } - - for (iExtIter = 0; iExtIter < nExtIter; iExtIter++){ - - iPoint_Global = 0; - - filename = config->GetSolution_AdjFileName(); - - filename = config->GetObjFunc_Extension(filename); - - if (config->GetUnsteady_Simulation()){ - filename = config->GetUnsteady_FileName(filename, iExtIter); - } - - restart_file.open(filename.data(), ios::in); - if (restart_file.fail()) { - cout << "There is no adjoint restart file!! " << filename.data() << "."<< endl; - exit(EXIT_FAILURE); - } - - if (rank == MASTER_NODE) - cout << "Reading in sensitivity at iteration " << iExtIter << "."<< endl; - /*--- The first line is the header ---*/ - getline (restart_file, text_line); - - while (getline (restart_file, text_line)) { - istringstream point_line(text_line); - - /*--- Retrieve local index. If this node from the restart file lives - on a different processor, the value of iPoint_Local will be -1. - Otherwise, the local index for this node on the current processor - will be returned and used to instantiate the vars. ---*/ - iPoint_Local = Global2Local[iPoint_Global]; - - if (iPoint_Local >= 0){ - point_line >> index; - for (iDim = 0; iDim < skipVar; iDim++){ point_line >> dull_val;} - for (iDim = 0; iDim < nDim; iDim++){ - point_line >> Sens; - // Sensitivity[iPoint_Local*nDim+iDim] += Sens*delta_T/total_T; - Sensitivity[iPoint_Local*nDim+iDim] += Sens; - - } - } - iPoint_Global++; - } - restart_file.close(); - } -} - -su2double CPhysicalGeometry::Compute_MaxThickness(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { - unsigned long iVertex, jVertex, n, Trailing_Point, Leading_Point; - su2double Normal[3], Tangent[3], BiNormal[3], auxXCoord, auxYCoord, auxZCoord, zp1, zpn, MaxThickness_Value = 0, Thickness, Length, Xcoord_Trailing, Ycoord_Trailing, Zcoord_Trailing, ValCos, ValSin, XValue, ZValue, MaxDistance, Distance, AoA; - vector Xcoord, Ycoord, Zcoord, Z2coord, Xcoord_Normal, Ycoord_Normal, Zcoord_Normal, Xcoord_Airfoil_, Ycoord_Airfoil_, Zcoord_Airfoil_; - - /*--- Find the leading and trailing edges and compute the angle of attack ---*/ - - MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0; - for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) { - Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) + - pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) + - pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0)); - - if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; } - } - - AoA = atan((Zcoord_Airfoil[Leading_Point] - Zcoord_Airfoil[Trailing_Point]) / (Xcoord_Airfoil[Trailing_Point] - Xcoord_Airfoil[Leading_Point]))*180/PI_NUMBER; - - /*--- Translate to the origin ---*/ - - Xcoord_Trailing = Xcoord_Airfoil[0]; - Ycoord_Trailing = Ycoord_Airfoil[0]; - Zcoord_Trailing = Zcoord_Airfoil[0]; - - for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { - Xcoord_Airfoil_.push_back(Xcoord_Airfoil[iVertex] - Xcoord_Trailing); - Ycoord_Airfoil_.push_back(Ycoord_Airfoil[iVertex] - Ycoord_Trailing); - Zcoord_Airfoil_.push_back(Zcoord_Airfoil[iVertex] - Zcoord_Trailing); - } - - /*--- Rotate the airfoil ---*/ - - ValCos = cos(AoA*PI_NUMBER/180.0); - ValSin = sin(AoA*PI_NUMBER/180.0); - - for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { - XValue = Xcoord_Airfoil_[iVertex]; - ZValue = Zcoord_Airfoil_[iVertex]; - - Xcoord_Airfoil_[iVertex] = XValue*ValCos - ZValue*ValSin; - Zcoord_Airfoil_[iVertex] = ZValue*ValCos + XValue*ValSin; - - } - - /*--- Identify upper and lower side, and store the value of the normal --*/ - - for (iVertex = 1; iVertex < Xcoord_Airfoil_.size(); iVertex++) { - Tangent[0] = Xcoord_Airfoil_[iVertex] - Xcoord_Airfoil_[iVertex-1]; - Tangent[1] = Ycoord_Airfoil_[iVertex] - Ycoord_Airfoil_[iVertex-1]; - Tangent[2] = Zcoord_Airfoil_[iVertex] - Zcoord_Airfoil_[iVertex-1]; - Length = sqrt(pow(Tangent[0], 2.0) + pow(Tangent[1], 2.0) + pow(Tangent[2], 2.0)); - Tangent[0] /= Length; Tangent[1] /= Length; Tangent[2] /= Length; - - BiNormal[0] = Plane_Normal[0]; - BiNormal[1] = Plane_Normal[1]; - BiNormal[2] = Plane_Normal[2]; - Length = sqrt(pow(BiNormal[0], 2.0) + pow(BiNormal[1], 2.0) + pow(BiNormal[2], 2.0)); - BiNormal[0] /= Length; BiNormal[1] /= Length; BiNormal[2] /= Length; - - Normal[0] = Tangent[1]*BiNormal[2] - Tangent[2]*BiNormal[1]; - Normal[1] = Tangent[2]*BiNormal[0] - Tangent[0]*BiNormal[2]; - Normal[2] = Tangent[0]*BiNormal[1] - Tangent[1]*BiNormal[0]; - - Xcoord_Normal.push_back(Normal[0]); Ycoord_Normal.push_back(Normal[1]); Zcoord_Normal.push_back(Normal[2]); - - unsigned short index = 2; - if ((config->GetAxis_Orientation() == Z_AXIS) && (nDim == 3)) index = 0; - - if (Normal[index] >= 0.0) { - Xcoord.push_back(Xcoord_Airfoil_[iVertex]); - Ycoord.push_back(Ycoord_Airfoil_[iVertex]); - Zcoord.push_back(Zcoord_Airfoil_[iVertex]); - } - - } - - /*--- Order the arrays using the X component ---*/ - - for (iVertex = 0; iVertex < Xcoord.size(); iVertex++) { - for (jVertex = 0; jVertex < Xcoord.size() - 1 - iVertex; jVertex++) { - if (Xcoord[jVertex] > Xcoord[jVertex+1]) { - auxXCoord = Xcoord[jVertex]; Xcoord[jVertex] = Xcoord[jVertex+1]; Xcoord[jVertex+1] = auxXCoord; - auxYCoord = Ycoord[jVertex]; Ycoord[jVertex] = Ycoord[jVertex+1]; Ycoord[jVertex+1] = auxYCoord; - auxZCoord = Zcoord[jVertex]; Zcoord[jVertex] = Zcoord[jVertex+1]; Zcoord[jVertex+1] = auxZCoord; - } - } - } - - n = Xcoord.size(); - zp1 = (Zcoord[1]-Zcoord[0])/(Xcoord[1]-Xcoord[0]); - zpn = (Zcoord[n-1]-Zcoord[n-2])/(Xcoord[n-1]-Xcoord[n-2]); - Z2coord.resize(n+1); - SetSpline(Xcoord, Zcoord, n, zp1, zpn, Z2coord); - - /*--- Compute the thickness (we add a fabs because we can not guarantee the - right sorting of the points and the upper and/or lower part of the airfoil is not well defined) ---*/ - - MaxThickness_Value = 0.0; - for (iVertex = 0; iVertex < Xcoord_Airfoil_.size(); iVertex++) { - if (Zcoord_Normal[iVertex] < 0.0) { - Thickness = fabs(Zcoord_Airfoil_[iVertex] - GetSpline(Xcoord, Zcoord, Z2coord, n, Xcoord_Airfoil_[iVertex])); - if (Thickness > MaxThickness_Value) { MaxThickness_Value = Thickness; } - } - } - - return MaxThickness_Value; - -} - -su2double CPhysicalGeometry::Compute_AoA(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { - unsigned long iVertex, Trailing_Point, Leading_Point; - su2double MaxDistance, Distance, AoA = 0.0; - - /*--- Find the leading and trailing edges and compute the angle of attack ---*/ - MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0; - for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) { - Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) + - pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) + - pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0)); - - if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; } - } - - AoA = atan((Zcoord_Airfoil[Leading_Point] - Zcoord_Airfoil[Trailing_Point]) / (Xcoord_Airfoil[Trailing_Point] - Xcoord_Airfoil[Leading_Point]))*180/PI_NUMBER; - - return AoA; - -} - -su2double CPhysicalGeometry::Compute_Chord(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { - unsigned long iVertex, Trailing_Point; - su2double MaxDistance, Distance, Chord = 0.0; - - /*--- Find the leading and trailing edges and compute the angle of attack ---*/ - MaxDistance = 0.0; Trailing_Point = 0; - for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) { - - Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) + - pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) + - pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0)); - - if (MaxDistance < Distance) { MaxDistance = Distance; } - } - - Chord = MaxDistance; - - return Chord; - -} - -su2double CPhysicalGeometry::Compute_Thickness(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, su2double Location, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { - unsigned long iVertex, jVertex, n_Upper, n_Lower, Trailing_Point, Leading_Point; - su2double Thickness_Location, Normal[3], Tangent[3], BiNormal[3], auxXCoord, auxYCoord, auxZCoord, Thickness_Value = 0.0, Length, Xcoord_Trailing, Ycoord_Trailing, Zcoord_Trailing, ValCos, ValSin, XValue, ZValue, zp1, zpn, Chord, MaxDistance, Distance, AoA; - vector Xcoord_Upper, Ycoord_Upper, Zcoord_Upper, Z2coord_Upper, Xcoord_Lower, Ycoord_Lower, Zcoord_Lower, Z2coord_Lower, Z2coord, Xcoord_Normal, Ycoord_Normal, Zcoord_Normal, Xcoord_Airfoil_, Ycoord_Airfoil_, Zcoord_Airfoil_; - - /*--- Find the leading and trailing edges and compute the angle of attack ---*/ - - MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0; - for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) { - Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) + - pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) + - pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0)); - - if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; } - } - - AoA = atan((Zcoord_Airfoil[Leading_Point] - Zcoord_Airfoil[Trailing_Point]) / (Xcoord_Airfoil[Trailing_Point] - Xcoord_Airfoil[Leading_Point]))*180/PI_NUMBER; - Chord = MaxDistance; - - /*--- Translate to the origin ---*/ - - Xcoord_Trailing = Xcoord_Airfoil[0]; - Ycoord_Trailing = Ycoord_Airfoil[0]; - Zcoord_Trailing = Zcoord_Airfoil[0]; - - for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { - Xcoord_Airfoil_.push_back(Xcoord_Airfoil[iVertex] - Xcoord_Trailing); - Ycoord_Airfoil_.push_back(Ycoord_Airfoil[iVertex] - Ycoord_Trailing); - Zcoord_Airfoil_.push_back(Zcoord_Airfoil[iVertex] - Zcoord_Trailing); - } - - /*--- Rotate the airfoil ---*/ - - ValCos = cos(AoA*PI_NUMBER/180.0); - ValSin = sin(AoA*PI_NUMBER/180.0); - - for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { - XValue = Xcoord_Airfoil_[iVertex]; - ZValue = Zcoord_Airfoil_[iVertex]; - - Xcoord_Airfoil_[iVertex] = XValue*ValCos - ZValue*ValSin; - Zcoord_Airfoil_[iVertex] = ZValue*ValCos + XValue*ValSin; - } - - /*--- Identify upper and lower side, and store the value of the normal --*/ - - for (iVertex = 1; iVertex < Xcoord_Airfoil_.size(); iVertex++) { - Tangent[0] = Xcoord_Airfoil_[iVertex] - Xcoord_Airfoil_[iVertex-1]; - Tangent[1] = Ycoord_Airfoil_[iVertex] - Ycoord_Airfoil_[iVertex-1]; - Tangent[2] = Zcoord_Airfoil_[iVertex] - Zcoord_Airfoil_[iVertex-1]; - Length = sqrt(pow(Tangent[0], 2.0) + pow(Tangent[1], 2.0) + pow(Tangent[2], 2.0)); - Tangent[0] /= Length; Tangent[1] /= Length; Tangent[2] /= Length; - - BiNormal[0] = Plane_Normal[0]; - BiNormal[1] = Plane_Normal[1]; - BiNormal[2] = Plane_Normal[2]; - Length = sqrt(pow(BiNormal[0], 2.0) + pow(BiNormal[1], 2.0) + pow(BiNormal[2], 2.0)); - BiNormal[0] /= Length; BiNormal[1] /= Length; BiNormal[2] /= Length; - - Normal[0] = Tangent[1]*BiNormal[2] - Tangent[2]*BiNormal[1]; - Normal[1] = Tangent[2]*BiNormal[0] - Tangent[0]*BiNormal[2]; - Normal[2] = Tangent[0]*BiNormal[1] - Tangent[1]*BiNormal[0]; - - Xcoord_Normal.push_back(Normal[0]); Ycoord_Normal.push_back(Normal[1]); Zcoord_Normal.push_back(Normal[2]); - - unsigned short index = 2; - if ((config->GetAxis_Orientation() == Z_AXIS) && (nDim == 3)) index = 0; - - if (Normal[index] >= 0.0) { - Xcoord_Upper.push_back(Xcoord_Airfoil_[iVertex]); - Ycoord_Upper.push_back(Ycoord_Airfoil_[iVertex]); - Zcoord_Upper.push_back(Zcoord_Airfoil_[iVertex]); - } - else { - Xcoord_Lower.push_back(Xcoord_Airfoil_[iVertex]); - Ycoord_Lower.push_back(Ycoord_Airfoil_[iVertex]); - Zcoord_Lower.push_back(Zcoord_Airfoil_[iVertex]); - } - - } - - /*--- Order the arrays using the X component ---*/ - - for (iVertex = 0; iVertex < Xcoord_Upper.size(); iVertex++) { - for (jVertex = 0; jVertex < Xcoord_Upper.size() - 1 - iVertex; jVertex++) { - if (Xcoord_Upper[jVertex] > Xcoord_Upper[jVertex+1]) { - auxXCoord = Xcoord_Upper[jVertex]; Xcoord_Upper[jVertex] = Xcoord_Upper[jVertex+1]; Xcoord_Upper[jVertex+1] = auxXCoord; - auxYCoord = Ycoord_Upper[jVertex]; Ycoord_Upper[jVertex] = Ycoord_Upper[jVertex+1]; Ycoord_Upper[jVertex+1] = auxYCoord; - auxZCoord = Zcoord_Upper[jVertex]; Zcoord_Upper[jVertex] = Zcoord_Upper[jVertex+1]; Zcoord_Upper[jVertex+1] = auxZCoord; - } - } - } - - /*--- Order the arrays using the X component ---*/ - - for (iVertex = 0; iVertex < Xcoord_Lower.size(); iVertex++) { - for (jVertex = 0; jVertex < Xcoord_Lower.size() - 1 - iVertex; jVertex++) { - if (Xcoord_Lower[jVertex] > Xcoord_Lower[jVertex+1]) { - auxXCoord = Xcoord_Lower[jVertex]; Xcoord_Lower[jVertex] = Xcoord_Lower[jVertex+1]; Xcoord_Lower[jVertex+1] = auxXCoord; - auxYCoord = Ycoord_Lower[jVertex]; Ycoord_Lower[jVertex] = Ycoord_Lower[jVertex+1]; Ycoord_Lower[jVertex+1] = auxYCoord; - auxZCoord = Zcoord_Lower[jVertex]; Zcoord_Lower[jVertex] = Zcoord_Lower[jVertex+1]; Zcoord_Lower[jVertex+1] = auxZCoord; - } - } - } - - n_Upper = Xcoord_Upper.size(); - zp1 = (Zcoord_Upper[1]-Zcoord_Upper[0])/(Xcoord_Upper[1]-Xcoord_Upper[0]); - zpn = (Zcoord_Upper[n_Upper-1]-Zcoord_Upper[n_Upper-2])/(Xcoord_Upper[n_Upper-1]-Xcoord_Upper[n_Upper-2]); - Z2coord_Upper.resize(n_Upper+1); - SetSpline(Xcoord_Upper, Zcoord_Upper, n_Upper, zp1, zpn, Z2coord_Upper); - - n_Lower = Xcoord_Lower.size(); - zp1 = (Zcoord_Lower[1]-Zcoord_Lower[0])/(Xcoord_Lower[1]-Xcoord_Lower[0]); - zpn = (Zcoord_Lower[n_Lower-1]-Zcoord_Lower[n_Lower-2])/(Xcoord_Lower[n_Lower-1]-Xcoord_Lower[n_Lower-2]); - Z2coord_Lower.resize(n_Lower+1); - SetSpline(Xcoord_Lower, Zcoord_Lower, n_Lower, zp1, zpn, Z2coord_Lower); - - /*--- Compute the thickness (we add a fabs because we can not guarantee the - right sorting of the points and the upper and/or lower part of the airfoil is not well defined) ---*/ - - Thickness_Location = - Chord*(1.0-Location); - - Thickness_Value = fabs(GetSpline(Xcoord_Upper, Zcoord_Upper, Z2coord_Upper, n_Upper, Thickness_Location) - GetSpline(Xcoord_Lower, Zcoord_Lower, Z2coord_Lower, n_Lower, Thickness_Location)); - - return Thickness_Value; - -} - -su2double CPhysicalGeometry::Compute_Area(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { - unsigned long iVertex, jVertex; - su2double Normal[3], Tangent[3], BiNormal[3], auxXCoord, auxYCoord, auxZCoord, Area_Value = 0.0, Area_Value_Upper = 0.0, Area_Value_Lower = 0.0, Length, Xcoord_Trailing, Ycoord_Trailing, Zcoord_Trailing, ValCos, ValSin, XValue, ZValue; - vector Xcoord_Upper, Ycoord_Upper, Zcoord_Upper, Xcoord_Lower, Ycoord_Lower, Zcoord_Lower, Z2coord, Xcoord_Normal, Ycoord_Normal, Zcoord_Normal, Xcoord_Airfoil_, Ycoord_Airfoil_, Zcoord_Airfoil_; - unsigned long Trailing_Point, Leading_Point; - su2double MaxDistance, Distance, AoA; - - /*--- Find the leading and trailing edges and compute the angle of attack ---*/ - - MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0; - for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) { - Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) + - pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) + - pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0)); - - if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; } - } - - AoA = atan((Zcoord_Airfoil[Leading_Point] - Zcoord_Airfoil[Trailing_Point]) / (Xcoord_Airfoil[Trailing_Point] - Xcoord_Airfoil[Leading_Point]))*180/PI_NUMBER; - - /*--- Translate to the origin ---*/ - - Xcoord_Trailing = Xcoord_Airfoil[0]; - Ycoord_Trailing = Ycoord_Airfoil[0]; - Zcoord_Trailing = Zcoord_Airfoil[0]; - - for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { - Xcoord_Airfoil_.push_back(Xcoord_Airfoil[iVertex] - Xcoord_Trailing); - Ycoord_Airfoil_.push_back(Ycoord_Airfoil[iVertex] - Ycoord_Trailing); - Zcoord_Airfoil_.push_back(Zcoord_Airfoil[iVertex] - Zcoord_Trailing); - } - - /*--- Rotate the airfoil ---*/ - - ValCos = cos(AoA*PI_NUMBER/180.0); - ValSin = sin(AoA*PI_NUMBER/180.0); - - for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { - XValue = Xcoord_Airfoil_[iVertex]; - ZValue = Zcoord_Airfoil_[iVertex]; - - Xcoord_Airfoil_[iVertex] = XValue*ValCos - ZValue*ValSin; - Zcoord_Airfoil_[iVertex] = ZValue*ValCos + XValue*ValSin; - - } - - /*--- Identify upper and lower side, and store the value of the normal --*/ - - for (iVertex = 1; iVertex < Xcoord_Airfoil_.size(); iVertex++) { - Tangent[0] = Xcoord_Airfoil_[iVertex] - Xcoord_Airfoil_[iVertex-1]; - Tangent[1] = Ycoord_Airfoil_[iVertex] - Ycoord_Airfoil_[iVertex-1]; - Tangent[2] = Zcoord_Airfoil_[iVertex] - Zcoord_Airfoil_[iVertex-1]; - Length = sqrt(pow(Tangent[0], 2.0) + pow(Tangent[1], 2.0) + pow(Tangent[2], 2.0)); - Tangent[0] /= Length; Tangent[1] /= Length; Tangent[2] /= Length; - - BiNormal[0] = Plane_Normal[0]; - BiNormal[1] = Plane_Normal[1]; - BiNormal[2] = Plane_Normal[2]; - Length = sqrt(pow(BiNormal[0], 2.0) + pow(BiNormal[1], 2.0) + pow(BiNormal[2], 2.0)); - BiNormal[0] /= Length; BiNormal[1] /= Length; BiNormal[2] /= Length; - - Normal[0] = Tangent[1]*BiNormal[2] - Tangent[2]*BiNormal[1]; - Normal[1] = Tangent[2]*BiNormal[0] - Tangent[0]*BiNormal[2]; - Normal[2] = Tangent[0]*BiNormal[1] - Tangent[1]*BiNormal[0]; - - Xcoord_Normal.push_back(Normal[0]); Ycoord_Normal.push_back(Normal[1]); Zcoord_Normal.push_back(Normal[2]); - - unsigned short index = 2; - if ((config->GetAxis_Orientation() == Z_AXIS) && (nDim == 3)) index = 0; - - if (Normal[index] >= 0.0) { - Xcoord_Upper.push_back(Xcoord_Airfoil_[iVertex]); - Ycoord_Upper.push_back(Ycoord_Airfoil_[iVertex]); - Zcoord_Upper.push_back(Zcoord_Airfoil_[iVertex]); - } - else { - Xcoord_Lower.push_back(Xcoord_Airfoil_[iVertex]); - Ycoord_Lower.push_back(Ycoord_Airfoil_[iVertex]); - Zcoord_Lower.push_back(Zcoord_Airfoil_[iVertex]); - } - - } - - /*--- Order the arrays using the X component ---*/ - - for (iVertex = 0; iVertex < Xcoord_Upper.size(); iVertex++) { - for (jVertex = 0; jVertex < Xcoord_Upper.size() - 1 - iVertex; jVertex++) { - if (Xcoord_Upper[jVertex] > Xcoord_Upper[jVertex+1]) { - auxXCoord = Xcoord_Upper[jVertex]; Xcoord_Upper[jVertex] = Xcoord_Upper[jVertex+1]; Xcoord_Upper[jVertex+1] = auxXCoord; - auxYCoord = Ycoord_Upper[jVertex]; Ycoord_Upper[jVertex] = Ycoord_Upper[jVertex+1]; Ycoord_Upper[jVertex+1] = auxYCoord; - auxZCoord = Zcoord_Upper[jVertex]; Zcoord_Upper[jVertex] = Zcoord_Upper[jVertex+1]; Zcoord_Upper[jVertex+1] = auxZCoord; - } - } - } - - /*--- Order the arrays using the X component ---*/ - - for (iVertex = 0; iVertex < Xcoord_Lower.size(); iVertex++) { - for (jVertex = 0; jVertex < Xcoord_Lower.size() - 1 - iVertex; jVertex++) { - if (Xcoord_Lower[jVertex] > Xcoord_Lower[jVertex+1]) { - auxXCoord = Xcoord_Lower[jVertex]; Xcoord_Lower[jVertex] = Xcoord_Lower[jVertex+1]; Xcoord_Lower[jVertex+1] = auxXCoord; - auxYCoord = Ycoord_Lower[jVertex]; Ycoord_Lower[jVertex] = Ycoord_Lower[jVertex+1]; Ycoord_Lower[jVertex+1] = auxYCoord; - auxZCoord = Zcoord_Lower[jVertex]; Zcoord_Lower[jVertex] = Zcoord_Lower[jVertex+1]; Zcoord_Lower[jVertex+1] = auxZCoord; - } - } - } - - /*--- Compute total area ---*/ - - Area_Value_Upper = 0.0; - Area_Value_Lower = 0.0; - - for (iVertex = 0; iVertex < Xcoord_Upper.size()-1; iVertex++) - Area_Value_Upper += (Xcoord_Upper[iVertex+1] - Xcoord_Upper[iVertex]) * 0.5*(Zcoord_Upper[iVertex+1] + Zcoord_Upper[iVertex]); - for (iVertex = 0; iVertex < Xcoord_Lower.size()-1; iVertex++) - Area_Value_Lower += (Xcoord_Lower[iVertex+1] - Xcoord_Lower[iVertex]) * 0.5*(Zcoord_Lower[iVertex+1] + Zcoord_Lower[iVertex]); - - Area_Value = fabs(Area_Value_Upper - Area_Value_Lower); - return Area_Value; - -} - -su2double CPhysicalGeometry::Compute_Volume(CConfig *config, bool original_surface) { - - int rank = MASTER_NODE; - - /*--- MPI initialization ---*/ - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - unsigned short iPlane, nPlane = 0; - su2double Volume = 0.0, MinPlane, MaxPlane, MinXCoord, MaxXCoord, dPlane, *Area; - vector *Xcoord_Airfoil, *Ycoord_Airfoil, *Zcoord_Airfoil, *Variable_Airfoil; - - /*--- Make a large number of section cuts for approximating volume ---*/ - - nPlane = config->GetnVolSections(); - - /*--- Allocate memory for the section cutting ---*/ - - Area = new su2double [nPlane]; - - su2double **Plane_P0 = new su2double*[nPlane]; - for (iPlane = 0; iPlane < nPlane; iPlane++ ) - Plane_P0[iPlane] = new su2double[nDim]; - - su2double **Plane_Normal = new su2double*[nPlane]; - for (iPlane = 0; iPlane < nPlane; iPlane++ ) - Plane_Normal[iPlane] = new su2double[nDim]; - - - MinPlane = config->GetSection_Location(0); MaxPlane = config->GetSection_Location(1); - MinXCoord = -1E6; MaxXCoord = 1E6; - dPlane = fabs((MaxPlane - MinPlane)/su2double(nPlane-1)); - for (iPlane = 0; iPlane < nPlane; iPlane++) { - Plane_Normal[iPlane][0] = 0.0; Plane_P0[iPlane][0] = 0.0; - Plane_Normal[iPlane][1] = 0.0; Plane_P0[iPlane][1] = 0.0; - Plane_Normal[iPlane][2] = 0.0; Plane_P0[iPlane][2] = 0.0; - Plane_Normal[iPlane][config->GetAxis_Orientation()] = 1.0; - Plane_P0[iPlane][config->GetAxis_Orientation()] = MinPlane + iPlane*dPlane; - } - - /*--- Allocate some vectors for storing airfoil coordinates ---*/ - - Xcoord_Airfoil = new vector[nPlane]; - Ycoord_Airfoil = new vector[nPlane]; - Zcoord_Airfoil = new vector[nPlane]; - Variable_Airfoil = new vector[nPlane]; - - /*--- Create the section slices through the geometry ---*/ - - for (iPlane = 0; iPlane < nPlane; iPlane++) { - ComputeAirfoil_Section(Plane_P0[iPlane], Plane_Normal[iPlane], - MinXCoord, MaxXCoord, NULL, Xcoord_Airfoil[iPlane], - Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane], - Variable_Airfoil[iPlane], original_surface, config); - } - - /*--- Compute the area at each section ---*/ - - if (rank == MASTER_NODE) { - - for (iPlane = 0; iPlane < nPlane; iPlane++) { - Area[iPlane] = 0.0; - if (Xcoord_Airfoil[iPlane].size() != 0) { - Area[iPlane] = Compute_Area(Plane_P0[iPlane], Plane_Normal[iPlane], - iPlane, config, Xcoord_Airfoil[iPlane], - Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane], - original_surface); - } - } - - /*--- Compute the volume using a composite Simpson's rule ---*/ - - Volume = 0.0; - for (iPlane = 0; iPlane < nPlane-2; iPlane+=2) { - if (Xcoord_Airfoil[iPlane].size() != 0) { - Volume += (1.0/3.0)*dPlane*(Area[iPlane] + 4.0*Area[iPlane+1] + Area[iPlane+2]); - } - } - - } - - /*--- Free memory for the section cuts ---*/ - - delete [] Xcoord_Airfoil; - delete [] Ycoord_Airfoil; - delete [] Zcoord_Airfoil; - delete [] Variable_Airfoil; - - for (iPlane = 0; iPlane < nPlane; iPlane++) - delete [] Plane_P0[iPlane]; - delete [] Plane_P0; - - for (iPlane = 0; iPlane < nPlane; iPlane++) - delete [] Plane_Normal[iPlane]; - delete [] Plane_Normal; - - delete [] Area; - - /*--- Return the volume and exit ---*/ - - return Volume; -} - -CMultiGridGeometry::CMultiGridGeometry(CGeometry ***geometry, CConfig **config_container, unsigned short iMesh, unsigned short iZone) : CGeometry() { - - /*--- CGeometry & CConfig pointers to the fine grid level for clarity. We may - need access to the other zones in the mesh for zone boundaries. ---*/ - - CGeometry *fine_grid = geometry[iZone][iMesh-1]; - CConfig *config = config_container[iZone]; - - /*--- Local variables ---*/ - - unsigned long iPoint, Index_CoarseCV, CVPoint, iElem, iVertex, jPoint, iteration, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector, iParent, jVertex, *Buffer_Receive_Parent = NULL, *Buffer_Send_Parent = NULL, *Buffer_Receive_Children = NULL, *Buffer_Send_Children = NULL, *Parent_Remote = NULL, *Children_Remote = NULL, *Parent_Local = NULL, *Children_Local = NULL, Local_nPointCoarse, Local_nPointFine, Global_nPointCoarse, Global_nPointFine;; - short marker_seed; - bool agglomerate_seed = true; - unsigned short nChildren, iNode, counter, iMarker, jMarker, priority, MarkerS, MarkerR, *nChildren_MPI; - vector Suitable_Indirect_Neighbors, Aux_Parent; - vector::iterator it; - int rank; - - unsigned short nMarker_Max = config->GetnMarker_Max(); - - unsigned short *copy_marker = new unsigned short [nMarker_Max]; - -#ifndef HAVE_MPI - rank = MASTER_NODE; -#else - int send_to, receive_from; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Status status; -#endif - - nDim = fine_grid->GetnDim(); // Write the number of dimensions of the coarse grid. - - /*--- Create a queue system to deo the agglomeration - 1st) More than two markers ---> Vertices (never agglomerate) - 2nd) Two markers ---> Edges (agglomerate if same BC, never agglomerate if different BC) - 3rd) One marker ---> Surface (always agglomarate) - 4th) No marker ---> Internal Volume (always agglomarate) ---*/ - - /*--- Set a marker to indicate indirect agglomeration ---*/ - - if (iMesh == MESH_1) { - - for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) - fine_grid->node[iPoint]->SetAgglomerate_Indirect(false); - - for (iElem = 0; iElem < fine_grid->GetnElem(); iElem++) { - if ((fine_grid->elem[iElem]->GetVTK_Type() == HEXAHEDRON) || - (fine_grid->elem[iElem]->GetVTK_Type() == QUADRILATERAL)) { - for (iNode = 0; iNode < fine_grid->elem[iElem]->GetnNodes(); iNode++) { - iPoint = fine_grid->elem[iElem]->GetNode(iNode); - fine_grid->node[iPoint]->SetAgglomerate_Indirect(true); - } - } - } - - } - - /*--- Create the coarse grid structure using as baseline the fine grid ---*/ - - CMultiGridQueue MGQueue_InnerCV(fine_grid->GetnPoint()); - - node = new CPoint*[fine_grid->GetnPoint()]; - for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) { - - /*--- Create node structure ---*/ - - node[iPoint] = new CPoint(nDim, iPoint, config); - - /*--- Set the indirect agglomeration to false ---*/ - - node[iPoint]->SetAgglomerate_Indirect(false); - } - - Index_CoarseCV = 0; - - /*--- The first step is the boundary agglomeration. ---*/ - - for (iMarker = 0; iMarker < fine_grid->GetnMarker(); iMarker++) { - - for (iVertex = 0; iVertex < fine_grid->GetnVertex(iMarker); iVertex++) { - iPoint = fine_grid->vertex[iMarker][iVertex]->GetNode(); - - /*--- If the element has not being previously agglomerated and it belongs - to the physical domain, then the agglomeration is studied ---*/ - - if ((fine_grid->node[iPoint]->GetAgglomerate() == false) && - (fine_grid->node[iPoint]->GetDomain()) && - (GeometricalCheck(iPoint, fine_grid, config))) { - - nChildren = 1; - - /*--- We set an index for the parent control volume ---*/ - - fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV); - - /*--- We add the seed point (child) to the parent control volume ---*/ - - node[Index_CoarseCV]->SetChildren_CV(0, iPoint); - agglomerate_seed = true; counter = 0; marker_seed = iMarker; - - /*--- For a particular point in the fine grid we save all the markers - that are in that point ---*/ - - for (jMarker = 0; jMarker < fine_grid->GetnMarker(); jMarker ++) - if (fine_grid->node[iPoint]->GetVertex(jMarker) != -1) { - copy_marker[counter] = jMarker; - counter++; - } - - /*--- To aglomerate a vertex it must have only one physical bc!! - This can be improved. If there is only a marker, it is a good - candidate for agglomeration ---*/ - - if (counter == 1) agglomerate_seed = true; - - /*--- If there are two markers, we will aglomerate if one of the - marker is SEND_RECEIVE ---*/ - - if (counter == 2) { - if ((config->GetMarker_All_KindBC(copy_marker[0]) == SEND_RECEIVE) || - (config->GetMarker_All_KindBC(copy_marker[1]) == SEND_RECEIVE)) agglomerate_seed = true; - else agglomerate_seed = false; - } - - /*--- If there are more than 2 markers, the aglomeration will be discarted ---*/ - - if (counter > 2) agglomerate_seed = false; - - /*--- If the seed can be agglomerated, we try to agglomerate more points ---*/ - - if (agglomerate_seed) { - - /*--- Now we do a sweep over all the nodes that surround the seed point ---*/ - - for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { - - CVPoint = fine_grid->node[iPoint]->GetPoint(iNode); - - /*--- The new point can be agglomerated ---*/ - - if (SetBoundAgglomeration(CVPoint, marker_seed, fine_grid, config)) { - - /*--- We set the value of the parent ---*/ - - fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV); - - /*--- We set the value of the child ---*/ - - node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint); - nChildren++; - } - - } - - Suitable_Indirect_Neighbors.clear(); - - if (fine_grid->node[iPoint]->GetAgglomerate_Indirect()) - SetSuitableNeighbors(&Suitable_Indirect_Neighbors, iPoint, Index_CoarseCV, fine_grid); - - /*--- Now we do a sweep over all the indirect nodes that can be added ---*/ - - for (iNode = 0; iNode < Suitable_Indirect_Neighbors.size(); iNode ++) { - - CVPoint = Suitable_Indirect_Neighbors[iNode]; - - /*--- The new point can be agglomerated ---*/ - - if (SetBoundAgglomeration(CVPoint, marker_seed, fine_grid, config)) { - - /*--- We set the value of the parent ---*/ - - fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV); - - /*--- We set the indirect agglomeration information ---*/ - - if (fine_grid->node[CVPoint]->GetAgglomerate_Indirect()) - node[Index_CoarseCV]->SetAgglomerate_Indirect(true); - - /*--- We set the value of the child ---*/ - - node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint); - nChildren++; - } - } - - - } - - /*--- Update the number of child of the control volume ---*/ - - node[Index_CoarseCV]->SetnChildren_CV(nChildren); - Index_CoarseCV++; - } - } - } - - /*--- Agglomerate all the nodes that have more than one physical boundary condition, - Maybe here we can add the posibility of merging the vertex that have the same number, - and kind of markers---*/ - - for (iMarker = 0; iMarker < fine_grid->GetnMarker(); iMarker++) - for (iVertex = 0; iVertex < fine_grid->GetnVertex(iMarker); iVertex++) { - iPoint = fine_grid->vertex[iMarker][iVertex]->GetNode(); - if ((fine_grid->node[iPoint]->GetAgglomerate() == false) && - (fine_grid->node[iPoint]->GetDomain())) { - fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV); - node[Index_CoarseCV]->SetChildren_CV(0, iPoint); - node[Index_CoarseCV]->SetnChildren_CV(1); - Index_CoarseCV++; - } - } - - /*--- Update the queue with the results from the boundary agglomeration ---*/ - - for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) { - - /*--- The CV has been agglomerated, remove form the list ---*/ - - if (fine_grid->node[iPoint]->GetAgglomerate() == true) { - - MGQueue_InnerCV.RemoveCV(iPoint); - - } - - else { - - /*--- Count the number of agglomerated neighbors, and modify the queue ---*/ - - priority = 0; - for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { - jPoint = fine_grid->node[iPoint]->GetPoint(iNode); - if (fine_grid->node[jPoint]->GetAgglomerate() == true) priority++; - } - MGQueue_InnerCV.MoveCV(iPoint, priority); - } - } - - /*--- Agglomerate the domain nodes ---*/ - - iteration = 0; - while (!MGQueue_InnerCV.EmptyQueue() && (iteration < fine_grid->GetnPoint())) { - - iPoint = MGQueue_InnerCV.NextCV(); - iteration ++; - - /*--- If the element has not being previously agglomerated, belongs to the physical domain, - and satisfies several geometrical criteria then the seed CV is acepted for agglomeration ---*/ - - if ((fine_grid->node[iPoint]->GetAgglomerate() == false) && - (fine_grid->node[iPoint]->GetDomain()) && - (GeometricalCheck(iPoint, fine_grid, config))) { - - nChildren = 1; - - /*--- We set an index for the parent control volume ---*/ - - fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV); - - /*--- We add the seed point (child) to the parent control volume ---*/ - - node[Index_CoarseCV]->SetChildren_CV(0, iPoint); - - /*--- Update the queue with the seed point (remove the seed and - increase the priority of the neighbors) ---*/ - - MGQueue_InnerCV.Update(iPoint, fine_grid); - - /*--- Now we do a sweep over all the nodes that surround the seed point ---*/ - - for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { - - CVPoint = fine_grid->node[iPoint]->GetPoint(iNode); - - /*--- Determine if the CVPoint can be agglomerated ---*/ - - if ((fine_grid->node[CVPoint]->GetAgglomerate() == false) && - (fine_grid->node[CVPoint]->GetDomain()) && - (GeometricalCheck(CVPoint, fine_grid, config))) { - - /*--- We set the value of the parent ---*/ - - fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV); - - /*--- We set the value of the child ---*/ - - node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint); - nChildren++; - - /*--- Update the queue with the new control volume (remove the CV and - increase the priority of the neighbors) ---*/ - - MGQueue_InnerCV.Update(CVPoint, fine_grid); - - } - - } - - /*--- Subrotuine to identify the indirect neighbors ---*/ - - Suitable_Indirect_Neighbors.clear(); - if (fine_grid->node[iPoint]->GetAgglomerate_Indirect()) - SetSuitableNeighbors(&Suitable_Indirect_Neighbors, iPoint, Index_CoarseCV, fine_grid); - - /*--- Now we do a sweep over all the indirect nodes that can be added ---*/ - - for (iNode = 0; iNode < Suitable_Indirect_Neighbors.size(); iNode ++) { - - CVPoint = Suitable_Indirect_Neighbors[iNode]; - - /*--- The new point can be agglomerated ---*/ - - if ((fine_grid->node[CVPoint]->GetAgglomerate() == false) && - (fine_grid->node[CVPoint]->GetDomain())) { - - /*--- We set the value of the parent ---*/ - - fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV); - - /*--- We set the indirect agglomeration information ---*/ - - if (fine_grid->node[CVPoint]->GetAgglomerate_Indirect()) - node[Index_CoarseCV]->SetAgglomerate_Indirect(true); - - /*--- We set the value of the child ---*/ - - node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint); - nChildren++; - - /*--- Update the queue with the new control volume (remove the CV and - increase the priority of the neighbors) ---*/ - - MGQueue_InnerCV.Update(CVPoint, fine_grid); - - } - } - - /*--- Update the number of control of childrens ---*/ - - node[Index_CoarseCV]->SetnChildren_CV(nChildren); - Index_CoarseCV++; - } - else { - - /*--- The seed point can not be agglomerated because of size, domain, streching, etc. - move the point to the lowest priority ---*/ - - MGQueue_InnerCV.MoveCV(iPoint, -1); - } - - } - - /*--- Add all the elements that have not being agglomerated, in the previous stage ---*/ - - for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) { - if ((fine_grid->node[iPoint]->GetAgglomerate() == false) && (fine_grid->node[iPoint]->GetDomain())) { - - nChildren = 1; - fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV); - if (fine_grid->node[iPoint]->GetAgglomerate_Indirect()) - node[Index_CoarseCV]->SetAgglomerate_Indirect(true); - node[Index_CoarseCV]->SetChildren_CV(0, iPoint); - node[Index_CoarseCV]->SetnChildren_CV(nChildren); - Index_CoarseCV++; - - } - } - - nPointDomain = Index_CoarseCV; - - /*--- Check that there are no hanging nodes ---*/ - - unsigned long iFinePoint, iFinePoint_Neighbor, iCoarsePoint, iCoarsePoint_Complete; - unsigned short iChildren; - - /*--- Find the point surrounding a point ---*/ - - for (iCoarsePoint = 0; iCoarsePoint < nPointDomain; iCoarsePoint ++) { - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - for (iNode = 0; iNode < fine_grid->node[iFinePoint]->GetnPoint(); iNode ++) { - iFinePoint_Neighbor = fine_grid->node[iFinePoint]->GetPoint(iNode); - iParent = fine_grid->node[iFinePoint_Neighbor]->GetParent_CV(); - if (iParent != iCoarsePoint) node[iCoarsePoint]->SetPoint(iParent); - } - } - } - - /*--- Detect isolated points and merge them with its correct neighbor ---*/ - - for (iCoarsePoint = 0; iCoarsePoint < nPointDomain; iCoarsePoint ++) { - - if (node[iCoarsePoint]->GetnPoint() == 1) { - - /*--- Find the neighbor of the isolated point. This neighbor is the right control volume ---*/ - - iCoarsePoint_Complete = node[iCoarsePoint]->GetPoint(0); - - /*--- Add the children to the connected control volume (and modify it parent indexing). - Identify the child CV from the finest grid and added to the correct control volume. - Set the parent CV of iFinePoint. Instead of using the original - (iCoarsePoint) one use the new one (iCoarsePoint_Complete) ---*/ - - nChildren = node[iCoarsePoint_Complete]->GetnChildren_CV(); - - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - node[iCoarsePoint_Complete]->SetChildren_CV(nChildren, iFinePoint); - nChildren++; - fine_grid->node[iFinePoint]->SetParent_CV(iCoarsePoint_Complete); - } - - /*--- Update the number of children control volumes ---*/ - - node[iCoarsePoint_Complete]->SetnChildren_CV(nChildren); - node[iCoarsePoint]->SetnChildren_CV(0); - - } - } - - // unsigned long iPointFree = nPointDomain-1; - // iCoarsePoint = 0; - // - // do { - // - // if (node[iCoarsePoint]->GetnChildren_CV() == 0) { - // - // while (node[iPointFree]->GetnChildren_CV() == 0) { - // Index_CoarseCV--; - // iPointFree--; - // } - // - // nChildren = node[iPointFree]->GetnChildren_CV(); - // for (iChildren = 0; iChildren < nChildren; iChildren ++) { - // iFinePoint = node[iPointFree]->GetChildren_CV(iChildren); - // node[iCoarsePoint]->SetChildren_CV(iChildren, iFinePoint); - // fine_grid->node[iFinePoint]->SetParent_CV(iCoarsePoint); - // } - // node[iCoarsePoint]->SetnChildren_CV(nChildren); - // node[iPointFree]->SetnChildren_CV(0); - // - // Index_CoarseCV--; - // iPointFree--; - // - // } - // - // iCoarsePoint++; - // - // } while ((iCoarsePoint-1) < Index_CoarseCV); - // - // nPointDomain = Index_CoarseCV; - - /*--- Reset the point surrounding a point ---*/ - - for (iCoarsePoint = 0; iCoarsePoint < nPointDomain; iCoarsePoint ++) { - node[iCoarsePoint]->ResetPoint(); - } - - /*--- Dealing with MPI parallelization, the objective is that the received nodes must be agglomerated - in the same way as the donor nodes. Send the node agglomeration information of the donor - (parent and children), Sending only occurs with MPI ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = fine_grid->nVertex[MarkerS]; nVertexR = fine_grid->nVertex[MarkerR]; - nBufferS_Vector = nVertexS; nBufferR_Vector = nVertexR; - - /*--- Allocate Receive and send buffers ---*/ - - Buffer_Receive_Children = new unsigned long [nBufferR_Vector]; - Buffer_Send_Children = new unsigned long [nBufferS_Vector]; - - Buffer_Receive_Parent = new unsigned long [nBufferR_Vector]; - Buffer_Send_Parent = new unsigned long [nBufferS_Vector]; - - /*--- Copy the information that should be sended ---*/ - - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = fine_grid->vertex[MarkerS][iVertex]->GetNode(); - Buffer_Send_Children[iVertex] = iPoint; - Buffer_Send_Parent[iVertex] = fine_grid->node[iPoint]->GetParent_CV(); - } - -#ifdef HAVE_MPI - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Children, nBufferS_Vector, MPI_UNSIGNED_LONG, send_to,0, - Buffer_Receive_Children, nBufferR_Vector, MPI_UNSIGNED_LONG, receive_from,0, MPI_COMM_WORLD, &status); - SU2_MPI::Sendrecv(Buffer_Send_Parent, nBufferS_Vector, MPI_UNSIGNED_LONG, send_to,1, - Buffer_Receive_Parent, nBufferR_Vector, MPI_UNSIGNED_LONG, receive_from,1, MPI_COMM_WORLD, &status); -#else - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - Buffer_Receive_Children[iVertex] = Buffer_Send_Children[iVertex]; - Buffer_Receive_Parent[iVertex] = Buffer_Send_Parent[iVertex]; - } -#endif - - /*--- Deallocate send buffer ---*/ - - delete [] Buffer_Send_Children; - delete [] Buffer_Send_Parent; - - /*--- Create a list of the parent nodes without repeated parents ---*/ - - Aux_Parent.clear(); - for (iVertex = 0; iVertex < nVertexR; iVertex++) - Aux_Parent.push_back (Buffer_Receive_Parent[iVertex]); - - sort(Aux_Parent.begin(), Aux_Parent.end()); - it = unique(Aux_Parent.begin(), Aux_Parent.end()); - Aux_Parent.resize(it - Aux_Parent.begin()); - - /*--- Allocate some structures ---*/ - - Parent_Remote = new unsigned long[nVertexR]; - Children_Remote = new unsigned long[nVertexR]; - Parent_Local = new unsigned long[nVertexR]; - Children_Local = new unsigned long[nVertexR]; - - /*--- Create the local vector and remote for the parents and the children ---*/ - - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - Parent_Remote[iVertex] = Buffer_Receive_Parent[iVertex]; - - /*--- We use the same sorting as in the donor domain ---*/ - - for (jVertex = 0; jVertex < Aux_Parent.size(); jVertex++) { - if (Parent_Remote[iVertex] == Aux_Parent[jVertex]) { - Parent_Local[iVertex] = jVertex + Index_CoarseCV; - break; - } - } - - Children_Remote[iVertex] = Buffer_Receive_Children[iVertex]; - Children_Local[iVertex] = fine_grid->vertex[MarkerR][iVertex]->GetNode(); - - } - - Index_CoarseCV += Aux_Parent.size(); - - nChildren_MPI = new unsigned short [Index_CoarseCV]; - for (iParent = 0; iParent < Index_CoarseCV; iParent++) - nChildren_MPI[iParent] = 0; - - /*--- Create the final structure ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Be careful, it is possible that a node change the agglomeration configuration, the priority - is always, when receive the information ---*/ - - fine_grid->node[Children_Local[iVertex]]->SetParent_CV(Parent_Local[iVertex]); - node[Parent_Local[iVertex]]->SetChildren_CV(nChildren_MPI[Parent_Local[iVertex]], Children_Local[iVertex]); - nChildren_MPI[Parent_Local[iVertex]]++; - node[Parent_Local[iVertex]]->SetnChildren_CV(nChildren_MPI[Parent_Local[iVertex]]); - node[Parent_Local[iVertex]]->SetDomain(false); - - } - - /*--- Deallocate auxiliar structures ---*/ - - delete[] nChildren_MPI; - delete[] Parent_Remote; - delete[] Children_Remote; - delete[] Parent_Local; - delete[] Children_Local; - - /*--- Deallocate receive buffer ---*/ - - delete [] Buffer_Receive_Children; - delete [] Buffer_Receive_Parent; - - } - - } - - /*--- Update the number of points after the MPI agglomeration ---*/ - - nPoint = Index_CoarseCV; - - /*--- Console output with the summary of the agglomeration ---*/ - - Local_nPointCoarse = nPoint; - Local_nPointFine = fine_grid->GetnPoint(); - -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&Local_nPointCoarse, &Global_nPointCoarse, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&Local_nPointFine, &Global_nPointFine, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#else - Global_nPointCoarse = Local_nPointCoarse; - Global_nPointFine = Local_nPointFine; -#endif - - su2double Coeff = 1.0, CFL = 0.0, factor = 1.5; - - if (iMesh != MESH_0) { - if (nDim == 2) Coeff = pow(su2double(Global_nPointFine)/su2double(Global_nPointCoarse), 1./2.); - if (nDim == 3) Coeff = pow(su2double(Global_nPointFine)/su2double(Global_nPointCoarse), 1./3.); - CFL = factor*config->GetCFL(iMesh-1)/Coeff; - config->SetCFL(iMesh, CFL); - } - - su2double ratio = su2double(Global_nPointFine)/su2double(Global_nPointCoarse); - - if (((nDim == 2) && (ratio < 2.5)) || - ((nDim == 3) && (ratio < 2.5))) { - config->SetMGLevels(iMesh-1); - } - else { - if (rank == MASTER_NODE) { - if (iMesh == 1) cout <<"MG level: "<< iMesh-1 <<" -> CVs: " << Global_nPointFine << ". Agglomeration rate 1/1.00. CFL "<< config->GetCFL(iMesh-1) <<"." << endl; - cout <<"MG level: "<< iMesh <<" -> CVs: " << Global_nPointCoarse << ". Agglomeration rate 1/" << ratio <<". CFL "<< CFL <<"." << endl; - } - } - - delete [] copy_marker; - -} - - -CMultiGridGeometry::~CMultiGridGeometry(void) { - -} - -bool CMultiGridGeometry::SetBoundAgglomeration(unsigned long CVPoint, short marker_seed, CGeometry *fine_grid, CConfig *config) { - - bool agglomerate_CV = false; - unsigned short counter, jMarker; - - unsigned short nMarker_Max = config->GetnMarker_Max(); - - unsigned short *copy_marker = new unsigned short [nMarker_Max]; - - /*--- Basic condition, the element has not being previously agglomerated, it belongs to the domain, - and has passed some basic geometrical check ---*/ - - if ((fine_grid->node[CVPoint]->GetAgglomerate() == false) && - (fine_grid->node[CVPoint]->GetDomain()) && - (GeometricalCheck(CVPoint, fine_grid, config))) { - - /*--- If the element belong to the boundary, we must be careful ---*/ - - if (fine_grid->node[CVPoint]->GetBoundary()) { - - /*--- Identify the markers of the vertex that we want to agglomerate ---*/ - - counter = 0; - for (jMarker = 0; jMarker < fine_grid->GetnMarker(); jMarker ++) - if (fine_grid->node[CVPoint]->GetVertex(jMarker) != -1) { - copy_marker[counter] = jMarker; - counter++; - } - - /*--- The basic condition is that the aglomerated vertex must have the same physical marker, - but eventually a send-receive condition ---*/ - - /*--- Only one marker in the vertex that is going to be aglomerated ---*/ - - if (counter == 1) { - - /*--- We agglomerate if there is only a marker and is the same marker as the seed marker ---*/ - - if (copy_marker[0] == marker_seed) - agglomerate_CV = true; - - /*--- If there is only a marker, but the marker is the SEND_RECEIVE ---*/ - - if (config->GetMarker_All_KindBC(copy_marker[0]) == SEND_RECEIVE) - agglomerate_CV = true; - - } - - /*--- If there are two markers in the vertex that is going to be aglomerated ---*/ - - if (counter == 2) { - - /*--- First we verify that the seed is a physical boundary ---*/ - - if (config->GetMarker_All_KindBC(marker_seed) != SEND_RECEIVE) { - - /*--- Then we check that one of the marker is equal to the seed marker, and the other is send/receive ---*/ - - if (((copy_marker[0] == marker_seed) && (config->GetMarker_All_KindBC(copy_marker[1]) == SEND_RECEIVE)) || - ((config->GetMarker_All_KindBC(copy_marker[0]) == SEND_RECEIVE) && (copy_marker[1] == marker_seed))) - agglomerate_CV = true; - } - - } - - } - - /*--- If the element belong to the domain, it is allways aglomerated ---*/ - - else { agglomerate_CV = true; } - - } - - delete [] copy_marker; - - return agglomerate_CV; - -} - - -bool CMultiGridGeometry::GeometricalCheck(unsigned long iPoint, CGeometry *fine_grid, CConfig *config) { - - su2double max_dimension = 1.2; - - /*--- Evaluate the total size of the element ---*/ - - bool Volume = true; - su2double ratio = pow(fine_grid->node[iPoint]->GetVolume(), 1.0/su2double(nDim))*max_dimension; - su2double limit = pow(config->GetDomainVolume(), 1.0/su2double(nDim)); - if ( ratio > limit ) Volume = false; - - /*--- Evaluate the stretching of the element ---*/ - - bool Stretching = true; - - /* unsigned short iNode, iDim; - unsigned long jPoint; - su2double *Coord_i = fine_grid->node[iPoint]->GetCoord(); - su2double max_dist = 0.0 ; su2double min_dist = 1E20; - for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { - jPoint = fine_grid->node[iPoint]->GetPoint(iNode); - su2double *Coord_j = fine_grid->node[jPoint]->GetCoord(); - su2double distance = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - distance += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); - distance = sqrt(distance); - max_dist = max(distance, max_dist); - min_dist = min(distance, min_dist); - } - if ( max_dist/min_dist > 100.0 ) Stretching = false;*/ - - return (Stretching && Volume); - -} - -void CMultiGridGeometry::SetSuitableNeighbors(vector *Suitable_Indirect_Neighbors, unsigned long iPoint, - unsigned long Index_CoarseCV, CGeometry *fine_grid) { - - unsigned long jPoint, kPoint, lPoint; - unsigned short iNode, jNode, iNeighbor, jNeighbor, kNode; - bool SecondNeighborSeed, ThirdNeighborSeed; - vector::iterator it; - - /*--- Create a list with the first neighbors, including the seed ---*/ - - vector First_Neighbor_Points; - First_Neighbor_Points.push_back(iPoint); - for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { - jPoint = fine_grid->node[iPoint]->GetPoint(iNode); - First_Neighbor_Points.push_back(jPoint); - } - - /*--- Create a list with the second neighbors, without first, and seed neighbors ---*/ - - vector Second_Neighbor_Points, Second_Origin_Points, Suitable_Second_Neighbors; - - for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { - jPoint = fine_grid->node[iPoint]->GetPoint(iNode); - - for (jNode = 0; jNode < fine_grid->node[jPoint]->GetnPoint(); jNode ++) { - kPoint = fine_grid->node[jPoint]->GetPoint(jNode); - - /*--- Check that the second neighbor do not belong to the first neighbor or the seed ---*/ - - SecondNeighborSeed = true; - for (iNeighbor = 0; iNeighbor < First_Neighbor_Points.size(); iNeighbor ++) - if (kPoint == First_Neighbor_Points[iNeighbor]) { - SecondNeighborSeed = false; break; - } - - if (SecondNeighborSeed) { - Second_Neighbor_Points.push_back(kPoint); - Second_Origin_Points.push_back(jPoint); - } - - } - } - - /*--- Identify those second neighbors that are repeated (candidate to be added) ---*/ - - for (iNeighbor = 0; iNeighbor < Second_Neighbor_Points.size(); iNeighbor ++) - - for (jNeighbor = 0; jNeighbor < Second_Neighbor_Points.size(); jNeighbor ++) - - /*--- Repeated second neighbor with different origin ---*/ - - if ((Second_Neighbor_Points[iNeighbor] == Second_Neighbor_Points[jNeighbor]) && - (Second_Origin_Points[iNeighbor] != Second_Origin_Points[jNeighbor]) && - (iNeighbor < jNeighbor)) { - - Suitable_Indirect_Neighbors->push_back(Second_Neighbor_Points[iNeighbor]); - - /*--- Create alist with the suitable second neighbor, that we will use - to compute the third neighbors --*/ - - Suitable_Second_Neighbors.push_back(Second_Neighbor_Points[iNeighbor]); - - } - - - /*--- Remove repeated from the suitable second neighbors ---*/ - - sort(Suitable_Second_Neighbors.begin(), Suitable_Second_Neighbors.end()); - it = unique(Suitable_Second_Neighbors.begin(), Suitable_Second_Neighbors.end()); - Suitable_Second_Neighbors.resize(it - Suitable_Second_Neighbors.begin()); - - /*--- Remove repeated from first neighbors ---*/ - - sort(First_Neighbor_Points.begin(), First_Neighbor_Points.end()); - it = unique(First_Neighbor_Points.begin(), First_Neighbor_Points.end()); - First_Neighbor_Points.resize(it - First_Neighbor_Points.begin()); - - /*--- Create a list with the third neighbors, without first, second, and seed neighbors ---*/ - - vector Third_Neighbor_Points, Third_Origin_Points; - - for (jNode = 0; jNode < Suitable_Second_Neighbors.size(); jNode ++) { - kPoint = Suitable_Second_Neighbors[jNode]; - - for (kNode = 0; kNode < fine_grid->node[kPoint]->GetnPoint(); kNode ++) { - lPoint = fine_grid->node[kPoint]->GetPoint(kNode); - - /*--- Check that the third neighbor do not belong to the first neighbors or the seed ---*/ - - ThirdNeighborSeed = true; - - for (iNeighbor = 0; iNeighbor < First_Neighbor_Points.size(); iNeighbor ++) - if (lPoint == First_Neighbor_Points[iNeighbor]) { - ThirdNeighborSeed = false; - break; - } - - /*--- Check that the third neighbor do not belong to the second neighbors ---*/ - - for (iNeighbor = 0; iNeighbor < Suitable_Second_Neighbors.size(); iNeighbor ++) - if (lPoint == Suitable_Second_Neighbors[iNeighbor]) { - ThirdNeighborSeed = false; - break; - } - - if (ThirdNeighborSeed) { - Third_Neighbor_Points.push_back(lPoint); - Third_Origin_Points.push_back(kPoint); - } - - } - } - - /*--- Identify those third neighbors that are repeated (candidate to be added) ---*/ - - for (iNeighbor = 0; iNeighbor < Third_Neighbor_Points.size(); iNeighbor ++) - for (jNeighbor = 0; jNeighbor < Third_Neighbor_Points.size(); jNeighbor ++) - - /*--- Repeated second neighbor with different origin ---*/ - - if ((Third_Neighbor_Points[iNeighbor] == Third_Neighbor_Points[jNeighbor]) && - (Third_Origin_Points[iNeighbor] != Third_Origin_Points[jNeighbor]) && - (iNeighbor < jNeighbor)) { - - Suitable_Indirect_Neighbors->push_back(Third_Neighbor_Points[iNeighbor]); - - } - - /*--- Remove repeated from Suitable Indirect Neighbors List ---*/ - - sort(Suitable_Indirect_Neighbors->begin(), Suitable_Indirect_Neighbors->end()); - it = unique(Suitable_Indirect_Neighbors->begin(), Suitable_Indirect_Neighbors->end()); - Suitable_Indirect_Neighbors->resize(it - Suitable_Indirect_Neighbors->begin()); - -} - -void CMultiGridGeometry::SetPoint_Connectivity(CGeometry *fine_grid) { - - unsigned long iFinePoint, iFinePoint_Neighbor, iParent, iCoarsePoint; - unsigned short iChildren, iNode; - - /*--- Set the point surrounding a point ---*/ - - for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) { - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - for (iNode = 0; iNode < fine_grid->node[iFinePoint]->GetnPoint(); iNode ++) { - iFinePoint_Neighbor = fine_grid->node[iFinePoint]->GetPoint(iNode); - iParent = fine_grid->node[iFinePoint_Neighbor]->GetParent_CV(); - if (iParent != iCoarsePoint) node[iCoarsePoint]->SetPoint(iParent); - } - } - } - - /*--- Set the number of neighbors variable, this is - important for JST and multigrid in parallel ---*/ - - for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) - node[iCoarsePoint]->SetnNeighbor(node[iCoarsePoint]->GetnPoint()); - -} - -void CMultiGridGeometry::SetVertex(CGeometry *fine_grid, CConfig *config) { - unsigned long iVertex, iFinePoint, iCoarsePoint; - unsigned short iMarker, iMarker_Tag, iChildren; - - nMarker = fine_grid->GetnMarker(); - unsigned short nMarker_Max = config->GetnMarker_Max(); - - /*--- If any children node belong to the boundary then the entire control - volume will belong to the boundary ---*/ - for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - if (fine_grid->node[iFinePoint]->GetBoundary()) { - node[iCoarsePoint]->SetBoundary(nMarker); - break; - } - } - - vertex = new CVertex**[nMarker]; - nVertex = new unsigned long [nMarker]; - - Tag_to_Marker = new string [nMarker_Max]; - for (iMarker_Tag = 0; iMarker_Tag < nMarker_Max; iMarker_Tag++) - Tag_to_Marker[iMarker_Tag] = fine_grid->GetMarker_Tag(iMarker_Tag); - - /*--- Compute the number of vertices to do the dimensionalization ---*/ - for (iMarker = 0; iMarker < nMarker; iMarker++) nVertex[iMarker] = 0; - - - for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) { - if (node[iCoarsePoint]->GetBoundary()) { - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - for (iMarker = 0; iMarker < nMarker; iMarker ++) { - if ((fine_grid->node[iFinePoint]->GetVertex(iMarker) != -1) && (node[iCoarsePoint]->GetVertex(iMarker) == -1)) { - iVertex = nVertex[iMarker]; - node[iCoarsePoint]->SetVertex(iVertex, iMarker); - nVertex[iMarker]++; - } - } - } - } - } - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - vertex[iMarker] = new CVertex* [fine_grid->GetnVertex(iMarker)+1]; - nVertex[iMarker] = 0; - } - - for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) - if (node[iCoarsePoint]->GetBoundary()) - for (iMarker = 0; iMarker < nMarker; iMarker ++) - node[iCoarsePoint]->SetVertex(-1, iMarker); - - for (iMarker = 0; iMarker < nMarker; iMarker++) nVertex[iMarker] = 0; - - for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) - if (node[iCoarsePoint]->GetBoundary()) - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - for (iMarker = 0; iMarker < fine_grid->GetnMarker(); iMarker ++) { - if ((fine_grid->node[iFinePoint]->GetVertex(iMarker) != -1) && (node[iCoarsePoint]->GetVertex(iMarker) == -1)) { - iVertex = nVertex[iMarker]; - vertex[iMarker][iVertex] = new CVertex(iCoarsePoint, nDim); - node[iCoarsePoint]->SetVertex(iVertex, iMarker); - - /*--- Set the transformation to apply ---*/ - unsigned long ChildVertex = fine_grid->node[iFinePoint]->GetVertex(iMarker); - unsigned short RotationKind = fine_grid->vertex[iMarker][ChildVertex]->GetRotation_Type(); - vertex[iMarker][iVertex]->SetRotation_Type(RotationKind); - nVertex[iMarker]++; - } - } - } -} - -void CMultiGridGeometry::MatchNearField(CConfig *config) { - - unsigned short iMarker; - unsigned long iVertex, iPoint; - int iProcessor; - -#ifndef HAVE_MPI - iProcessor = MASTER_NODE; -#else - MPI_Comm_rank(MPI_COMM_WORLD, &iProcessor); -#endif - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - vertex[iMarker][iVertex]->SetDonorPoint(iPoint, iProcessor); - } - } - } - } - -} - -void CMultiGridGeometry::MatchActuator_Disk(CConfig *config) { - - unsigned short iMarker; - unsigned long iVertex, iPoint; - int iProcessor; - -#ifndef HAVE_MPI - iProcessor = MASTER_NODE; -#else - MPI_Comm_rank(MPI_COMM_WORLD, &iProcessor); -#endif - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_KindBC(iMarker) == ACTDISK_INLET) || - (config->GetMarker_All_KindBC(iMarker) == ACTDISK_OUTLET)) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - vertex[iMarker][iVertex]->SetDonorPoint(iPoint, iProcessor); - } - } - } - } - -} - -void CMultiGridGeometry::MatchInterface(CConfig *config) { - - unsigned short iMarker; - unsigned long iVertex, iPoint; - int iProcessor; - -#ifndef HAVE_MPI - iProcessor = MASTER_NODE; -#else - MPI_Comm_rank(MPI_COMM_WORLD, &iProcessor); -#endif - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - vertex[iMarker][iVertex]->SetDonorPoint(iPoint, iProcessor); - } - } - } - } - -} - - -void CMultiGridGeometry::SetControlVolume(CConfig *config, CGeometry *fine_grid, unsigned short action) { - - unsigned long iFinePoint, iFinePoint_Neighbor, iCoarsePoint, iEdge, iParent; - long FineEdge, CoarseEdge; - unsigned short iChildren, iNode, iDim; - bool change_face_orientation; - su2double *Normal, Coarse_Volume, Area, *NormalFace = NULL; - Normal = new su2double [nDim]; - - /*--- Compute the area of the coarse volume ---*/ - for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) { - node[iCoarsePoint]->SetVolume(0.0); - Coarse_Volume = 0.0; - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - Coarse_Volume += fine_grid->node[iFinePoint]->GetVolume(); - } - node[iCoarsePoint]->SetVolume(Coarse_Volume); - } - - /*--- Update or not the values of faces at the edge ---*/ - if (action != ALLOCATE) { - for (iEdge=0; iEdge < nEdge; iEdge++) - edge[iEdge]->SetZeroValues(); - } - - for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - - for (iNode = 0; iNode < fine_grid->node[iFinePoint]->GetnPoint(); iNode ++) { - iFinePoint_Neighbor = fine_grid->node[iFinePoint]->GetPoint(iNode); - iParent = fine_grid->node[iFinePoint_Neighbor]->GetParent_CV(); - if ((iParent != iCoarsePoint) && (iParent < iCoarsePoint)) { - - FineEdge = fine_grid->FindEdge(iFinePoint, iFinePoint_Neighbor); - - change_face_orientation = false; - if (iFinePoint < iFinePoint_Neighbor) change_face_orientation = true; - - CoarseEdge = FindEdge(iParent, iCoarsePoint); - - fine_grid->edge[FineEdge]->GetNormal(Normal); - - if (change_face_orientation) { - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - edge[CoarseEdge]->AddNormal(Normal); - } - else { - edge[CoarseEdge]->AddNormal(Normal); - } - } - } - } - delete[] Normal; - - /*--- Check if there is a normal with null area ---*/ - - for (iEdge = 0; iEdge < nEdge; iEdge++) { - NormalFace = edge[iEdge]->GetNormal(); - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += NormalFace[iDim]*NormalFace[iDim]; - Area = sqrt(Area); - if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS; - } - -} - -void CMultiGridGeometry::SetBoundControlVolume(CConfig *config, CGeometry *fine_grid, unsigned short action) { - unsigned long iCoarsePoint, iFinePoint, FineVertex, iVertex; - unsigned short iMarker, iChildren, iDim; - su2double *Normal, Area, *NormalFace = NULL; - - Normal = new su2double [nDim]; - - if (action != ALLOCATE) { - for (iMarker = 0; iMarker < nMarker; iMarker++) - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) - vertex[iMarker][iVertex]->SetZeroValues(); - } - - for (iMarker = 0; iMarker < nMarker; iMarker ++) - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iCoarsePoint = vertex[iMarker][iVertex]->GetNode(); - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - if (fine_grid->node[iFinePoint]->GetVertex(iMarker)!=-1) { - FineVertex = fine_grid->node[iFinePoint]->GetVertex(iMarker); - fine_grid->vertex[iMarker][FineVertex]->GetNormal(Normal); - vertex[iMarker][iVertex]->AddNormal(Normal); - } - } - } - - delete[] Normal; - - /*--- Check if there is a normal with null area ---*/ - for (iMarker = 0; iMarker < nMarker; iMarker ++) - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - NormalFace = vertex[iMarker][iVertex]->GetNormal(); - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += NormalFace[iDim]*NormalFace[iDim]; - Area = sqrt(Area); - if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS; - } - -} - -void CMultiGridGeometry::SetCoord(CGeometry *geometry) { - unsigned long Point_Fine, Point_Coarse; - unsigned short iChildren, iDim; - su2double Area_Parent, Area_Children; - su2double *Coordinates_Fine, *Coordinates; - Coordinates = new su2double[nDim]; - - for (Point_Coarse = 0; Point_Coarse < GetnPoint(); Point_Coarse++) { - Area_Parent = node[Point_Coarse]->GetVolume(); - for (iDim = 0; iDim < nDim; iDim++) Coordinates[iDim] = 0.0; - for (iChildren = 0; iChildren < node[Point_Coarse]->GetnChildren_CV(); iChildren++) { - Point_Fine = node[Point_Coarse]->GetChildren_CV(iChildren); - Area_Children = geometry->node[Point_Fine]->GetVolume(); - Coordinates_Fine = geometry->node[Point_Fine]->GetCoord(); - for (iDim = 0; iDim < nDim; iDim++) - Coordinates[iDim] += Coordinates_Fine[iDim]*Area_Children/Area_Parent; - } - for (iDim = 0; iDim < nDim; iDim++) - node[Point_Coarse]->SetCoord(iDim, Coordinates[iDim]); - } - delete[] Coordinates; -} - -void CMultiGridGeometry::SetRotationalVelocity(CConfig *config, unsigned short val_iZone) { - - unsigned long iPoint_Coarse; - su2double *RotVel, Distance[3] = {0.0,0.0,0.0}, *Coord; - su2double Center[3] = {0.0,0.0,0.0}, Omega[3] = {0.0,0.0,0.0}, L_Ref; - RotVel = new su2double [3]; - - /*--- Center of rotation & angular velocity vector from config. ---*/ - - Center[0] = config->GetMotion_Origin_X(val_iZone); - Center[1] = config->GetMotion_Origin_Y(val_iZone); - Center[2] = config->GetMotion_Origin_Z(val_iZone); - Omega[0] = config->GetRotation_Rate_X(val_iZone)/config->GetOmega_Ref(); - Omega[1] = config->GetRotation_Rate_Y(val_iZone)/config->GetOmega_Ref(); - Omega[2] = config->GetRotation_Rate_Z(val_iZone)/config->GetOmega_Ref(); - L_Ref = config->GetLength_Ref(); - - /*--- Loop over all nodes and set the rotational velocity. ---*/ - - for (iPoint_Coarse = 0; iPoint_Coarse < GetnPoint(); iPoint_Coarse++) { - - /*--- Get the coordinates of the current node ---*/ - - Coord = node[iPoint_Coarse]->GetCoord(); - - /*--- Calculate the non-dim. distance from the rotation center ---*/ - - Distance[0] = (Coord[0]-Center[0])/L_Ref; - Distance[1] = (Coord[1]-Center[1])/L_Ref; - Distance[2] = (Coord[2]-Center[2])/L_Ref; - - /*--- Calculate the angular velocity as omega X r ---*/ - - RotVel[0] = Omega[1]*(Distance[2]) - Omega[2]*(Distance[1]); - RotVel[1] = Omega[2]*(Distance[0]) - Omega[0]*(Distance[2]); - RotVel[2] = Omega[0]*(Distance[1]) - Omega[1]*(Distance[0]); - - /*--- Store the grid velocity at this node ---*/ - - node[iPoint_Coarse]->SetGridVel(RotVel); - - } - - delete [] RotVel; - -} - -void CMultiGridGeometry::SetTranslationalVelocity(CConfig *config) { - - unsigned iDim; - unsigned long iPoint_Coarse; - su2double xDot[3]; - - /*--- Get the translational velocity vector from config ---*/ - - xDot[0] = config->GetTranslation_Rate_X(ZONE_0)/config->GetVelocity_Ref(); - xDot[1] = config->GetTranslation_Rate_Y(ZONE_0)/config->GetVelocity_Ref(); - xDot[2] = config->GetTranslation_Rate_Z(ZONE_0)/config->GetVelocity_Ref(); - - /*--- Loop over all nodes and set the translational velocity ---*/ - - for (iPoint_Coarse = 0; iPoint_Coarse < nPoint; iPoint_Coarse++) { - - /*--- Store the grid velocity at this node ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - node[iPoint_Coarse]->SetGridVel(iDim,xDot[iDim]); - - } - -} - -void CMultiGridGeometry::SetGridVelocity(CConfig *config, unsigned long iter) { - - /*--- Local variables ---*/ - - su2double *Coord_nP1 = NULL, *Coord_n = NULL, *Coord_nM1 = NULL; - su2double TimeStep, GridVel = 0.0; - unsigned long Point_Coarse; - unsigned short iDim; - - /*--- Compute the velocity of each node in the volume mesh ---*/ - - for (Point_Coarse = 0; Point_Coarse < GetnPoint(); Point_Coarse++) { - - /*--- Coordinates of the current point at n+1, n, & n-1 time levels ---*/ - - Coord_nM1 = node[Point_Coarse]->GetCoord_n1(); - Coord_n = node[Point_Coarse]->GetCoord_n(); - Coord_nP1 = node[Point_Coarse]->GetCoord(); - - /*--- Unsteady time step ---*/ - - TimeStep = config->GetDelta_UnstTimeND(); - - /*--- Compute mesh velocity with 1st or 2nd-order approximation ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - GridVel = ( Coord_nP1[iDim] - Coord_n[iDim] ) / TimeStep; - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - GridVel = ( 3.0*Coord_nP1[iDim] - 4.0*Coord_n[iDim] - + 1.0*Coord_nM1[iDim] ) / (2.0*TimeStep); - - /*--- Store grid velocity for this point ---*/ - - node[Point_Coarse]->SetGridVel(iDim, GridVel); - - } - } -} - -void CMultiGridGeometry::SetRestricted_GridVelocity(CGeometry *fine_mesh, CConfig *config) { - - /*--- Local variables ---*/ - unsigned short iDim, iChild; - unsigned long Point_Coarse, Point_Fine; - su2double Area_Parent, Area_Child, Grid_Vel[3], *Grid_Vel_Fine; - - /*--- Loop over all coarse mesh points ---*/ - for (Point_Coarse = 0; Point_Coarse < GetnPoint(); Point_Coarse++) { - Area_Parent = node[Point_Coarse]->GetVolume(); - - /*--- Zero out the grid velocity ---*/ - for (iDim = 0; iDim < nDim; iDim++) - Grid_Vel[iDim] = 0.0; - - /*--- Loop over all of the children for this coarse CV and compute - a grid velocity based on the values in the child CVs (fine mesh). ---*/ - for (iChild = 0; iChild < node[Point_Coarse]->GetnChildren_CV(); iChild++) { - Point_Fine = node[Point_Coarse]->GetChildren_CV(iChild); - Area_Child = fine_mesh->node[Point_Fine]->GetVolume(); - Grid_Vel_Fine = fine_mesh->node[Point_Fine]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - Grid_Vel[iDim] += Grid_Vel_Fine[iDim]*Area_Child/Area_Parent; - } - - /*--- Set the grid velocity for this coarse node. ---*/ - for (iDim = 0; iDim < nDim; iDim++) - node[Point_Coarse]->SetGridVel(iDim, Grid_Vel[iDim]); - } -} - - -void CMultiGridGeometry::FindNormal_Neighbor(CConfig *config) { - - unsigned short iMarker, iDim; - unsigned long iPoint, iVertex; - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE && - config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY && - config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY ) { - - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - - iPoint = vertex[iMarker][iVertex]->GetNode(); - - /*--- If the node belong to the domain ---*/ - if (node[iPoint]->GetDomain()) { - - /*--- Compute closest normal neighbor ---*/ - su2double cos_max, scalar_prod, norm_vect, norm_Normal, cos_alpha, diff_coord; - unsigned long Point_Normal = 0, jPoint; - unsigned short iNeigh; - su2double *Normal = vertex[iMarker][iVertex]->GetNormal(); - cos_max = -1.0; - for (iNeigh = 0; iNeigh < node[iPoint]->GetnPoint(); iNeigh++) { - jPoint = node[iPoint]->GetPoint(iNeigh); - scalar_prod = 0.0; norm_vect = 0.0; norm_Normal = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - diff_coord = node[jPoint]->GetCoord(iDim)-node[iPoint]->GetCoord(iDim); - scalar_prod += diff_coord*Normal[iDim]; - norm_vect += diff_coord*diff_coord; - norm_Normal += Normal[iDim]*Normal[iDim]; - } - norm_vect = sqrt(norm_vect); - norm_Normal = sqrt(norm_Normal); - cos_alpha = scalar_prod/(norm_vect*norm_Normal); - - /*--- Get maximum cosine (not minimum because normals are oriented inwards) ---*/ - if (cos_alpha >= cos_max) { - Point_Normal = jPoint; - cos_max = cos_alpha; - } - } - vertex[iMarker][iVertex]->SetNormal_Neighbor(Point_Normal); - } - } - } - } -} - - -void CMultiGridGeometry::SetGeometryPlanes(CConfig *config) { - bool loop_on; - unsigned short iMarker = 0; - su2double auxXCoord, auxYCoord, auxZCoord, *Face_Normal = NULL, auxArea, *Xcoord = NULL, *Ycoord = NULL, *Zcoord = NULL, *FaceArea = NULL; - unsigned long jVertex, iVertex, ixCoord, iPoint, iVertex_Wall, nVertex_Wall = 0; - - /*--- Compute the total number of points on the near-field ---*/ - nVertex_Wall = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) || - (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ) - nVertex_Wall += nVertex[iMarker]; - - - /*--- Create an array with all the coordinates, points, pressures, face area, - equivalent area, and nearfield weight ---*/ - Xcoord = new su2double[nVertex_Wall]; - Ycoord = new su2double[nVertex_Wall]; - if (nDim == 3) Zcoord = new su2double[nVertex_Wall]; - FaceArea = new su2double[nVertex_Wall]; - - /*--- Copy the boundary information to an array ---*/ - iVertex_Wall = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) || - (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ) - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - Xcoord[iVertex_Wall] = node[iPoint]->GetCoord(0); - Ycoord[iVertex_Wall] = node[iPoint]->GetCoord(1); - if (nDim==3) Zcoord[iVertex_Wall] = node[iPoint]->GetCoord(2); - Face_Normal = vertex[iMarker][iVertex]->GetNormal(); - FaceArea[iVertex_Wall] = fabs(Face_Normal[nDim-1]); - iVertex_Wall ++; - } - - - //vector XCoordList; - vector::iterator IterXCoordList; - - for (iVertex = 0; iVertex < nVertex_Wall; iVertex++) - XCoordList.push_back(Xcoord[iVertex]); - - sort( XCoordList.begin(), XCoordList.end()); - IterXCoordList = unique( XCoordList.begin(), XCoordList.end()); - XCoordList.resize( IterXCoordList - XCoordList.begin() ); - - /*--- Create vectors and distribute the values among the different PhiAngle queues ---*/ - Xcoord_plane.resize(XCoordList.size()); - Ycoord_plane.resize(XCoordList.size()); - if (nDim==3) Zcoord_plane.resize(XCoordList.size()); - FaceArea_plane.resize(XCoordList.size()); - Plane_points.resize(XCoordList.size()); - - - su2double dist_ratio; - unsigned long iCoord; - - /*--- Distribute the values among the different PhiAngles ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint++) { - if (node[iPoint]->GetDomain()) { - loop_on = true; - for (ixCoord = 0; ixCoord < XCoordList.size()-1 && loop_on; ixCoord++) { - dist_ratio = (node[iPoint]->GetCoord(0) - XCoordList[ixCoord])/(XCoordList[ixCoord+1]- XCoordList[ixCoord]); - if (dist_ratio >= 0 && dist_ratio <= 1.0) { - if (dist_ratio <= 0.5) iCoord = ixCoord; - else iCoord = ixCoord+1; - Xcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(0) ); - Ycoord_plane[iCoord].push_back(node[iPoint]->GetCoord(1) ); - if (nDim==3) Zcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(2) ); - FaceArea_plane[iCoord].push_back(node[iPoint]->GetVolume()); ///// CHECK AREA CALCULATION - Plane_points[iCoord].push_back(iPoint ); - loop_on = false; - } - } - } - } - - unsigned long auxPoint; - /*--- Order the arrays in ascending values of y ---*/ - for (ixCoord = 0; ixCoord < XCoordList.size(); ixCoord++) - for (iVertex = 0; iVertex < Xcoord_plane[ixCoord].size(); iVertex++) - for (jVertex = 0; jVertex < Xcoord_plane[ixCoord].size() - 1 - iVertex; jVertex++) - if (Ycoord_plane[ixCoord][jVertex] > Ycoord_plane[ixCoord][jVertex+1]) { - auxXCoord = Xcoord_plane[ixCoord][jVertex]; Xcoord_plane[ixCoord][jVertex] = Xcoord_plane[ixCoord][jVertex+1]; Xcoord_plane[ixCoord][jVertex+1] = auxXCoord; - auxYCoord = Ycoord_plane[ixCoord][jVertex]; Ycoord_plane[ixCoord][jVertex] = Ycoord_plane[ixCoord][jVertex+1]; Ycoord_plane[ixCoord][jVertex+1] = auxYCoord; - auxPoint = Plane_points[ixCoord][jVertex]; Plane_points[ixCoord][jVertex] = Plane_points[ixCoord][jVertex+1]; Plane_points[ixCoord][jVertex+1] = auxPoint; - if (nDim==3) { - auxZCoord = Zcoord_plane[ixCoord][jVertex]; Zcoord_plane[ixCoord][jVertex] = Zcoord_plane[ixCoord][jVertex+1]; Zcoord_plane[ixCoord][jVertex+1] = auxZCoord; - } - auxArea = FaceArea_plane[ixCoord][jVertex]; FaceArea_plane[ixCoord][jVertex] = FaceArea_plane[ixCoord][jVertex+1]; FaceArea_plane[ixCoord][jVertex+1] = auxArea; - } - - /*--- Delete structures ---*/ - delete[] Xcoord; delete[] Ycoord; - if (nDim==3) delete[] Zcoord; - delete[] FaceArea; -} - -CPeriodicGeometry::CPeriodicGeometry(CGeometry *geometry, CConfig *config) { - unsigned long nElem_new, nPoint_new, jPoint, iPoint, iElem, jElem, iVertex, - nelem_triangle = 0, nelem_quad = 0, nelem_tetra = 0, nelem_hexa = 0, nelem_prism = 0, - nelem_pyramid = 0, iIndex, newElementsBound = 0; - unsigned short iMarker, nPeriodic = 0, iPeriodic; - su2double *center, *angles, rotMatrix[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}, - translation[3], *trans, theta, phi, psi, cosTheta, sinTheta, cosPhi, sinPhi, cosPsi, sinPsi, - dx, dy, dz, rotCoord[3], *Coord_i; - unsigned short nMarker_Max = config->GetnMarker_Max(); - - /*--- We only create the mirror structure for the second boundary ---*/ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) { - /*--- Evaluate the number of periodic boundary conditions ---*/ - nPeriodic++; - } - } - bool *CreateMirror = new bool[nPeriodic+1]; - CreateMirror[0] = false; - for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { - if (iPeriodic <= nPeriodic/2) CreateMirror[iPeriodic] = false; - else CreateMirror[iPeriodic] = true; - } - - /*--- Write the number of dimensions of the problem ---*/ - nDim = geometry->GetnDim(); - - /*--- Copy the new boundary element information from the geometry class. - Be careful, as these are pointers to vectors/objects. ---*/ - nNewElem_BoundPer = geometry->nNewElem_Bound; - newBoundPer = geometry->newBound; - - /*--- Count the number of new boundary elements. ---*/ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - newElementsBound += nNewElem_BoundPer[iMarker]; - - /*--- Loop over the original grid to perform the dimensionalizaton of the new vectors ---*/ - nElem_new = 0; nPoint_new = 0; - for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { - if (CreateMirror[iPeriodic]) { - nElem_new += geometry->PeriodicElem[iPeriodic].size(); - nPoint_new += geometry->PeriodicPoint[iPeriodic][0].size(); - } - } - - cout << "Number of new points: " << nPoint_new << "." << endl; - cout << "Number of new interior elements: " << nElem_new << "." << endl; - cout << "Number of new boundary elements added to preexisting markers: " << newElementsBound << "." << endl; - - /*--- Create a copy of the original grid ---*/ - elem = new CPrimalGrid*[geometry->GetnElem() + nElem_new]; - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - switch(geometry->elem[iElem]->GetVTK_Type()) { - case TRIANGLE: - elem[iElem] = new CTriangle(geometry->elem[iElem]->GetNode(0), - geometry->elem[iElem]->GetNode(1), - geometry->elem[iElem]->GetNode(2), 2); - nelem_triangle++; - break; - - case QUADRILATERAL: - elem[iElem] = new CQuadrilateral(geometry->elem[iElem]->GetNode(0), - geometry->elem[iElem]->GetNode(1), - geometry->elem[iElem]->GetNode(2), - geometry->elem[iElem]->GetNode(3), 2); - nelem_quad++; - break; - - case TETRAHEDRON: - elem[iElem] = new CTetrahedron(geometry->elem[iElem]->GetNode(0), - geometry->elem[iElem]->GetNode(1), - geometry->elem[iElem]->GetNode(2), - geometry->elem[iElem]->GetNode(3)); - nelem_tetra++; - break; - - case HEXAHEDRON: - elem[iElem] = new CHexahedron(geometry->elem[iElem]->GetNode(0), - geometry->elem[iElem]->GetNode(1), - geometry->elem[iElem]->GetNode(2), - geometry->elem[iElem]->GetNode(3), - geometry->elem[iElem]->GetNode(4), - geometry->elem[iElem]->GetNode(5), - geometry->elem[iElem]->GetNode(6), - geometry->elem[iElem]->GetNode(7)); - nelem_hexa++; - break; - - case PRISM: - elem[iElem] = new CPrism(geometry->elem[iElem]->GetNode(0), - geometry->elem[iElem]->GetNode(1), - geometry->elem[iElem]->GetNode(2), - geometry->elem[iElem]->GetNode(3), - geometry->elem[iElem]->GetNode(4), - geometry->elem[iElem]->GetNode(5)); - nelem_prism++; - break; - - case PYRAMID: - elem[iElem] = new CPyramid(geometry->elem[iElem]->GetNode(0), - geometry->elem[iElem]->GetNode(1), - geometry->elem[iElem]->GetNode(2), - geometry->elem[iElem]->GetNode(3), - geometry->elem[iElem]->GetNode(4)); - nelem_pyramid++; - break; - - } - } - - /*--- Create a list with all the points and the new index ---*/ - unsigned long *Index = new unsigned long [geometry->GetnPoint()]; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) Index[iPoint] = 0; - - for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { - if (CreateMirror[iPeriodic]) { - for (iIndex = 0; iIndex < geometry->PeriodicPoint[iPeriodic][0].size(); iIndex++) { - iPoint = geometry->PeriodicPoint[iPeriodic][0][iIndex]; - Index[iPoint] = geometry->PeriodicPoint[iPeriodic][1][iIndex]; - } - } - } - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) - if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - jPoint = geometry->vertex[iMarker][iVertex]->GetDonorPoint(); - Index[iPoint] = jPoint; - } - - /*--- Add the new elements due to the periodic boundary condtion ---*/ - iElem = geometry->GetnElem(); - - for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { - if (CreateMirror[iPeriodic]) { - for (iIndex = 0; iIndex < geometry->PeriodicElem[iPeriodic].size(); iIndex++) { - jElem = geometry->PeriodicElem[iPeriodic][iIndex]; - - switch(geometry->elem[jElem]->GetVTK_Type()) { - case TRIANGLE: - elem[iElem] = new CTriangle(Index[geometry->elem[jElem]->GetNode(0)], - Index[geometry->elem[jElem]->GetNode(1)], - Index[geometry->elem[jElem]->GetNode(2)], 2); - iElem++; nelem_triangle++; - break; - - case QUADRILATERAL: - elem[iElem] = new CQuadrilateral(Index[geometry->elem[jElem]->GetNode(0)], - Index[geometry->elem[jElem]->GetNode(1)], - Index[geometry->elem[jElem]->GetNode(2)], - Index[geometry->elem[jElem]->GetNode(3)], 2); - iElem++; nelem_quad++; - break; - - case TETRAHEDRON: - elem[iElem] = new CTetrahedron(Index[geometry->elem[jElem]->GetNode(0)], - Index[geometry->elem[jElem]->GetNode(1)], - Index[geometry->elem[jElem]->GetNode(2)], - Index[geometry->elem[jElem]->GetNode(3)]); - iElem++; nelem_tetra++; - break; - - case HEXAHEDRON: - elem[iElem] = new CHexahedron(Index[geometry->elem[jElem]->GetNode(0)], - Index[geometry->elem[jElem]->GetNode(1)], - Index[geometry->elem[jElem]->GetNode(2)], - Index[geometry->elem[jElem]->GetNode(3)], - Index[geometry->elem[jElem]->GetNode(4)], - Index[geometry->elem[jElem]->GetNode(5)], - Index[geometry->elem[jElem]->GetNode(6)], - Index[geometry->elem[jElem]->GetNode(7)]); - iElem++; nelem_hexa++; - break; - - case PRISM: - elem[iElem] = new CPrism(Index[geometry->elem[jElem]->GetNode(0)], - Index[geometry->elem[jElem]->GetNode(1)], - Index[geometry->elem[jElem]->GetNode(2)], - Index[geometry->elem[jElem]->GetNode(3)], - Index[geometry->elem[jElem]->GetNode(4)], - Index[geometry->elem[jElem]->GetNode(5)]); - iElem++; nelem_prism++; - break; - - case PYRAMID: - elem[iElem] = new CPyramid(Index[geometry->elem[jElem]->GetNode(0)], - Index[geometry->elem[jElem]->GetNode(1)], - Index[geometry->elem[jElem]->GetNode(2)], - Index[geometry->elem[jElem]->GetNode(3)], - Index[geometry->elem[jElem]->GetNode(4)]); - iElem++; nelem_pyramid++; - break; - - } - } - } - } - - nElem = geometry->GetnElem() + nElem_new; - - /*--- Add the old points ---*/ - node = new CPoint*[geometry->GetnPoint() + nPoint_new]; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { - if (geometry->GetnDim() == 2) - node[iPoint] = new CPoint(geometry->node[iPoint]->GetCoord(0), - geometry->node[iPoint]->GetCoord(1), iPoint, config); - if (geometry->GetnDim() == 3) - node[iPoint] = new CPoint(geometry->node[iPoint]->GetCoord(0), - geometry->node[iPoint]->GetCoord(1), - geometry->node[iPoint]->GetCoord(2), iPoint, config); - } - - /*--- Add the new points due to the periodic boundary condtion (only in the mirror part) ---*/ - for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { - if (CreateMirror[iPeriodic]) { - for (iIndex = 0; iIndex < geometry->PeriodicPoint[iPeriodic][0].size(); iIndex++) { - - /*--- From iPeriodic obtain the iMarker ---*/ - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) - if (iPeriodic == config->GetMarker_All_PerBound(iMarker)) break; - - /*--- Retrieve the supplied periodic information. ---*/ - center = config->GetPeriodicRotCenter(config->GetMarker_All_TagBound(iMarker)); - angles = config->GetPeriodicRotAngles(config->GetMarker_All_TagBound(iMarker)); - trans = config->GetPeriodicTranslation(config->GetMarker_All_TagBound(iMarker)); - - /*--- Store center - trans as it is constant and will be added on. - Note the subtraction, as this is the inverse translation. ---*/ - translation[0] = center[0] - trans[0]; - translation[1] = center[1] - trans[1]; - translation[2] = center[2] - trans[2]; - - /*--- Store angles separately for clarity. Compute sines/cosines. - Note the negative sign, as this is the inverse rotation. ---*/ - theta = -angles[0]; - phi = -angles[1]; - psi = -angles[2]; - - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; - rotMatrix[1][0] = cosPhi*sinPsi; - rotMatrix[2][0] = -sinPhi; - - rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; - rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; - rotMatrix[2][1] = sinTheta*cosPhi; - - rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Retrieve node information for this boundary point. ---*/ - iPoint = geometry->PeriodicPoint[iPeriodic][0][iIndex]; - jPoint = geometry->PeriodicPoint[iPeriodic][1][iIndex]; - Coord_i = geometry->node[iPoint]->GetCoord(); - - /*--- Get the position vector from rot center to point. ---*/ - dx = Coord_i[0] - center[0]; - dy = Coord_i[1] - center[1]; - if (nDim == 3) { - dz = Coord_i[2] - center[2]; - } else { - dz = 0.0; - } - - /*--- Compute transformed point coordinates. ---*/ - rotCoord[0] = rotMatrix[0][0]*dx + rotMatrix[0][1]*dy + rotMatrix[0][2]*dz + translation[0]; - rotCoord[1] = rotMatrix[1][0]*dx + rotMatrix[1][1]*dy + rotMatrix[1][2]*dz + translation[1]; - rotCoord[2] = rotMatrix[2][0]*dx + rotMatrix[2][1]*dy + rotMatrix[2][2]*dz + translation[2]; - - /*--- Save the new points with the new coordinates. ---*/ - if (geometry->GetnDim() == 2) - node[jPoint] = new CPoint(rotCoord[0], rotCoord[1], jPoint, config); - if (geometry->GetnDim() == 3) - node[jPoint] = new CPoint(rotCoord[0], rotCoord[1], rotCoord[2], jPoint, config); - - } - } - } - - nPoint = geometry->GetnPoint() + nPoint_new; - - /*--- Add the old boundary, reserving space for two new bc (send/recive periodic bc) ---*/ - nMarker = geometry->GetnMarker() + 2; - nElem_Bound = new unsigned long [nMarker]; - bound = new CPrimalGrid**[nMarker]; - Tag_to_Marker = new string [nMarker_Max]; - config->SetnMarker_All(nMarker); - - /*--- Copy the olf boundary ---*/ - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - - bound[iMarker] = new CPrimalGrid* [geometry->GetnElem_Bound(iMarker)]; - - for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { - if (geometry->bound[iMarker][iVertex]->GetVTK_Type() == LINE) - bound[iMarker][iVertex] = new CLine(geometry->bound[iMarker][iVertex]->GetNode(0), - geometry->bound[iMarker][iVertex]->GetNode(1), 2); - if (geometry->bound[iMarker][iVertex]->GetVTK_Type() == TRIANGLE) - bound[iMarker][iVertex] = new CTriangle(geometry->bound[iMarker][iVertex]->GetNode(0), - geometry->bound[iMarker][iVertex]->GetNode(1), - geometry->bound[iMarker][iVertex]->GetNode(2), 3); - if (geometry->bound[iMarker][iVertex]->GetVTK_Type() == QUADRILATERAL) - bound[iMarker][iVertex] = new CQuadrilateral(geometry->bound[iMarker][iVertex]->GetNode(0), - geometry->bound[iMarker][iVertex]->GetNode(1), - geometry->bound[iMarker][iVertex]->GetNode(2), - geometry->bound[iMarker][iVertex]->GetNode(3), 3); - } - - nElem_Bound[iMarker] = geometry->GetnElem_Bound(iMarker); - Tag_to_Marker[iMarker] = geometry->GetMarker_Tag(iMarker); - - } - - delete [] Index; - delete [] CreateMirror; - -} - -CPeriodicGeometry::~CPeriodicGeometry(void) { - unsigned long iElem_Bound; - unsigned short iMarker; - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - if (newBoundPer[iMarker][iElem_Bound] != NULL) delete [] newBoundPer[iMarker][iElem_Bound]; - } - } - if (newBoundPer != NULL) delete[] newBoundPer; - - if (nNewElem_BoundPer != NULL) delete[] nNewElem_BoundPer; - -} - -void CPeriodicGeometry::SetPeriodicBoundary(CGeometry *geometry, CConfig *config) { - unsigned short iMarker, iPeriodic, nPeriodic = 0, iMarkerSend, iMarkerReceive; - unsigned long iVertex, Counter_Send = 0, Counter_Receive = 0, iIndex; - - /*--- Compute the number of periodic bc on the geometry ---*/ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) - nPeriodic++; - - /*--- First compute the Send/Receive boundaries, count the number of points ---*/ - Counter_Send = 0; Counter_Receive = 0; - for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { - if (geometry->PeriodicPoint[iPeriodic][0].size() != 0) - Counter_Send += geometry->PeriodicPoint[iPeriodic][0].size(); - if (geometry->PeriodicPoint[iPeriodic][1].size() != 0) - Counter_Receive += geometry->PeriodicPoint[iPeriodic][1].size(); - } - - /*--- Adimensionalization of the new boundaries ---*/ - iMarkerSend = nMarker - 2; iMarkerReceive = nMarker - 1; - config->SetMarker_All_SendRecv(iMarkerSend,1); - config->SetMarker_All_SendRecv(iMarkerReceive,-1); - nElem_Bound[iMarkerSend] = Counter_Send; - nElem_Bound[iMarkerReceive] = Counter_Receive; - bound[iMarkerSend] = new CPrimalGrid* [Counter_Send]; - bound[iMarkerReceive] = new CPrimalGrid* [Counter_Receive]; - - /*--- First we do the send ---*/ - iVertex = 0; - for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) - if (geometry->PeriodicPoint[iPeriodic][0].size() != 0) - for (iIndex = 0; iIndex < geometry->PeriodicPoint[iPeriodic][0].size(); iIndex++) { - bound[iMarkerSend][iVertex] = new CVertexMPI(geometry->PeriodicPoint[iPeriodic][0][iIndex], nDim); - bound[iMarkerSend][iVertex]->SetRotation_Type(iPeriodic); - iVertex++; - } - - /*--- Second we do the receive ---*/ - iVertex = 0; - for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) - if (geometry->PeriodicPoint[iPeriodic][1].size() != 0) - for (iIndex = 0; iIndex < geometry->PeriodicPoint[iPeriodic][1].size(); iIndex++) { - bound[iMarkerReceive][iVertex] = new CVertexMPI(geometry->PeriodicPoint[iPeriodic][1][iIndex], nDim); - bound[iMarkerReceive][iVertex]->SetRotation_Type(iPeriodic); - iVertex++; - } - -} - -void CPeriodicGeometry::SetMeshFile(CGeometry *geometry, CConfig *config, string val_mesh_out_filename) { - unsigned long iElem, iPoint, iElem_Bound, GhostPoints; - unsigned short iMarker, iNodes, iDim; - unsigned short iMarkerReceive, iPeriodic, nPeriodic = 0; - ofstream output_file; - string Grid_Marker; - char *cstr; - su2double *center, *angles, *transl; - - cstr = new char [val_mesh_out_filename.size()+1]; - strcpy (cstr, val_mesh_out_filename.c_str()); - - /*--- Open .su2 grid file ---*/ - output_file.precision(15); - output_file.open(cstr, ios::out); - - /*--- Ghost points, look at the nodes in the send receive ---*/ - iMarkerReceive = nMarker - 1; - GhostPoints = nElem_Bound[iMarkerReceive]; - - /*--- Change the numbering to guarantee that the all the receive - points are at the end of the file ---*/ - unsigned long OldnPoint = geometry->GetnPoint(); - unsigned long *NewSort = new unsigned long[nPoint]; - for (iPoint = 0; iPoint < nPoint; iPoint++) { - NewSort[iPoint] = iPoint; - } - - unsigned long Index = OldnPoint-1; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (bound[iMarker][0]->GetVTK_Type() == VERTEX) { - if (config->GetMarker_All_SendRecv(iMarker) < 0) { - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - if (bound[iMarker][iElem_Bound]->GetNode(0) < geometry->GetnPoint()) { - NewSort[bound[iMarker][iElem_Bound]->GetNode(0)] = Index; - NewSort[Index] = bound[iMarker][iElem_Bound]->GetNode(0); - Index--; - } - } - } - } - } - - - /*--- Write dimension, number of elements and number of points ---*/ - output_file << "NDIME= " << nDim << endl; - output_file << "NELEM= " << nElem << endl; - for (iElem = 0; iElem < nElem; iElem++) { - output_file << elem[iElem]->GetVTK_Type(); - for (iNodes = 0; iNodes < elem[iElem]->GetnNodes(); iNodes++) - output_file << "\t" << NewSort[elem[iElem]->GetNode(iNodes)]; - output_file << "\t"<GetCoord(iDim) ; - output_file << "\t" << iPoint << endl; - } - - output_file << "NMARK= " << nMarker << endl; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (bound[iMarker][0]->GetVTK_Type() != VERTEX) { - - Grid_Marker = config->GetMarker_All_TagBound(iMarker); - output_file << "MARKER_TAG= " << Grid_Marker << endl; - output_file << "MARKER_ELEMS= " << nElem_Bound[iMarker] + nNewElem_BoundPer[iMarker] << endl; - - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ; - for (iNodes = 0; iNodes < bound[iMarker][iElem_Bound]->GetnNodes()-1; iNodes++) - output_file << NewSort[bound[iMarker][iElem_Bound]->GetNode(iNodes)] << "\t" ; - iNodes = bound[iMarker][iElem_Bound]->GetnNodes()-1; - output_file << NewSort[bound[iMarker][iElem_Bound]->GetNode(iNodes)] << endl; - } - - /*--- Write any new elements at the end of the list. ---*/ - if (nNewElem_BoundPer[iMarker] > 0) { - for (iElem_Bound = 0; iElem_Bound < nNewElem_BoundPer[iMarker]; iElem_Bound++) { - output_file << newBoundPer[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ; - for (iNodes = 0; iNodes < newBoundPer[iMarker][iElem_Bound]->GetnNodes()-1; iNodes++) - output_file << NewSort[newBoundPer[iMarker][iElem_Bound]->GetNode(iNodes)] << "\t" ; - iNodes = newBoundPer[iMarker][iElem_Bound]->GetnNodes()-1; - output_file << NewSort[newBoundPer[iMarker][iElem_Bound]->GetNode(iNodes)] << endl; - } - } - - } - - if (bound[iMarker][0]->GetVTK_Type() == VERTEX) { - output_file << "MARKER_TAG= SEND_RECEIVE" << endl; - output_file << "MARKER_ELEMS= " << nElem_Bound[iMarker]<< endl; - if (config->GetMarker_All_SendRecv(iMarker) > 0) output_file << "SEND_TO= " << config->GetMarker_All_SendRecv(iMarker) << endl; - if (config->GetMarker_All_SendRecv(iMarker) < 0) output_file << "SEND_TO= " << config->GetMarker_All_SendRecv(iMarker) << endl; - - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" << - NewSort[bound[iMarker][iElem_Bound]->GetNode(0)] << "\t" << - bound[iMarker][iElem_Bound]->GetRotation_Type() << endl; - } - } - } - - /*--- Compute the number of periodic bc on the geometry ---*/ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) - nPeriodic++; - - output_file << "NPERIODIC= " << nPeriodic + 1 << endl; - - /*--- Periodic 0 correspond with no movement of the surface ---*/ - output_file << "PERIODIC_INDEX= 0" << endl; - output_file << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << endl; - output_file << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << endl; - output_file << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << endl; - - /*--- From iPeriodic obtain the iMarker ---*/ - for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { - for (iMarker = 0; iMarker < nMarker; iMarker++) - if (iPeriodic == config->GetMarker_All_PerBound(iMarker)) break; - - /*--- Retrieve the supplied periodic information. ---*/ - center = config->GetPeriodicRotCenter(config->GetMarker_All_TagBound(iMarker)); - angles = config->GetPeriodicRotAngles(config->GetMarker_All_TagBound(iMarker)); - transl = config->GetPeriodicTranslation(config->GetMarker_All_TagBound(iMarker)); - - output_file << "PERIODIC_INDEX= " << iPeriodic << endl; - output_file << center[0] << "\t" << center[1] << "\t" << center[2] << endl; - output_file << angles[0] << "\t" << angles[1] << "\t" << angles[2] << endl; - output_file << transl[0] << "\t" << transl[1] << "\t" << transl[2] << endl; - - } - - - output_file.close(); - - /*--- Free memory ---*/ - delete [] NewSort; - -} - -void CPeriodicGeometry::SetTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file) { - - unsigned long iElem, iPoint; - unsigned short iDim; - ofstream Tecplot_File; - - Tecplot_File.open(mesh_filename, ios::out); - Tecplot_File << "TITLE= \"Visualization of the volumetric grid\"" << endl; - - if (nDim == 2) { - Tecplot_File << "VARIABLES = \"x\",\"y\" " << endl; - Tecplot_File << "ZONE NODES= "<< nPoint <<", ELEMENTS= "<< nElem <<", DATAPACKING=POINT, ZONETYPE=FEQUADRILATERAL"<< endl; - } - if (nDim == 3) { - Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\" " << endl; - Tecplot_File << "ZONE NODES= "<< nPoint <<", ELEMENTS= "<< nElem <<", DATAPACKING=POINT, ZONETYPE=FEBRICK"<< endl; - } - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - for (iDim = 0; iDim < nDim; iDim++) - Tecplot_File << scientific << node[iPoint]->GetCoord(iDim) << "\t"; - Tecplot_File << "\n"; - } - - for (iElem = 0; iElem < nElem; iElem++) { - if (elem[iElem]->GetVTK_Type() == TRIANGLE) { - Tecplot_File << - elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< - elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(2)+1 << endl; - } - if (elem[iElem]->GetVTK_Type() == QUADRILATERAL) { - Tecplot_File << - elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< - elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 << endl; - } - if (elem[iElem]->GetVTK_Type() == TETRAHEDRON) { - Tecplot_File << - elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< - elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(2)+1 <<" "<< - elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<< - elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(3)+1 << endl; - } - if (elem[iElem]->GetVTK_Type() == HEXAHEDRON) { - Tecplot_File << - elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< - elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<< - elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(5)+1 <<" "<< - elem[iElem]->GetNode(6)+1 <<" "<< elem[iElem]->GetNode(7)+1 << endl; - } - if (elem[iElem]->GetVTK_Type() == PYRAMID) { - Tecplot_File << - elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< - elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<< - elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(4)+1 <<" "<< - elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(4)+1 << endl; - } - if (elem[iElem]->GetVTK_Type() == PRISM) { - Tecplot_File << - elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< - elem[iElem]->GetNode(1)+1 <<" "<< elem[iElem]->GetNode(2)+1 <<" "<< - elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(4)+1 <<" "<< - elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(5)+1 << endl; - } - } - - Tecplot_File.close(); -} - -CMultiGridQueue::CMultiGridQueue(unsigned long val_npoint) { - unsigned long iPoint; - - nPoint = val_npoint; - Priority = new short[nPoint]; - RightCV = new bool[nPoint]; - - QueueCV.resize(1); - - /*--- Queue initialization with all the points in the finer grid ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint ++) { - QueueCV[0].push_back(iPoint); - Priority[iPoint] = 0; - RightCV[iPoint] = true; - } - -} - -CMultiGridQueue::~CMultiGridQueue(void) { - - delete[] Priority; - delete[] RightCV; - -} - -void CMultiGridQueue::AddCV(unsigned long val_new_point, unsigned short val_number_neighbors) { - - unsigned short Max_Neighbors = QueueCV.size()-1; - - /*--- Basic check ---*/ - if (val_new_point > nPoint) { - cout << "The index of the CV is greater than the size of the priority list." << endl; - exit(EXIT_FAILURE); - } - - /*--- Resize the list ---*/ - if (val_number_neighbors > Max_Neighbors) - QueueCV.resize(val_number_neighbors+1); - - /*--- Find the point in the queue ---*/ - bool InQueue = false; - if (Priority[val_new_point] == val_number_neighbors) InQueue = true; - - if (!InQueue) { - /*--- Add the control volume, and update the priority list ---*/ - QueueCV[val_number_neighbors].push_back(val_new_point); - Priority[val_new_point] = val_number_neighbors; - } - -} - -void CMultiGridQueue::RemoveCV(unsigned long val_remove_point) { - unsigned short iPoint; - bool check; - - /*--- Basic check ---*/ - if (val_remove_point > nPoint) { - cout << "The index of the CV is greater than the size of the priority list." << endl; - exit(EXIT_FAILURE); - } - - /*--- Find priority of the Control Volume ---*/ - short Number_Neighbors = Priority[val_remove_point]; - if (Number_Neighbors == -1) { - cout << "The CV "<< val_remove_point <<" is not in the priority list. (RemoveCV)" << endl; - exit(EXIT_FAILURE); - } - - /*--- Find the point in the queue ---*/ - vector::iterator ItQueue = find(QueueCV[Number_Neighbors].begin(), - QueueCV[Number_Neighbors].end(), - val_remove_point); - if ( ItQueue != QueueCV[Number_Neighbors].end() ) QueueCV[Number_Neighbors].erase(ItQueue); - - Priority[val_remove_point] = -1; - - /*--- Check that the size of the queue is the right one ---*/ - unsigned short Size_QueueCV = 0; - check = false; - for (iPoint = 0; iPoint < QueueCV.size(); iPoint ++) - if (QueueCV[iPoint].size() != 0) { Size_QueueCV = iPoint; check = true;} - - /*--- Resize the queue, if check = false, the queue is empty, at least - we need one element in the queue ---*/ - if (check) QueueCV.resize(Size_QueueCV+1); - else QueueCV.resize(1); - -} - -void CMultiGridQueue::MoveCV(unsigned long val_move_point, short val_number_neighbors) { - - if (val_number_neighbors < 0) { - val_number_neighbors = 0; - RightCV[val_move_point] = false; - } - else { - RightCV[val_move_point] = true; - } - - /*--- Remove the control volume ---*/ - RemoveCV(val_move_point); - - /*--- Add a new control volume ---*/ - AddCV(val_move_point, val_number_neighbors); - -} - -void CMultiGridQueue::IncrPriorityCV(unsigned long val_incr_point) { - - /*--- Find the priority list ---*/ - short Number_Neighbors = Priority[val_incr_point]; - if (Number_Neighbors == -1) { - cout << "The CV "<< val_incr_point <<" is not in the priority list. (IncrPriorityCV)" << endl; - exit(EXIT_FAILURE); - } - - /*--- Remove the control volume ---*/ - RemoveCV(val_incr_point); - - /*--- Increase the priority ---*/ - AddCV(val_incr_point, Number_Neighbors+1); - -} - -void CMultiGridQueue::RedPriorityCV(unsigned long val_red_point) { - - /*--- Find the priority list ---*/ - short Number_Neighbors = Priority[val_red_point]; - if (Number_Neighbors == -1) { - cout << "The CV "<< val_red_point <<" is not in the priority list. (RedPriorityCV)" << endl; - exit(EXIT_FAILURE); - } - - if (Number_Neighbors != 0) { - - /*--- Remove the control volume ---*/ - RemoveCV(val_red_point); - - /*--- Increase the priority ---*/ - AddCV(val_red_point, Number_Neighbors-1); - - } - -} - -void CMultiGridQueue::VisualizeQueue(void) { - unsigned short iPoint; - unsigned long jPoint; - - cout << endl; - for (iPoint = 0; iPoint < QueueCV.size(); iPoint ++) { - cout << "Number of neighbors " << iPoint <<": "; - for (jPoint = 0; jPoint < QueueCV[iPoint].size(); jPoint ++) { - cout << QueueCV[iPoint][jPoint] << " "; - } - cout << endl; - } - -} - -void CMultiGridQueue::VisualizePriority(void) { - unsigned long iPoint; - - for (iPoint = 0; iPoint < nPoint; iPoint ++) - cout << "Control Volume: " << iPoint <<" Priority: " << Priority[iPoint] << endl; - -} - -long CMultiGridQueue::NextCV(void) { - if (QueueCV.size() != 0) return QueueCV[QueueCV.size()-1][0]; - else return -1; -} - -bool CMultiGridQueue::EmptyQueue(void) { - unsigned short iPoint; - - /*--- In case there is only the no agglomerated elements, - check if they can be agglomerated or we have already finished ---*/ - bool check = true; - - if ( QueueCV.size() == 1 ) { - for (iPoint = 0; iPoint < QueueCV[0].size(); iPoint ++) { - if (RightCV[QueueCV[0][iPoint]]) { check = false; break; } - } - } - else { - for (iPoint = 1; iPoint < QueueCV.size(); iPoint ++) - if (QueueCV[iPoint].size() != 0) { check = false; break;} - } - - return check; -} - -unsigned long CMultiGridQueue::TotalCV(void) { - unsigned short iPoint; - unsigned long TotalCV; - - TotalCV = 0; - for (iPoint = 0; iPoint < QueueCV.size(); iPoint ++) - if (QueueCV[iPoint].size() != 0) { TotalCV += QueueCV[iPoint].size(); } - - return TotalCV; -} - -void CMultiGridQueue::Update(unsigned long iPoint, CGeometry *fine_grid) { - unsigned short iNode; - unsigned long jPoint; - - RemoveCV(iPoint); - for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { - jPoint = fine_grid->node[iPoint]->GetPoint(iNode); - if (fine_grid->node[jPoint]->GetAgglomerate() == false) - IncrPriorityCV(jPoint); - } - -} +/*! + * \file geometry_structure.cpp + * \brief Main subroutines for creating the primal grid and multigrid structure. + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#include "../include/geometry_structure.hpp" + +/*--- Epsilon definition ---*/ + +#define EPSILON 0.000001 + +/*--- Cross product ---*/ + +#define CROSS(dest,v1,v2) \ +(dest)[0] = (v1)[1]*(v2)[2] - (v1)[2]*(v2)[1]; \ +(dest)[1] = (v1)[2]*(v2)[0] - (v1)[0]*(v2)[2]; \ +(dest)[2] = (v1)[0]*(v2)[1] - (v1)[1]*(v2)[0]; + +/*--- Cross product ---*/ + +#define DOT(v1,v2) ((v1)[0]*(v2)[0] + (v1)[1]*(v2)[1] + (v1)[2]*(v2)[2]); + +/*--- a = b - c ---*/ + +#define SUB(dest,v1,v2) \ +(dest)[0] = (v1)[0] - (v2)[0]; \ +(dest)[1] = (v1)[1] - (v2)[1]; \ +(dest)[2] = (v1)[2] - (v2)[2]; + +CGeometry::CGeometry(void) { + + nEdge = 0; + nPoint = 0; + nElem = 0; + + nElem_Bound = NULL; + Tag_to_Marker = NULL; + elem = NULL; + face = NULL; + bound = NULL; + node = NULL; + edge = NULL; + vertex = NULL; + nVertex = NULL; + newBound = NULL; + nNewElem_Bound = NULL; + Marker_All_SendRecv = NULL; + + // PeriodicPoint[MAX_NUMBER_PERIODIC][2].clear(); + // PeriodicElem[MAX_NUMBER_PERIODIC].clear(); + // XCoordList.clear(); + + // Xcoord_plane.clear(); + // Ycoord_plane.clear(); + // Zcoord_plane.clear(); + // FaceArea_plane.clear(); + // Plane_points.clear(); + +} + +CGeometry::~CGeometry(void) { + + unsigned long iElem, iElem_Bound, iFace, iVertex, iEdge; + unsigned short iMarker; + + if (elem != NULL) { + for (iElem = 0; iElem < nElem; iElem++) + if (elem[iElem] != NULL) delete elem[iElem]; + delete[] elem; + } + + if (bound != NULL) { + for (iMarker = 0; iMarker < nMarker; iMarker++) { + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + if (bound[iMarker][iElem_Bound] != NULL) delete bound[iMarker][iElem_Bound]; + } + } + delete[] bound; + } + + if (face != NULL) { + for (iFace = 0; iFace < nFace; iFace ++) + if (face[iFace] != NULL) delete face[iFace]; + delete[] face; + } + +// if (node != NULL) { +// for (iPoint = 0; iPoint < nPoint; iPoint ++) +// if (node[iPoint] != NULL) delete node[iPoint]; +// delete[] node; +// } + + if (edge != NULL) { + for (iEdge = 0; iEdge < nEdge; iEdge ++) + if (edge[iEdge] != NULL) delete [] edge[iEdge]; + delete[] edge; + } + + if (vertex != NULL) { + for (iMarker = 0; iMarker < nMarker; iMarker++) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + if (vertex[iMarker][iVertex] != NULL) delete [] vertex[iMarker][iVertex]; + } + } + delete[] vertex; + } + + if (newBound != NULL) { + for (iMarker = 0; iMarker < nMarker; iMarker++) { + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + if (newBound[iMarker][iElem_Bound] != NULL) delete [] newBound[iMarker][iElem_Bound]; + } + } + delete[] newBound; + } + + if (nElem_Bound != NULL) delete[] nElem_Bound; + if (nVertex != NULL) delete[] nVertex; + if (nNewElem_Bound != NULL) delete[] nNewElem_Bound; + if (Marker_All_SendRecv != NULL) delete[] Marker_All_SendRecv; + if (Tag_to_Marker != NULL) delete[] Tag_to_Marker; + + // PeriodicPoint[MAX_NUMBER_PERIODIC][2].~vector(); + // PeriodicElem[MAX_NUMBER_PERIODIC].~vector(); + // XCoordList.~vector(); + + // Xcoord_plane.~vector() + // Ycoord_plane.~vector() + // Zcoord_plane.~vector() + // FaceArea_plane.~vector() + // Plane_points.~vector() + +} + +su2double CGeometry::Point2Plane_Distance(su2double *Coord, su2double *iCoord, su2double *jCoord, su2double *kCoord) { + su2double CrossProduct[3], iVector[3], jVector[3], distance, modulus; + unsigned short iDim; + + for (iDim = 0; iDim < 3; iDim ++) { + iVector[iDim] = jCoord[iDim] - iCoord[iDim]; + jVector[iDim] = kCoord[iDim] - iCoord[iDim]; + } + + CrossProduct[0] = iVector[1]*jVector[2] - iVector[2]*jVector[1]; + CrossProduct[1] = iVector[2]*jVector[0] - iVector[0]*jVector[2]; + CrossProduct[2] = iVector[0]*jVector[1] - iVector[1]*jVector[0]; + + modulus = sqrt(CrossProduct[0]*CrossProduct[0]+CrossProduct[1]*CrossProduct[1]+CrossProduct[2]*CrossProduct[2]); + + distance = 0.0; + for (iDim = 0; iDim < 3; iDim ++) + distance += CrossProduct[iDim]*(Coord[iDim]-iCoord[iDim]); + distance /= modulus; + + return distance; + +} + +long CGeometry::FindEdge(unsigned long first_point, unsigned long second_point) { + unsigned long iPoint = 0; + unsigned short iNode; + for (iNode = 0; iNode < node[first_point]->GetnPoint(); iNode++) { + iPoint = node[first_point]->GetPoint(iNode); + if (iPoint == second_point) break; + } + + if (iPoint == second_point) return node[first_point]->GetEdge(iNode); + else { + cout << "\n\n !!! Error !!!\n" << endl; + cout <<"Can't find the edge that connects "<< first_point <<" and "<< second_point <<"."<< endl; + exit(EXIT_FAILURE); + return -1; + } +} + +bool CGeometry::CheckEdge(unsigned long first_point, unsigned long second_point) { + unsigned long iPoint = 0; + unsigned short iNode; + for (iNode = 0; iNode < node[first_point]->GetnPoint(); iNode++) { + iPoint = node[first_point]->GetPoint(iNode); + if (iPoint == second_point) break; + } + + if (iPoint == second_point) return true; + else return false; + +} + +void CGeometry::SetEdges(void) { + unsigned long iPoint, jPoint; + long iEdge; + unsigned short jNode, iNode; + long TestEdge = 0; + + nEdge = 0; + for (iPoint = 0; iPoint < nPoint; iPoint++) + for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) { + jPoint = node[iPoint]->GetPoint(iNode); + for (jNode = 0; jNode < node[jPoint]->GetnPoint(); jNode++) + if (node[jPoint]->GetPoint(jNode) == iPoint) { + TestEdge = node[jPoint]->GetEdge(jNode); + break; + } + if (TestEdge == -1) { + node[iPoint]->SetEdge(nEdge, iNode); + node[jPoint]->SetEdge(nEdge, jNode); + nEdge++; + } + } + + edge = new CEdge*[nEdge]; + + for (iPoint = 0; iPoint < nPoint; iPoint++) + for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) { + jPoint = node[iPoint]->GetPoint(iNode); + iEdge = FindEdge(iPoint, jPoint); + if (iPoint < jPoint) edge[iEdge] = new CEdge(iPoint, jPoint, nDim); + } +} + +void CGeometry::SetFaces(void) { + // unsigned long iPoint, jPoint, iFace; + // unsigned short jNode, iNode; + // long TestFace = 0; + // + // nFace = 0; + // for (iPoint = 0; iPoint < nPoint; iPoint++) + // for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) { + // jPoint = node[iPoint]->GetPoint(iNode); + // for (jNode = 0; jNode < node[jPoint]->GetnPoint(); jNode++) + // if (node[jPoint]->GetPoint(jNode) == iPoint) { + // TestFace = node[jPoint]->GetFace(jNode); + // break; + // } + // if (TestFace == -1) { + // node[iPoint]->SetFace(nFace, iNode); + // node[jPoint]->SetFace(nFace, jNode); + // nFace++; + // } + // } + // + // face = new CFace*[nFace]; + // + // for (iPoint = 0; iPoint < nPoint; iPoint++) + // for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) { + // jPoint = node[iPoint]->GetPoint(iNode); + // iFace = FindFace(iPoint, jPoint); + // if (iPoint < jPoint) face[iFace] = new CFace(iPoint, jPoint, nDim); + // } +} + +void CGeometry::TestGeometry(void) { + + ofstream para_file; + + para_file.open("test_geometry.dat", ios::out); + + su2double *Normal = new su2double[nDim]; + + for (unsigned long iEdge = 0; iEdge < nEdge; iEdge++) { + para_file << "Edge index: " << iEdge << endl; + para_file << " Point index: " << edge[iEdge]->GetNode(0) << "\t" << edge[iEdge]->GetNode(1) << endl; + edge[iEdge]->GetNormal(Normal); + para_file << " Face normal : "; + for (unsigned short iDim = 0; iDim < nDim; iDim++) + para_file << Normal[iDim] << "\t"; + para_file << endl; + } + + para_file << endl; + para_file << endl; + para_file << endl; + para_file << endl; + + for (unsigned short iMarker =0; iMarker < nMarker; iMarker++) { + para_file << "Marker index: " << iMarker << endl; + for (unsigned long iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + para_file << " Vertex index: " << iVertex << endl; + para_file << " Point index: " << vertex[iMarker][iVertex]->GetNode() << endl; + para_file << " Point coordinates : "; + for (unsigned short iDim = 0; iDim < nDim; iDim++) { + para_file << node[vertex[iMarker][iVertex]->GetNode()]->GetCoord(iDim) << "\t";} + para_file << endl; + vertex[iMarker][iVertex]->GetNormal(Normal); + para_file << " Face normal : "; + for (unsigned short iDim = 0; iDim < nDim; iDim++) + para_file << Normal[iDim] << "\t"; + para_file << endl; + } + } + +} + +void CGeometry::SetSpline(vector &x, vector &y, unsigned long n, su2double yp1, su2double ypn, vector &y2) { + unsigned long i, k; + su2double p, qn, sig, un, *u; + + u = new su2double [n]; + + if (yp1 > 0.99e30) // The lower boundary condition is set either to be "nat + y2[0]=u[0]=0.0; // -ural" + else { // or else to have a specified first derivative. + y2[0] = -0.5; + u[0]=(3.0/(x[1]-x[0]))*((y[1]-y[0])/(x[1]-x[0])-yp1); + } + + for (i=2; i<=n-1; i++) { // This is the decomposition loop of the tridiagonal al- + sig=(x[i-1]-x[i-2])/(x[i]-x[i-2]); // gorithm. y2 and u are used for tem- + p=sig*y2[i-2]+2.0; // porary storage of the decomposed + y2[i-1]=(sig-1.0)/p; // factors. + + su2double a1 = (y[i]-y[i-1])/(x[i]-x[i-1]); if (x[i] == x[i-1]) a1 = 1.0; + su2double a2 = (y[i-1]-y[i-2])/(x[i-1]-x[i-2]); if (x[i-1] == x[i-2]) a2 = 1.0; + u[i-1]= a1 - a2; + u[i-1]=(6.0*u[i-1]/(x[i]-x[i-2])-sig*u[i-2])/p; + + } + + if (ypn > 0.99e30) // The upper boundary condition is set either to be + qn=un=0.0; // "natural" + else { // or else to have a specified first derivative. + qn=0.5; + un=(3.0/(x[n-1]-x[n-2]))*(ypn-(y[n-1]-y[n-2])/(x[n-1]-x[n-2])); + } + y2[n-1]=(un-qn*u[n-2])/(qn*y2[n-2]+1.0); + for (k=n-1; k>=1; k--) // This is the backsubstitution loop of the tridiagonal + y2[k-1]=y2[k-1]*y2[k]+u[k-1]; // algorithm. + + delete[] u; + +} + +su2double CGeometry::GetSpline(vector&xa, vector&ya, vector&y2a, unsigned long n, su2double x) { + unsigned long klo, khi, k; + su2double h, b, a, y; + + if (x < xa[0]) x = xa[0]; // Clip max and min values + if (x > xa[n-1]) x = xa[n-1]; + + klo = 1; // We will find the right place in the table by means of + khi = n; // bisection. This is optimal if sequential calls to this + while (khi-klo > 1) { // routine are at random values of x. If sequential calls + k = (khi+klo) >> 1; // are in order, and closely spaced, one would do better + if (xa[k-1] > x) khi = k; // to store previous values of klo and khi and test if + else klo=k; // they remain appropriate on the next call. + } // klo and khi now bracket the input value of x + h = xa[khi-1] - xa[klo-1]; + if (h == 0.0) h = EPS; // cout << "Bad xa input to routine splint" << endl; // The xa’s must be distinct. + a = (xa[khi-1]-x)/h; + b = (x-xa[klo-1])/h; // Cubic spline polynomial is now evaluated. + y = a*ya[klo-1]+b*ya[khi-1]+((a*a*a-a)*y2a[klo-1]+(b*b*b-b)*y2a[khi-1])*(h*h)/6.0; + + return y; +} + +bool CGeometry::SegmentIntersectsPlane(su2double *Segment_P0, su2double *Segment_P1, su2double Variable_P0, su2double Variable_P1, + su2double *Plane_P0, su2double *Plane_Normal, su2double *Intersection, su2double &Variable_Interp) { + su2double u[3], v[3], Denominator, Numerator, Aux, ModU; + unsigned short iDim; + + for (iDim = 0; iDim < 3; iDim++) { + u[iDim] = Segment_P1[iDim] - Segment_P0[iDim]; + v[iDim] = Plane_P0[iDim] - Segment_P0[iDim]; + } + + ModU = sqrt(u[0]*u[0]+u[1]*u[1]+u[2]*u[2]); + + Numerator = Plane_Normal[0]*v[0] + Plane_Normal[1]*v[1] + Plane_Normal[2]*v[2]; + Denominator = Plane_Normal[0]*u[0] + Plane_Normal[1]*u[1] + Plane_Normal[2]*u[2]; + + if (fabs(Denominator) <= 0.0) return (false); // No intersection. + + Aux = Numerator / Denominator; + + if (Aux < 0.0 || Aux > 1.0) return (false); // No intersection. + + for (iDim = 0; iDim < 3; iDim++) + Intersection[iDim] = Segment_P0[iDim] + Aux * u[iDim]; + + + /*--- Check that the intersection is in the segment ---*/ + + for (iDim = 0; iDim < 3; iDim++) { + u[iDim] = Segment_P0[iDim] - Intersection[iDim]; + v[iDim] = Segment_P1[iDim] - Intersection[iDim]; + } + + Variable_Interp = Variable_P0 + (Variable_P1 - Variable_P0)*sqrt(u[0]*u[0]+u[1]*u[1]+u[2]*u[2])/ModU; + + Denominator = Plane_Normal[0]*u[0] + Plane_Normal[1]*u[1] + Plane_Normal[2]*u[2]; + Numerator = Plane_Normal[0]*v[0] + Plane_Normal[1]*v[1] + Plane_Normal[2]*v[2]; + + Aux = Numerator * Denominator; + + if (Aux > 0.0) return (false); // Intersection outside the segment. + + return (true); + +} + +bool CGeometry::RayIntersectsTriangle(su2double orig[3], su2double dir[3], + su2double vert0[3], su2double vert1[3], su2double vert2[3], + su2double *intersect) { + + su2double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; + su2double det, inv_det, t, u, v; + + /*--- Find vectors for two edges sharing vert0 ---*/ + + SUB(edge1, vert1, vert0); + SUB(edge2, vert2, vert0); + + /*--- Begin calculating determinant - also used to calculate U parameter ---*/ + + CROSS(pvec, dir, edge2); + + /*--- If determinant is near zero, ray lies in plane of triangle ---*/ + + det = DOT(edge1, pvec); + + + if (det > -EPSILON && det < EPSILON) return(false); + + inv_det = 1.0 / det; + + /*--- Calculate distance from vert0 to ray origin ---*/ + + SUB(tvec, orig, vert0); + + /*--- Calculate U parameter and test bounds ---*/ + + u = inv_det * DOT(tvec, pvec); + + if (u < 0.0 || u > 1.0) return(false); + + /*--- prepare to test V parameter ---*/ + + CROSS(qvec, tvec, edge1); + + /*--- Calculate V parameter and test bounds ---*/ + + v = inv_det * DOT(dir, qvec); + + if (v < 0.0 || u + v > 1.0) return(false); + + /*--- Calculate t, ray intersects triangle ---*/ + + t = inv_det * DOT(edge2, qvec); + + /*--- Compute the intersection point in cartesian coordinates ---*/ + + intersect[0] = orig[0] + (t * dir[0]); + intersect[1] = orig[1] + (t * dir[1]); + intersect[2] = orig[2] + (t * dir[2]); + + return (true); + +} + +bool CGeometry::SegmentIntersectsTriangle(su2double point0[3], su2double point1[3], + su2double vert0[3], su2double vert1[3], su2double vert2[3]) { + + su2double dir[3], intersect[3], u[3], v[3], edge1[3], edge2[3], Plane_Normal[3], Denominator, Numerator, Aux; + + SUB(dir, point1, point0); + + if (RayIntersectsTriangle(point0, dir, vert0, vert1, vert2, intersect)) { + + /*--- Check that the intersection is in the segment ---*/ + + SUB(u, point0, intersect); + SUB(v, point1, intersect); + + SUB(edge1, vert1, vert0); + SUB(edge2, vert2, vert0); + CROSS(Plane_Normal, edge1, edge2); + + Denominator = DOT(Plane_Normal, u); + Numerator = DOT(Plane_Normal, v); + + Aux = Numerator * Denominator; + + /*--- Intersection outside the segment ---*/ + + if (Aux > 0.0) return (false); + + } + else { + + /*--- No intersection with the ray ---*/ + + return (false); + + } + + /*--- Intersection inside the segment ---*/ + + return (true); + +} + +void CGeometry::ComputeAirfoil_Section(su2double *Plane_P0, su2double *Plane_Normal, + su2double MinXCoord, su2double MaxXCoord, su2double *FlowVariable, + vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, + vector &Zcoord_Airfoil, vector &Variable_Airfoil, + bool original_surface, CConfig *config) { + + unsigned short iMarker, iNode, jNode, iDim; + bool intersect; + long MinDist_Point, MinDistAngle_Point; + unsigned long iPoint, jPoint, iElem, Trailing_Point, Airfoil_Point, iVertex, jVertex; + su2double Segment_P0[3] = {0.0, 0.0, 0.0}, Segment_P1[3] = {0.0, 0.0, 0.0}, Variable_P0 = 0.0, Variable_P1 = 0.0, Intersection[3] = {0.0, 0.0, 0.0}, Trailing_Coord, MinDist_Value, MinDistAngle_Value, Dist_Value, + Airfoil_Tangent[3] = {0.0, 0.0, 0.0}, Segment[3] = {0.0, 0.0, 0.0}, Length, Angle_Value, MaxAngle = 30, *VarCoord = NULL, CosValue, Variable_Interp; + vector Xcoord, Ycoord, Zcoord, Variable; + vector Duplicate; + vector::iterator it; + int rank = MASTER_NODE; + su2double **Coord_Variation = NULL; + +#ifdef HAVE_MPI + unsigned long nLocalVertex, nGlobalVertex, MaxLocalVertex, *Buffer_Send_nVertex, *Buffer_Receive_nVertex, nBuffer; + int nProcessor, iProcessor; + su2double *Buffer_Send_Coord, *Buffer_Receive_Coord; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + Xcoord_Airfoil.clear(); + Ycoord_Airfoil.clear(); + Zcoord_Airfoil.clear(); + Variable_Airfoil.clear(); + + /*--- Set the right plane in 2D (note the change in Y-Z plane) ---*/ + + if (nDim == 2) { + Plane_P0[0] = 0.0; Plane_P0[1] = 0.0; Plane_P0[2] = 0.0; + Plane_Normal[0] = 0.0; Plane_Normal[1] = 1.0; Plane_Normal[2] = 0.0; + } + + /*--- the grid variation is stored using a vertices information, + we should go from vertex to points ---*/ + + if (original_surface == false) { + + Coord_Variation = new su2double *[nPoint]; + for (iPoint = 0; iPoint < nPoint; iPoint++) + Coord_Variation[iPoint] = new su2double [nDim]; + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_GeoEval(iMarker) == YES) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + VarCoord = vertex[iMarker][iVertex]->GetVarCoord(); + iPoint = vertex[iMarker][iVertex]->GetNode(); + for (iDim = 0; iDim < nDim; iDim++) + Coord_Variation[iPoint][iDim] = VarCoord[iDim]; + } + } + } + + } + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (config->GetMarker_All_GeoEval(iMarker) == YES) { + for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) { + for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { + iPoint = bound[iMarker][iElem]->GetNode(iNode); + for (jNode = 0; jNode < bound[iMarker][iElem]->GetnNodes(); jNode++) { + jPoint = bound[iMarker][iElem]->GetNode(jNode); + + if ((jPoint > iPoint) && ((node[iPoint]->GetCoord(0) > MinXCoord) && (node[iPoint]->GetCoord(0) < MaxXCoord))) { + + Segment_P0[0] = 0.0; Segment_P0[1] = 0.0; Segment_P0[2] = 0.0; Variable_P0 = 0.0; + Segment_P1[0] = 0.0; Segment_P1[1] = 0.0; Segment_P1[2] = 0.0; Variable_P1 = 0.0; + + for (iDim = 0; iDim < nDim; iDim++) { + if (original_surface == true) { + Segment_P0[iDim] = node[iPoint]->GetCoord(iDim); + Segment_P1[iDim] = node[jPoint]->GetCoord(iDim); + } + else { + Segment_P0[iDim] = node[iPoint]->GetCoord(iDim) + Coord_Variation[iPoint][iDim]; + Segment_P1[iDim] = node[jPoint]->GetCoord(iDim) + Coord_Variation[jPoint][iDim]; + } + } + + if (FlowVariable != NULL) { + Variable_P0 = FlowVariable[iPoint]; + Variable_P1 = FlowVariable[jPoint]; + } + + /*--- In 2D add the points directly (note the change between Y and Z coordinate) ---*/ + + if (nDim == 2) { + Xcoord.push_back(Segment_P0[0]); Xcoord.push_back(Segment_P1[0]); + Ycoord.push_back(Segment_P0[2]); Ycoord.push_back(Segment_P1[2]); + Zcoord.push_back(Segment_P0[1]); Zcoord.push_back(Segment_P1[1]); + Variable.push_back(Variable_P0); Variable.push_back(Variable_P1); + } + /*--- In 3D compute the intersection ---*/ + + else if (nDim == 3) { + intersect = SegmentIntersectsPlane(Segment_P0, Segment_P1, Variable_P0, Variable_P1, Plane_P0, Plane_Normal, Intersection, Variable_Interp); + if (intersect == true) { + Xcoord.push_back(Intersection[0]); + Ycoord.push_back(Intersection[1]); + Zcoord.push_back(Intersection[2]); + Variable.push_back(Variable_Interp); + } + } + + } + + } + } + } + } + } + + if (original_surface == false) { + + for (iPoint = 0; iPoint < nPoint; iPoint++) + delete [] Coord_Variation[iPoint]; + delete [] Coord_Variation; + + } + + +#ifdef HAVE_MPI + + /*--- Copy the coordinates of all the points in the plane to the master node ---*/ + + nLocalVertex = 0, nGlobalVertex = 0, MaxLocalVertex = 0; + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); + + Buffer_Send_nVertex = new unsigned long [1]; + Buffer_Receive_nVertex = new unsigned long [nProcessor]; + + nLocalVertex = Xcoord.size(); + + Buffer_Send_nVertex[0] = nLocalVertex; + + SU2_MPI::Allreduce(&nLocalVertex, &nGlobalVertex, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&nLocalVertex, &MaxLocalVertex, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + Buffer_Send_Coord = new su2double [MaxLocalVertex*4]; + Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex*4]; + nBuffer = MaxLocalVertex*4; + + for (iVertex = 0; iVertex < nLocalVertex; iVertex++) { + Buffer_Send_Coord[iVertex*4 + 0] = Xcoord[iVertex]; + Buffer_Send_Coord[iVertex*4 + 1] = Ycoord[iVertex]; + Buffer_Send_Coord[iVertex*4 + 2] = Zcoord[iVertex]; + Buffer_Send_Coord[iVertex*4 + 3] = Variable[iVertex]; + } + + SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer, MPI_DOUBLE, MPI_COMM_WORLD); + + /*--- Clean the vectors before adding the new vertices only to the master node ---*/ + + Xcoord.clear(); + Ycoord.clear(); + Zcoord.clear(); + Variable.clear(); + + /*--- Copy the boundary to the master node vectors ---*/ + if (rank == MASTER_NODE) { + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { + Xcoord.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalVertex*4 + iVertex*4 + 0] ); + Ycoord.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalVertex*4 + iVertex*4 + 1] ); + Zcoord.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalVertex*4 + iVertex*4 + 2] ); + Variable.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalVertex*4 + iVertex*4 + 3] ); + } + } + } + + delete[] Buffer_Send_Coord; delete[] Buffer_Receive_Coord; + delete[] Buffer_Send_nVertex; delete[] Buffer_Receive_nVertex; + +#endif + + if ((rank == MASTER_NODE) && (Xcoord.size() != 0)) { + + /*--- Create a list with the duplicated points ---*/ + + for (iVertex = 0; iVertex < Xcoord.size()-1; iVertex++) { + for (jVertex = iVertex+1; jVertex < Xcoord.size(); jVertex++) { + Segment[0] = Xcoord[jVertex] - Xcoord[iVertex]; + Segment[1] = Ycoord[jVertex] - Ycoord[iVertex]; + Segment[2] = Zcoord[jVertex] - Zcoord[iVertex]; + Dist_Value = sqrt(pow(Segment[0], 2.0) + pow(Segment[1], 2.0) + pow(Segment[2], 2.0)); + if (Dist_Value < 1E-6) { + Duplicate.push_back (jVertex); + } + } + } + + sort(Duplicate.begin(), Duplicate.end()); + it = unique(Duplicate.begin(), Duplicate.end()); + Duplicate.resize(it - Duplicate.begin()); + + /*--- Remove duplicated points (starting from the back) ---*/ + + for (iVertex = Duplicate.size(); iVertex > 0; iVertex--) { + Xcoord.erase (Xcoord.begin() + Duplicate[iVertex-1]); + Ycoord.erase (Ycoord.begin() + Duplicate[iVertex-1]); + Zcoord.erase (Zcoord.begin() + Duplicate[iVertex-1]); + Variable.erase (Variable.begin() + Duplicate[iVertex-1]); + } + + if (Xcoord.size() != 1) { + + /*--- Find the trailing edge ---*/ + + Trailing_Point = 0; Trailing_Coord = Xcoord[0]; + for (iVertex = 1; iVertex < Xcoord.size(); iVertex++) { + if (Xcoord[iVertex] > Trailing_Coord) { + Trailing_Point = iVertex; Trailing_Coord = Xcoord[iVertex]; + } + } + + /*--- Add the trailing edge to the list, and remove from the original list ---*/ + Xcoord_Airfoil.push_back(Xcoord[Trailing_Point]); Ycoord_Airfoil.push_back(Ycoord[Trailing_Point]); Zcoord_Airfoil.push_back(Zcoord[Trailing_Point]); Variable_Airfoil.push_back(Variable[Trailing_Point]); + Xcoord.erase (Xcoord.begin() + Trailing_Point); Ycoord.erase (Ycoord.begin() + Trailing_Point); Zcoord.erase (Zcoord.begin() + Trailing_Point); Variable.erase (Variable.begin() + Trailing_Point); + + /*--- Find the next point using the right hand side rule ---*/ + MinDist_Value = 1E6; MinDist_Point = 0; + for (iVertex = 0; iVertex < Xcoord.size(); iVertex++) { + Segment[0] = Xcoord[iVertex] - Xcoord_Airfoil[0]; + Segment[1] = Ycoord[iVertex] - Ycoord_Airfoil[0]; + Segment[2] = Zcoord[iVertex] - Zcoord_Airfoil[0]; + Dist_Value = sqrt(pow(Segment[0], 2.0) + pow(Segment[1], 2.0) + pow(Segment[2], 2.0)); + Segment[0] /= Dist_Value; Segment[1] /= Dist_Value; Segment[2] /= Dist_Value; + + if ((Dist_Value < MinDist_Value) && (Segment[2] > 0.0)) { MinDist_Point = iVertex; MinDist_Value = Dist_Value; } + } + + Xcoord_Airfoil.push_back(Xcoord[MinDist_Point]); Ycoord_Airfoil.push_back(Ycoord[MinDist_Point]); Zcoord_Airfoil.push_back(Zcoord[MinDist_Point]); Variable_Airfoil.push_back(Variable[MinDist_Point]); + Xcoord.erase (Xcoord.begin() + MinDist_Point); Ycoord.erase (Ycoord.begin() + MinDist_Point); Zcoord.erase (Zcoord.begin() + MinDist_Point); Variable.erase (Variable.begin() + MinDist_Point); + + /*--- Algorithm for the rest of the points ---*/ + do { + + /*--- Last added point in the list ---*/ + Airfoil_Point = Xcoord_Airfoil.size() - 1; + + /*--- Compute the slope of the curve ---*/ + Airfoil_Tangent[0] = Xcoord_Airfoil[Airfoil_Point] - Xcoord_Airfoil[Airfoil_Point-1]; + Airfoil_Tangent[1] = Ycoord_Airfoil[Airfoil_Point] - Ycoord_Airfoil[Airfoil_Point-1]; + Airfoil_Tangent[2] = Zcoord_Airfoil[Airfoil_Point] - Zcoord_Airfoil[Airfoil_Point-1]; + Length = sqrt(pow(Airfoil_Tangent[0], 2.0) + pow(Airfoil_Tangent[1], 2.0) + pow(Airfoil_Tangent[2], 2.0)); + Airfoil_Tangent[0] /= Length; Airfoil_Tangent[1] /= Length; Airfoil_Tangent[2] /= Length; + + /*--- Find the closest point with the right slope ---*/ + MinDist_Value = 1E6; MinDistAngle_Value = 180; + MinDist_Point = -1; MinDistAngle_Point = -1; + for (iVertex = 0; iVertex < Xcoord.size(); iVertex++) { + + Segment[0] = Xcoord[iVertex] - Xcoord_Airfoil[Airfoil_Point]; + Segment[1] = Ycoord[iVertex] - Ycoord_Airfoil[Airfoil_Point]; + Segment[2] = Zcoord[iVertex] - Zcoord_Airfoil[Airfoil_Point]; + + /*--- Compute the distance to each point ---*/ + Dist_Value = sqrt(pow(Segment[0], 2.0) + pow(Segment[1], 2.0) + pow(Segment[2], 2.0)); + + /*--- Compute the angle of the point ---*/ + Segment[0] /= Dist_Value; Segment[1] /= Dist_Value; Segment[2] /= Dist_Value; + + /*--- Clip the value of the cosine, this is important due to the round errors ---*/ + CosValue = Airfoil_Tangent[0]*Segment[0] + Airfoil_Tangent[1]*Segment[1] + Airfoil_Tangent[2]*Segment[2]; + if (CosValue >= 1.0) CosValue = 1.0; + if (CosValue <= -1.0) CosValue = -1.0; + + Angle_Value = acos(CosValue) * 180 / PI_NUMBER; + + if (Dist_Value < MinDist_Value) { MinDist_Point = iVertex; MinDist_Value = Dist_Value; } + if ((Dist_Value < MinDistAngle_Value) && (Angle_Value < MaxAngle)) {MinDistAngle_Point = iVertex; MinDistAngle_Value = Dist_Value;} + + } + + if ( MinDistAngle_Point != -1) MinDist_Point = MinDistAngle_Point; + + /*--- Add and remove the min distance to the list ---*/ + Xcoord_Airfoil.push_back(Xcoord[MinDist_Point]); Ycoord_Airfoil.push_back(Ycoord[MinDist_Point]); Zcoord_Airfoil.push_back(Zcoord[MinDist_Point]); Variable_Airfoil.push_back(Variable[MinDist_Point]); + Xcoord.erase(Xcoord.begin() + MinDist_Point); Ycoord.erase(Ycoord.begin() + MinDist_Point); Zcoord.erase(Zcoord.begin() + MinDist_Point); Variable.erase(Variable.begin() + MinDist_Point); + + } while (Xcoord.size() != 0); + + /*--- Clean the vector before using them again for storing the upper or the lower side ---*/ + + Xcoord.clear(); Ycoord.clear(); Zcoord.clear(); Variable.clear(); + + } + + + } + +} + + +void CGeometry::RegisterCoordinates(CConfig *config){ + unsigned short iDim; + unsigned long iPoint; + + for (iPoint = 0; iPoint < nPoint; iPoint++){ + for (iDim = 0; iDim < nDim; iDim++){ + AD::RegisterInput(node[iPoint]->GetCoord()[iDim]); + } + } +} + +void CGeometry::UpdateGeometry(CGeometry **geometry_container, CConfig *config){ + + unsigned short iMesh; + geometry_container[MESH_0]->Set_MPI_Coord(config); + + geometry_container[MESH_0]->SetCoord_CG(); + geometry_container[MESH_0]->SetControlVolume(config, UPDATE); + geometry_container[MESH_0]->SetBoundControlVolume(config, UPDATE); + + for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++){ + /*--- Update the control volume structures ---*/ + + geometry_container[iMesh]->SetControlVolume(config,geometry_container[iMesh-1], UPDATE); + geometry_container[iMesh]->SetBoundControlVolume(config,geometry_container[iMesh-1], UPDATE); + geometry_container[iMesh]->SetCoord(geometry_container[iMesh-1]); + + } + if (config->GetKind_Solver() == DISC_ADJ_RANS) + geometry_container[MESH_0]->ComputeWall_Distance(config); +} + +void CGeometry::ComputeSurf_Curvature(CConfig *config) { + unsigned short iMarker, iNeigh_Point, iDim, iNode, iNeighbor_Nodes, Neighbor_Node; + unsigned long Neighbor_Point, iVertex, iPoint, jPoint, iElem_Bound, iEdge, nLocalVertex, MaxLocalVertex , *Buffer_Send_nVertex, *Buffer_Receive_nVertex, TotalnPointDomain; + int iProcessor, nProcessor; + vector Point_NeighborList, Elem_NeighborList, Point_Triangle, Point_Edge, Point_Critical; + vector::iterator it; + su2double U[3] = {0.0,0.0,0.0}, V[3] = {0.0,0.0,0.0}, W[3] = {0.0,0.0,0.0}, Length_U, Length_V, Length_W, CosValue, Angle_Value, *K, *Angle_Defect, *Area_Vertex, *Angle_Alpha, *Angle_Beta, **NormalMeanK, MeanK, GaussK, MaxPrinK, cot_alpha, cot_beta, delta, X1, X2, X3, Y1, Y2, Y3, radius, *Buffer_Send_Coord, *Buffer_Receive_Coord, *Coord, Dist, MinDist, MaxK, MinK, SigmaK; + bool *Check_Edge; + int rank; + +#ifndef HAVE_MPI + rank = MASTER_NODE; +#else + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Allocate surface curvature ---*/ + K = new su2double [nPoint]; + for (iPoint = 0; iPoint < nPoint; iPoint++) K[iPoint] = 0.0; + + if (nDim == 2) { + + /*--- Loop over all the markers ---*/ + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { + + /*--- Loop through all marker vertices again, this time also + finding the neighbors of each node.---*/ + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + + if (node[iPoint]->GetDomain()) { + /*--- Loop through neighbors. In 2-D, there should be 2 nodes on either + side of this vertex that lie on the same surface. ---*/ + Point_Edge.clear(); + + for (iNeigh_Point = 0; iNeigh_Point < node[iPoint]->GetnPoint(); iNeigh_Point++) { + Neighbor_Point = node[iPoint]->GetPoint(iNeigh_Point); + + /*--- Check if this neighbor lies on the surface. If so, + add to the list of neighbors. ---*/ + if (node[Neighbor_Point]->GetPhysicalBoundary()) { + Point_Edge.push_back(Neighbor_Point); + } + + } + + if (Point_Edge.size() == 2) { + + /*--- Compute the curvature using three points ---*/ + X1 = node[iPoint]->GetCoord(0); + X2 = node[Point_Edge[0]]->GetCoord(0); + X3 = node[Point_Edge[1]]->GetCoord(0); + Y1 = node[iPoint]->GetCoord(1); + Y2 = node[Point_Edge[0]]->GetCoord(1); + Y3 = node[Point_Edge[1]]->GetCoord(1); + + radius = sqrt(((X2-X1)*(X2-X1) + (Y2-Y1)*(Y2-Y1))* + ((X2-X3)*(X2-X3) + (Y2-Y3)*(Y2-Y3))* + ((X3-X1)*(X3-X1) + (Y3-Y1)*(Y3-Y1)))/ + (2.0*fabs(X1*Y2+X2*Y3+X3*Y1-X1*Y3-X2*Y1-X3*Y2)+EPS); + + K[iPoint] = 1.0/radius; + node[iPoint]->SetCurvature(K[iPoint]); + } + + } + + } + + } + + } + + } + + else { + + Angle_Defect = new su2double [nPoint]; + Area_Vertex = new su2double [nPoint]; + for (iPoint = 0; iPoint < nPoint; iPoint++) { + Angle_Defect[iPoint] = 2*PI_NUMBER; + Area_Vertex[iPoint] = 0.0; + } + + Angle_Alpha = new su2double [nEdge]; + Angle_Beta = new su2double [nEdge]; + Check_Edge = new bool [nEdge]; + for (iEdge = 0; iEdge < nEdge; iEdge++) { + Angle_Alpha[iEdge] = 0.0; + Angle_Beta[iEdge] = 0.0; + Check_Edge[iEdge] = true; + } + + NormalMeanK = new su2double *[nPoint]; + for (iPoint = 0; iPoint < nPoint; iPoint++) { + NormalMeanK[iPoint] = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) { + NormalMeanK[iPoint][iDim] = 0.0; + } + } + + /*--- Loop over all the markers ---*/ + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { + + /*--- Loop over all the boundary elements ---*/ + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + + /*--- Only triangles ---*/ + if (bound[iMarker][iElem_Bound]->GetVTK_Type() == TRIANGLE) { + + /*--- Loop over all the nodes of the boundary element ---*/ + for (iNode = 0; iNode < bound[iMarker][iElem_Bound]->GetnNodes(); iNode++) { + + iPoint = bound[iMarker][iElem_Bound]->GetNode(iNode); + + Point_Triangle.clear(); + + for (iNeighbor_Nodes = 0; iNeighbor_Nodes < bound[iMarker][iElem_Bound]->GetnNeighbor_Nodes(iNode); iNeighbor_Nodes++) { + Neighbor_Node = bound[iMarker][iElem_Bound]->GetNeighbor_Nodes(iNode, iNeighbor_Nodes); + Neighbor_Point = bound[iMarker][iElem_Bound]->GetNode(Neighbor_Node); + Point_Triangle.push_back(Neighbor_Point); + } + + iEdge = FindEdge(Point_Triangle[0], Point_Triangle[1]); + + for (iDim = 0; iDim < nDim; iDim++) { + U[iDim] = node[Point_Triangle[0]]->GetCoord(iDim) - node[iPoint]->GetCoord(iDim); + V[iDim] = node[Point_Triangle[1]]->GetCoord(iDim) - node[iPoint]->GetCoord(iDim); + } + + W[0] = 0.5*(U[1]*V[2]-U[2]*V[1]); W[1] = -0.5*(U[0]*V[2]-U[2]*V[0]); W[2] = 0.5*(U[0]*V[1]-U[1]*V[0]); + + Length_U = 0.0, Length_V = 0.0, Length_W = 0.0, CosValue = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { Length_U += U[iDim]*U[iDim]; Length_V += V[iDim]*V[iDim]; Length_W += W[iDim]*W[iDim]; } + Length_U = sqrt(Length_U); Length_V = sqrt(Length_V); Length_W = sqrt(Length_W); + for (iDim = 0; iDim < nDim; iDim++) { U[iDim] /= Length_U; V[iDim] /= Length_V; CosValue += U[iDim]*V[iDim]; } + if (CosValue >= 1.0) CosValue = 1.0; + if (CosValue <= -1.0) CosValue = -1.0; + + Angle_Value = acos(CosValue); + Area_Vertex[iPoint] += Length_W; + Angle_Defect[iPoint] -= Angle_Value; + if (Angle_Alpha[iEdge] == 0.0) Angle_Alpha[iEdge] = Angle_Value; + else Angle_Beta[iEdge] = Angle_Value; + + } + } + } + } + } + + /*--- Compute mean curvature ---*/ + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + if (bound[iMarker][iElem_Bound]->GetVTK_Type() == TRIANGLE) { + for (iNode = 0; iNode < bound[iMarker][iElem_Bound]->GetnNodes(); iNode++) { + iPoint = bound[iMarker][iElem_Bound]->GetNode(iNode); + + for (iNeighbor_Nodes = 0; iNeighbor_Nodes < bound[iMarker][iElem_Bound]->GetnNeighbor_Nodes(iNode); iNeighbor_Nodes++) { + Neighbor_Node = bound[iMarker][iElem_Bound]->GetNeighbor_Nodes(iNode, iNeighbor_Nodes); + jPoint = bound[iMarker][iElem_Bound]->GetNode(Neighbor_Node); + + iEdge = FindEdge(iPoint, jPoint); + + if (Check_Edge[iEdge]) { + + Check_Edge[iEdge] = false; + + if (tan(Angle_Alpha[iEdge]) != 0.0) cot_alpha = 1.0/tan(Angle_Alpha[iEdge]); else cot_alpha = 0.0; + if (tan(Angle_Beta[iEdge]) != 0.0) cot_beta = 1.0/tan(Angle_Beta[iEdge]); else cot_beta = 0.0; + + /*--- iPoint, and jPoint ---*/ + for (iDim = 0; iDim < nDim; iDim++) { + if (Area_Vertex[iPoint] != 0.0) NormalMeanK[iPoint][iDim] += 3.0 * (cot_alpha + cot_beta) * (node[iPoint]->GetCoord(iDim) - node[jPoint]->GetCoord(iDim)) / Area_Vertex[iPoint]; + if (Area_Vertex[jPoint] != 0.0) NormalMeanK[jPoint][iDim] += 3.0 * (cot_alpha + cot_beta) * (node[jPoint]->GetCoord(iDim) - node[iPoint]->GetCoord(iDim)) / Area_Vertex[jPoint]; + } + } + + } + } + } + } + } + } + + /*--- Compute Gauss, mean, max and min principal curvature, + and set the list of critical points ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + + if (node[iPoint]->GetDomain()) { + + if (Area_Vertex[iPoint] != 0.0) GaussK = 3.0*Angle_Defect[iPoint]/Area_Vertex[iPoint]; + else GaussK = 0.0; + + MeanK = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + MeanK += NormalMeanK[iPoint][iDim]*NormalMeanK[iPoint][iDim]; + MeanK = sqrt(MeanK); + + delta = max((MeanK*MeanK - GaussK), 0.0); + + MaxPrinK = MeanK + sqrt(delta); + + /*--- Store the curvature value ---*/ + K[iPoint] = MaxPrinK; + node[iPoint]->SetCurvature(K[iPoint]); + } + + } + } + } + + delete [] Angle_Defect; + delete [] Area_Vertex; + delete [] Angle_Alpha; + delete [] Angle_Beta; + delete [] Check_Edge; + + for (iPoint = 0; iPoint < nPoint; iPoint++) + delete [] NormalMeanK[iPoint]; + delete [] NormalMeanK; + + } + + /*--- Sharp edge detection is based in the statistical + distribution of the curvature ---*/ + + MaxK = K[0]; MinK = K[0]; MeanK = 0.0; TotalnPointDomain = 0; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + MaxK = max(MaxK, fabs(K[iPoint])); + MinK = min(MinK, fabs(K[iPoint])); + MeanK += fabs(K[iPoint]); + TotalnPointDomain++; + } + } + } + } + +#ifdef HAVE_MPI + su2double MyMeanK = MeanK; MeanK = 0.0; + su2double MyMaxK = MaxK; MaxK = 0.0; + unsigned long MynPointDomain = TotalnPointDomain; TotalnPointDomain = 0; + SU2_MPI::Allreduce(&MyMeanK, &MeanK, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyMaxK, &MaxK, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MynPointDomain, &TotalnPointDomain, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); +#endif + + /*--- Compute the mean ---*/ + MeanK /= su2double(TotalnPointDomain); + + /*--- Compute the standard deviation ---*/ + SigmaK = 0.0; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + SigmaK += (fabs(K[iPoint]) - MeanK) * (fabs(K[iPoint]) - MeanK); + } + } + } + } + +#ifdef HAVE_MPI + su2double MySigmaK = SigmaK; SigmaK = 0.0; + SU2_MPI::Allreduce(&MySigmaK, &SigmaK, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); +#endif + + SigmaK = sqrt(SigmaK/su2double(TotalnPointDomain)); + + if (rank == MASTER_NODE) + cout << "Max K: " << MaxK << ". Mean K: " << MeanK << ". Standard deviation K: " << SigmaK << "." << endl; + + Point_Critical.clear(); + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + if (fabs(K[iPoint]) > MeanK + config->GetRefSharpEdges()*SigmaK) { + Point_Critical.push_back(iPoint); + } + } + } + } + } + + /*--- Variables and buffers needed for MPI ---*/ + +#ifdef HAVE_MPI + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); +#else + nProcessor = 1; +#endif + + Buffer_Send_nVertex = new unsigned long [1]; + Buffer_Receive_nVertex = new unsigned long [nProcessor]; + + /*--- Count the total number of critical edge nodes. ---*/ + + nLocalVertex = Point_Critical.size(); + Buffer_Send_nVertex[0] = nLocalVertex; + + /*--- Communicate to all processors the total number of critical edge nodes. ---*/ + +#ifdef HAVE_MPI + MaxLocalVertex = 0; + SU2_MPI::Allreduce(&nLocalVertex, &MaxLocalVertex, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); +#else + MaxLocalVertex = nLocalVertex; + Buffer_Receive_nVertex[0] = nLocalVertex; +#endif + + + /*--- Create and initialize to zero some buffers to hold the coordinates + of the boundary nodes that are communicated from each partition (all-to-all). ---*/ + + Buffer_Send_Coord = new su2double [MaxLocalVertex*nDim]; + Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex*nDim]; + +#ifdef HAVE_MPI + unsigned long nBuffer = MaxLocalVertex*nDim; +#endif + + for (iVertex = 0; iVertex < MaxLocalVertex; iVertex++) { + for (iDim = 0; iDim < nDim; iDim++) { + Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; + } + } + + /*--- Retrieve and store the coordinates of the sharp edges boundary nodes on + the local partition and broadcast them to all partitions. ---*/ + + for (iVertex = 0; iVertex < Point_Critical.size(); iVertex++) { + iPoint = Point_Critical[iVertex]; + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[iVertex*nDim+iDim] = node[iPoint]->GetCoord(iDim); + } + +#ifdef HAVE_MPI + SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer, MPI_DOUBLE, MPI_COMM_WORLD); +#else + for (iVertex = 0; iVertex < Point_Critical.size(); iVertex++) { + for (iDim = 0; iDim < nDim; iDim++) { + Buffer_Receive_Coord[iVertex*nDim+iDim] = Buffer_Send_Coord[iVertex*nDim+iDim]; + } + } +#endif + + /*--- Loop over all interior mesh nodes on the local partition and compute + the distances to each of the no-slip boundary nodes in the entire mesh. + Store the minimum distance to the wall for each interior mesh node. ---*/ + + for (iPoint = 0; iPoint < GetnPoint(); iPoint++) { + Coord = node[iPoint]->GetCoord(); + + MinDist = 1E20; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { + Dist = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Dist += (Coord[iDim]-Buffer_Receive_Coord[(iProcessor*MaxLocalVertex+iVertex)*nDim+iDim])* + (Coord[iDim]-Buffer_Receive_Coord[(iProcessor*MaxLocalVertex+iVertex)*nDim+iDim]); + } + if (Dist!=0.0) Dist = sqrt(Dist); + else Dist = 0.0; + if (Dist < MinDist) MinDist = Dist; + } + } + node[iPoint]->SetSharpEdge_Distance(MinDist); + } + + /*--- Deallocate Max curvature ---*/ + delete[] K; + + /*--- Deallocate the buffers needed for the MPI communication. ---*/ + delete[] Buffer_Send_Coord; + delete[] Buffer_Receive_Coord; + delete[] Buffer_Send_nVertex; + delete[] Buffer_Receive_nVertex; + +} + +CPhysicalGeometry::CPhysicalGeometry() : CGeometry() { + + Global_to_Local_Point = NULL; + Local_to_Global_Point = NULL; + Local_to_Global_Marker = NULL; + Global_to_Local_Marker = NULL; + +} + +CPhysicalGeometry::CPhysicalGeometry(CConfig *config, unsigned short val_iZone, unsigned short val_nZone) : CGeometry() { + + Global_to_Local_Point = NULL; + Local_to_Global_Point = NULL; + Local_to_Global_Marker = NULL; + Global_to_Local_Marker = NULL; + + string text_line, Marker_Tag; + ifstream mesh_file; + unsigned short iDim, iMarker, iNodes; + unsigned long iPoint, LocaNodes = 0, iElem_Bound; + su2double *NewCoord; + nZone = val_nZone; + ofstream boundary_file; + string Grid_Marker; + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + string val_mesh_filename = config->GetMesh_FileName(); + unsigned short val_format = config->GetMesh_FileFormat(); + + /*--- Initialize counters for local/global points & elements ---*/ + + if (rank == MASTER_NODE) + cout << endl <<"---------------------- Read Grid File Information -----------------------" << endl; + + switch (val_format) { + case SU2: + Read_SU2_Format_Parallel(config, val_mesh_filename, val_iZone, val_nZone); + LocaNodes = local_node; + break; + case CGNS: + Read_CGNS_Format_Parallel(config, val_mesh_filename, val_iZone, val_nZone); + LocaNodes = local_node; + break; + default: + if (rank == MASTER_NODE) cout << "Unrecognized mesh format specified!" << endl; +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + break; + } + + /*--- After reading the mesh, assert that the dimension is equal to 2 or 3. ---*/ + + assert((nDim == 2) || (nDim == 3)); + + /*--- Loop over the points element to re-scale the mesh, and plot it (only SU2_CFD) ---*/ + + if (config->GetKind_SU2() == SU2_CFD) { + + NewCoord = new su2double [nDim]; + + /*--- The US system uses feet, but SU2 assumes that the grid is in inches ---*/ + + if (config->GetSystemMeasurements() == US) { + for (iPoint = 0; iPoint < LocaNodes; iPoint++) { + for (iDim = 0; iDim < nDim; iDim++) { + NewCoord[iDim] = node[iPoint]->GetCoord(iDim)/12.0; + } + node[iPoint]->SetCoord(NewCoord); + } + } + + delete [] NewCoord; + + } + + /*--- If SU2_DEF then write a file with the boundary information ---*/ + + if ((config->GetKind_SU2() == SU2_DEF) && (rank == MASTER_NODE)) { + + /*--- Open .su2 grid file ---*/ + + boundary_file.open("boundary.su2", ios::out); + + /*--- Loop through and write the boundary info ---*/ + + boundary_file << "NMARK= " << nMarker << endl; + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + Grid_Marker = config->GetMarker_All_TagBound(iMarker); + boundary_file << "MARKER_TAG= " << Grid_Marker << endl; + boundary_file << "MARKER_ELEMS= " << nElem_Bound[iMarker]<< endl; + + if (nDim == 2) { + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + boundary_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ; + for (iNodes = 0; iNodes < bound[iMarker][iElem_Bound]->GetnNodes(); iNodes++) + boundary_file << bound[iMarker][iElem_Bound]->GetNode(iNodes) << "\t" ; + boundary_file << iElem_Bound << endl; + } + } + + if (nDim == 3) { + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + boundary_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ; + for (iNodes = 0; iNodes < bound[iMarker][iElem_Bound]->GetnNodes(); iNodes++) + boundary_file << bound[iMarker][iElem_Bound]->GetNode(iNodes) << "\t" ; + boundary_file << iElem_Bound << endl; + } + } + + } + + boundary_file.close(); + + } + +} + + +CPhysicalGeometry::CPhysicalGeometry(CGeometry *geometry, CConfig *config) { + + Global_to_Local_Point = NULL; + Local_to_Global_Point = NULL; + Local_to_Global_Marker = NULL; + Global_to_Local_Marker = NULL; + + unsigned long iter, iPoint, jPoint, iElem, jElem, iVertex; + unsigned long nElemTotal = 0, nPointTotal = 0, nPointDomainTotal = 0, nElemTriangle = 0, nElemQuadrilateral = 0, nElemTetrahedron = 0, nElemHexahedron = 0, nElemPrism = 0, nElemPyramid = 0; +// unsigned long nPointGhost = 0, nPointPeriodic = 0; + unsigned long iElemTotal, iPointTotal, iPointGhost, iPointDomain, iPointPeriodic, iElemTriangle, iElemQuadrilateral, iElemTetrahedron, iElemHexahedron, iElemPrism, iElemPyramid; + unsigned long nBoundLineTotal = 0, iBoundLineTotal; + unsigned long nBoundTriangleTotal = 0, iBoundTriangleTotal; + unsigned long nBoundQuadrilateralTotal = 0, iBoundQuadrilateralTotal; + unsigned long ReceptorColor = 0, DonorColor = 0, Transformation; + unsigned long *nElem_Color = NULL, **Elem_Color = NULL, Max_nElem_Color = 0; + unsigned long nTotalSendDomain_Periodic = 0, iTotalSendDomain_Periodic = 0, nTotalReceivedDomain_Periodic = 0, iTotalReceivedDomain_Periodic = 0, *nSendDomain_Periodic = NULL, *nReceivedDomain_Periodic = NULL; + unsigned long Buffer_Send_nPointTotal = 0, Buffer_Send_nPointDomainTotal = 0, Buffer_Send_nPointGhost = 0, Buffer_Send_nPointPeriodic = 0; + unsigned long Buffer_Send_nElemTotal, Buffer_Send_nElemTriangle = 0, Buffer_Send_nElemQuadrilateral = 0, Buffer_Send_nElemTetrahedron = 0, Buffer_Send_nElemHexahedron = 0, Buffer_Send_nElemPrism = 0, Buffer_Send_nElemPyramid = 0; + unsigned long Buffer_Send_nTotalSendDomain_Periodic = 0, Buffer_Send_nTotalReceivedDomain_Periodic = 0, *Buffer_Send_nSendDomain_Periodic = NULL, *Buffer_Send_nReceivedDomain_Periodic = NULL; + unsigned long Buffer_Send_nBoundLineTotal = 0, Buffer_Send_nBoundTriangleTotal = 0, Buffer_Send_nBoundQuadrilateralTotal = 0; + unsigned long iVertexDomain, iBoundLine, iBoundTriangle, iBoundQuadrilateral; + + /*--- Need to su2double-check these shorts in case we go to nprocs > ~32,000 ---*/ + + unsigned short iNode, iDim, iMarker, jMarker, nMarkerDomain = 0, iMarkerDomain; + unsigned short nDomain = 0, iDomain, jDomain, nPeriodic = 0, iPeriodic, overhead = 4, Buffer_Send_nMarkerDomain = 0, Buffer_Send_nDim = 0, Buffer_Send_nZone = 0, Buffer_Send_nPeriodic = 0; + + bool *MarkerIn = NULL, **VertexIn = NULL, CheckDomain; + long vnodes_local[8], *Global2Local_Point = NULL; + vector DomainList; + short *Marker_All_SendRecv_Copy = NULL; + string *Marker_All_TagBound_Copy = NULL; + unsigned short nMarker_Max = config->GetnMarker_Max(); + + int rank = MASTER_NODE; + int size = SINGLE_NODE; + + /*--- Some dynamic arrays so we're not allocating too much on the stack ---*/ + + unsigned long *nVertexDomain = new unsigned long[nMarker_Max]; + unsigned long *nBoundLine = new unsigned long[nMarker_Max]; + unsigned long *nBoundTriangle = new unsigned long[nMarker_Max]; + unsigned long *nBoundQuadrilateral = new unsigned long[nMarker_Max]; + unsigned long *Buffer_Send_nVertexDomain = new unsigned long[nMarker_Max]; + unsigned long *Buffer_Send_nBoundLine = new unsigned long[nMarker_Max]; + unsigned long *Buffer_Send_nBoundTriangle = new unsigned long[nMarker_Max]; + unsigned long *Buffer_Send_nBoundQuadrilateral = new unsigned long[nMarker_Max]; + short *Buffer_Send_Marker_All_SendRecv = new short[nMarker_Max]; + char *Marker_All_TagBound = new char[nMarker_Max*MAX_STRING_SIZE]; + char *Buffer_Send_Marker_All_TagBound = new char[nMarker_Max*MAX_STRING_SIZE]; + + +#ifdef HAVE_MPI + + /*--- MPI initialization ---*/ + + MPI_Comm_size(MPI_COMM_WORLD, &size); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + /*--- MPI status and request arrays for non-blocking communications ---*/ + + MPI_Status send_stat[31], recv_stat[31]; + MPI_Request send_req[31], recv_req[31]; + +#endif + + /*--- Define buffer vector interior domain ---*/ + + su2double *Buffer_Send_Coord = NULL, *Buffer_Receive_Coord = NULL; + unsigned long *Buffer_Send_Color = NULL, *Buffer_Receive_Color = NULL; + unsigned long *Buffer_Send_GlobalPointIndex = NULL, *Buffer_Receive_GlobalPointIndex = NULL; + unsigned long *Buffer_Send_Triangle = NULL, *Buffer_Receive_Triangle = NULL; + unsigned long *Buffer_Send_Quadrilateral = NULL, *Buffer_Receive_Quadrilateral = NULL; + unsigned long *Buffer_Send_Tetrahedron = NULL, *Buffer_Receive_Tetrahedron = NULL; + unsigned long *Buffer_Send_Hexahedron = NULL, *Buffer_Receive_Hexahedron = NULL; + unsigned long *Buffer_Send_Prism = NULL, *Buffer_Receive_Prism = NULL; + unsigned long *Buffer_Send_Pyramid = NULL, *Buffer_Receive_Pyramid = NULL; + + /*--- Define buffer vector boundary ---*/ + + unsigned long *Buffer_Send_BoundLine = NULL, *Buffer_Receive_BoundLine = NULL; + unsigned long *Buffer_Send_BoundTriangle = NULL, *Buffer_Receive_BoundTriangle = NULL; + unsigned long *Buffer_Send_BoundQuadrilateral = NULL, *Buffer_Receive_BoundQuadrilateral = NULL; + unsigned long *Buffer_Send_Local2Global_Marker = NULL, *Buffer_Receive_Local2Global_Marker = NULL; + + /*--- Define buffer vector periodic boundary conditions ---*/ + + su2double *Buffer_Send_Center = NULL, *Buffer_Receive_Center = NULL; + su2double *Buffer_Send_Rotation = NULL, *Buffer_Receive_Rotation = NULL; + su2double *Buffer_Send_Translate = NULL, *Buffer_Receive_Translate = NULL; + + /*--- Define buffer vector periodic boundary conditions ---*/ + + unsigned long *Buffer_Send_SendDomain_Periodic = NULL, *Buffer_Receive_SendDomain_Periodic = NULL; + unsigned long *Buffer_Send_SendDomain_PeriodicTrans = NULL, *Buffer_Receive_SendDomain_PeriodicTrans = NULL; + unsigned long *Buffer_Send_SendDomain_PeriodicReceptor = NULL, *Buffer_Receive_SendDomain_PeriodicReceptor = NULL; + unsigned long *Buffer_Send_ReceivedDomain_Periodic = NULL, *Buffer_Receive_ReceivedDomain_Periodic = NULL; + unsigned long *Buffer_Send_ReceivedDomain_PeriodicTrans = NULL, *Buffer_Receive_ReceivedDomain_PeriodicTrans = NULL; + unsigned long *Buffer_Send_ReceivedDomain_PeriodicDonor = NULL, *Buffer_Receive_ReceivedDomain_PeriodicDonor = NULL; + + + /*--- Basic dimensionalization ---*/ + + nDomain = size; + Marker_All_SendRecv = new short[nMarker_Max]; + nSendDomain_Periodic = new unsigned long [nDomain]; + nReceivedDomain_Periodic = new unsigned long [nDomain]; + + /*--- Auxiliar vector based on the original geometry ---*/ + + if (rank == MASTER_NODE) { + + MarkerIn = new bool [geometry->GetnMarker()]; + + VertexIn = new bool* [geometry->GetnMarker()]; + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) + VertexIn[iMarker] = new bool [geometry->GetnElem_Bound(iMarker)]; + + Global2Local_Point = new long[geometry->GetnPoint()]; + + Buffer_Send_nDim = geometry->GetnDim(); + Buffer_Send_nZone = geometry->GetnZone(); + + Buffer_Send_nPeriodic = config->GetnPeriodicIndex(); + Buffer_Send_Center = new su2double[Buffer_Send_nPeriodic*3]; + Buffer_Send_Rotation = new su2double[Buffer_Send_nPeriodic*3]; + Buffer_Send_Translate = new su2double[Buffer_Send_nPeriodic*3]; + + Buffer_Send_nSendDomain_Periodic = new unsigned long [nDomain]; + Buffer_Send_nReceivedDomain_Periodic = new unsigned long [nDomain]; + + /*--- Divide the elements in color list to speed up the grid partitioning ---*/ + + nElem_Color = new unsigned long[nDomain]; + for (iDomain = 0; iDomain < nDomain; iDomain++) nElem_Color[iDomain] = 0; + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + DomainList.clear(); + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { + iPoint = geometry->elem[iElem]->GetNode(iNode); + iDomain = geometry->node[iPoint]->GetColor(); + + CheckDomain = true; + for (jDomain = 0; jDomain < DomainList.size(); jDomain++) { + if (DomainList[jDomain] == iDomain) { CheckDomain = false; break; } + } + + /*--- If the element is not in the list, then add it ---*/ + if (CheckDomain) { + DomainList.push_back(iDomain); + nElem_Color[iDomain]++; + } + + } + } + + /*--- Find the maximum number of elements per color to allocate the list ---*/ + + Max_nElem_Color = 0; + for (iDomain = 0; iDomain < nDomain; iDomain++) { + if (nElem_Color[iDomain] > Max_nElem_Color) Max_nElem_Color = nElem_Color[iDomain]; + } + + /*--- Allocate the element color array ---*/ + + Elem_Color = new unsigned long* [nDomain]; + for (iDomain = 0; iDomain < nDomain; iDomain++) { + Elem_Color[iDomain] = new unsigned long[Max_nElem_Color]; + nElem_Color[iDomain] = 0; + } + + /*--- Create the lement list based on the color ---*/ + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + DomainList.clear(); + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { + iPoint = geometry->elem[iElem]->GetNode(iNode); + iDomain = geometry->node[iPoint]->GetColor(); + + /*--- Check if the element has been already added to the color ---*/ + + CheckDomain = true; + for (jDomain = 0; jDomain < DomainList.size(); jDomain++) { + if (DomainList[jDomain] == iDomain) { CheckDomain = false; break; } + } + + if (CheckDomain) { + DomainList.push_back(iDomain); + Elem_Color[iDomain][nElem_Color[iDomain]] = iElem; + nElem_Color[iDomain]++; + } + + } + } + + + /*--- Create a local copy of config->GetMarker_All_SendRecv and + config->GetMarker_All_TagBound in the master node ---*/ + + Marker_All_SendRecv_Copy = new short [geometry->GetnMarker()]; + Marker_All_TagBound_Copy = new string[geometry->GetnMarker()]; + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + Marker_All_SendRecv_Copy[iMarker] = config->GetMarker_All_SendRecv(iMarker); + Marker_All_TagBound_Copy[iMarker] = config->GetMarker_All_TagBound(iMarker); + } + + + } + + for (iDomain = 0; iDomain < nDomain; iDomain++) { + + if (rank == MASTER_NODE) { + + /*--- Interior dimensionalization. Loop over the original grid to perform the + dimensionalizaton of the domain variables ---*/ + + Buffer_Send_nElemTotal = 0; Buffer_Send_nPointTotal = 0; Buffer_Send_nPointGhost = 0; Buffer_Send_nPointDomainTotal = 0; Buffer_Send_nPointPeriodic = 0; + Buffer_Send_nElemTriangle = 0; Buffer_Send_nElemQuadrilateral = 0; Buffer_Send_nElemTetrahedron = 0; Buffer_Send_nElemHexahedron = 0; Buffer_Send_nElemPrism = 0; Buffer_Send_nElemPyramid = 0; + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) Global2Local_Point[iPoint] = -1; + + for (jElem = 0; jElem < nElem_Color[iDomain]; jElem++) { + + iElem = Elem_Color[iDomain][jElem]; + + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { + iPoint = geometry->elem[iElem]->GetNode(iNode); + if (Global2Local_Point[iPoint] == -1) { + Global2Local_Point[iPoint] = 1; + Buffer_Send_nPointTotal++; + if ( geometry->node[iPoint]->GetColor() != iDomain ) Buffer_Send_nPointGhost++; + else { + if (iPoint > geometry->GetnPointDomain() - 1) { Buffer_Send_nPointGhost++; Buffer_Send_nPointPeriodic++; } + else Buffer_Send_nPointDomainTotal++; + } + } + } + + switch(geometry->elem[iElem]->GetVTK_Type()) { + case TRIANGLE: Buffer_Send_nElemTriangle++; break; + case QUADRILATERAL: Buffer_Send_nElemQuadrilateral++; break; + case TETRAHEDRON: Buffer_Send_nElemTetrahedron++; break; + case HEXAHEDRON: Buffer_Send_nElemHexahedron++; break; + case PRISM: Buffer_Send_nElemPrism++; break; + case PYRAMID: Buffer_Send_nElemPyramid++; break; + } + Buffer_Send_nElemTotal++; + + } + + /*--- Boundary dimensionalization. Dimensionalization with physical boundaries, compute Buffer_Send_nMarkerDomain, + Buffer_Send_nVertexDomain[nMarkerDomain] ---*/ + + Buffer_Send_nMarkerDomain = 0; Buffer_Send_nBoundLineTotal = 0; Buffer_Send_nBoundTriangleTotal = 0; Buffer_Send_nBoundQuadrilateralTotal = 0; + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + Buffer_Send_nVertexDomain[iMarker] = 0; + Buffer_Send_nBoundLine[iMarker] = 0; + Buffer_Send_nBoundTriangle[iMarker] = 0; + Buffer_Send_nBoundQuadrilateral[iMarker] = 0; + + Buffer_Send_Marker_All_SendRecv[iMarker] = Marker_All_SendRecv_Copy[iMarker]; + SPRINTF(&Buffer_Send_Marker_All_TagBound[iMarker*MAX_STRING_SIZE], "%s", Marker_All_TagBound_Copy[iMarker].c_str()); + } + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { + MarkerIn[iMarker] = false; Buffer_Send_nVertexDomain[Buffer_Send_nMarkerDomain] = 0; + + for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { + VertexIn[iMarker][iVertex] = false; + for (iNode = 0; iNode < geometry->bound[iMarker][iVertex]->GetnNodes(); iNode++) { + iPoint = geometry->bound[iMarker][iVertex]->GetNode(iNode); + if (geometry->node[iPoint]->GetColor() == iDomain) VertexIn[iMarker][iVertex] = true; + } + + if (VertexIn[iMarker][iVertex]) { + switch(geometry->bound[iMarker][iVertex]->GetVTK_Type()) { + case LINE: Buffer_Send_nBoundLine[Buffer_Send_nMarkerDomain]++; Buffer_Send_nBoundLineTotal++; break; + case TRIANGLE: Buffer_Send_nBoundTriangle[Buffer_Send_nMarkerDomain]++; Buffer_Send_nBoundTriangleTotal++; break; + case QUADRILATERAL: Buffer_Send_nBoundQuadrilateral[Buffer_Send_nMarkerDomain]++; Buffer_Send_nBoundQuadrilateralTotal++; break; + } + + Buffer_Send_nVertexDomain[Buffer_Send_nMarkerDomain] ++; + MarkerIn[iMarker] = true; + + } + } + + if (MarkerIn[iMarker]) { Buffer_Send_nMarkerDomain++; } + + } + } + + /*--- Copy periodic information from the config file ---*/ + + for (iPeriodic = 0; iPeriodic < Buffer_Send_nPeriodic; iPeriodic++) { + for (iDim = 0; iDim < 3; iDim++) { + Buffer_Send_Center[iDim+iPeriodic*3] = config->GetPeriodicCenter(iPeriodic)[iDim]; + Buffer_Send_Rotation[iDim+iPeriodic*3] = config->GetPeriodicRotation(iPeriodic)[iDim]; + Buffer_Send_Translate[iDim+iPeriodic*3] = config->GetPeriodicTranslate(iPeriodic)[iDim]; + } + } + + /*--- Dimensionalization of the periodic auxiliar vectors ---*/ + + for (jDomain = 0; jDomain < nDomain; jDomain++) { + Buffer_Send_nSendDomain_Periodic[jDomain] = 0; + Buffer_Send_nReceivedDomain_Periodic[jDomain] = 0; + } + Buffer_Send_nTotalSendDomain_Periodic = 0; + Buffer_Send_nTotalReceivedDomain_Periodic = 0; + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { + for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { + iPoint = geometry->bound[iMarker][iVertex]->GetNode(0); + if (iDomain == geometry->node[iPoint]->GetColor()) { + + if (config->GetMarker_All_SendRecv(iMarker) > 0) { + + /*--- Identify the color of the receptor ---*/ + + for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) { + if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker))) { + jPoint = geometry->bound[jMarker][iVertex]->GetNode(0); + ReceptorColor = geometry->node[jPoint]->GetColor(); + } + } + + Buffer_Send_nSendDomain_Periodic[ReceptorColor]++; + Buffer_Send_nTotalSendDomain_Periodic++; + + } + if (config->GetMarker_All_SendRecv(iMarker) < 0) { + + /*--- Identify the color of the donor ---*/ + + for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) { + if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker))) { + jPoint = geometry->bound[jMarker][iVertex]->GetNode(0); + DonorColor = geometry->node[jPoint]->GetColor(); + } + } + + Buffer_Send_nReceivedDomain_Periodic[DonorColor]++; + Buffer_Send_nTotalReceivedDomain_Periodic++; + + } + } + } + } + } + + /*--- Allocate the buffer vectors in the appropiate domain (master, iDomain) ---*/ + + Buffer_Send_Coord = new su2double [Buffer_Send_nPointTotal*Buffer_Send_nDim]; + Buffer_Send_Color = new unsigned long [Buffer_Send_nPointTotal]; + Buffer_Send_GlobalPointIndex = new unsigned long [Buffer_Send_nPointTotal]; + Buffer_Send_Triangle = new unsigned long [Buffer_Send_nElemTriangle*3]; + Buffer_Send_Quadrilateral = new unsigned long [Buffer_Send_nElemQuadrilateral*4]; + Buffer_Send_Tetrahedron = new unsigned long [Buffer_Send_nElemTetrahedron*4]; + Buffer_Send_Hexahedron = new unsigned long [Buffer_Send_nElemHexahedron*8]; + Buffer_Send_Prism = new unsigned long [Buffer_Send_nElemPrism*6]; + Buffer_Send_Pyramid = new unsigned long [Buffer_Send_nElemPyramid*5]; + + Buffer_Send_BoundLine = new unsigned long [Buffer_Send_nBoundLineTotal*2]; + Buffer_Send_BoundTriangle = new unsigned long [Buffer_Send_nBoundTriangleTotal*3]; + Buffer_Send_BoundQuadrilateral = new unsigned long [Buffer_Send_nBoundQuadrilateralTotal*4]; + Buffer_Send_Local2Global_Marker = new unsigned long [Buffer_Send_nMarkerDomain]; + + Buffer_Send_SendDomain_Periodic = new unsigned long [Buffer_Send_nTotalSendDomain_Periodic]; + Buffer_Send_SendDomain_PeriodicTrans = new unsigned long [Buffer_Send_nTotalSendDomain_Periodic]; + Buffer_Send_SendDomain_PeriodicReceptor = new unsigned long [Buffer_Send_nTotalSendDomain_Periodic]; + Buffer_Send_ReceivedDomain_Periodic = new unsigned long [Buffer_Send_nTotalReceivedDomain_Periodic]; + Buffer_Send_ReceivedDomain_PeriodicTrans = new unsigned long [Buffer_Send_nTotalReceivedDomain_Periodic]; + Buffer_Send_ReceivedDomain_PeriodicDonor = new unsigned long [Buffer_Send_nTotalReceivedDomain_Periodic]; + + if (iDomain != MASTER_NODE) { + +#ifdef HAVE_MPI + + SU2_MPI::Isend(&Buffer_Send_nDim, 1, MPI_UNSIGNED_SHORT, iDomain, 0, MPI_COMM_WORLD, &send_req[0]); + SU2_MPI::Isend(&Buffer_Send_nZone, 1, MPI_UNSIGNED_SHORT, iDomain, 1, MPI_COMM_WORLD, &send_req[1]); + SU2_MPI::Isend(&Buffer_Send_nPointTotal, 1, MPI_UNSIGNED_LONG, iDomain, 2, MPI_COMM_WORLD, &send_req[2]); + SU2_MPI::Isend(&Buffer_Send_nPointDomainTotal, 1, MPI_UNSIGNED_LONG, iDomain, 3, MPI_COMM_WORLD, &send_req[3]); +// SU2_MPI::Isend(&Buffer_Send_nPointGhost, 1, MPI_UNSIGNED_LONG, iDomain, 4, MPI_COMM_WORLD, &send_req[4]); +// SU2_MPI::Isend(&Buffer_Send_nPointPeriodic, 1, MPI_UNSIGNED_LONG, iDomain, 5, MPI_COMM_WORLD, &send_req[5]); + SU2_MPI::Isend(&Buffer_Send_nElemTotal, 1, MPI_UNSIGNED_LONG, iDomain, 6, MPI_COMM_WORLD, &send_req[6]); + SU2_MPI::Isend(&Buffer_Send_nElemTriangle, 1, MPI_UNSIGNED_LONG, iDomain, 7, MPI_COMM_WORLD, &send_req[7]); + SU2_MPI::Isend(&Buffer_Send_nElemQuadrilateral, 1, MPI_UNSIGNED_LONG, iDomain, 8, MPI_COMM_WORLD, &send_req[8]); + SU2_MPI::Isend(&Buffer_Send_nElemTetrahedron, 1, MPI_UNSIGNED_LONG, iDomain, 9, MPI_COMM_WORLD, &send_req[9]); + SU2_MPI::Isend(&Buffer_Send_nElemHexahedron, 1, MPI_UNSIGNED_LONG, iDomain, 10, MPI_COMM_WORLD, &send_req[10]); + SU2_MPI::Isend(&Buffer_Send_nElemPrism, 1, MPI_UNSIGNED_LONG, iDomain, 11, MPI_COMM_WORLD, &send_req[11]); + SU2_MPI::Isend(&Buffer_Send_nElemPyramid, 1, MPI_UNSIGNED_LONG, iDomain, 12, MPI_COMM_WORLD, &send_req[12]); + + SU2_MPI::Isend(&Buffer_Send_nBoundLineTotal, 1, MPI_UNSIGNED_LONG, iDomain, 13, MPI_COMM_WORLD, &send_req[13]); + SU2_MPI::Isend(&Buffer_Send_nBoundTriangleTotal, 1, MPI_UNSIGNED_LONG, iDomain, 14, MPI_COMM_WORLD, &send_req[14]); + SU2_MPI::Isend(&Buffer_Send_nBoundQuadrilateralTotal, 1, MPI_UNSIGNED_LONG, iDomain, 15, MPI_COMM_WORLD, &send_req[15]); + SU2_MPI::Isend(&Buffer_Send_nMarkerDomain, 1, MPI_UNSIGNED_SHORT, iDomain, 16, MPI_COMM_WORLD, &send_req[16]); + SU2_MPI::Isend(Buffer_Send_nVertexDomain, nMarker_Max, MPI_UNSIGNED_LONG, iDomain, 17, MPI_COMM_WORLD, &send_req[17]); + SU2_MPI::Isend(Buffer_Send_nBoundLine, nMarker_Max, MPI_UNSIGNED_LONG, iDomain, 18, MPI_COMM_WORLD, &send_req[18]); + SU2_MPI::Isend(Buffer_Send_nBoundTriangle, nMarker_Max, MPI_UNSIGNED_LONG, iDomain, 19, MPI_COMM_WORLD, &send_req[19]); + SU2_MPI::Isend(Buffer_Send_nBoundQuadrilateral, nMarker_Max, MPI_UNSIGNED_LONG, iDomain, 20, MPI_COMM_WORLD, &send_req[20]); + SU2_MPI::Isend(Buffer_Send_Marker_All_SendRecv, nMarker_Max, MPI_SHORT, iDomain, 21, MPI_COMM_WORLD, &send_req[21]); + SU2_MPI::Isend(Buffer_Send_Marker_All_TagBound, nMarker_Max*MAX_STRING_SIZE, MPI_CHAR, iDomain, 22, MPI_COMM_WORLD, &send_req[22]); + + SU2_MPI::Isend(&Buffer_Send_nPeriodic, 1, MPI_UNSIGNED_SHORT, iDomain, 23, MPI_COMM_WORLD, &send_req[23]); + SU2_MPI::Isend(Buffer_Send_Center, nPeriodic*3, MPI_DOUBLE, iDomain, 24, MPI_COMM_WORLD, &send_req[24]); + SU2_MPI::Isend(Buffer_Send_Rotation, nPeriodic*3, MPI_DOUBLE, iDomain, 25, MPI_COMM_WORLD, &send_req[25]); + SU2_MPI::Isend(Buffer_Send_Translate, nPeriodic*3, MPI_DOUBLE, iDomain, 26, MPI_COMM_WORLD, &send_req[26]); + + SU2_MPI::Isend(&Buffer_Send_nTotalSendDomain_Periodic, 1, MPI_UNSIGNED_LONG, iDomain, 27, MPI_COMM_WORLD, &send_req[27]); + SU2_MPI::Isend(&Buffer_Send_nTotalReceivedDomain_Periodic, 1, MPI_UNSIGNED_LONG, iDomain, 28, MPI_COMM_WORLD, &send_req[28]); + SU2_MPI::Isend(Buffer_Send_nSendDomain_Periodic, nDomain, MPI_UNSIGNED_LONG, iDomain, 29, MPI_COMM_WORLD, &send_req[29]); + SU2_MPI::Isend(Buffer_Send_nReceivedDomain_Periodic, nDomain, MPI_UNSIGNED_LONG, iDomain, 30, MPI_COMM_WORLD, &send_req[30]); + + /*--- Wait for this set of non-blocking comm. to complete ---*/ + + SU2_MPI::Waitall(29, send_req, send_stat); + +#endif + + + } else { + + /*--- We are the master node, so simply copy values into place ---*/ + + nDim = Buffer_Send_nDim; + nZone = Buffer_Send_nZone; + + nPeriodic = Buffer_Send_nPeriodic; + + nPointTotal = Buffer_Send_nPointTotal; + nPointDomainTotal = Buffer_Send_nPointDomainTotal; +// nPointGhost = Buffer_Send_nPointGhost; +// nPointPeriodic = Buffer_Send_nPointPeriodic; + + nElemTotal = Buffer_Send_nElemTotal; + nElemTriangle = Buffer_Send_nElemTriangle; + nElemQuadrilateral = Buffer_Send_nElemQuadrilateral; + nElemTetrahedron = Buffer_Send_nElemTetrahedron; + nElemHexahedron = Buffer_Send_nElemHexahedron; + nElemPrism = Buffer_Send_nElemPrism; + nElemPyramid = Buffer_Send_nElemPyramid; + + nelem_triangle = nElemTriangle; + nelem_quad = nElemQuadrilateral; + nelem_tetra = nElemTetrahedron; + nelem_hexa = nElemHexahedron; + nelem_prism = nElemPrism; + nelem_pyramid = nElemPyramid; + + nBoundLineTotal = Buffer_Send_nBoundLineTotal; + nBoundTriangleTotal = Buffer_Send_nBoundTriangleTotal; + nBoundQuadrilateralTotal = Buffer_Send_nBoundQuadrilateralTotal; + nMarkerDomain = Buffer_Send_nMarkerDomain; + + for (iMarker = 0; iMarker < nMarker_Max; iMarker++) { + nVertexDomain[iMarker] = Buffer_Send_nVertexDomain[iMarker]; + nBoundLine[iMarker] = Buffer_Send_nBoundLine[iMarker]; + nBoundTriangle[iMarker] = Buffer_Send_nBoundTriangle[iMarker]; + nBoundQuadrilateral[iMarker] = Buffer_Send_nBoundQuadrilateral[iMarker]; + Marker_All_SendRecv[iMarker] = Buffer_Send_Marker_All_SendRecv[iMarker]; + for (iter = 0; iter < MAX_STRING_SIZE; iter++) + Marker_All_TagBound[iMarker*MAX_STRING_SIZE+iter] = Buffer_Send_Marker_All_TagBound[iMarker*MAX_STRING_SIZE+iter]; + } + + Buffer_Receive_Center = new su2double[nPeriodic*3]; + Buffer_Receive_Rotation = new su2double[nPeriodic*3]; + Buffer_Receive_Translate = new su2double[nPeriodic*3]; + + for (iter = 0; iter < nPeriodic*3; iter++) { + Buffer_Receive_Center[iter] = Buffer_Send_Center[iter]; + Buffer_Receive_Rotation[iter] = Buffer_Send_Rotation[iter]; + Buffer_Receive_Translate[iter] = Buffer_Send_Translate[iter]; + } + + nTotalSendDomain_Periodic = Buffer_Send_nTotalSendDomain_Periodic; + nTotalReceivedDomain_Periodic = Buffer_Send_nTotalReceivedDomain_Periodic; + + for (iter = 0; iter < nDomain; iter++) { + nSendDomain_Periodic[iter] = Buffer_Send_nSendDomain_Periodic[iter]; + nReceivedDomain_Periodic[iter] = Buffer_Send_nReceivedDomain_Periodic[iter]; + } + + } + } + + /*--- Receive the size of buffers---*/ + + if (rank == iDomain) { + + /*--- Receive the size of buffers---*/ + + if (rank != MASTER_NODE) { + +#ifdef HAVE_MPI + + SU2_MPI::Irecv(&nDim, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, 0, MPI_COMM_WORLD, &recv_req[0]); + SU2_MPI::Irecv(&nZone, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, 1, MPI_COMM_WORLD, &recv_req[1]); + SU2_MPI::Irecv(&nPointTotal, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 2, MPI_COMM_WORLD, &recv_req[2]); + SU2_MPI::Irecv(&nPointDomainTotal, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 3, MPI_COMM_WORLD, &recv_req[3]); +// SU2_MPI::Irecv(&nPointGhost, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 4, MPI_COMM_WORLD, &recv_req[4]); +// SU2_MPI::Irecv(&nPointPeriodic, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 5, MPI_COMM_WORLD, &recv_req[5]); + SU2_MPI::Irecv(&nElemTotal, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 6, MPI_COMM_WORLD, &recv_req[6]); + SU2_MPI::Irecv(&nElemTriangle, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 7, MPI_COMM_WORLD, &recv_req[7]); + SU2_MPI::Irecv(&nElemQuadrilateral, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 8, MPI_COMM_WORLD, &recv_req[8]); + SU2_MPI::Irecv(&nElemTetrahedron, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 9, MPI_COMM_WORLD, &recv_req[9]); + SU2_MPI::Irecv(&nElemHexahedron, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 10, MPI_COMM_WORLD, &recv_req[10]); + SU2_MPI::Irecv(&nElemPrism, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 11, MPI_COMM_WORLD, &recv_req[11]); + SU2_MPI::Irecv(&nElemPyramid, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 12, MPI_COMM_WORLD, &recv_req[12]); + + SU2_MPI::Irecv(&nBoundLineTotal, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 13, MPI_COMM_WORLD, &recv_req[13]); + SU2_MPI::Irecv(&nBoundTriangleTotal, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 14, MPI_COMM_WORLD, &recv_req[14]); + SU2_MPI::Irecv(&nBoundQuadrilateralTotal, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 15, MPI_COMM_WORLD, &recv_req[15]); + SU2_MPI::Irecv(&nMarkerDomain, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, 16, MPI_COMM_WORLD, &recv_req[16]); + SU2_MPI::Irecv(nVertexDomain, nMarker_Max, MPI_UNSIGNED_LONG, MASTER_NODE, 17, MPI_COMM_WORLD, &recv_req[17]); + SU2_MPI::Irecv(nBoundLine, nMarker_Max, MPI_UNSIGNED_LONG, MASTER_NODE, 18, MPI_COMM_WORLD, &recv_req[18]); + SU2_MPI::Irecv(nBoundTriangle, nMarker_Max, MPI_UNSIGNED_LONG, MASTER_NODE, 19, MPI_COMM_WORLD, &recv_req[19]); + SU2_MPI::Irecv(nBoundQuadrilateral, nMarker_Max, MPI_UNSIGNED_LONG, MASTER_NODE, 20, MPI_COMM_WORLD, &recv_req[20]); + SU2_MPI::Irecv(Marker_All_SendRecv, nMarker_Max, MPI_SHORT, MASTER_NODE, 21, MPI_COMM_WORLD, &recv_req[21]); + SU2_MPI::Irecv(Marker_All_TagBound, nMarker_Max*MAX_STRING_SIZE, MPI_CHAR, MASTER_NODE, 22, MPI_COMM_WORLD, &recv_req[22]); + SU2_MPI::Irecv(&nPeriodic, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, 23, MPI_COMM_WORLD, &recv_req[23]); + + /*--- Wait for the this set of non-blocking recv's to complete ---*/ + + SU2_MPI::Waitall(22, recv_req, recv_stat); + +#endif + + /*--- Update the number of elements (local) ---*/ + + nelem_triangle = nElemTriangle; + nelem_quad = nElemQuadrilateral; + nelem_tetra = nElemTetrahedron; + nelem_hexa = nElemHexahedron; + nelem_prism = nElemPrism; + nelem_pyramid = nElemPyramid; + + /*--- Marker_All_TagBound and Marker_All_SendRecv, set the same values in the config files of all the files ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + config->SetMarker_All_SendRecv(iMarker, Marker_All_SendRecv[iMarker]); + config->SetMarker_All_TagBound(iMarker, string(&Marker_All_TagBound[iMarker*MAX_STRING_SIZE])); + } + + /*--- Periodic boundary conditions, set the values in the config files of all the files ---*/ + + Buffer_Receive_Center = new su2double[nPeriodic*3]; + Buffer_Receive_Rotation = new su2double[nPeriodic*3]; + Buffer_Receive_Translate = new su2double[nPeriodic*3]; + +#ifdef HAVE_MPI + + SU2_MPI::Irecv(Buffer_Receive_Center, nPeriodic*3, MPI_DOUBLE, MASTER_NODE, 24, MPI_COMM_WORLD, &recv_req[0]); + SU2_MPI::Irecv(Buffer_Receive_Rotation, nPeriodic*3, MPI_DOUBLE, MASTER_NODE, 25, MPI_COMM_WORLD, &recv_req[1]); + SU2_MPI::Irecv(Buffer_Receive_Translate, nPeriodic*3, MPI_DOUBLE, MASTER_NODE, 26, MPI_COMM_WORLD, &recv_req[2]); + + SU2_MPI::Irecv(&nTotalSendDomain_Periodic, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 27, MPI_COMM_WORLD, &recv_req[3]); + SU2_MPI::Irecv(&nTotalReceivedDomain_Periodic, 1, MPI_UNSIGNED_LONG, MASTER_NODE, 28, MPI_COMM_WORLD, &recv_req[4]); + SU2_MPI::Irecv(nSendDomain_Periodic, nDomain, MPI_UNSIGNED_LONG, MASTER_NODE, 29, MPI_COMM_WORLD, &recv_req[5]); + SU2_MPI::Irecv(nReceivedDomain_Periodic, nDomain, MPI_UNSIGNED_LONG, MASTER_NODE, 30, MPI_COMM_WORLD, &recv_req[6]); + + /*--- Wait for this set of non-blocking comm. to complete ---*/ + + SU2_MPI::Waitall(7, recv_req, recv_stat); + +#endif + + config->SetnPeriodicIndex(nPeriodic); + + for (iPeriodic = 0; iPeriodic < nPeriodic; iPeriodic++) { + + su2double* center = new su2double[3]; // Do not deallocate the memory + su2double* rotation = new su2double[3]; // Do not deallocate the memory + su2double* translate = new su2double[3]; // Do not deallocate the memory + + for (iDim = 0; iDim < 3; iDim++) { + center[iDim] = Buffer_Receive_Center[iDim+iPeriodic*3]; + rotation[iDim] = Buffer_Receive_Rotation[iDim+iPeriodic*3]; + translate[iDim] = Buffer_Receive_Translate[iDim+iPeriodic*3]; + } + config->SetPeriodicCenter(iPeriodic, center); + config->SetPeriodicRotation(iPeriodic, rotation); + config->SetPeriodicTranslate(iPeriodic, translate); + } + + } + + delete [] Buffer_Receive_Center; + delete [] Buffer_Receive_Rotation; + delete [] Buffer_Receive_Translate; + + /*--- Allocate the receive buffer vector ---*/ + + Buffer_Receive_Coord = new su2double [nPointTotal*nDim]; + Buffer_Receive_Color = new unsigned long [nPointTotal]; + Buffer_Receive_GlobalPointIndex = new unsigned long [nPointTotal]; + Buffer_Receive_Triangle = new unsigned long [nElemTriangle*3]; + Buffer_Receive_Quadrilateral = new unsigned long [nElemQuadrilateral*4]; + Buffer_Receive_Tetrahedron = new unsigned long [nElemTetrahedron*4]; + Buffer_Receive_Hexahedron = new unsigned long [nElemHexahedron*8]; + Buffer_Receive_Prism = new unsigned long [nElemPrism*6]; + Buffer_Receive_Pyramid = new unsigned long [nElemPyramid*5]; + Buffer_Receive_BoundLine = new unsigned long [nBoundLineTotal*2]; + Buffer_Receive_BoundTriangle = new unsigned long [nBoundTriangleTotal*3]; + Buffer_Receive_BoundQuadrilateral = new unsigned long [nBoundQuadrilateralTotal*4]; + Buffer_Receive_Local2Global_Marker = new unsigned long [nMarkerDomain]; + + Buffer_Receive_SendDomain_Periodic = new unsigned long [nTotalSendDomain_Periodic]; + Buffer_Receive_SendDomain_PeriodicTrans = new unsigned long [nTotalSendDomain_Periodic]; + Buffer_Receive_SendDomain_PeriodicReceptor = new unsigned long [nTotalSendDomain_Periodic]; + Buffer_Receive_ReceivedDomain_Periodic = new unsigned long [nTotalReceivedDomain_Periodic]; + Buffer_Receive_ReceivedDomain_PeriodicTrans = new unsigned long [nTotalReceivedDomain_Periodic]; + Buffer_Receive_ReceivedDomain_PeriodicDonor = new unsigned long [nTotalReceivedDomain_Periodic]; + + } + + /*--- Set the value of the Send buffers ---*/ + + if (rank == MASTER_NODE) { + + /*--- Set the value of the interior geometry ---*/ + + iElemTotal = 0; + iPointDomain = 0; + iPointPeriodic = Buffer_Send_nPointDomainTotal; + iPointGhost = Buffer_Send_nPointDomainTotal + Buffer_Send_nPointPeriodic; + iElemTriangle = 0; + iElemQuadrilateral = 0; + iElemTetrahedron = 0; + iElemHexahedron = 0; + iElemPrism = 0; + iElemPyramid = 0; + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) Global2Local_Point[iPoint] = -1; + + for (jElem = 0; jElem < nElem_Color[iDomain]; jElem++) { + + iElem = Elem_Color[iDomain][jElem]; + + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { + iPoint = geometry->elem[iElem]->GetNode(iNode); + if (Global2Local_Point[iPoint] == -1) { + + if ( geometry->node[iPoint]->GetColor() == iDomain ) { + if ( iPoint > geometry->GetnPointDomain() - 1) iPointTotal = iPointPeriodic; + else iPointTotal = iPointDomain; + } + else iPointTotal = iPointGhost; + + Global2Local_Point[iPoint] = iPointTotal; + Buffer_Send_Color[iPointTotal] = geometry->node[iPoint]->GetColor(); + Buffer_Send_GlobalPointIndex[iPointTotal] = iPoint; + for (iDim = 0; iDim < Buffer_Send_nDim; iDim++) + Buffer_Send_Coord[Buffer_Send_nDim*iPointTotal+iDim] = geometry->node[iPoint]->GetCoord(iDim); + + if ( geometry->node[iPoint]->GetColor() == iDomain ) { + if ( iPoint > geometry->GetnPointDomain() - 1) iPointPeriodic++; + else iPointDomain++; + } + else iPointGhost++; + + } + + vnodes_local[iNode] = Global2Local_Point[iPoint]; + + } + + switch(geometry->elem[iElem]->GetVTK_Type()) { + case TRIANGLE: + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) + Buffer_Send_Triangle[3*iElemTriangle+iNode] = vnodes_local[iNode]; + iElemTriangle++; break; + case QUADRILATERAL: + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) + Buffer_Send_Quadrilateral[4*iElemQuadrilateral+iNode] = vnodes_local[iNode]; + iElemQuadrilateral++; break; + case TETRAHEDRON: + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) + Buffer_Send_Tetrahedron[4*iElemTetrahedron+iNode] = vnodes_local[iNode]; + iElemTetrahedron++; break; + case HEXAHEDRON: + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) + Buffer_Send_Hexahedron[8*iElemHexahedron+iNode] = vnodes_local[iNode]; + iElemHexahedron++; break; + case PRISM: + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) + Buffer_Send_Prism[6*iElemPrism+iNode] = vnodes_local[iNode]; + iElemPrism++; break; + case PYRAMID: + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) + Buffer_Send_Pyramid[5*iElemPyramid+iNode] = vnodes_local[iNode]; + iElemPyramid++; break; + } + + iElemTotal++; + + } + + /*--- Set the value of the boundary geometry ---*/ + + iMarkerDomain = 0; + iBoundLineTotal = 0; iBoundTriangleTotal = 0; iBoundQuadrilateralTotal = 0; + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + if ((config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) && (MarkerIn[iMarker])) { + for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { + + if (VertexIn[iMarker][iVertex]) { + + for (iNode = 0; iNode < geometry->bound[iMarker][iVertex]->GetnNodes(); iNode++) { + vnodes_local[iNode] = Global2Local_Point[geometry->bound[iMarker][iVertex]->GetNode(iNode)]; + } + + switch(geometry->bound[iMarker][iVertex]->GetVTK_Type()) { + case LINE: + Buffer_Send_BoundLine[2*iBoundLineTotal+0] = vnodes_local[0]; + Buffer_Send_BoundLine[2*iBoundLineTotal+1] = vnodes_local[1]; + iBoundLineTotal++; + break; + case TRIANGLE: + Buffer_Send_BoundTriangle[3*iBoundTriangleTotal+0] = vnodes_local[0]; + Buffer_Send_BoundTriangle[3*iBoundTriangleTotal+1] = vnodes_local[1]; + Buffer_Send_BoundTriangle[3*iBoundTriangleTotal+2] = vnodes_local[2]; + iBoundTriangleTotal++; + break; + case QUADRILATERAL: + Buffer_Send_BoundQuadrilateral[4*iBoundQuadrilateralTotal+0] = vnodes_local[0]; + Buffer_Send_BoundQuadrilateral[4*iBoundQuadrilateralTotal+1] = vnodes_local[1]; + Buffer_Send_BoundQuadrilateral[4*iBoundQuadrilateralTotal+2] = vnodes_local[2]; + Buffer_Send_BoundQuadrilateral[4*iBoundQuadrilateralTotal+3] = vnodes_local[3]; + iBoundQuadrilateralTotal++; + break; + } + } + } + + Buffer_Send_Local2Global_Marker[iMarkerDomain] = iMarker; + iMarkerDomain++; + + } + } + + /*--- Evaluate the number of already existing periodic boundary conditions ---*/ + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { + + for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { + + iPoint = geometry->bound[iMarker][iVertex]->GetNode(0); + Transformation = geometry->bound[iMarker][iVertex]->GetRotation_Type(); + + if (iDomain == geometry->node[iPoint]->GetColor()) { + + /*--- If the information is going to be sended, find the + domain of the receptor ---*/ + + if (config->GetMarker_All_SendRecv(iMarker) > 0) { + + /*--- Identify the color of the receptor ---*/ + + for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) { + if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker))) { + jPoint = geometry->bound[jMarker][iVertex]->GetNode(0); + ReceptorColor = geometry->node[jPoint]->GetColor(); + } + } + + /*--- For each color of the receptor we will han an extra marker (+) ---*/ + + Buffer_Send_SendDomain_Periodic[iTotalSendDomain_Periodic] = Global2Local_Point[iPoint]; + Buffer_Send_SendDomain_PeriodicTrans[iTotalSendDomain_Periodic] = Transformation; + Buffer_Send_SendDomain_PeriodicReceptor[iTotalSendDomain_Periodic] = ReceptorColor; + + iTotalSendDomain_Periodic++; + + } + + /*--- If the information is goint to be received, find the domain if the donor ---*/ + + if (config->GetMarker_All_SendRecv(iMarker) < 0) { + + /*--- Identify the color of the donor ---*/ + + for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) { + if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker) )) { + jPoint = geometry->bound[jMarker][iVertex]->GetNode(0); + DonorColor = geometry->node[jPoint]->GetColor(); + } + } + + /*--- For each color of the donor we will han an extra marker (-) ---*/ + + Buffer_Send_ReceivedDomain_Periodic[iTotalReceivedDomain_Periodic] = Global2Local_Point[iPoint]; + Buffer_Send_ReceivedDomain_PeriodicTrans[iTotalReceivedDomain_Periodic] = Transformation; + Buffer_Send_ReceivedDomain_PeriodicDonor[iTotalReceivedDomain_Periodic] = DonorColor; + + iTotalReceivedDomain_Periodic++; + + } + } + } + } + } + + /*--- Send the buffers with the geometrical information ---*/ + + if (iDomain != MASTER_NODE) { + +#ifdef HAVE_MPI + + SU2_MPI::Isend(Buffer_Send_Coord, Buffer_Send_nPointTotal*Buffer_Send_nDim, MPI_DOUBLE, iDomain, 0, MPI_COMM_WORLD, &send_req[0]); + SU2_MPI::Isend(Buffer_Send_GlobalPointIndex, Buffer_Send_nPointTotal, MPI_UNSIGNED_LONG, iDomain, 1, MPI_COMM_WORLD, &send_req[1]); + SU2_MPI::Isend(Buffer_Send_Color, Buffer_Send_nPointTotal, MPI_UNSIGNED_LONG, iDomain, 2, MPI_COMM_WORLD, &send_req[2]); + SU2_MPI::Isend(Buffer_Send_Triangle, Buffer_Send_nElemTriangle*3, MPI_UNSIGNED_LONG, iDomain, 3, MPI_COMM_WORLD, &send_req[3]); + SU2_MPI::Isend(Buffer_Send_Quadrilateral, Buffer_Send_nElemQuadrilateral*4, MPI_UNSIGNED_LONG, iDomain, 4, MPI_COMM_WORLD, &send_req[4]); + SU2_MPI::Isend(Buffer_Send_Tetrahedron, Buffer_Send_nElemTetrahedron*4, MPI_UNSIGNED_LONG, iDomain, 5, MPI_COMM_WORLD, &send_req[5]); + SU2_MPI::Isend(Buffer_Send_Hexahedron, Buffer_Send_nElemHexahedron*8, MPI_UNSIGNED_LONG, iDomain, 6, MPI_COMM_WORLD, &send_req[6]); + SU2_MPI::Isend(Buffer_Send_Prism, Buffer_Send_nElemPrism*6, MPI_UNSIGNED_LONG, iDomain, 7, MPI_COMM_WORLD, &send_req[7]); + SU2_MPI::Isend(Buffer_Send_Pyramid, Buffer_Send_nElemPyramid*5, MPI_UNSIGNED_LONG, iDomain, 8, MPI_COMM_WORLD, &send_req[8]); + SU2_MPI::Isend(Buffer_Send_BoundLine, Buffer_Send_nBoundLineTotal*2, MPI_UNSIGNED_LONG, iDomain, 9, MPI_COMM_WORLD, &send_req[9]); + SU2_MPI::Isend(Buffer_Send_BoundTriangle, Buffer_Send_nBoundTriangleTotal*3, MPI_UNSIGNED_LONG, iDomain, 10, MPI_COMM_WORLD, &send_req[10]); + SU2_MPI::Isend(Buffer_Send_BoundQuadrilateral, Buffer_Send_nBoundQuadrilateralTotal*4, MPI_UNSIGNED_LONG, iDomain, 11, MPI_COMM_WORLD, &send_req[11]); + SU2_MPI::Isend(Buffer_Send_Local2Global_Marker, Buffer_Send_nMarkerDomain, MPI_UNSIGNED_LONG, iDomain, 12, MPI_COMM_WORLD, &send_req[12]); + + SU2_MPI::Isend(Buffer_Send_SendDomain_Periodic, Buffer_Send_nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, 13, MPI_COMM_WORLD, &send_req[13]); + SU2_MPI::Isend(Buffer_Send_SendDomain_PeriodicTrans, Buffer_Send_nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, 14, MPI_COMM_WORLD, &send_req[14]); + SU2_MPI::Isend(Buffer_Send_SendDomain_PeriodicReceptor, Buffer_Send_nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, 15, MPI_COMM_WORLD, &send_req[15]); + SU2_MPI::Isend(Buffer_Send_ReceivedDomain_Periodic, Buffer_Send_nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, 16, MPI_COMM_WORLD, &send_req[16]); + SU2_MPI::Isend(Buffer_Send_ReceivedDomain_PeriodicTrans, Buffer_Send_nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, 17, MPI_COMM_WORLD, &send_req[17]); + SU2_MPI::Isend(Buffer_Send_ReceivedDomain_PeriodicDonor, Buffer_Send_nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, 18, MPI_COMM_WORLD, &send_req[18]); + + /*--- Wait for this set of non-blocking comm. to complete ---*/ + + SU2_MPI::Waitall(19, send_req, send_stat); + +#endif + + } else { + + for (iter = 0; iter < Buffer_Send_nPointTotal*Buffer_Send_nDim; iter++) + Buffer_Receive_Coord[iter] = Buffer_Send_Coord[iter]; + + for (iter = 0; iter < Buffer_Send_nPointTotal; iter++) { + Buffer_Receive_GlobalPointIndex[iter] = Buffer_Send_GlobalPointIndex[iter]; + Buffer_Receive_Color[iter] = Buffer_Send_Color[iter]; + } + + for (iter = 0; iter < Buffer_Send_nElemTriangle*3; iter++) + Buffer_Receive_Triangle[iter] = Buffer_Send_Triangle[iter]; + + for (iter = 0; iter < Buffer_Send_nElemQuadrilateral*4; iter++) + Buffer_Receive_Quadrilateral[iter] = Buffer_Send_Quadrilateral[iter]; + + for (iter = 0; iter < Buffer_Send_nElemTetrahedron*4; iter++) + Buffer_Receive_Tetrahedron[iter] = Buffer_Send_Tetrahedron[iter]; + + for (iter = 0; iter < Buffer_Send_nElemHexahedron*8; iter++) + Buffer_Receive_Hexahedron[iter] = Buffer_Send_Hexahedron[iter]; + + for (iter = 0; iter < Buffer_Send_nElemPrism*6; iter++) + Buffer_Receive_Prism[iter] = Buffer_Send_Prism[iter]; + + for (iter = 0; iter < Buffer_Send_nElemPyramid*5; iter++) + Buffer_Receive_Pyramid[iter] = Buffer_Send_Pyramid[iter]; + + for (iter = 0; iter < Buffer_Send_nBoundLineTotal*2; iter++) + Buffer_Receive_BoundLine[iter] = Buffer_Send_BoundLine[iter]; + + for (iter = 0; iter < Buffer_Send_nBoundTriangleTotal*3; iter++) + Buffer_Receive_BoundTriangle[iter] = Buffer_Send_BoundTriangle[iter]; + + for (iter = 0; iter < Buffer_Send_nBoundQuadrilateralTotal*4; iter++) + Buffer_Receive_BoundQuadrilateral[iter] = Buffer_Send_BoundQuadrilateral[iter]; + + for (iter = 0; iter < Buffer_Send_nMarkerDomain; iter++) + Buffer_Receive_Local2Global_Marker[iter] = Buffer_Send_Local2Global_Marker[iter]; + + for (iter = 0; iter < Buffer_Send_nTotalSendDomain_Periodic; iter++) { + Buffer_Receive_SendDomain_Periodic[iter] = Buffer_Send_SendDomain_Periodic[iter]; + Buffer_Receive_SendDomain_PeriodicTrans[iter] = Buffer_Send_SendDomain_PeriodicTrans[iter]; + Buffer_Receive_SendDomain_PeriodicReceptor[iter] = Buffer_Send_SendDomain_PeriodicReceptor[iter]; + } + + for (iter = 0; iter < Buffer_Send_nTotalReceivedDomain_Periodic; iter++) { + Buffer_Receive_ReceivedDomain_Periodic[iter] = Buffer_Send_ReceivedDomain_Periodic[iter]; + Buffer_Receive_ReceivedDomain_PeriodicTrans[iter] = Buffer_Send_ReceivedDomain_PeriodicTrans[iter]; + Buffer_Receive_ReceivedDomain_PeriodicDonor[iter] = Buffer_Send_ReceivedDomain_PeriodicDonor[iter]; + } + + } + + delete[] Buffer_Send_Coord; + delete[] Buffer_Send_GlobalPointIndex; + delete[] Buffer_Send_Color; + delete[] Buffer_Send_Triangle; + delete[] Buffer_Send_Quadrilateral; + delete[] Buffer_Send_Tetrahedron; + delete[] Buffer_Send_Hexahedron; + delete[] Buffer_Send_Prism; + delete[] Buffer_Send_Pyramid; + delete[] Buffer_Send_BoundLine; + delete[] Buffer_Send_BoundTriangle; + delete[] Buffer_Send_BoundQuadrilateral; + delete[] Buffer_Send_Local2Global_Marker; + + delete[] Buffer_Send_SendDomain_Periodic; + delete[] Buffer_Send_SendDomain_PeriodicTrans; + delete[] Buffer_Send_SendDomain_PeriodicReceptor; + delete[] Buffer_Send_ReceivedDomain_Periodic; + delete[] Buffer_Send_ReceivedDomain_PeriodicTrans; + delete[] Buffer_Send_ReceivedDomain_PeriodicDonor; + + } + + if (rank == iDomain) { + + if (rank != MASTER_NODE) { + + /*--- Receive the buffers with the geometrical information ---*/ + +#ifdef HAVE_MPI + + SU2_MPI::Irecv(Buffer_Receive_Coord, nPointTotal*nDim, MPI_DOUBLE, MASTER_NODE, 0, MPI_COMM_WORLD, &recv_req[0]); + SU2_MPI::Irecv(Buffer_Receive_GlobalPointIndex, nPointTotal, MPI_UNSIGNED_LONG, MASTER_NODE, 1, MPI_COMM_WORLD, &recv_req[1]); + SU2_MPI::Irecv(Buffer_Receive_Color, nPointTotal, MPI_UNSIGNED_LONG, MASTER_NODE, 2, MPI_COMM_WORLD, &recv_req[2]); + SU2_MPI::Irecv(Buffer_Receive_Triangle, nElemTriangle*3, MPI_UNSIGNED_LONG, MASTER_NODE, 3, MPI_COMM_WORLD, &recv_req[3]); + SU2_MPI::Irecv(Buffer_Receive_Quadrilateral, nElemQuadrilateral*4, MPI_UNSIGNED_LONG, MASTER_NODE, 4, MPI_COMM_WORLD, &recv_req[4]); + SU2_MPI::Irecv(Buffer_Receive_Tetrahedron, nElemTetrahedron*4, MPI_UNSIGNED_LONG, MASTER_NODE, 5, MPI_COMM_WORLD, &recv_req[5]); + SU2_MPI::Irecv(Buffer_Receive_Hexahedron, nElemHexahedron*8, MPI_UNSIGNED_LONG, MASTER_NODE, 6, MPI_COMM_WORLD, &recv_req[6]); + SU2_MPI::Irecv(Buffer_Receive_Prism, nElemPrism*6, MPI_UNSIGNED_LONG, MASTER_NODE, 7, MPI_COMM_WORLD, &recv_req[7]); + SU2_MPI::Irecv(Buffer_Receive_Pyramid, nElemPyramid*5, MPI_UNSIGNED_LONG, MASTER_NODE, 8, MPI_COMM_WORLD, &recv_req[8]); + SU2_MPI::Irecv(Buffer_Receive_BoundLine, nBoundLineTotal*2, MPI_UNSIGNED_LONG, MASTER_NODE, 9, MPI_COMM_WORLD, &recv_req[9]); + SU2_MPI::Irecv(Buffer_Receive_BoundTriangle, nBoundTriangleTotal*3, MPI_UNSIGNED_LONG, MASTER_NODE, 10, MPI_COMM_WORLD, &recv_req[10]); + SU2_MPI::Irecv(Buffer_Receive_BoundQuadrilateral, nBoundQuadrilateralTotal*4, MPI_UNSIGNED_LONG, MASTER_NODE, 11, MPI_COMM_WORLD, &recv_req[11]); + SU2_MPI::Irecv(Buffer_Receive_Local2Global_Marker, nMarkerDomain, MPI_UNSIGNED_LONG, MASTER_NODE, 12, MPI_COMM_WORLD, &recv_req[12]); + + SU2_MPI::Irecv(Buffer_Receive_SendDomain_Periodic, nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, MASTER_NODE, 13, MPI_COMM_WORLD, &recv_req[13]); + SU2_MPI::Irecv(Buffer_Receive_SendDomain_PeriodicTrans, nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, MASTER_NODE, 14, MPI_COMM_WORLD, &recv_req[14]); + SU2_MPI::Irecv(Buffer_Receive_SendDomain_PeriodicReceptor, nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, MASTER_NODE, 15, MPI_COMM_WORLD, &recv_req[15]); + SU2_MPI::Irecv(Buffer_Receive_ReceivedDomain_Periodic, nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, MASTER_NODE, 16, MPI_COMM_WORLD, &recv_req[16]); + SU2_MPI::Irecv(Buffer_Receive_ReceivedDomain_PeriodicTrans, nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, MASTER_NODE, 17, MPI_COMM_WORLD, &recv_req[17]); + SU2_MPI::Irecv(Buffer_Receive_ReceivedDomain_PeriodicDonor, nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, MASTER_NODE, 18, MPI_COMM_WORLD, &recv_req[18]); + + /*--- Wait for this set of non-blocking recv's to complete ---*/ + + SU2_MPI::Waitall(19, recv_req, recv_stat); + +#endif + + } + + /*--- Create the domain structures for the points ---*/ + + nPoint = nPointTotal; + nPointDomain = nPointDomainTotal; + node = new CPoint*[nPoint]; + Local_to_Global_Point = new long[nPoint]; + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + Local_to_Global_Point[iPoint] = Buffer_Receive_GlobalPointIndex[iPoint]; + if ( nDim == 2 ) node[iPoint] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0], Buffer_Receive_Coord[iPoint*nDim+1], Local_to_Global_Point[iPoint], config); + if ( nDim == 3 ) node[iPoint] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0], Buffer_Receive_Coord[iPoint*nDim+1], Buffer_Receive_Coord[iPoint*nDim+2], Local_to_Global_Point[iPoint], config); + node[iPoint]->SetColor(Buffer_Receive_Color[iPoint]); + } + + delete[] Buffer_Receive_Coord; + delete[] Buffer_Receive_GlobalPointIndex; + delete[] Buffer_Receive_Color; + + /*--- Create the domain structures for the elements ---*/ + + nElem = nElemTotal; iElem = 0; + elem = new CPrimalGrid*[nElem]; + + for (iElemTriangle = 0; iElemTriangle < nElemTriangle; iElemTriangle++) { + elem[iElem] = new CTriangle(Buffer_Receive_Triangle[iElemTriangle*3+0], Buffer_Receive_Triangle[iElemTriangle*3+1], Buffer_Receive_Triangle[iElemTriangle*3+2], 2); + iElem++; + } + for (iElemQuadrilateral = 0; iElemQuadrilateral < nElemQuadrilateral; iElemQuadrilateral++) { + elem[iElem] = new CQuadrilateral(Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+0], Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+1], Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+2], Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+3], 2); + iElem++; + } + for (iElemTetrahedron = 0; iElemTetrahedron < nElemTetrahedron; iElemTetrahedron++) { + elem[iElem] = new CTetrahedron(Buffer_Receive_Tetrahedron[iElemTetrahedron*4+0], Buffer_Receive_Tetrahedron[iElemTetrahedron*4+1], Buffer_Receive_Tetrahedron[iElemTetrahedron*4+2], Buffer_Receive_Tetrahedron[iElemTetrahedron*4+3]); + iElem++; + } + for (iElemHexahedron = 0; iElemHexahedron < nElemHexahedron; iElemHexahedron++) { + elem[iElem] = new CHexahedron(Buffer_Receive_Hexahedron[iElemHexahedron*8+0], Buffer_Receive_Hexahedron[iElemHexahedron*8+1], Buffer_Receive_Hexahedron[iElemHexahedron*8+2], Buffer_Receive_Hexahedron[iElemHexahedron*8+3], Buffer_Receive_Hexahedron[iElemHexahedron*8+4], Buffer_Receive_Hexahedron[iElemHexahedron*8+5], Buffer_Receive_Hexahedron[iElemHexahedron*8+6], Buffer_Receive_Hexahedron[iElemHexahedron*8+7]); + iElem++; + } + for (iElemPrism = 0; iElemPrism < nElemPrism; iElemPrism++) { + elem[iElem] = new CPrism(Buffer_Receive_Prism[iElemPrism*6+0], Buffer_Receive_Prism[iElemPrism*6+1], Buffer_Receive_Prism[iElemPrism*6+2], Buffer_Receive_Prism[iElemPrism*6+3], Buffer_Receive_Prism[iElemPrism*6+4], Buffer_Receive_Prism[iElemPrism*6+5]); + iElem++; + } + for (iElemPyramid = 0; iElemPyramid < nElemPyramid; iElemPyramid++) { + elem[iElem] = new CPyramid(Buffer_Receive_Pyramid[iElemPyramid*5+0], Buffer_Receive_Pyramid[iElemPyramid*5+1], Buffer_Receive_Pyramid[iElemPyramid*5+2], Buffer_Receive_Pyramid[iElemPyramid*5+3], Buffer_Receive_Pyramid[iElemPyramid*5+4]); + iElem++; + } + + delete[] Buffer_Receive_Triangle; + delete[] Buffer_Receive_Quadrilateral; + delete[] Buffer_Receive_Tetrahedron; + delete[] Buffer_Receive_Hexahedron; + delete[] Buffer_Receive_Prism; + delete[] Buffer_Receive_Pyramid; + + /*--- Create the domain structures for the boundaries ---*/ + + nMarker = nMarkerDomain; + + nElem_Bound = new unsigned long [nMarker_Max]; + Local_to_Global_Marker = new unsigned short [nMarker_Max]; + Tag_to_Marker = new string [nMarker_Max]; + string *TagBound_Copy = new string [nMarker_Max]; + short *SendRecv_Copy = new short [nMarker_Max]; + + for (iMarker = 0; iMarker < nMarker; iMarker++) nElem_Bound[iMarker] = nVertexDomain[iMarker]; + + bound = new CPrimalGrid**[nMarker+(overhead*nDomain)]; + for (iMarker = 0; iMarker < nMarker; iMarker++) bound[iMarker] = new CPrimalGrid* [nElem_Bound[iMarker]]; + + iBoundLineTotal = 0; iBoundTriangleTotal = 0; iBoundQuadrilateralTotal = 0; + + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + iVertexDomain = 0; + + for (iBoundLine = 0; iBoundLine < nBoundLine[iMarker]; iBoundLine++) { + bound[iMarker][iVertexDomain] = new CLine(Buffer_Receive_BoundLine[iBoundLineTotal*2+0], + Buffer_Receive_BoundLine[iBoundLineTotal*2+1], 2); + iVertexDomain++; iBoundLineTotal++; + } + for (iBoundTriangle = 0; iBoundTriangle < nBoundTriangle[iMarker]; iBoundTriangle++) { + bound[iMarker][iVertexDomain] = new CTriangle(Buffer_Receive_BoundTriangle[iBoundTriangleTotal*3+0], + Buffer_Receive_BoundTriangle[iBoundTriangleTotal*3+1], + Buffer_Receive_BoundTriangle[iBoundTriangleTotal*3+2], 3); + iVertexDomain++; iBoundTriangleTotal++; + } + for (iBoundQuadrilateral = 0; iBoundQuadrilateral < nBoundQuadrilateral[iMarker]; iBoundQuadrilateral++) { + bound[iMarker][iVertexDomain] = new CQuadrilateral(Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+0], + Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+1], + Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+2], + Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+3], 3); + iVertexDomain++; iBoundQuadrilateralTotal++; + } + + Local_to_Global_Marker[iMarker] = Buffer_Receive_Local2Global_Marker[iMarker]; + + /*--- Now each domain has the right information ---*/ + + string Grid_Marker = config->GetMarker_All_TagBound(Local_to_Global_Marker[iMarker]); + short SendRecv = config->GetMarker_All_SendRecv(Local_to_Global_Marker[iMarker]); + TagBound_Copy[iMarker] = Grid_Marker; + SendRecv_Copy[iMarker] = SendRecv; + + } + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + config->SetMarker_All_TagBound(iMarker, TagBound_Copy[iMarker]); + config->SetMarker_All_SendRecv(iMarker, SendRecv_Copy[iMarker]); + } + + /*--- Add the new periodic markers to the domain ---*/ + + iTotalSendDomain_Periodic = 0; + iTotalReceivedDomain_Periodic = 0; + + for (jDomain = 0; jDomain < nDomain; jDomain++) { + + if (nSendDomain_Periodic[jDomain] != 0) { + nVertexDomain[nMarker] = 0; + bound[nMarker] = new CPrimalGrid* [nSendDomain_Periodic[jDomain]]; + + iVertex = 0; + for (iTotalSendDomain_Periodic = 0; iTotalSendDomain_Periodic < nTotalSendDomain_Periodic; iTotalSendDomain_Periodic++) { + if (Buffer_Receive_SendDomain_PeriodicReceptor[iTotalSendDomain_Periodic] == jDomain) { + bound[nMarker][iVertex] = new CVertexMPI(Buffer_Receive_SendDomain_Periodic[iTotalSendDomain_Periodic], nDim); + bound[nMarker][iVertex]->SetRotation_Type(Buffer_Receive_SendDomain_PeriodicTrans[iTotalSendDomain_Periodic]); + nVertexDomain[nMarker]++; iVertex++; + } + } + + Marker_All_SendRecv[nMarker] = jDomain+1; + nElem_Bound[nMarker] = nVertexDomain[nMarker]; + nMarker++; + } + + if (nReceivedDomain_Periodic[jDomain] != 0) { + nVertexDomain[nMarker] = 0; + bound[nMarker] = new CPrimalGrid* [nReceivedDomain_Periodic[jDomain]]; + + iVertex = 0; + for (iTotalReceivedDomain_Periodic = 0; iTotalReceivedDomain_Periodic < nTotalReceivedDomain_Periodic; iTotalReceivedDomain_Periodic++) { + if (Buffer_Receive_ReceivedDomain_PeriodicDonor[iTotalReceivedDomain_Periodic] == jDomain) { + bound[nMarker][iVertex] = new CVertexMPI(Buffer_Receive_ReceivedDomain_Periodic[iTotalReceivedDomain_Periodic], nDim); + bound[nMarker][iVertex]->SetRotation_Type(Buffer_Receive_ReceivedDomain_PeriodicTrans[iTotalReceivedDomain_Periodic]); + nVertexDomain[nMarker]++; iVertex++; + } + } + + Marker_All_SendRecv[nMarker] = -(jDomain+1); + nElem_Bound[nMarker] = nVertexDomain[nMarker]; + nMarker++; + } + + } + + delete[] TagBound_Copy; + delete[] SendRecv_Copy; + + delete[] Buffer_Receive_BoundLine; + delete[] Buffer_Receive_BoundTriangle; + delete[] Buffer_Receive_BoundQuadrilateral; + delete[] Buffer_Receive_Local2Global_Marker; + + delete[] Buffer_Receive_SendDomain_Periodic; + delete[] Buffer_Receive_SendDomain_PeriodicTrans; + delete[] Buffer_Receive_SendDomain_PeriodicReceptor; + delete[] Buffer_Receive_ReceivedDomain_Periodic; + delete[] Buffer_Receive_ReceivedDomain_PeriodicTrans; + delete[] Buffer_Receive_ReceivedDomain_PeriodicDonor; + + } + + } + + + /*--- Set the value of Marker_All_SendRecv and Marker_All_TagBound in the config structure ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + config->SetMarker_All_SendRecv(iMarker, Marker_All_SendRecv[iMarker]); + } + + /*--- Set the value of Global_nPoint and Global_nPointDomain ---*/ + + unsigned long Local_nPoint = nPoint; + unsigned long Local_nPointDomain = nPointDomain; + +#ifdef HAVE_MPI + + SU2_MPI::Allreduce(&Local_nPoint, &Global_nPoint, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&Local_nPointDomain, &Global_nPointDomain, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + +#else + + Global_nPoint = Local_nPoint; + Global_nPointDomain = Local_nPointDomain; + +#endif + + if (rank == MASTER_NODE) { + + delete [] MarkerIn; + delete [] nElem_Color; + + delete [] Buffer_Send_Center; + delete [] Buffer_Send_Rotation; + delete [] Buffer_Send_Translate; + + delete [] Buffer_Send_nSendDomain_Periodic; + delete [] Buffer_Send_nReceivedDomain_Periodic; + + delete [] Marker_All_SendRecv_Copy; + delete [] Marker_All_TagBound_Copy; + + for (iDomain = 0; iDomain < nDomain; iDomain++) { + delete[] Elem_Color[iDomain]; + } + delete[] Elem_Color; + delete[] Global2Local_Point; + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) + delete [] VertexIn[iMarker]; + delete[] VertexIn; + + } + + delete [] nSendDomain_Periodic; + delete [] nReceivedDomain_Periodic; + + delete [] nVertexDomain; + delete [] nBoundLine; + delete [] nBoundTriangle; + delete [] nBoundQuadrilateral; + delete [] Buffer_Send_nVertexDomain; + delete [] Buffer_Send_nBoundLine; + delete [] Buffer_Send_nBoundTriangle; + delete [] Buffer_Send_nBoundQuadrilateral; + delete [] Buffer_Send_Marker_All_SendRecv; + delete [] Marker_All_TagBound; + delete [] Buffer_Send_Marker_All_TagBound; + +} + +CPhysicalGeometry::CPhysicalGeometry(CGeometry *geometry, CConfig *config, int option) { + + Global_to_Local_Point = NULL; + Local_to_Global_Point = NULL; + Local_to_Global_Marker = NULL; + Global_to_Local_Marker = NULL; + + unsigned long iter, iPoint, jPoint, iElem, iVertex; + //unsigned long nElemTotal = 0, nPointTotal = 0, nPointDomainTotal = 0, nPointGhost = 0, nPointPeriodic = 0, nElemTriangle = 0, nElemQuadrilateral = 0, nElemTetrahedron = 0, nElemHexahedron = 0, nElemPrism = 0, nElemPyramid = 0; + unsigned long iElemTotal, iPointTotal, iPointGhost, iPointDomain, iPointPeriodic, iElemTriangle, iElemQuadrilateral, iElemTetrahedron, iElemHexahedron, iElemPrism, iElemPyramid, iPointCurrent; + unsigned long nBoundLineTotal = 0, iBoundLineTotal; + unsigned long nBoundTriangleTotal = 0, iBoundTriangleTotal; + unsigned long nBoundQuadrilateralTotal = 0, iBoundQuadrilateralTotal; + unsigned long ReceptorColor = 0, DonorColor = 0, Transformation; + unsigned long nTotalSendDomain_Periodic = 0, iTotalSendDomain_Periodic, nTotalReceivedDomain_Periodic = 0, iTotalReceivedDomain_Periodic, *nSendDomain_Periodic = NULL, *nReceivedDomain_Periodic = NULL; + unsigned long Buffer_Send_nPointTotal = 0, Buffer_Send_nPointDomainTotal = 0, Buffer_Send_nPointGhost = 0, Buffer_Send_nPointPeriodic = 0; + unsigned long Buffer_Send_nElemTotal, Buffer_Send_nElemTriangle = 0, Buffer_Send_nElemQuadrilateral = 0, Buffer_Send_nElemTetrahedron = 0, Buffer_Send_nElemHexahedron = 0, Buffer_Send_nElemPrism = 0, Buffer_Send_nElemPyramid = 0; + unsigned long Buffer_Send_nTotalSendDomain_Periodic = 0, Buffer_Send_nTotalReceivedDomain_Periodic = 0, *Buffer_Send_nSendDomain_Periodic = NULL, *Buffer_Send_nReceivedDomain_Periodic = NULL; + unsigned long Buffer_Send_nBoundLineTotal = 0, Buffer_Send_nBoundTriangleTotal = 0, Buffer_Send_nBoundQuadrilateralTotal = 0; + unsigned long iVertexDomain, iBoundLine, iBoundTriangle, iBoundQuadrilateral; + + /*--- Need to su2double-check these shorts in case we go to nprocs > ~32,000 ---*/ + unsigned long iNode, iDim, iMarker, jMarker, nMarkerDomain = 0, iMarkerDomain; + unsigned long nDomain = 0, iDomain, jDomain, nPeriodic = 0, iPeriodic, overhead = 4, Buffer_Send_nMarkerDomain = 0, Buffer_Send_nDim = 0, Buffer_Send_nZone = 0, Buffer_Send_nPeriodic = 0; + + bool *MarkerIn = NULL, **VertexIn = NULL, *PointIn = NULL, *ElemIn = NULL; + long vnodes_local[8]; + + vector DomainList; + short *Marker_All_SendRecv_Copy = NULL; + string *Marker_All_TagBound_Copy = NULL; + + int rank = MASTER_NODE; + int size = SINGLE_NODE; + unsigned short nMarker_Max = config->GetnMarker_Max(); + + /*--- Some dynamic arrays so we're not allocating too much on the stack ---*/ + + unsigned long *nVertexDomain = new unsigned long[nMarker_Max]; + unsigned long *nBoundLine = new unsigned long[nMarker_Max]; + unsigned long *nBoundTriangle = new unsigned long[nMarker_Max]; + unsigned long *nBoundQuadrilateral = new unsigned long[nMarker_Max]; + + unsigned long *Buffer_Send_nVertexDomain = new unsigned long[nMarker_Max]; + unsigned long *Buffer_Send_nBoundLine = new unsigned long[nMarker_Max]; + unsigned long *Buffer_Send_nBoundTriangle = new unsigned long[nMarker_Max]; + unsigned long *Buffer_Send_nBoundQuadrilateral = new unsigned long[nMarker_Max]; + + short *Buffer_Send_Marker_All_SendRecv = new short[nMarker_Max]; + + char *Marker_All_TagBound = new char[nMarker_Max*MAX_STRING_SIZE]; + char *Buffer_Send_Marker_All_TagBound = new char[nMarker_Max*MAX_STRING_SIZE]; + + +#ifdef HAVE_MPI + + /*--- MPI initialization ---*/ + + MPI_Comm_size(MPI_COMM_WORLD, &size); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + /*--- MPI status and request arrays for non-blocking communications ---*/ + + MPI_Status status, status2; + unsigned long source; + int recv_count=0; + + int offset = 17; + MPI_Status *send_stat = new MPI_Status[offset+size]; + MPI_Status *recv_stat = new MPI_Status[offset+size]; + + MPI_Request *send_req = new MPI_Request[offset+size]; + MPI_Request *recv_req = new MPI_Request[offset+size]; + +#endif + + if (rank == MASTER_NODE && size > SINGLE_NODE) + cout << "Communicating partition data and creating halo layers." << endl; + + /*--- Define buffer vector interior domain ---*/ + + su2double *Buffer_Send_Coord = NULL; + unsigned long *Buffer_Send_Color = NULL; + unsigned long *Buffer_Send_GlobalPointIndex = NULL; + unsigned long *Buffer_Send_Triangle = NULL; + unsigned long *Buffer_Send_Quadrilateral = NULL; + unsigned long *Buffer_Send_Tetrahedron = NULL; + unsigned long *Buffer_Send_Hexahedron = NULL; + unsigned long *Buffer_Send_Prism = NULL; + unsigned long *Buffer_Send_Pyramid = NULL; + unsigned long *Buffer_Send_GlobElem = NULL; + + /*--- Define buffer vector boundary ---*/ + + unsigned long *Buffer_Send_BoundLine = NULL, *Buffer_Receive_BoundLine = NULL; + unsigned long *Buffer_Send_BoundTriangle = NULL, *Buffer_Receive_BoundTriangle = NULL; + unsigned long *Buffer_Send_BoundQuadrilateral = NULL, *Buffer_Receive_BoundQuadrilateral = NULL; + unsigned long *Buffer_Send_Local2Global_Marker = NULL, *Buffer_Receive_Local2Global_Marker = NULL; + + /*--- Define buffer vector periodic boundary conditions ---*/ + + su2double *Buffer_Send_Center = NULL, *Buffer_Receive_Center = NULL; + su2double *Buffer_Send_Rotation = NULL, *Buffer_Receive_Rotation = NULL; + su2double *Buffer_Send_Translate = NULL, *Buffer_Receive_Translate = NULL; + + /*--- Define buffer vector periodic boundary conditions ---*/ + + unsigned long *Buffer_Send_SendDomain_Periodic = NULL, *Buffer_Receive_SendDomain_Periodic = NULL; + unsigned long *Buffer_Send_SendDomain_PeriodicTrans = NULL, *Buffer_Receive_SendDomain_PeriodicTrans = NULL; + unsigned long *Buffer_Send_SendDomain_PeriodicReceptor = NULL, *Buffer_Receive_SendDomain_PeriodicReceptor = NULL; + unsigned long *Buffer_Send_ReceivedDomain_Periodic = NULL, *Buffer_Receive_ReceivedDomain_Periodic = NULL; + unsigned long *Buffer_Send_ReceivedDomain_PeriodicTrans = NULL, *Buffer_Receive_ReceivedDomain_PeriodicTrans = NULL; + unsigned long *Buffer_Send_ReceivedDomain_PeriodicDonor = NULL, *Buffer_Receive_ReceivedDomain_PeriodicDonor = NULL; + + /*--- Variables below are needed specifically for the ParMETIS version ---*/ + + unsigned long *Global_to_local_Point_recv; + unsigned long *local_colour_values; + unsigned long *local_colour_temp; + unsigned long *Local_to_global_elem; + + unsigned short *nDim_s = new unsigned short[size]; + unsigned short *nDim_r = new unsigned short[size]; + unsigned short *nZone_s = new unsigned short[size]; + unsigned short *nZone_r = new unsigned short[size]; + + unsigned long *nPointTotal_s = new unsigned long[size]; + unsigned long *nPointDomainTotal_s = new unsigned long[size]; + unsigned long *nPointGhost_s = new unsigned long[size]; + unsigned long *nPointPeriodic_s = new unsigned long[size]; + unsigned long *nElemTotal_s = new unsigned long[size]; + unsigned long *nElemTriangle_s = new unsigned long[size]; + unsigned long *nElemQuadrilateral_s = new unsigned long[size]; + unsigned long *nElemTetrahedron_s = new unsigned long[size]; + unsigned long *nElemHexahedron_s = new unsigned long[size]; + unsigned long *nElemPrism_s = new unsigned long[size]; + unsigned long *nElemPyramid_s = new unsigned long[size]; + + unsigned long *nPointTotal_r = new unsigned long[size]; + unsigned long *nPointDomainTotal_r = new unsigned long[size]; + unsigned long *nPointGhost_r = new unsigned long[size]; + unsigned long *nPointPeriodic_r = new unsigned long[size]; + unsigned long *nElemTotal_r = new unsigned long[size]; + unsigned long *nElemTriangle_r = new unsigned long[size]; + unsigned long *nElemQuadrilateral_r = new unsigned long[size]; + unsigned long *nElemTetrahedron_r = new unsigned long[size]; + unsigned long *nElemHexahedron_r = new unsigned long[size]; + unsigned long *nElemPrism_r = new unsigned long[size]; + unsigned long *nElemPyramid_r = new unsigned long[size]; + + unsigned long nPointTotal_r_tot=0; + unsigned long nPointDomainTotal_r_tot=0; + unsigned long nPointGhost_r_tot=0; + unsigned long nPointPeriodic_r_tot=0; + unsigned long nElemTotal_r_tot=0; + unsigned long nElemTriangle_r_tot=0; + unsigned long nElemQuadrilateral_r_tot=0; + unsigned long nElemTetrahedron_r_tot=0; + unsigned long nElemHexahedron_r_tot=0; + unsigned long nElemPrism_r_tot=0; + unsigned long nElemPyramid_r_tot=0; + + unsigned long Buffer_Size_Coord = 0; + unsigned long Buffer_Size_Color = 0; + unsigned long Buffer_Size_GlobalPointIndex = 0; + unsigned long Buffer_Size_Triangle = 0; + unsigned long Buffer_Size_Quadrilateral = 0; + unsigned long Buffer_Size_Tetrahedron = 0; + unsigned long Buffer_Size_Hexahedron = 0; + unsigned long Buffer_Size_Prism = 0; + unsigned long Buffer_Size_Pyramid = 0; + unsigned long Buffer_Size_GlobElem = 0; + + unsigned long ElemTotal_Counter = 0; + unsigned long PointTotal_Counter = 0; + unsigned long PointDomain_Counter = 0; + + /*--- WARNING: check the next two counters ---*/ + unsigned long PointPeriodic_Counter = 0; + unsigned long PointGhost_Counter = 0; + unsigned long ElemTriangle_Counter = 0; + unsigned long ElemQuadrilateral_Counter = 0; + unsigned long ElemTetrahedron_Counter = 0; + unsigned long ElemHexahedron_Counter = 0; + unsigned long ElemPrism_Counter = 0; + unsigned long ElemPyramid_Counter = 0; + + unsigned long *Local_to_global_Triangle; + unsigned long *Local_to_global_Quadrilateral; + unsigned long *Local_to_global_Tetrahedron; + unsigned long *Local_to_global_Hexahedron; + unsigned long *Local_to_global_Prism; + unsigned long *Local_to_global_Pyramid; + + bool *Triangle_presence; + bool *Quadrilateral_presence; + bool *Tetrahedron_presence; + bool *Hexahedron_presence; + bool *Prism_presence; + bool *Pyramid_presence; + bool *Element_presence; + + Element_presence = new bool[geometry->GetnElem()]; + Triangle_presence = new bool[geometry->GetnElem()]; + Quadrilateral_presence = new bool[geometry->GetnElem()]; + Tetrahedron_presence = new bool[geometry->GetnElem()]; + Hexahedron_presence = new bool[geometry->GetnElem()]; + Prism_presence = new bool[geometry->GetnElem()]; + Pyramid_presence = new bool[geometry->GetnElem()]; + + for (unsigned long i=0; i < geometry->GetnElem(); i++) { + Element_presence[i] = false; + Triangle_presence[i] = false; + Quadrilateral_presence[i] = false; + Tetrahedron_presence[i] = false; + Hexahedron_presence[i] = false; + Prism_presence[i] = false; + Pyramid_presence[i] = false; + } + + su2double *Buffer_Receive_Coord_loc = NULL; + + unsigned long *Buffer_Receive_Color_loc = NULL; + unsigned long *Buffer_Receive_GlobalPointIndex_loc = NULL; + unsigned long *Buffer_Receive_Triangle_loc = NULL; + unsigned long *Buffer_Receive_Quadrilateral_loc = NULL; + unsigned long *Buffer_Receive_Tetrahedron_loc = NULL; + unsigned long *Buffer_Receive_Hexahedron_loc = NULL; + unsigned long *Buffer_Receive_Prism_loc = NULL; + unsigned long *Buffer_Receive_Pyramid_loc = NULL; + + unsigned long *Buffer_Receive_GlobElem_loc = NULL; + unsigned long *Buffer_Receive_Triangle_presence_loc = NULL; + unsigned long *Buffer_Receive_Quadrilateral_presence_loc = NULL; + unsigned long *Buffer_Receive_Tetrahedron_presence_loc = NULL; + unsigned long *Buffer_Receive_Hexahedron_presence_loc = NULL; + unsigned long *Buffer_Receive_Prism_presence_loc = NULL; + unsigned long *Buffer_Receive_Pyramid_presence_loc = NULL; + + /*--- Allocate the memory that we only need if we have MPI support ---*/ + +#ifdef HAVE_MPI + + su2double *Buffer_Receive_Coord = NULL; + unsigned long *Buffer_Receive_Color = NULL; + unsigned long *Buffer_Receive_GlobalPointIndex = NULL; + unsigned long *Buffer_Receive_Triangle = NULL; + unsigned long *Buffer_Receive_Quadrilateral = NULL; + unsigned long *Buffer_Receive_Tetrahedron = NULL; + unsigned long *Buffer_Receive_Hexahedron = NULL; + unsigned long *Buffer_Receive_Prism = NULL; + unsigned long *Buffer_Receive_Pyramid = NULL; + unsigned long *Buffer_Receive_GlobElem = NULL; + + unsigned long **Buffer_Receive_Triangle_presence = new unsigned long*[size]; + unsigned long **Buffer_Receive_Quadrilateral_presence = new unsigned long*[size]; + unsigned long **Buffer_Receive_Tetrahedron_presence = new unsigned long*[size]; + unsigned long **Buffer_Receive_Hexahedron_presence = new unsigned long*[size]; + unsigned long **Buffer_Receive_Prism_presence = new unsigned long*[size]; + unsigned long **Buffer_Receive_Pyramid_presence = new unsigned long*[size]; + +#endif + + /*--- Basic dimensionalization ---*/ + + nDomain = size; + + Marker_All_SendRecv = new short[nMarker_Max]; + nSendDomain_Periodic = new unsigned long [nDomain]; + nReceivedDomain_Periodic = new unsigned long [nDomain]; + + /*--- Auxiliar vector based on the original geometry ---*/ + + ElemIn = new bool[geometry->no_of_local_elements]; + PointIn = new bool[geometry->GetnPoint()]; + + + Buffer_Send_nDim = geometry->GetnDim(); + Buffer_Send_nZone = geometry->GetnZone(); + + // DOUBLE CHECK THESE, SINCE WE DO THIS AGAIN AT BOTTOM WITH THE MASTER +// MarkerIn = new bool [geometry->GetnMarker()]; +// VertexIn = new bool* [geometry->GetnMarker()]; +// for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) +// VertexIn[iMarker] = new bool [geometry->GetnElem_Bound(iMarker)]; +// + // +// Buffer_Send_nPeriodic = config->GetnPeriodicIndex(); +// Buffer_Send_Center = new su2double[Buffer_Send_nPeriodic*3]; +// Buffer_Send_Rotation = new su2double[Buffer_Send_nPeriodic*3]; +// Buffer_Send_Translate = new su2double[Buffer_Send_nPeriodic*3]; + // +// Buffer_Send_nSendDomain_Periodic = new unsigned long [nDomain]; +// Buffer_Send_nReceivedDomain_Periodic = new unsigned long [nDomain]; + + /*--- Divide the elements in color list to speed up the grid partitioning ---*/ + + Local_to_global_elem= new unsigned long [geometry->no_of_local_elements]; + for (unsigned long i=0; iGetnElem(); i++) { + if (geometry->Global_to_local_elem[i] != -1) { + Local_to_global_elem[geometry->Global_to_local_elem[i]] = i; + } + } + + Global_to_local_Point_recv = new unsigned long[geometry->GetnPoint()]; + for (unsigned long i=0; iGetnPoint(); i++) { + Global_to_local_Point_recv[i]=-1; + } + +// unsigned long *Global_to_Local_Point_loc; +// Global_to_Local_Point_loc = new unsigned long[geometry->GetnPoint()]; +// for (iPoint=0; iPointGetnPoint(); iPoint++) { +// Global_to_Local_Point_loc[iPoint]=-1; +// } + + local_colour_values = new unsigned long[geometry->GetnPoint()]; + local_colour_temp = new unsigned long[geometry->ending_node[rank]-geometry->starting_node[rank]]; + + for (unsigned long i=0; iending_node[rank]-geometry->starting_node[rank]; i++) { + local_colour_temp[i]=geometry->node[i]->GetColor(); + local_colour_values[geometry->starting_node[rank]+i]=local_colour_temp[i]; + } + + /*--- Communicate the grid coloring to all partitions. This information + will be repeatedly used throughout the organization of the partitions + and sorting out their ghost points/elements. ---*/ + +#ifdef HAVE_MPI + + int comm_counter=0; + for (iDomain=0; iDomain < (unsigned long)size; iDomain++) { + if (iDomain != (unsigned long)rank) { + SU2_MPI::Isend(local_colour_temp, geometry->ending_node[rank]-geometry->starting_node[rank], + MPI_UNSIGNED_LONG, iDomain, iDomain, MPI_COMM_WORLD, &send_req[comm_counter]); + comm_counter++; + } + } + + for (iDomain=0; iDomain < (unsigned long)size-1; iDomain++) { + MPI_Probe(MPI_ANY_SOURCE, rank, MPI_COMM_WORLD, &status2); + source = status2.MPI_SOURCE; + MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(&local_colour_values[geometry->starting_node[source]], recv_count, + MPI_UNSIGNED_LONG, source, rank, MPI_COMM_WORLD, &status2); + } + + /*--- Wait for the sends to complete (will be true since we're using + blocking recv's above. ---*/ + + SU2_MPI::Waitall(size-1, send_req, send_stat); + +#endif + + /*--- Free temporary buffer for communicating colors. ---*/ + + delete [] local_colour_temp; + +#ifdef HAVE_MPI + MPI_Barrier(MPI_COMM_WORLD); +#endif + //cout << " ==== Rank " << rank << " starting first send " << endl; + + /*--- This loop gets the array sizes of points, elements, etc. for each + rank to send to each other rank. ---*/ + + for (iDomain = 0; iDomain < nDomain; iDomain++) { + + /*--- Interior dimensionalization. Loop over the original grid to + perform the dimensionalizaton of the domain variables ---*/ + + Buffer_Send_nElemTotal = 0; + Buffer_Send_nPointTotal = 0; + Buffer_Send_nPointGhost = 0; + Buffer_Send_nPointDomainTotal = 0; + Buffer_Send_nPointPeriodic = 0; + Buffer_Send_nElemTriangle = 0; + Buffer_Send_nElemQuadrilateral = 0; + Buffer_Send_nElemTetrahedron = 0; + Buffer_Send_nElemHexahedron = 0; + Buffer_Send_nElemPrism = 0; + Buffer_Send_nElemPyramid = 0; + + /*--- Initialize the global to local mapping ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + PointIn[iPoint] = false; + } + + /*--- Loop over all of the local elements and count the number of each + type of point and element that needs to be sent. ---*/ + + for (iElem = 0; iElem < geometry->no_of_local_elements; iElem++) { + + /*--- Check if the element belongs to the domain ---*/ + + ElemIn[iElem] = false; + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { + iPoint = geometry->elem[iElem]->GetNode(iNode); + if (local_colour_values[iPoint] == iDomain) { + ElemIn[iElem] = true; break; + } + } + + /*--- If this element is needed by iDomain, get information + about the number of points and element type. ---*/ + + if (ElemIn[iElem]) { + + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { + iPoint = geometry->elem[iElem]->GetNode(iNode); + + /*--- If we haven't already found this point... ---*/ + + if (PointIn[iPoint] == false) { + + /*--- Mark point as found and collect information ---*/ + + PointIn[iPoint] = true; + + if ((iPoint >= geometry->starting_node[rank]) && + (iPoint < geometry->ending_node[rank])) { + + Buffer_Send_nPointTotal++; + + /*--- Increment our counters ---*/ + if ( local_colour_values[iPoint] == iDomain ) { + if ( iPoint > geometry->GetnPointDomain() - 1) + Buffer_Send_nPointPeriodic++; + else + Buffer_Send_nPointDomainTotal++; + } + else Buffer_Send_nPointGhost++; + + + } + } + } + + /*--- Increment the counter for the current type of element ---*/ + + switch(geometry->elem[iElem]->GetVTK_Type()) { + case TRIANGLE: Buffer_Send_nElemTriangle++; break; + case QUADRILATERAL: Buffer_Send_nElemQuadrilateral++; break; + case TETRAHEDRON: Buffer_Send_nElemTetrahedron++; break; + case HEXAHEDRON: Buffer_Send_nElemHexahedron++; break; + case PRISM: Buffer_Send_nElemPrism++; break; + case PYRAMID: Buffer_Send_nElemPyramid++; break; + } + + /*--- Increment the total number of elements for iDomain ---*/ + + Buffer_Send_nElemTotal++; + + } + } + + /*--- Store the counts on a partition by partition basis. ---*/ + + nDim_s[iDomain] = geometry->GetnDim(); + nZone_s[iDomain] = Buffer_Send_nZone; + nPointTotal_s[iDomain] = Buffer_Send_nPointTotal; + nPointDomainTotal_s[iDomain] = Buffer_Send_nPointDomainTotal; + nPointGhost_s[iDomain] = Buffer_Send_nPointGhost; + nPointPeriodic_s[iDomain] = Buffer_Send_nPointPeriodic; + nElemTotal_s[iDomain] = Buffer_Send_nElemTotal; + nElemTriangle_s[iDomain] = Buffer_Send_nElemTriangle; + nElemQuadrilateral_s[iDomain] = Buffer_Send_nElemQuadrilateral; + nElemTetrahedron_s[iDomain] = Buffer_Send_nElemTetrahedron; + nElemHexahedron_s[iDomain] = Buffer_Send_nElemHexahedron; + nElemPrism_s[iDomain] = Buffer_Send_nElemPrism; + nElemPyramid_s[iDomain] = Buffer_Send_nElemPyramid; + + /*--- Total counts for allocating send buffers below ---*/ + + Buffer_Size_Coord += nPointTotal_s[iDomain]*nDim_s[iDomain]; + Buffer_Size_Color += nPointTotal_s[iDomain]; + Buffer_Size_GlobalPointIndex += nPointTotal_s[iDomain]; + Buffer_Size_Triangle += nElemTriangle_s[iDomain]; + Buffer_Size_Quadrilateral += nElemQuadrilateral_s[iDomain]; + Buffer_Size_Tetrahedron += nElemTetrahedron_s[iDomain]; + Buffer_Size_Hexahedron += nElemHexahedron_s[iDomain]; + Buffer_Size_Prism += nElemPrism_s[iDomain]; + Buffer_Size_Pyramid += nElemPyramid_s[iDomain]; + Buffer_Size_GlobElem += nElemTotal_s[iDomain]; + + } + + /*--- Allocate the buffer vectors in the appropiate domain (master, iDomain) ---*/ + + Buffer_Send_Coord = new su2double[Buffer_Size_Coord]; + Buffer_Send_Color = new unsigned long[Buffer_Size_Color]; + Buffer_Send_GlobalPointIndex = new unsigned long[Buffer_Size_GlobalPointIndex]; + Buffer_Send_Triangle = new unsigned long[Buffer_Size_Triangle*N_POINTS_TRIANGLE]; + Buffer_Send_Quadrilateral = new unsigned long[Buffer_Size_Quadrilateral*N_POINTS_QUADRILATERAL]; + Buffer_Send_Tetrahedron = new unsigned long[Buffer_Size_Tetrahedron*N_POINTS_TETRAHEDRON]; + Buffer_Send_Hexahedron = new unsigned long[Buffer_Size_Hexahedron*N_POINTS_HEXAHEDRON]; + Buffer_Send_Prism = new unsigned long[Buffer_Size_Prism*N_POINTS_PRISM]; + Buffer_Send_Pyramid = new unsigned long[Buffer_Size_Pyramid*N_POINTS_PYRAMID]; + Buffer_Send_GlobElem = new unsigned long[Buffer_Size_GlobElem]; + + Local_to_global_Triangle = new unsigned long[Buffer_Size_Triangle]; + Local_to_global_Quadrilateral = new unsigned long[Buffer_Size_Quadrilateral]; + Local_to_global_Tetrahedron = new unsigned long[Buffer_Size_Tetrahedron]; + Local_to_global_Hexahedron = new unsigned long[Buffer_Size_Hexahedron]; + Local_to_global_Prism = new unsigned long[Buffer_Size_Prism]; + Local_to_global_Pyramid = new unsigned long[Buffer_Size_Pyramid]; + + /*--- Initialize the counters for the larger send buffers (by domain) ---*/ + + ElemTotal_Counter = 0; + PointTotal_Counter = 0; + PointDomain_Counter = 0; + /*--- WARNING: check the next two counters ---*/ + PointPeriodic_Counter = 0; + PointGhost_Counter = 0; + ElemTriangle_Counter = 0; + ElemQuadrilateral_Counter = 0; + ElemTetrahedron_Counter = 0; + ElemHexahedron_Counter = 0; + ElemPrism_Counter = 0; + ElemPyramid_Counter = 0; + + /*--- Now that we know the sizes of the point, elem, etc. arrays, we can + allocate and send the information in large chunks to all processors. ---*/ + + for (iDomain = 0; iDomain < nDomain; iDomain++) { + + /*--- A rank does not communicate with itself through MPI ---*/ + + if ((unsigned long)rank != iDomain) { + +#ifdef HAVE_MPI + + /*--- Communicate the counts to iDomain with non-blocking sends ---*/ + + SU2_MPI::Isend(&nDim_s[iDomain], 1, MPI_UNSIGNED_SHORT, iDomain, + iDomain*13+0, MPI_COMM_WORLD, &send_req[0]); + + SU2_MPI::Isend(&nZone_s[iDomain], 1, MPI_UNSIGNED_SHORT, iDomain, + iDomain*13+1, MPI_COMM_WORLD, &send_req[1]); + + SU2_MPI::Isend(&nPointTotal_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, + iDomain*13+2, MPI_COMM_WORLD, &send_req[2]); + + SU2_MPI::Isend(&nPointDomainTotal_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, + iDomain*13+3, MPI_COMM_WORLD, &send_req[3]); + + SU2_MPI::Isend(&nPointGhost_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, + iDomain*13+4, MPI_COMM_WORLD, &send_req[4]); + + SU2_MPI::Isend(&nPointPeriodic_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, + iDomain*13+5, MPI_COMM_WORLD, &send_req[5]); + + SU2_MPI::Isend(&nElemTotal_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, + iDomain*13+6, MPI_COMM_WORLD, &send_req[6]); + + SU2_MPI::Isend(&nElemTriangle_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, + iDomain*13+7, MPI_COMM_WORLD, &send_req[7]); + + SU2_MPI::Isend(&nElemQuadrilateral_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, + iDomain*13+8, MPI_COMM_WORLD, &send_req[8]); + + SU2_MPI::Isend(&nElemTetrahedron_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, + iDomain*13+9, MPI_COMM_WORLD, &send_req[9]); + + SU2_MPI::Isend(&nElemHexahedron_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, + iDomain*13+10, MPI_COMM_WORLD, &send_req[10]); + + SU2_MPI::Isend(&nElemPrism_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, + iDomain*13+11, MPI_COMM_WORLD, &send_req[11]); + + SU2_MPI::Isend(&nElemPyramid_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain, + iDomain*13+12, MPI_COMM_WORLD, &send_req[12]); + +#endif + + } else { + + /*--- If iDomain = rank, we simply copy values into place in memory ---*/ + + nDim = nDim_s[iDomain]; + nZone = nZone_s[iDomain]; +// nPointTotal = nPointTotal_s[iDomain]; +// nPointDomainTotal = nPointDomainTotal_s[iDomain]; +// nPointGhost = nPointGhost_s[iDomain]; +// nPointPeriodic = nPointPeriodic_s[iDomain]; +// nElemTotal = nElemTotal_s[iDomain]; +// nElemTriangle = nElemTriangle_s[iDomain]; +// nElemQuadrilateral = nElemQuadrilateral_s[iDomain]; +// nElemTetrahedron = nElemTetrahedron_s[iDomain]; +// nElemHexahedron = nElemHexahedron_s[iDomain]; +// nElemPrism = nElemPrism_s[iDomain]; +// nElemPyramid = nElemPyramid_s[iDomain]; + + nDim_r[iDomain] = nDim_s[iDomain]; + nZone_r[iDomain] = nZone_s[iDomain]; + nPointTotal_r[iDomain] = nPointTotal_s[iDomain]; + nPointDomainTotal_r[iDomain] = nPointDomainTotal_s[iDomain]; + nPointPeriodic_r[iDomain] = nPointPeriodic_s[iDomain]; + nElemTotal_r[iDomain] = nElemTotal_s[iDomain]; + nElemTriangle_r[iDomain] = nElemTriangle_s[iDomain]; + nElemQuadrilateral_r[iDomain] = nElemQuadrilateral_s[iDomain]; + nElemTetrahedron_r[iDomain] = nElemTetrahedron_s[iDomain]; + nElemHexahedron_r[iDomain] = nElemHexahedron_s[iDomain]; + nElemPrism_r[iDomain] = nElemPrism_s[iDomain]; + nElemPyramid_r[iDomain] = nElemPyramid_s[iDomain]; + + nPointTotal_r_tot += nPointTotal_r[iDomain]; + nPointDomainTotal_r_tot += nPointDomainTotal_r[iDomain]; + nPointGhost_r_tot += nPointGhost_r[iDomain]; + nPointPeriodic_r_tot += nPointPeriodic_r[iDomain]; + nElemTotal_r_tot += nElemTotal_r[iDomain]; + nElemTriangle_r_tot += nElemTriangle_r[iDomain]; + nElemQuadrilateral_r_tot += nElemQuadrilateral_r[iDomain]; + nElemTetrahedron_r_tot += nElemTetrahedron_r[iDomain]; + nElemHexahedron_r_tot += nElemHexahedron_r[iDomain]; + nElemPrism_r_tot += nElemPrism_r[iDomain]; + nElemPyramid_r_tot += nElemPyramid_r[iDomain]; + + } + + /*--- Receive the counts. All processors are sending their counters to + iDomain up above, so only iDomain needs to perform the recv here from + all other ranks. ---*/ + + if ((unsigned long)rank == iDomain) { + + for (jDomain = 0; jDomain < (unsigned long)size; jDomain++) { + + /*--- A rank does not communicate with itself through MPI ---*/ + + if ((unsigned long)rank != jDomain) { + +#ifdef HAVE_MPI + + /*--- Recv the data by probing for the current sender, jDomain, + first and then receiving the values from it. ---*/ + + MPI_Probe(jDomain, 13*rank+0, MPI_COMM_WORLD, &status2); + SU2_MPI::Recv(&nDim_r[jDomain], 1, MPI_UNSIGNED_SHORT, jDomain, + rank*13+0, MPI_COMM_WORLD, &status2); + + MPI_Probe(jDomain, 13*rank+1, MPI_COMM_WORLD, &status2); + SU2_MPI::Recv(&nZone_r[jDomain], 1, MPI_UNSIGNED_SHORT, jDomain, + rank*13+1, MPI_COMM_WORLD, &status2); + + MPI_Probe(jDomain, 13*rank+2, MPI_COMM_WORLD, &status2); + SU2_MPI::Recv(&nPointTotal_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, + rank*13+2, MPI_COMM_WORLD, &status2); + + MPI_Probe(jDomain, 13*rank+3, MPI_COMM_WORLD, &status2); + SU2_MPI::Recv(&nPointDomainTotal_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, + rank*13+3, MPI_COMM_WORLD, &status2); + + MPI_Probe(jDomain, 13*rank+4, MPI_COMM_WORLD, &status2); + SU2_MPI::Recv(&nPointGhost_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, + rank*13+4, MPI_COMM_WORLD, &status2); + + MPI_Probe(jDomain, 13*rank+5, MPI_COMM_WORLD, &status2); + SU2_MPI::Recv(&nPointPeriodic_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, + rank*13+5, MPI_COMM_WORLD, &status2); + + MPI_Probe(jDomain, 13*rank+6, MPI_COMM_WORLD, &status2); + SU2_MPI::Recv(&nElemTotal_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, + rank*13+6, MPI_COMM_WORLD, &status2); + + MPI_Probe(jDomain, 13*rank+7, MPI_COMM_WORLD, &status2); + SU2_MPI::Recv(&nElemTriangle_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, + rank*13+7, MPI_COMM_WORLD, &status2); + + MPI_Probe(jDomain, 13*rank+8, MPI_COMM_WORLD, &status2); + SU2_MPI::Recv(&nElemQuadrilateral_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, + rank*13+8, MPI_COMM_WORLD, &status2); + + MPI_Probe(jDomain, 13*rank+9, MPI_COMM_WORLD, &status2); + SU2_MPI::Recv(&nElemTetrahedron_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, + rank*13+9, MPI_COMM_WORLD, &status2); + + MPI_Probe(jDomain, 13*rank+10, MPI_COMM_WORLD, &status2); + SU2_MPI::Recv(&nElemHexahedron_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, + rank*13+10, MPI_COMM_WORLD, &status2); + + MPI_Probe(jDomain, 13*rank+11, MPI_COMM_WORLD, &status2); + SU2_MPI::Recv(&nElemPrism_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, + rank*13+11, MPI_COMM_WORLD, &status2); + + MPI_Probe(jDomain, 13*rank+12, MPI_COMM_WORLD, &status2); + SU2_MPI::Recv(&nElemPyramid_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain, + rank*13+12, MPI_COMM_WORLD, &status2); + +#endif + + /*--- These are the cumulative totals that we will recv below. ----*/ + + nPointTotal_r_tot += nPointTotal_r[jDomain]; + nPointDomainTotal_r_tot += nPointDomainTotal_r[jDomain]; + nPointGhost_r_tot += nPointGhost_r[jDomain]; + nPointPeriodic_r_tot += nPointPeriodic_r[jDomain]; + nElemTotal_r_tot += nElemTotal_r[jDomain]; + nElemTriangle_r_tot += nElemTriangle_r[jDomain]; + nElemQuadrilateral_r_tot += nElemQuadrilateral_r[jDomain]; + nElemTetrahedron_r_tot += nElemTetrahedron_r[jDomain]; + nElemHexahedron_r_tot += nElemHexahedron_r[jDomain]; + nElemPrism_r_tot += nElemPrism_r[jDomain]; + nElemPyramid_r_tot += nElemPyramid_r[jDomain]; + + } + } + + } + } + + for (iDomain = 0; iDomain < nDomain; iDomain++) { + + /*--- Wait for the non-blocking sends to complete. ---*/ + +#ifdef HAVE_MPI + if ((unsigned long)rank != iDomain) SU2_MPI::Waitall(13, send_req, send_stat); + MPI_Barrier(MPI_COMM_WORLD); +#endif + //cout << " ==== Rank " << rank << " finished sending counts " << endl; + + + } + + for (iDomain = 0; iDomain < nDomain; iDomain++) { + + + /*--- Above was number of elements to send and receive, and here is where + we send/recv the actual elements. Here you're sending global index values, + which are later changed to local. ---*/ + + /*--- Set the value of the interior geometry. Initialize counters. ---*/ + + iElemTotal = 0; + iPointTotal = 0; + iPointDomain = 0; + iPointPeriodic = nPointDomainTotal_s[iDomain]; + iPointGhost = nPointDomainTotal_s[iDomain] + nPointPeriodic_s[iDomain]; + iElemTriangle = 0; + iElemQuadrilateral = 0; + iElemTetrahedron = 0; + iElemHexahedron = 0; + iElemPrism = 0; + iElemPyramid = 0; + + /*--- Initialize the global to local mapping ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) PointIn[iPoint] = false; + + /*--- Load up the actual elements into the buffers for sending. ---*/ + + for (iElem = 0; iElem < geometry->no_of_local_elements; iElem++) { + + /*--- Check if the element belongs to the domain ---*/ + + ElemIn[iElem] = false; + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { + iPoint = geometry->elem[iElem]->GetNode(iNode); + if (local_colour_values[iPoint] == iDomain) { + ElemIn[iElem] = true; break; + } + } + + /*--- If this element should be sent ---*/ + + if (ElemIn[iElem]) { + + /*--- We need to send this element, so add it to the send buffer. The + local to global mapping has already been done as a class data member. ---*/ + + Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal] = Local_to_global_elem[iElem]; + + /*--- Loop through the nodes of the current element ---*/ + + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { + + /*--- Get the global index for this node in the element ---*/ + iPoint = geometry->elem[iElem]->GetNode(iNode); + + /*--- Store the connectivity for this element for each node ---*/ + vnodes_local[iNode] = iPoint; + + /*--- Check if this point has been found previously ---*/ + + if (PointIn[iPoint] == false) { + + /*--- Check if this node lives on the current rank based on the + initial linear partitioning. We are only ever sending nodes that + we own in the linear partitioning (no duplicate nodes are sent) ---*/ + + if ((iPoint >= geometry->starting_node[rank]) && + (iPoint < geometry->ending_node[rank])) { + + /*--- Decide whether this is an interior, periodic, or ghost node ---*/ + + if (local_colour_values[iPoint] == iDomain) { + + /*--- If iDomain owns the point, it must be either an interior + node (iPoint < nPointDomain) or a periodic node. ---*/ + + if (iPoint > geometry->GetnPointDomain() - 1) + iPointCurrent = iPointPeriodic; + else + iPointCurrent = iPointDomain; + + } else { + + /*--- Otherwise, it must be a ghost point for iDomain ---*/ + iPointCurrent = iPointGhost; + + } + + /*--- Setting global to local, the color, and index. ---*/ + + PointIn[iPoint] = true; + + Buffer_Send_Color[PointTotal_Counter+iPointCurrent] = local_colour_values[iPoint]; + Buffer_Send_GlobalPointIndex[PointTotal_Counter+iPointCurrent] = iPoint; + + /*--- Get the coordinates for this point ---*/ + + for (iDim = 0; iDim < nDim_s[iDomain]; iDim++) { + + /*--- iPoint is the global index, but we store everything local + to this rank. So we need to subtract the starting index. All + ranks re-index their points from zero. ---*/ + Buffer_Send_Coord[nDim_s[iDomain]*(PointTotal_Counter+iPointCurrent)+iDim] = geometry->node[iPoint-geometry->starting_node[rank]]->GetCoord(iDim); + } + + /*--- Increment our counters ---*/ + if ( local_colour_values[iPoint] == iDomain ) { + if ( iPoint > geometry->GetnPointDomain() - 1) + iPointPeriodic++; + else + iPointDomain++; + } + else iPointGhost++; + + /*--- Increment the total number of points we're sending ---*/ + iPointTotal++; + + } + } + } + + /*--- Load the connectivity for the current element into the send buffer. + Also store the local to global mapping for the elements. + Note that we are using the vnode_local array we filled above to store + the connectivity. Loop through each element type. ---*/ + + switch(geometry->elem[iElem]->GetVTK_Type()) { + case TRIANGLE: + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) + Buffer_Send_Triangle[3*(ElemTriangle_Counter+iElemTriangle)+iNode] = vnodes_local[iNode]; + Local_to_global_Triangle[ElemTriangle_Counter+iElemTriangle] = Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal]; + iElemTriangle++; break; + case QUADRILATERAL: + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) + Buffer_Send_Quadrilateral[4*(ElemQuadrilateral_Counter+iElemQuadrilateral)+iNode] = vnodes_local[iNode]; + Local_to_global_Quadrilateral[ElemQuadrilateral_Counter+iElemQuadrilateral] =Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal]; + iElemQuadrilateral++; break; + case TETRAHEDRON: + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) + Buffer_Send_Tetrahedron[4*(ElemTetrahedron_Counter+iElemTetrahedron)+iNode] = vnodes_local[iNode]; + Local_to_global_Tetrahedron[ElemTetrahedron_Counter+iElemTetrahedron] =Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal]; + iElemTetrahedron++; break; + case HEXAHEDRON: + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) + Buffer_Send_Hexahedron[8*(ElemHexahedron_Counter+iElemHexahedron)+iNode] = vnodes_local[iNode]; + Local_to_global_Hexahedron[ElemHexahedron_Counter+iElemHexahedron] =Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal]; + iElemHexahedron++; break; + case PRISM: + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) + Buffer_Send_Prism[6*(ElemPrism_Counter+iElemPrism)+iNode] = vnodes_local[iNode]; + Local_to_global_Prism[ElemPrism_Counter+iElemPrism] =Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal]; + iElemPrism++; break; + case PYRAMID: + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) + Buffer_Send_Pyramid[5*(ElemPyramid_Counter+iElemPyramid)+iNode] = vnodes_local[iNode]; + Local_to_global_Pyramid[ElemPyramid_Counter+iElemPyramid] = Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal]; + iElemPyramid++; break; + } + + /*--- Regardless of the type, increment the total count ---*/ + iElemTotal++; + + } + } + + /*--- Send the buffers with the geometrical information ---*/ + + if (iDomain != (unsigned long)rank) { + +#ifdef HAVE_MPI + + /*--- Communicate the coordinates, global index, colors, and element + date to iDomain with non-blocking sends. ---*/ + + SU2_MPI::Isend(&Buffer_Send_Coord[PointTotal_Counter*nDim_s[iDomain]], + nPointTotal_s[iDomain]*nDim_s[iDomain], MPI_DOUBLE, iDomain, + iDomain*16+0, MPI_COMM_WORLD, &send_req[0]); + + SU2_MPI::Isend(&Buffer_Send_GlobalPointIndex[PointTotal_Counter], + nPointTotal_s[iDomain], MPI_UNSIGNED_LONG, iDomain, + iDomain*16+1, MPI_COMM_WORLD, &send_req[1]); + + SU2_MPI::Isend(&Buffer_Send_Color[PointTotal_Counter], + nPointTotal_s[iDomain], MPI_UNSIGNED_LONG, iDomain, + iDomain*16+2, MPI_COMM_WORLD, &send_req[2]); + + SU2_MPI::Isend(&Buffer_Send_Triangle[ElemTriangle_Counter*3], + nElemTriangle_s[iDomain]*3, MPI_UNSIGNED_LONG, iDomain, + iDomain*16+3, MPI_COMM_WORLD, &send_req[3]); + + SU2_MPI::Isend(&Buffer_Send_Quadrilateral[ElemQuadrilateral_Counter*4], + nElemQuadrilateral_s[iDomain]*4, MPI_UNSIGNED_LONG, iDomain, + iDomain*16+4, MPI_COMM_WORLD, &send_req[4]); + + SU2_MPI::Isend(&Buffer_Send_Tetrahedron[ElemTetrahedron_Counter*4], + nElemTetrahedron_s[iDomain]*4, MPI_UNSIGNED_LONG, iDomain, + iDomain*16+5, MPI_COMM_WORLD, &send_req[5]); + + SU2_MPI::Isend(&Buffer_Send_Hexahedron[ElemHexahedron_Counter*8], + nElemHexahedron_s[iDomain]*8, MPI_UNSIGNED_LONG, iDomain, + iDomain*16+6, MPI_COMM_WORLD, &send_req[6]); + + SU2_MPI::Isend(&Buffer_Send_Prism[ElemPrism_Counter*6], + nElemPrism_s[iDomain]*6, MPI_UNSIGNED_LONG, iDomain, + iDomain*16+7, MPI_COMM_WORLD, &send_req[7]); + + SU2_MPI::Isend(&Buffer_Send_Pyramid[ElemPyramid_Counter*5], + nElemPyramid_s[iDomain]*5, MPI_UNSIGNED_LONG, iDomain, + iDomain*16+8, MPI_COMM_WORLD, &send_req[8]); + + SU2_MPI::Isend(&Buffer_Send_GlobElem[ElemTotal_Counter], + nElemTotal_s[iDomain], MPI_UNSIGNED_LONG, iDomain, + iDomain*16+9, MPI_COMM_WORLD, &send_req[9]); + + SU2_MPI::Isend(&Local_to_global_Triangle[ElemTriangle_Counter], + nElemTriangle_s[iDomain], MPI_UNSIGNED_LONG, iDomain, + iDomain*16+10, MPI_COMM_WORLD, &send_req[10]); + + SU2_MPI::Isend(&Local_to_global_Quadrilateral[ElemQuadrilateral_Counter], + nElemQuadrilateral_s[iDomain], MPI_UNSIGNED_LONG, iDomain, + iDomain*16+11, MPI_COMM_WORLD, &send_req[11]); + + SU2_MPI::Isend(&Local_to_global_Tetrahedron[ElemTetrahedron_Counter], + nElemTetrahedron_s[iDomain], MPI_UNSIGNED_LONG, iDomain, + iDomain*16+12, MPI_COMM_WORLD, &send_req[12]); + + SU2_MPI::Isend(&Local_to_global_Hexahedron[ElemHexahedron_Counter], + nElemHexahedron_s[iDomain], MPI_UNSIGNED_LONG, iDomain, + iDomain*16+13, MPI_COMM_WORLD, &send_req[13]); + + SU2_MPI::Isend(&Local_to_global_Prism[ElemPrism_Counter], + nElemPrism_s[iDomain], MPI_UNSIGNED_LONG, iDomain, + iDomain*16+14, MPI_COMM_WORLD, &send_req[14]); + + SU2_MPI::Isend(&Local_to_global_Pyramid[ElemPyramid_Counter], + nElemPyramid_s[iDomain], MPI_UNSIGNED_LONG, iDomain, + iDomain*16+15, MPI_COMM_WORLD, &send_req[15]); + +#endif + + } else { + + /*--- Allocate local memory for the local recv of the elements ---*/ + + Buffer_Receive_Coord_loc = new su2double[nPointTotal_s[iDomain]*nDim_s[iDomain]]; + + Buffer_Receive_GlobalPointIndex_loc = new unsigned long[nPointTotal_s[iDomain]]; + Buffer_Receive_Color_loc = new unsigned long[nPointTotal_s[iDomain]]; + Buffer_Receive_Triangle_loc = new unsigned long[nElemTriangle_s[iDomain]*N_POINTS_TRIANGLE]; + Buffer_Receive_Quadrilateral_loc = new unsigned long[nElemQuadrilateral_s[iDomain]*N_POINTS_QUADRILATERAL]; + Buffer_Receive_Tetrahedron_loc = new unsigned long[nElemTetrahedron_s[iDomain]*N_POINTS_TETRAHEDRON]; + Buffer_Receive_Hexahedron_loc = new unsigned long[nElemHexahedron_s[iDomain]*N_POINTS_HEXAHEDRON]; + Buffer_Receive_Prism_loc = new unsigned long[nElemPrism_s[iDomain]*N_POINTS_PRISM]; + Buffer_Receive_Pyramid_loc = new unsigned long[nElemPyramid_s[iDomain]*N_POINTS_PYRAMID]; + Buffer_Receive_GlobElem_loc = new unsigned long[nElemTotal_s[iDomain]]; + + Buffer_Receive_Triangle_presence_loc = new unsigned long[nElemTriangle_s[iDomain]]; + Buffer_Receive_Quadrilateral_presence_loc = new unsigned long[nElemQuadrilateral_s[iDomain]]; + Buffer_Receive_Tetrahedron_presence_loc = new unsigned long[nElemTetrahedron_s[iDomain]]; + Buffer_Receive_Hexahedron_presence_loc = new unsigned long[nElemHexahedron_s[iDomain]]; + Buffer_Receive_Prism_presence_loc = new unsigned long[nElemPrism_s[iDomain]]; + Buffer_Receive_Pyramid_presence_loc = new unsigned long[nElemPyramid_s[iDomain]]; + + for (iter = 0; iter < nPointTotal_s[iDomain]*nDim_s[iDomain]; iter++) + Buffer_Receive_Coord_loc[iter] = Buffer_Send_Coord[PointTotal_Counter*nDim_s[iDomain]+iter]; + + for (iter = 0; iter < nPointTotal_s[iDomain]; iter++) { + Buffer_Receive_GlobalPointIndex_loc[iter] = Buffer_Send_GlobalPointIndex[PointTotal_Counter+iter]; + Buffer_Receive_Color_loc[iter] = Buffer_Send_Color[PointTotal_Counter+iter]; + } + + for (iter = 0; iter < nElemTriangle_s[iDomain]*N_POINTS_TRIANGLE; iter++) + Buffer_Receive_Triangle_loc[iter] = Buffer_Send_Triangle[ElemTriangle_Counter*N_POINTS_TRIANGLE+iter]; + + for (iter = 0; iter < nElemQuadrilateral_s[iDomain]*N_POINTS_QUADRILATERAL; iter++) + Buffer_Receive_Quadrilateral_loc[iter] = Buffer_Send_Quadrilateral[ElemQuadrilateral_Counter*N_POINTS_QUADRILATERAL+iter]; + + for (iter = 0; iter < nElemTetrahedron_s[iDomain]*N_POINTS_TETRAHEDRON; iter++) + Buffer_Receive_Tetrahedron_loc[iter] = Buffer_Send_Tetrahedron[ElemTetrahedron_Counter*N_POINTS_TETRAHEDRON+iter]; + + for (iter = 0; iter < nElemHexahedron_s[iDomain]*N_POINTS_HEXAHEDRON; iter++) + Buffer_Receive_Hexahedron_loc[iter] = Buffer_Send_Hexahedron[ElemHexahedron_Counter*N_POINTS_HEXAHEDRON+iter]; + + for (iter = 0; iter < nElemPrism_s[iDomain]*N_POINTS_PRISM; iter++) + Buffer_Receive_Prism_loc[iter] = Buffer_Send_Prism[ElemPrism_Counter*N_POINTS_PRISM+iter]; + + for (iter = 0; iter < nElemPyramid_s[iDomain]*N_POINTS_PYRAMID; iter++) + Buffer_Receive_Pyramid_loc[iter] = Buffer_Send_Pyramid[ElemPyramid_Counter*N_POINTS_PYRAMID+iter]; + + for (unsigned long i=0; i geometry->GetnPointDomain() - 1) { + + /*--- Set the starting point for the local index of the recv points. + The temp_node_count increments for the interior nodes, between 0 up + to nPointDomain-1. ---*/ + index = temp_node_count_periodic; + + /*--- Get the global index ---*/ + Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex[iPoint]; + + /*--- Allocating the Point object ---*/ + if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0], + Buffer_Receive_Coord[iPoint*nDim+1], + Local_to_Global_Point[index], config); + if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0], + Buffer_Receive_Coord[iPoint*nDim+1], + Buffer_Receive_Coord[iPoint*nDim+2], + Local_to_Global_Point[index], config); + + /*--- Set the color ---*/ + node[index]->SetColor(Buffer_Receive_Color[iPoint]); + + /*--- Increment the interior node counter ---*/ + temp_node_count_periodic++; + + + } + + else { + + + /*--- Set the starting point for the local index of the recv points. + The temp_node_count increments for the interior nodes, between 0 up + to nPointDomain-1. ---*/ + index = temp_node_count; + + /*--- Get the global index ---*/ + Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex[iPoint]; + + /*--- Allocating the Point object ---*/ + if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0], + Buffer_Receive_Coord[iPoint*nDim+1], + Local_to_Global_Point[index], config); + if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0], + Buffer_Receive_Coord[iPoint*nDim+1], + Buffer_Receive_Coord[iPoint*nDim+2], + Local_to_Global_Point[index], config); + + /*--- Set the color ---*/ + node[index]->SetColor(Buffer_Receive_Color[iPoint]); + + /*--- Increment the interior node counter ---*/ + temp_node_count++; + + + + + } + + + } else { + + /*--- Set the starting point for the local index of the recv points. + The temp_node_count_domain increments for the ghost nodes, between + nPointDomain up to nPoint. ---*/ + + index=temp_node_count_ghost; + + /*--- Get the global index ---*/ + Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex[iPoint]; + + /*--- Allocating the Point object ---*/ + if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0], + Buffer_Receive_Coord[iPoint*nDim+1], + Local_to_Global_Point[index], config); + if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0], + Buffer_Receive_Coord[iPoint*nDim+1], + Buffer_Receive_Coord[iPoint*nDim+2], + Local_to_Global_Point[index], config); + + /*--- Set the color ---*/ + node[index]->SetColor(Buffer_Receive_Color[iPoint]); + + /*--- Increment the ghost node counter ---*/ + temp_node_count_ghost++; + + } + } + + /*--- Delete memory for recv the point stuff ---*/ + delete [] Buffer_Receive_Coord; + delete [] Buffer_Receive_Color; + delete [] Buffer_Receive_GlobalPointIndex; + +#endif + + } else { + + /*--- Recv the point data from ourselves (same procedure as above) ---*/ + + unsigned long index = 0; + for (iPoint = 0; iPoint < nPointTotal_r[iDomain]; iPoint++) { + + if (Buffer_Receive_Color_loc[iPoint] == (unsigned long)rank) { + + /*--- If iDomain owns the point, it must be either an interior + node (iPoint < nPointDomain) or a periodic node. ---*/ + + if (Buffer_Receive_GlobalPointIndex_loc[iPoint] > geometry->GetnPointDomain() - 1) { + + index = temp_node_count_periodic; + + Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex_loc[iPoint]; + if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0], + Buffer_Receive_Coord_loc[iPoint*nDim+1], + Local_to_Global_Point[index], config); + if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0], + Buffer_Receive_Coord_loc[iPoint*nDim+1], + Buffer_Receive_Coord_loc[iPoint*nDim+2], + Local_to_Global_Point[index], config); + node[index]->SetColor(Buffer_Receive_Color_loc[iPoint]); + temp_node_count_periodic++; + + + + + } + else { + + index = temp_node_count; + Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex_loc[iPoint]; + if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0], + Buffer_Receive_Coord_loc[iPoint*nDim+1], + Local_to_Global_Point[index], config); + if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0], + Buffer_Receive_Coord_loc[iPoint*nDim+1], + Buffer_Receive_Coord_loc[iPoint*nDim+2], + Local_to_Global_Point[index], config); + node[index]->SetColor(Buffer_Receive_Color_loc[iPoint]); + temp_node_count++; + + + + } + + + } else{ + + index=temp_node_count_ghost; + Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex_loc[iPoint]; + if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0], + Buffer_Receive_Coord_loc[iPoint*nDim+1], + Local_to_Global_Point[index], config); + if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0], + Buffer_Receive_Coord_loc[iPoint*nDim+1], + Buffer_Receive_Coord_loc[iPoint*nDim+2], + Local_to_Global_Point[index], config); + node[index]->SetColor(Buffer_Receive_Color_loc[iPoint]); + temp_node_count_ghost++; + + } + } + + delete [] Buffer_Receive_Coord_loc; + delete [] Buffer_Receive_Color_loc; + delete [] Buffer_Receive_GlobalPointIndex_loc; + + } + } + + /*--- Get the global to local mapping ---*/ + + for (iPoint = 0; iPoint < nPointTotal_r_tot; iPoint++) { + Global_to_local_Point_recv[Local_to_Global_Point[iPoint]] = iPoint; + } + + + //cout << " ==== Rank " << rank << " recv of point data finished" << endl; +#ifdef HAVE_MPI + MPI_Barrier(MPI_COMM_WORLD); +#endif + /*--- Recv all of the element data. First decide which elements we need to own on each proc ---*/ + + iElem = 0; + for (iDomain = 0; iDomain < (unsigned long)size; iDomain++) { + + if ((unsigned long)rank != iDomain) { + +#ifdef HAVE_MPI + + /*--- Allocate memory for the element recv ---*/ + + Buffer_Receive_Triangle_presence[iDomain] = new unsigned long[nElemTriangle_r[iDomain]]; + Buffer_Receive_Quadrilateral_presence[iDomain] = new unsigned long[nElemQuadrilateral_r[iDomain]]; + Buffer_Receive_Tetrahedron_presence[iDomain] = new unsigned long[nElemTetrahedron_r[iDomain]]; + Buffer_Receive_Hexahedron_presence[iDomain] = new unsigned long[nElemHexahedron_r[iDomain]]; + Buffer_Receive_Prism_presence[iDomain] = new unsigned long[nElemPrism_r[iDomain]]; + Buffer_Receive_Pyramid_presence[iDomain] = new unsigned long[nElemPyramid_r[iDomain]]; + + /*--- Recv the element data ---*/ + + MPI_Probe(iDomain, rank*16+10, MPI_COMM_WORLD, &status2); + source = status2.MPI_SOURCE; + MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(&Buffer_Receive_Triangle_presence[iDomain][0], + recv_count, MPI_UNSIGNED_LONG, source, + rank*16+10, MPI_COMM_WORLD, &status2); + + MPI_Probe(iDomain, rank*16+11, MPI_COMM_WORLD, &status2); + source = status2.MPI_SOURCE; + MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(&Buffer_Receive_Quadrilateral_presence[iDomain][0], + recv_count, MPI_UNSIGNED_LONG, source, + rank*16+11, MPI_COMM_WORLD, &status2); + + MPI_Probe(iDomain, rank*16+12, MPI_COMM_WORLD, &status2); + source = status2.MPI_SOURCE; + MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(&Buffer_Receive_Tetrahedron_presence[iDomain][0], + recv_count, MPI_UNSIGNED_LONG, source, + rank*16+12, MPI_COMM_WORLD, &status2); + + MPI_Probe(iDomain, rank*16+13, MPI_COMM_WORLD, &status2); + source = status2.MPI_SOURCE; + MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(&Buffer_Receive_Hexahedron_presence[iDomain][0], + recv_count, MPI_UNSIGNED_LONG, source, + rank*16+13, MPI_COMM_WORLD, &status2); + + MPI_Probe(iDomain, rank*16+14, MPI_COMM_WORLD, &status2); + source = status2.MPI_SOURCE; + MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(&Buffer_Receive_Prism_presence[iDomain][0], + recv_count, MPI_UNSIGNED_LONG, source, + rank*16+14, MPI_COMM_WORLD, &status2); + + MPI_Probe(iDomain, rank*16+15, MPI_COMM_WORLD, &status2); + source = status2.MPI_SOURCE; + MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(&Buffer_Receive_Pyramid_presence[iDomain][0], + recv_count, MPI_UNSIGNED_LONG, source, + rank*16+15, MPI_COMM_WORLD, &status2); + + /*--- Wait to complete the above sends ---*/ + + //if (rank!=iDomain) SU2_MPI::Waitall(6, &send_req[10], &send_stat[10]); + + /*--- Allocating the elements after the recv ---*/ + + for (iElemTriangle = 0; iElemTriangle < nElemTriangle_r[iDomain]; iElemTriangle++) { + if (Triangle_presence[Buffer_Receive_Triangle_presence[iDomain][iElemTriangle]] == false) { + Triangle_presence[Buffer_Receive_Triangle_presence[iDomain][iElemTriangle]] = true; + iElem++; + } + } + + for (iElemQuadrilateral = 0; iElemQuadrilateral < nElemQuadrilateral_r[iDomain]; iElemQuadrilateral++) { + if (Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence[iDomain][iElemQuadrilateral]] == false) { + Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence[iDomain][iElemQuadrilateral]] = true; + iElem++; + } + } + + for (iElemTetrahedron = 0; iElemTetrahedron < nElemTetrahedron_r[iDomain]; iElemTetrahedron++) { + if (Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence[iDomain][iElemTetrahedron]] == false) { + Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence[iDomain][iElemTetrahedron]] = true; + iElem++; + } + } + + for (iElemHexahedron = 0; iElemHexahedron < nElemHexahedron_r[iDomain]; iElemHexahedron++) { + if (Hexahedron_presence[Buffer_Receive_Hexahedron_presence[iDomain][iElemHexahedron]] == false) { + Hexahedron_presence[Buffer_Receive_Hexahedron_presence[iDomain][iElemHexahedron]] = true; + iElem++; + } + } + + for (iElemPrism = 0; iElemPrism < nElemPrism_r[iDomain]; iElemPrism++) { + if (Prism_presence[Buffer_Receive_Prism_presence[iDomain][iElemPrism]] == false) { + Prism_presence[Buffer_Receive_Prism_presence[iDomain][iElemPrism]] = true; + iElem++; + } + } + + for (iElemPyramid = 0; iElemPyramid < nElemPyramid_r[iDomain]; iElemPyramid++) { + if (Pyramid_presence[Buffer_Receive_Pyramid_presence[iDomain][iElemPyramid]] == false) { + Pyramid_presence[Buffer_Receive_Pyramid_presence[iDomain][iElemPyramid]] = true; + iElem++; + } + } + +#endif + + } else { + + /*--- Store the element data from our own local rank info ---*/ + + for (iElemTriangle = 0; iElemTriangle < nElemTriangle_r[iDomain]; iElemTriangle++) { + if (Triangle_presence[Buffer_Receive_Triangle_presence_loc[iElemTriangle]] == false) { + Triangle_presence[Buffer_Receive_Triangle_presence_loc[iElemTriangle]] = true; + iElem++; + } + } + + for (iElemQuadrilateral = 0; iElemQuadrilateral < nElemQuadrilateral_r[iDomain]; iElemQuadrilateral++) { + if (Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence_loc[iElemQuadrilateral]] == false) { + Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence_loc[iElemQuadrilateral]] = true; + iElem++; + } + } + + for (iElemTetrahedron = 0; iElemTetrahedron < nElemTetrahedron_r[iDomain]; iElemTetrahedron++) { + if (Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence_loc[iElemTetrahedron]] == false) { + Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence_loc[iElemTetrahedron]] = true; + iElem++; + } + } + + for (iElemHexahedron = 0; iElemHexahedron < nElemHexahedron_r[iDomain]; iElemHexahedron++) { + if (Hexahedron_presence[Buffer_Receive_Hexahedron_presence_loc[iElemHexahedron]] == false) { + Hexahedron_presence[Buffer_Receive_Hexahedron_presence_loc[iElemHexahedron]] = true; + iElem++; + } + } + + for (iElemPrism = 0; iElemPrism < nElemPrism_r[iDomain]; iElemPrism++) { + if (Prism_presence[Buffer_Receive_Prism_presence_loc[iElemPrism]] == false) { + Prism_presence[Buffer_Receive_Prism_presence_loc[iElemPrism]] = true; + iElem++; + } + } + + for (iElemPyramid = 0; iElemPyramid < nElemPyramid_r[iDomain]; iElemPyramid++) { + if (Pyramid_presence[Buffer_Receive_Pyramid_presence_loc[iElemPyramid]] == false) { + Pyramid_presence[Buffer_Receive_Pyramid_presence_loc[iElemPyramid]] = true; + iElem++; + } + } + + } + } + +#ifdef HAVE_MPI + MPI_Barrier(MPI_COMM_WORLD); +#endif + + /*--- iElem now contains the number of elements that this processor needs in + total. Now we can complete the recv of the element connectivity and only + store the elements that we need on this particular rank. Initialize space + for the elements on this rank. ---*/ + + nElem = iElem; iElem = 0; + elem = new CPrimalGrid*[nElem]; + unsigned long iElemTria = 0; + unsigned long iElemRect = 0; + unsigned long iElemTetr = 0; + unsigned long iElemHexa = 0; + unsigned long iElemPris = 0; + unsigned long iElemPyra = 0; + + /*--- Reset presence before storing elems now that we know nElem ---*/ + + for (unsigned long i = 0; i < geometry->GetnElem(); i++) { + Element_presence[i] = false; + Triangle_presence[i] = false; + Quadrilateral_presence[i] = false; + Tetrahedron_presence[i] = false; + Hexahedron_presence[i] = false; + Prism_presence[i] = false; + Pyramid_presence[i] = false; + } + + /*--- Now recv all of the element connectivity data ---*/ + + for (iDomain = 0; iDomain < (unsigned long)size; iDomain++) { + + if ((unsigned long)rank != iDomain) { + +#ifdef HAVE_MPI + + /*--- Allocate memory for the element recv ---*/ + + Buffer_Receive_Triangle = new unsigned long[nElemTriangle_r[iDomain]*N_POINTS_TRIANGLE]; + Buffer_Receive_Quadrilateral = new unsigned long[nElemQuadrilateral_r[iDomain]*N_POINTS_QUADRILATERAL]; + Buffer_Receive_Tetrahedron = new unsigned long[nElemTetrahedron_r[iDomain]*N_POINTS_TETRAHEDRON]; + Buffer_Receive_Hexahedron = new unsigned long[nElemHexahedron_r[iDomain]*N_POINTS_HEXAHEDRON]; + Buffer_Receive_Prism = new unsigned long[nElemPrism_r[iDomain]*N_POINTS_PRISM]; + Buffer_Receive_Pyramid = new unsigned long[nElemPyramid_r[iDomain]*N_POINTS_PYRAMID]; + Buffer_Receive_GlobElem = new unsigned long[nElemTotal_r[iDomain]]; + + /*--- Recv the element data ---*/ + + MPI_Probe(iDomain, rank*16+3, MPI_COMM_WORLD, &status2); + source = status2.MPI_SOURCE; + MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(Buffer_Receive_Triangle, recv_count, MPI_UNSIGNED_LONG, + source, rank*16+3, MPI_COMM_WORLD, &status2); + + MPI_Probe(iDomain, rank*16+4, MPI_COMM_WORLD, &status2); + source = status2.MPI_SOURCE; + MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(Buffer_Receive_Quadrilateral, recv_count, MPI_UNSIGNED_LONG, + source, rank*16+4, MPI_COMM_WORLD, &status2); + + MPI_Probe(iDomain, rank*16+5, MPI_COMM_WORLD, &status2); + source = status2.MPI_SOURCE; + MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(Buffer_Receive_Tetrahedron, recv_count, MPI_UNSIGNED_LONG, + source, rank*16+5, MPI_COMM_WORLD, &status2); + + MPI_Probe(iDomain, rank*16+6, MPI_COMM_WORLD, &status2); + source = status2.MPI_SOURCE; + MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(Buffer_Receive_Hexahedron, recv_count, MPI_UNSIGNED_LONG, + source, rank*16+6, MPI_COMM_WORLD, &status2); + + MPI_Probe(iDomain, rank*16+7, MPI_COMM_WORLD, &status2); + source = status2.MPI_SOURCE; + MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(Buffer_Receive_Prism, recv_count, MPI_UNSIGNED_LONG, + source, rank*16+7, MPI_COMM_WORLD, &status2); + + MPI_Probe(iDomain, rank*16+8, MPI_COMM_WORLD, &status2); + source = status2.MPI_SOURCE; + MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(Buffer_Receive_Pyramid, recv_count, MPI_UNSIGNED_LONG, + source, rank*16+8, MPI_COMM_WORLD, &status2); + + MPI_Probe(iDomain, rank*16+9, MPI_COMM_WORLD, &status2); + source = status2.MPI_SOURCE; + MPI_Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(Buffer_Receive_GlobElem, recv_count, MPI_UNSIGNED_LONG, + source, rank*16+9, MPI_COMM_WORLD, &status2); + + /*--- Wait to complete the above sends ---*/ + + //if (rank!=iDomain) SU2_MPI::Waitall(7, &send_req[3], &send_stat[3]); + //cout << " ==== Rank " << rank << " recv from " << iDomain << " would be waiting here... " << endl; + + /*--- Allocating the elements after the recv. Note that here we are + reusing the presence arrays to make sure that we find the exact same + set of elements that were counted above to get nElem. ---*/ + + for (iElemTriangle = 0; iElemTriangle < nElemTriangle_r[iDomain]; iElemTriangle++) { + if (Triangle_presence[Buffer_Receive_Triangle_presence[iDomain][iElemTriangle]] == false) { + Triangle_presence[Buffer_Receive_Triangle_presence[iDomain][iElemTriangle]] = true; + elem[iElem] = new CTriangle(Global_to_local_Point_recv[Buffer_Receive_Triangle[iElemTriangle*3+0]], + Global_to_local_Point_recv[Buffer_Receive_Triangle[iElemTriangle*3+1]], + Global_to_local_Point_recv[Buffer_Receive_Triangle[iElemTriangle*3+2]], 2); + iElem++; iElemTria++; + } + } + + for (iElemQuadrilateral = 0; iElemQuadrilateral < nElemQuadrilateral_r[iDomain]; iElemQuadrilateral++) { + if (Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence[iDomain][iElemQuadrilateral]] == false) { + Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence[iDomain][iElemQuadrilateral]] = true; + elem[iElem] = new CQuadrilateral(Global_to_local_Point_recv[Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+0]], + Global_to_local_Point_recv[Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+1]], + Global_to_local_Point_recv[Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+2]], + Global_to_local_Point_recv[Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+3]], 2); + iElem++; iElemRect++; + } + } + + for (iElemTetrahedron = 0; iElemTetrahedron < nElemTetrahedron_r[iDomain]; iElemTetrahedron++) { + if (Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence[iDomain][iElemTetrahedron]] == false) { + Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence[iDomain][iElemTetrahedron]] = true; + elem[iElem] = new CTetrahedron(Global_to_local_Point_recv[Buffer_Receive_Tetrahedron[iElemTetrahedron*4+0]], + Global_to_local_Point_recv[Buffer_Receive_Tetrahedron[iElemTetrahedron*4+1]], + Global_to_local_Point_recv[Buffer_Receive_Tetrahedron[iElemTetrahedron*4+2]], + Global_to_local_Point_recv[Buffer_Receive_Tetrahedron[iElemTetrahedron*4+3]]); + iElem++; iElemTetr++; + } + } + + for (iElemHexahedron = 0; iElemHexahedron < nElemHexahedron_r[iDomain]; iElemHexahedron++) { + if (Hexahedron_presence[Buffer_Receive_Hexahedron_presence[iDomain][iElemHexahedron]] == false) { + Hexahedron_presence[Buffer_Receive_Hexahedron_presence[iDomain][iElemHexahedron]] = true; + elem[iElem] = new CHexahedron(Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+0]], + Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+1]], + Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+2]], + Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+3]], + Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+4]], + Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+5]], + Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+6]], + Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+7]]); + iElem++; iElemHexa++; + } + } + + for (iElemPrism = 0; iElemPrism < nElemPrism_r[iDomain]; iElemPrism++) { + if (Prism_presence[Buffer_Receive_Prism_presence[iDomain][iElemPrism]] == false) { + Prism_presence[Buffer_Receive_Prism_presence[iDomain][iElemPrism]] = true; + elem[iElem] = new CPrism(Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+0]], + Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+1]], + Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+2]], + Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+3]], + Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+4]], + Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+5]]); + iElem++; iElemPris++; + } + } + + for (iElemPyramid = 0; iElemPyramid < nElemPyramid_r[iDomain]; iElemPyramid++) { + if (Pyramid_presence[Buffer_Receive_Pyramid_presence[iDomain][iElemPyramid]] == false ) { + Pyramid_presence[Buffer_Receive_Pyramid_presence[iDomain][iElemPyramid]] = true; + elem[iElem] = new CPyramid(Global_to_local_Point_recv[Buffer_Receive_Pyramid[iElemPyramid*5+0]], + Global_to_local_Point_recv[Buffer_Receive_Pyramid[iElemPyramid*5+1]], + Global_to_local_Point_recv[Buffer_Receive_Pyramid[iElemPyramid*5+2]], + Global_to_local_Point_recv[Buffer_Receive_Pyramid[iElemPyramid*5+3]], + Global_to_local_Point_recv[Buffer_Receive_Pyramid[iElemPyramid*5+4]]); + iElem++; iElemPyra++; + } + } + + /*--- Free memory for the element data --*/ + + delete[] Buffer_Receive_Triangle; + delete[] Buffer_Receive_Quadrilateral; + delete[] Buffer_Receive_Tetrahedron; + delete[] Buffer_Receive_Hexahedron; + delete[] Buffer_Receive_Prism; + delete[] Buffer_Receive_Pyramid; + + delete[] Buffer_Receive_Triangle_presence[iDomain]; + delete[] Buffer_Receive_Quadrilateral_presence[iDomain]; + delete[] Buffer_Receive_Tetrahedron_presence[iDomain]; + delete[] Buffer_Receive_Hexahedron_presence[iDomain]; + delete[] Buffer_Receive_Prism_presence[iDomain]; + delete[] Buffer_Receive_Pyramid_presence[iDomain]; + +#endif + + } else { + + /*--- Store the element data from our local rank ---*/ + + for (iElemTriangle = 0; iElemTriangle < nElemTriangle_r[iDomain]; iElemTriangle++) { + if (Triangle_presence[Buffer_Receive_Triangle_presence_loc[iElemTriangle]] == false ) { + Triangle_presence[Buffer_Receive_Triangle_presence_loc[iElemTriangle]] = true; + elem[iElem] = new CTriangle(Global_to_local_Point_recv[Buffer_Receive_Triangle_loc[iElemTriangle*3+0]], + Global_to_local_Point_recv[Buffer_Receive_Triangle_loc[iElemTriangle*3+1]], + Global_to_local_Point_recv[Buffer_Receive_Triangle_loc[iElemTriangle*3+2]], 2); + iElem++; iElemTria++; + } + } + + for (iElemQuadrilateral = 0; iElemQuadrilateral < nElemQuadrilateral_r[iDomain]; iElemQuadrilateral++) { + if (Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence_loc[iElemQuadrilateral]] == false) { + Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence_loc[iElemQuadrilateral]] = true; + elem[iElem] = new CQuadrilateral(Global_to_local_Point_recv[Buffer_Receive_Quadrilateral_loc[iElemQuadrilateral*4+0]], + Global_to_local_Point_recv[Buffer_Receive_Quadrilateral_loc[iElemQuadrilateral*4+1]], + Global_to_local_Point_recv[Buffer_Receive_Quadrilateral_loc[iElemQuadrilateral*4+2]], + Global_to_local_Point_recv[Buffer_Receive_Quadrilateral_loc[iElemQuadrilateral*4+3]], 2); + iElem++; iElemRect++; + } + } + + for (iElemTetrahedron = 0; iElemTetrahedron < nElemTetrahedron_r[iDomain]; iElemTetrahedron++) { + if (Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence_loc[iElemTetrahedron]] == false) { + Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence_loc[iElemTetrahedron]] = true; + elem[iElem] = new CTetrahedron(Global_to_local_Point_recv[Buffer_Receive_Tetrahedron_loc[iElemTetrahedron*4+0]], + Global_to_local_Point_recv[Buffer_Receive_Tetrahedron_loc[iElemTetrahedron*4+1]], + Global_to_local_Point_recv[Buffer_Receive_Tetrahedron_loc[iElemTetrahedron*4+2]], + Global_to_local_Point_recv[Buffer_Receive_Tetrahedron_loc[iElemTetrahedron*4+3]]); + iElem++; iElemTetr++; + } + } + + for (iElemHexahedron = 0; iElemHexahedron < nElemHexahedron_r[iDomain]; iElemHexahedron++) { + if (Hexahedron_presence[Buffer_Receive_Hexahedron_presence_loc[iElemHexahedron]] == false) { + Hexahedron_presence[Buffer_Receive_Hexahedron_presence_loc[iElemHexahedron]] = true; + elem[iElem] = new CHexahedron(Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+0]], + Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+1]], + Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+2]], + Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+3]], + Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+4]], + Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+5]], + Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+6]], + Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+7]]); + iElem++; iElemHexa++; + } + } + + for (iElemPrism = 0; iElemPrism < nElemPrism_r[iDomain]; iElemPrism++) { + if (Prism_presence[Buffer_Receive_Prism_presence_loc[iElemPrism]] == false) { + Prism_presence[Buffer_Receive_Prism_presence_loc[iElemPrism]] = true; + elem[iElem] = new CPrism(Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+0]], + Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+1]], + Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+2]], + Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+3]], + Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+4]], + Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+5]]); + iElem++; iElemPris++; + } + } + + for (iElemPyramid = 0; iElemPyramid < nElemPyramid_r[iDomain]; iElemPyramid++) { + if (Pyramid_presence[Buffer_Receive_Pyramid_presence_loc[iElemPyramid]] == false) { + Pyramid_presence[Buffer_Receive_Pyramid_presence_loc[iElemPyramid]] = true; + elem[iElem] = new CPyramid(Global_to_local_Point_recv[Buffer_Receive_Pyramid_loc[iElemPyramid*5+0]], + Global_to_local_Point_recv[Buffer_Receive_Pyramid_loc[iElemPyramid*5+1]], + Global_to_local_Point_recv[Buffer_Receive_Pyramid_loc[iElemPyramid*5+2]], + Global_to_local_Point_recv[Buffer_Receive_Pyramid_loc[iElemPyramid*5+3]], + Global_to_local_Point_recv[Buffer_Receive_Pyramid_loc[iElemPyramid*5+4]]); + iElem++; iElemPyra++; + } + } + + /*--- Free memory for element data ---*/ + + delete[] Buffer_Receive_Triangle_loc; + delete[] Buffer_Receive_Quadrilateral_loc; + delete[] Buffer_Receive_Tetrahedron_loc; + delete[] Buffer_Receive_Hexahedron_loc; + delete[] Buffer_Receive_Prism_loc; + delete[] Buffer_Receive_Pyramid_loc; + + delete[] Buffer_Receive_Triangle_presence_loc; + delete[] Buffer_Receive_Quadrilateral_presence_loc; + delete[] Buffer_Receive_Tetrahedron_presence_loc; + delete[] Buffer_Receive_Hexahedron_presence_loc; + delete[] Buffer_Receive_Prism_presence_loc; + delete[] Buffer_Receive_Pyramid_presence_loc; + + } + } + +#ifdef HAVE_MPI + for (iDomain = 0; iDomain < (unsigned long)size; iDomain++) { + if ((unsigned long)rank != iDomain) SU2_MPI::Waitall(16, send_req, send_stat); + } + MPI_Barrier(MPI_COMM_WORLD); +#endif + + /*--- Free all of the memory used for communicating points and elements ---*/ + + delete[] Buffer_Send_Coord; + delete[] Buffer_Send_GlobalPointIndex; + delete[] Buffer_Send_Color; + delete[] Buffer_Send_Triangle; + delete[] Buffer_Send_Quadrilateral; + delete[] Buffer_Send_Tetrahedron; + delete[] Buffer_Send_Hexahedron; + delete[] Buffer_Send_Prism; + delete[] Buffer_Send_Pyramid; + delete[] Buffer_Send_BoundLine; + delete[] Buffer_Send_BoundTriangle; + delete[] Buffer_Send_BoundQuadrilateral; + delete[] Buffer_Send_Local2Global_Marker; + + delete[] Buffer_Send_SendDomain_Periodic; + delete[] Buffer_Send_SendDomain_PeriodicTrans; + delete[] Buffer_Send_SendDomain_PeriodicReceptor; + delete[] Buffer_Send_ReceivedDomain_Periodic; + delete[] Buffer_Send_ReceivedDomain_PeriodicTrans; + delete[] Buffer_Send_ReceivedDomain_PeriodicDonor; + + delete[] Local_to_global_Triangle; + delete[] Local_to_global_Quadrilateral; + delete[] Local_to_global_Tetrahedron; + delete[] Local_to_global_Hexahedron; + delete[] Local_to_global_Prism; + delete[] Local_to_global_Pyramid; + + + /*--- Communicate the number of each element type to all processors. These + values are important for merging and writing output later. ---*/ + +#ifdef HAVE_MPI + unsigned long Local_nElem = nElem; + SU2_MPI::Allreduce(&Local_nElem, &Global_nElem, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); +#else + Global_nElem = nElem; +#endif + + if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) + cout << Global_nElem << " interior elements including halo cells. " << endl; + + /*--- Store total number of each element type after incrementing the + counters in the recv loop above (to make sure there aren't repeats). ---*/ + + nelem_triangle = iElemTria; + nelem_quad = iElemRect; + nelem_tetra = iElemTetr; + nelem_hexa = iElemHexa; + nelem_prism = iElemPris; + nelem_pyramid = iElemPyra; + +#ifdef HAVE_MPI + unsigned long Local_nElemTri = nelem_triangle; + unsigned long Local_nElemQuad = nelem_quad; + unsigned long Local_nElemTet = nelem_tetra; + unsigned long Local_nElemHex = nelem_hexa; + unsigned long Local_nElemPrism = nelem_prism; + unsigned long Local_nElemPyramid = nelem_pyramid; + SU2_MPI::Allreduce(&Local_nElemTri, &Global_nelem_triangle, 1, + MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&Local_nElemQuad, &Global_nelem_quad, 1, + MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&Local_nElemTet, &Global_nelem_tetra, 1, + MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&Local_nElemHex, &Global_nelem_hexa, 1, + MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&Local_nElemPrism, &Global_nelem_prism, 1, + MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&Local_nElemPyramid, &Global_nelem_pyramid, 1, + MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); +#else + Global_nelem_triangle = nelem_triangle; + Global_nelem_quad = nelem_quad; + Global_nelem_tetra = nelem_tetra; + Global_nelem_hexa = nelem_hexa; + Global_nelem_prism = nelem_prism; + Global_nelem_pyramid = nelem_pyramid; +#endif + + /*--- Print information about the elements to the console ---*/ + + if (rank == MASTER_NODE) { + if (Global_nelem_triangle > 0) cout << Global_nelem_triangle << " triangles." << endl; + if (Global_nelem_quad > 0) cout << Global_nelem_quad << " quadrilaterals." << endl; + if (Global_nelem_tetra > 0) cout << Global_nelem_tetra << " tetrahedra." << endl; + if (Global_nelem_hexa > 0) cout << Global_nelem_hexa << " hexahedra." << endl; + if (Global_nelem_prism > 0) cout << Global_nelem_prism << " prisms." << endl; + if (Global_nelem_pyramid > 0) cout << Global_nelem_pyramid << " pyramids." << endl; + } + + delete [] Triangle_presence; + delete [] Quadrilateral_presence; + delete [] Tetrahedron_presence; + delete [] Hexahedron_presence; + delete [] Prism_presence; + delete [] Pyramid_presence; + + /*--- Now partition the boundary elements on the markers. Note that, for + now, we are still performing the boundary partitioning using the master + node alone. The boundaries should make up a much smaller portion of the + mesh, so this is ok for now, but we will transition to a parallel version + of this soon that follows the same procedure above for the interior. ---*/ + + if (rank == MASTER_NODE) { + + /*--- Create auxiliary vectors based on the original geometry ---*/ + + MarkerIn = new bool[geometry->GetnMarker()]; + VertexIn = new bool*[geometry->GetnMarker()]; + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) + VertexIn[iMarker] = new bool[geometry->GetnElem_Bound(iMarker)]; + + Buffer_Send_nDim = geometry->GetnDim(); + Buffer_Send_nZone = geometry->GetnZone(); + Buffer_Send_nPeriodic = config->GetnPeriodicIndex(); + Buffer_Send_Center = new su2double[Buffer_Send_nPeriodic*3]; + Buffer_Send_Rotation = new su2double[Buffer_Send_nPeriodic*3]; + Buffer_Send_Translate = new su2double[Buffer_Send_nPeriodic*3]; + + Buffer_Send_nSendDomain_Periodic = new unsigned long[nDomain]; + Buffer_Send_nReceivedDomain_Periodic = new unsigned long[nDomain]; + + /*--- Create a local copy of config->GetMarker_All_SendRecv and + config->GetMarker_All_TagBound in the master node ---*/ + + Marker_All_SendRecv_Copy = new short[geometry->GetnMarker()]; + Marker_All_TagBound_Copy = new string[geometry->GetnMarker()]; + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + Marker_All_SendRecv_Copy[iMarker] = config->GetMarker_All_SendRecv(iMarker); + Marker_All_TagBound_Copy[iMarker] = config->GetMarker_All_TagBound(iMarker); + } + + } + + for (iDomain = 0; iDomain < nDomain; iDomain++) { + + if (rank == MASTER_NODE) { + + /*--- Interior dimensionalization. Loop over the original grid + to perform the dimensionalizaton of the domain variables ---*/ + +// Buffer_Send_nElemTotal = 0; +// Buffer_Send_nPointTotal = 0; +// Buffer_Send_nPointGhost = 0; +// Buffer_Send_nPointDomainTotal = 0; +// Buffer_Send_nPointPeriodic = 0; +// Buffer_Send_nElemTriangle = 0; +// Buffer_Send_nElemQuadrilateral = 0; +// Buffer_Send_nElemTetrahedron = 0; +// Buffer_Send_nElemHexahedron = 0; +// Buffer_Send_nElemPrism = 0; +// Buffer_Send_nElemPyramid = 0; + + /*--- Boundary dimensionalization. Dimensionalization with physical + boundaries, compute Buffer_Send_nMarkerDomain, + Buffer_Send_nVertexDomain[nMarkerDomain] ---*/ + + Buffer_Send_nMarkerDomain = 0; + Buffer_Send_nBoundLineTotal = 0; + Buffer_Send_nBoundTriangleTotal = 0; + Buffer_Send_nBoundQuadrilateralTotal = 0; + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + Buffer_Send_nVertexDomain[iMarker] = 0; + Buffer_Send_nBoundLine[iMarker] = 0; + Buffer_Send_nBoundTriangle[iMarker] = 0; + Buffer_Send_nBoundQuadrilateral[iMarker] = 0; + Buffer_Send_Marker_All_SendRecv[iMarker] = Marker_All_SendRecv_Copy[iMarker]; + SPRINTF(&Buffer_Send_Marker_All_TagBound[iMarker*MAX_STRING_SIZE], "%s", + Marker_All_TagBound_Copy[iMarker].c_str()); + } + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { + + MarkerIn[iMarker] = false; + Buffer_Send_nVertexDomain[Buffer_Send_nMarkerDomain] = 0; + + for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { + VertexIn[iMarker][iVertex] = false; + for (iNode = 0; iNode < geometry->bound[iMarker][iVertex]->GetnNodes(); iNode++) { + iPoint = geometry->bound[iMarker][iVertex]->GetNode(iNode); + if (local_colour_values[iPoint] == iDomain) VertexIn[iMarker][iVertex] = true; + } + + /*--- If this vertex should be sent, increment the element type ---*/ + if (VertexIn[iMarker][iVertex]) { + switch(geometry->bound[iMarker][iVertex]->GetVTK_Type()) { + case LINE: + Buffer_Send_nBoundLine[Buffer_Send_nMarkerDomain]++; + Buffer_Send_nBoundLineTotal++; + break; + case TRIANGLE: + Buffer_Send_nBoundTriangle[Buffer_Send_nMarkerDomain]++; + Buffer_Send_nBoundTriangleTotal++; + break; + case QUADRILATERAL: + Buffer_Send_nBoundQuadrilateral[Buffer_Send_nMarkerDomain]++; + Buffer_Send_nBoundQuadrilateralTotal++; + break; + } + + /*--- Increment the total number of vertices to be sent ---*/ + Buffer_Send_nVertexDomain[Buffer_Send_nMarkerDomain]++; + MarkerIn[iMarker] = true; + + } + } + + /*--- Increment the number of markers to be sent ---*/ + if (MarkerIn[iMarker]) { Buffer_Send_nMarkerDomain++; } + + } + } + + /*--- Copy periodic information from the config file ---*/ + + for (iPeriodic = 0; iPeriodic < Buffer_Send_nPeriodic; iPeriodic++) { + for (iDim = 0; iDim < 3; iDim++) { + Buffer_Send_Center[iDim+iPeriodic*3] = config->GetPeriodicCenter(iPeriodic)[iDim]; + Buffer_Send_Rotation[iDim+iPeriodic*3] = config->GetPeriodicRotation(iPeriodic)[iDim]; + Buffer_Send_Translate[iDim+iPeriodic*3] = config->GetPeriodicTranslate(iPeriodic)[iDim]; + } + } + + /*--- Dimensionalization of the periodic auxiliary vectors ---*/ + + for (jDomain = 0; jDomain < nDomain; jDomain++) { + Buffer_Send_nSendDomain_Periodic[jDomain] = 0; + Buffer_Send_nReceivedDomain_Periodic[jDomain] = 0; + } + Buffer_Send_nTotalSendDomain_Periodic = 0; + Buffer_Send_nTotalReceivedDomain_Periodic = 0; + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { + for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { + iPoint = geometry->bound[iMarker][iVertex]->GetNode(0); + if (iDomain == local_colour_values[iPoint]) { + + if (config->GetMarker_All_SendRecv(iMarker) > 0) { + + /*--- Identify the color of the receptor ---*/ + + for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) { + if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker))) { + jPoint = geometry->bound[jMarker][iVertex]->GetNode(0); + ReceptorColor = local_colour_values[jPoint]; + } + } + + Buffer_Send_nSendDomain_Periodic[ReceptorColor]++; + Buffer_Send_nTotalSendDomain_Periodic++; + + } + if (config->GetMarker_All_SendRecv(iMarker) < 0) { + + /*--- Identify the color of the donor ---*/ + + for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) { + if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker))) { + jPoint = geometry->bound[jMarker][iVertex]->GetNode(0); + DonorColor = local_colour_values[jPoint]; + } + } + + Buffer_Send_nReceivedDomain_Periodic[DonorColor]++; + Buffer_Send_nTotalReceivedDomain_Periodic++; + + } + } + } + } + } + + /*--- Allocate the buffer vectors in the appropiate domain (master, iDomain) ---*/ + + Buffer_Send_BoundLine = new unsigned long[Buffer_Send_nBoundLineTotal*N_POINTS_LINE]; + Buffer_Send_BoundTriangle = new unsigned long[Buffer_Send_nBoundTriangleTotal*N_POINTS_TRIANGLE]; + Buffer_Send_BoundQuadrilateral = new unsigned long[Buffer_Send_nBoundQuadrilateralTotal*N_POINTS_QUADRILATERAL]; + Buffer_Send_Local2Global_Marker = new unsigned long[Buffer_Send_nMarkerDomain]; + + Buffer_Send_SendDomain_Periodic = new unsigned long[Buffer_Send_nTotalSendDomain_Periodic]; + Buffer_Send_SendDomain_PeriodicTrans = new unsigned long[Buffer_Send_nTotalSendDomain_Periodic]; + Buffer_Send_SendDomain_PeriodicReceptor = new unsigned long[Buffer_Send_nTotalSendDomain_Periodic]; + Buffer_Send_ReceivedDomain_Periodic = new unsigned long[Buffer_Send_nTotalReceivedDomain_Periodic]; + Buffer_Send_ReceivedDomain_PeriodicTrans = new unsigned long[Buffer_Send_nTotalReceivedDomain_Periodic]; + Buffer_Send_ReceivedDomain_PeriodicDonor = new unsigned long[Buffer_Send_nTotalReceivedDomain_Periodic]; + + if (iDomain != MASTER_NODE) { + + //cout << " Rank " << rank << " iDomain " << iDomain << endl; + +#ifdef HAVE_MPI + + SU2_MPI::Isend(&Buffer_Send_nBoundLineTotal, 1, + MPI_UNSIGNED_LONG, iDomain, + 0, MPI_COMM_WORLD, &send_req[0]); + + SU2_MPI::Isend(&Buffer_Send_nBoundTriangleTotal, 1, + MPI_UNSIGNED_LONG, iDomain, + 1, MPI_COMM_WORLD, &send_req[1]); + + SU2_MPI::Isend(&Buffer_Send_nBoundQuadrilateralTotal, 1, + MPI_UNSIGNED_LONG, iDomain, + 2, MPI_COMM_WORLD, &send_req[2]); + + SU2_MPI::Isend(&Buffer_Send_nMarkerDomain, 1, + MPI_UNSIGNED_SHORT, iDomain, + 3, MPI_COMM_WORLD, &send_req[3]); + + SU2_MPI::Isend(Buffer_Send_nVertexDomain, + nMarker_Max, MPI_UNSIGNED_LONG, iDomain, + 4, MPI_COMM_WORLD, &send_req[4]); + + SU2_MPI::Isend(Buffer_Send_nBoundLine, + nMarker_Max, MPI_UNSIGNED_LONG, iDomain, + 5, MPI_COMM_WORLD, &send_req[5]); + + SU2_MPI::Isend(Buffer_Send_nBoundTriangle, + nMarker_Max, MPI_UNSIGNED_LONG, iDomain, + 6, MPI_COMM_WORLD, &send_req[6]); + + SU2_MPI::Isend(Buffer_Send_nBoundQuadrilateral, + nMarker_Max, MPI_UNSIGNED_LONG, iDomain, + 7, MPI_COMM_WORLD, &send_req[7]); + + SU2_MPI::Isend(Buffer_Send_Marker_All_SendRecv, + nMarker_Max, MPI_SHORT, iDomain, + 8, MPI_COMM_WORLD, &send_req[8]); + + SU2_MPI::Isend(Buffer_Send_Marker_All_TagBound, + nMarker_Max*MAX_STRING_SIZE, MPI_CHAR, iDomain, + 9, MPI_COMM_WORLD, &send_req[9]); + + SU2_MPI::Isend(&Buffer_Send_nPeriodic, + 1, MPI_UNSIGNED_SHORT, iDomain, + 10, MPI_COMM_WORLD, &send_req[10]); + + SU2_MPI::Isend(Buffer_Send_Center, + nPeriodic*3, MPI_DOUBLE, iDomain, + 11, MPI_COMM_WORLD, &send_req[11]); + + SU2_MPI::Isend(Buffer_Send_Rotation, + nPeriodic*3, MPI_DOUBLE, iDomain, + 12, MPI_COMM_WORLD, &send_req[12]); + + SU2_MPI::Isend(Buffer_Send_Translate, + nPeriodic*3, MPI_DOUBLE, iDomain, + 13, MPI_COMM_WORLD, &send_req[13]); + + SU2_MPI::Isend(&Buffer_Send_nTotalSendDomain_Periodic, + 1, MPI_UNSIGNED_LONG, iDomain, + 14, MPI_COMM_WORLD, &send_req[14]); + + SU2_MPI::Isend(&Buffer_Send_nTotalReceivedDomain_Periodic, + 1, MPI_UNSIGNED_LONG, iDomain, + 15, MPI_COMM_WORLD, &send_req[15]); + + SU2_MPI::Isend(Buffer_Send_nSendDomain_Periodic, + nDomain, MPI_UNSIGNED_LONG, iDomain, + 16, MPI_COMM_WORLD, &send_req[16]); + + SU2_MPI::Isend(Buffer_Send_nReceivedDomain_Periodic, + nDomain, MPI_UNSIGNED_LONG, iDomain, + 17, MPI_COMM_WORLD, &send_req[17]); + + /*--- Wait for this set of non-blocking comm. to complete ---*/ + + SU2_MPI::Waitall(18, send_req, send_stat); + //cout << " Rank " << rank << " iDomain " << iDomain << " just waited for first sends" << endl; + +#endif + + } else { + + /*--- We are the master node, so simply copy values into place ---*/ + + nDim = Buffer_Send_nDim; + nZone = Buffer_Send_nZone; + + nPeriodic = Buffer_Send_nPeriodic; +// nPointGhost = Buffer_Send_nPointGhost; +// nPointPeriodic = Buffer_Send_nPointPeriodic; + + nBoundLineTotal = Buffer_Send_nBoundLineTotal; + nBoundTriangleTotal = Buffer_Send_nBoundTriangleTotal; + nBoundQuadrilateralTotal = Buffer_Send_nBoundQuadrilateralTotal; + nMarkerDomain = Buffer_Send_nMarkerDomain; + + for (iMarker = 0; iMarker < nMarker_Max; iMarker++) { + nVertexDomain[iMarker] = Buffer_Send_nVertexDomain[iMarker]; + nBoundLine[iMarker] = Buffer_Send_nBoundLine[iMarker]; + nBoundTriangle[iMarker] = Buffer_Send_nBoundTriangle[iMarker]; + nBoundQuadrilateral[iMarker] = Buffer_Send_nBoundQuadrilateral[iMarker]; + Marker_All_SendRecv[iMarker] = Buffer_Send_Marker_All_SendRecv[iMarker]; + for (iter = 0; iter < MAX_STRING_SIZE; iter++) + Marker_All_TagBound[iMarker*MAX_STRING_SIZE+iter] = Buffer_Send_Marker_All_TagBound[iMarker*MAX_STRING_SIZE+iter]; + } + + Buffer_Receive_Center = new su2double[nPeriodic*3]; + Buffer_Receive_Rotation = new su2double[nPeriodic*3]; + Buffer_Receive_Translate = new su2double[nPeriodic*3]; + + for (iter = 0; iter < nPeriodic*3; iter++) { + Buffer_Receive_Center[iter] = Buffer_Send_Center[iter]; + Buffer_Receive_Rotation[iter] = Buffer_Send_Rotation[iter]; + Buffer_Receive_Translate[iter] = Buffer_Send_Translate[iter]; + } + + nTotalSendDomain_Periodic = Buffer_Send_nTotalSendDomain_Periodic; + nTotalReceivedDomain_Periodic = Buffer_Send_nTotalReceivedDomain_Periodic; + + for (iter = 0; iter < nDomain; iter++) { + nSendDomain_Periodic[iter] = Buffer_Send_nSendDomain_Periodic[iter]; + nReceivedDomain_Periodic[iter] = Buffer_Send_nReceivedDomain_Periodic[iter]; + } + + } + } + + /*--- Each rank now begins to receive information from the master ---*/ + + if ((unsigned long)rank == iDomain) { + + /*--- First, receive the size of buffers before receiving the data ---*/ + + if (rank != MASTER_NODE) { + +#ifdef HAVE_MPI + + MPI_Probe(MASTER_NODE, 0, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(&nBoundLineTotal, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 0, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 1, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(&nBoundTriangleTotal, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 1, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 2, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(&nBoundQuadrilateralTotal, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 2, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 3, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_SHORT, &recv_count); + SU2_MPI::Recv(&nMarkerDomain, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 3, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 4, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(nVertexDomain, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 4, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 5, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(nBoundLine, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 5, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 6, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(nBoundTriangle, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 6, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 7, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(nBoundQuadrilateral, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 7, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 8, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_SHORT, &recv_count); + SU2_MPI::Recv(Marker_All_SendRecv, recv_count, MPI_SHORT, + MASTER_NODE, 8, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 9, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_CHAR, &recv_count); + SU2_MPI::Recv(Marker_All_TagBound, recv_count, MPI_CHAR, + MASTER_NODE, 9, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 10, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_SHORT, &recv_count); + SU2_MPI::Recv(&nPeriodic, recv_count, MPI_UNSIGNED_SHORT, + MASTER_NODE, 10, MPI_COMM_WORLD, &status); + +#endif + + /*--- Marker_All_TagBound and Marker_All_SendRecv, set the same + values in the config files of all the files ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + config->SetMarker_All_SendRecv(iMarker, + Marker_All_SendRecv[iMarker]); + config->SetMarker_All_TagBound(iMarker, + string(&Marker_All_TagBound[iMarker*MAX_STRING_SIZE])); + } + + + /*--- Periodic boundary conditions ---*/ + + Buffer_Receive_Center = new su2double[nPeriodic*3]; + Buffer_Receive_Rotation = new su2double[nPeriodic*3]; + Buffer_Receive_Translate = new su2double[nPeriodic*3]; + +#ifdef HAVE_MPI + + MPI_Probe(MASTER_NODE, 11, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_DOUBLE, &recv_count); + SU2_MPI::Recv(Buffer_Receive_Center, recv_count, MPI_DOUBLE, + MASTER_NODE, 11, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 12, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_DOUBLE, &recv_count); + SU2_MPI::Recv(Buffer_Receive_Rotation, recv_count, MPI_DOUBLE, + MASTER_NODE, 12, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 13, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_DOUBLE, &recv_count); + SU2_MPI::Recv(Buffer_Receive_Translate, recv_count, MPI_DOUBLE, + MASTER_NODE, 13, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 14, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(&nTotalSendDomain_Periodic, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 14, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 15, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(&nTotalReceivedDomain_Periodic, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 15, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 16, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(nSendDomain_Periodic, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 16, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 17, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(nReceivedDomain_Periodic, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 17, MPI_COMM_WORLD, &status); + +#endif + + config->SetnPeriodicIndex(nPeriodic); + + for (iPeriodic = 0; iPeriodic < nPeriodic; iPeriodic++) { + + su2double* center = new su2double[3]; // Do not deallocate the memory + su2double* rotation = new su2double[3]; // Do not deallocate the memory + su2double* translate = new su2double[3]; // Do not deallocate the memory + + for (iDim = 0; iDim < 3; iDim++) { + center[iDim] = Buffer_Receive_Center[iDim+iPeriodic*3]; + rotation[iDim] = Buffer_Receive_Rotation[iDim+iPeriodic*3]; + translate[iDim] = Buffer_Receive_Translate[iDim+iPeriodic*3]; + } + config->SetPeriodicCenter(iPeriodic, center); + config->SetPeriodicRotation(iPeriodic, rotation); + config->SetPeriodicTranslate(iPeriodic, translate); + } + + } + + delete [] Buffer_Receive_Center; + delete [] Buffer_Receive_Rotation; + delete [] Buffer_Receive_Translate; + + /*--- Allocate the receive buffer vector ---*/ + + Buffer_Receive_BoundLine = new unsigned long[nBoundLineTotal*2]; + Buffer_Receive_BoundTriangle = new unsigned long[nBoundTriangleTotal*3]; + Buffer_Receive_BoundQuadrilateral = new unsigned long[nBoundQuadrilateralTotal*4]; + Buffer_Receive_Local2Global_Marker = new unsigned long[nMarkerDomain]; + + Buffer_Receive_SendDomain_Periodic = new unsigned long[nTotalSendDomain_Periodic]; + Buffer_Receive_SendDomain_PeriodicTrans = new unsigned long[nTotalSendDomain_Periodic]; + Buffer_Receive_SendDomain_PeriodicReceptor = new unsigned long[nTotalSendDomain_Periodic]; + Buffer_Receive_ReceivedDomain_Periodic = new unsigned long[nTotalReceivedDomain_Periodic]; + Buffer_Receive_ReceivedDomain_PeriodicTrans = new unsigned long[nTotalReceivedDomain_Periodic]; + Buffer_Receive_ReceivedDomain_PeriodicDonor = new unsigned long[nTotalReceivedDomain_Periodic]; + + } + + + //cout << " &&&& Rank " << rank << " about to start bound elems " << endl; + + /*--- Set the value of the Send buffers ---*/ + + if (rank == MASTER_NODE) { + + /*--- Set the value of the boundary geometry ---*/ + + iMarkerDomain = 0; + iBoundLineTotal = 0; iBoundTriangleTotal = 0; iBoundQuadrilateralTotal = 0; + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + if ((config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) && (MarkerIn[iMarker])) { + for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { + + if (VertexIn[iMarker][iVertex]) { + + /*--- Send global index here and then convert to local on the recv ---*/ + + for (iNode = 0; iNode < geometry->bound[iMarker][iVertex]->GetnNodes(); iNode++) { + vnodes_local[iNode] = geometry->bound[iMarker][iVertex]->GetNode(iNode); + } + + switch(geometry->bound[iMarker][iVertex]->GetVTK_Type()) { + case LINE: + Buffer_Send_BoundLine[N_POINTS_LINE*iBoundLineTotal+0] = vnodes_local[0]; + Buffer_Send_BoundLine[N_POINTS_LINE*iBoundLineTotal+1] = vnodes_local[1]; + iBoundLineTotal++; + break; + case TRIANGLE: + Buffer_Send_BoundTriangle[N_POINTS_TRIANGLE*iBoundTriangleTotal+0] = vnodes_local[0]; + Buffer_Send_BoundTriangle[N_POINTS_TRIANGLE*iBoundTriangleTotal+1] = vnodes_local[1]; + Buffer_Send_BoundTriangle[N_POINTS_TRIANGLE*iBoundTriangleTotal+2] = vnodes_local[2]; + iBoundTriangleTotal++; + break; + case QUADRILATERAL: + Buffer_Send_BoundQuadrilateral[N_POINTS_QUADRILATERAL*iBoundQuadrilateralTotal+0] = vnodes_local[0]; + Buffer_Send_BoundQuadrilateral[N_POINTS_QUADRILATERAL*iBoundQuadrilateralTotal+1] = vnodes_local[1]; + Buffer_Send_BoundQuadrilateral[N_POINTS_QUADRILATERAL*iBoundQuadrilateralTotal+2] = vnodes_local[2]; + Buffer_Send_BoundQuadrilateral[N_POINTS_QUADRILATERAL*iBoundQuadrilateralTotal+3] = vnodes_local[3]; + iBoundQuadrilateralTotal++; + break; + } + } + } + + Buffer_Send_Local2Global_Marker[iMarkerDomain] = iMarker; + iMarkerDomain++; + + } + } + + /*--- Evaluate the number of already existing periodic boundary conditions ---*/ + + iTotalSendDomain_Periodic = 0; + iTotalReceivedDomain_Periodic = 0; + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { + + for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { + + iPoint = geometry->bound[iMarker][iVertex]->GetNode(0); + Transformation = geometry->bound[iMarker][iVertex]->GetRotation_Type(); + + if (iDomain == local_colour_values[iPoint]) { + + /*--- If the information is going to be sended, find the + domain of the receptor ---*/ + + if (config->GetMarker_All_SendRecv(iMarker) > 0) { + + /*--- Identify the color of the receptor ---*/ + + for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) { + if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker))) { + jPoint = geometry->bound[jMarker][iVertex]->GetNode(0); + ReceptorColor = local_colour_values[jPoint]; + } + } + + /*--- For each color of the receptor we will han an extra marker (+) ---*/ + + Buffer_Send_SendDomain_Periodic[iTotalSendDomain_Periodic] = iPoint; + Buffer_Send_SendDomain_PeriodicTrans[iTotalSendDomain_Periodic] = Transformation; + Buffer_Send_SendDomain_PeriodicReceptor[iTotalSendDomain_Periodic] = ReceptorColor; + + iTotalSendDomain_Periodic++; + + } + + /*--- If the information is goint to be received, find the domain if the donor ---*/ + + if (config->GetMarker_All_SendRecv(iMarker) < 0) { + + /*--- Identify the color of the donor ---*/ + + for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) { + if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker) )) { + jPoint = geometry->bound[jMarker][iVertex]->GetNode(0); + DonorColor = local_colour_values[jPoint]; + } + } + + /*--- For each color of the donor we will han an extra marker (-) ---*/ + + Buffer_Send_ReceivedDomain_Periodic[iTotalReceivedDomain_Periodic] = iPoint; + Buffer_Send_ReceivedDomain_PeriodicTrans[iTotalReceivedDomain_Periodic] = Transformation; + Buffer_Send_ReceivedDomain_PeriodicDonor[iTotalReceivedDomain_Periodic] = DonorColor; + + iTotalReceivedDomain_Periodic++; + + } + } + } + } + } + + /*--- Send the buffers with the geometrical information ---*/ + + if (iDomain != MASTER_NODE) { + +#ifdef HAVE_MPI + + SU2_MPI::Isend(Buffer_Send_BoundLine, + Buffer_Send_nBoundLineTotal*N_POINTS_LINE, MPI_UNSIGNED_LONG, iDomain, + 0, MPI_COMM_WORLD, &send_req[0]); + + SU2_MPI::Isend(Buffer_Send_BoundTriangle, + Buffer_Send_nBoundTriangleTotal*N_POINTS_TRIANGLE, MPI_UNSIGNED_LONG, iDomain, + 1, MPI_COMM_WORLD, &send_req[1]); + + SU2_MPI::Isend(Buffer_Send_BoundQuadrilateral, + Buffer_Send_nBoundQuadrilateralTotal*N_POINTS_QUADRILATERAL, MPI_UNSIGNED_LONG, iDomain, + 2, MPI_COMM_WORLD, &send_req[2]); + + SU2_MPI::Isend(Buffer_Send_Local2Global_Marker, + Buffer_Send_nMarkerDomain, MPI_UNSIGNED_LONG, iDomain, + 3, MPI_COMM_WORLD, &send_req[3]); + + SU2_MPI::Isend(Buffer_Send_SendDomain_Periodic, + Buffer_Send_nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, + 4, MPI_COMM_WORLD, &send_req[4]); + + SU2_MPI::Isend(Buffer_Send_SendDomain_PeriodicTrans, + Buffer_Send_nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, + 5, MPI_COMM_WORLD, &send_req[5]); + + SU2_MPI::Isend(Buffer_Send_SendDomain_PeriodicReceptor, + Buffer_Send_nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, + 6, MPI_COMM_WORLD, &send_req[6]); + + SU2_MPI::Isend(Buffer_Send_ReceivedDomain_Periodic, + Buffer_Send_nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, + 7, MPI_COMM_WORLD, &send_req[7]); + + SU2_MPI::Isend(Buffer_Send_ReceivedDomain_PeriodicTrans, + Buffer_Send_nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, + 8, MPI_COMM_WORLD, &send_req[8]); + + SU2_MPI::Isend(Buffer_Send_ReceivedDomain_PeriodicDonor, + Buffer_Send_nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, iDomain, + 9, MPI_COMM_WORLD, &send_req[9]); + + /*--- Wait for this set of non-blocking comm. to complete ---*/ + + SU2_MPI::Waitall(10, send_req, send_stat); + +#endif + + } else { + + /*--- Copy the data directly from our own rank ---*/ + + for (iter = 0; iter < Buffer_Send_nBoundLineTotal*N_POINTS_LINE; iter++) + Buffer_Receive_BoundLine[iter] = Buffer_Send_BoundLine[iter]; + + for (iter = 0; iter < Buffer_Send_nBoundTriangleTotal*N_POINTS_TRIANGLE; iter++) + Buffer_Receive_BoundTriangle[iter] = Buffer_Send_BoundTriangle[iter]; + + for (iter = 0; iter < Buffer_Send_nBoundQuadrilateralTotal*N_POINTS_QUADRILATERAL; iter++) + Buffer_Receive_BoundQuadrilateral[iter] = Buffer_Send_BoundQuadrilateral[iter]; + + for (iter = 0; iter < Buffer_Send_nMarkerDomain; iter++) + Buffer_Receive_Local2Global_Marker[iter] = Buffer_Send_Local2Global_Marker[iter]; + + for (iter = 0; iter < Buffer_Send_nTotalSendDomain_Periodic; iter++) { + Buffer_Receive_SendDomain_Periodic[iter] = Buffer_Send_SendDomain_Periodic[iter]; + Buffer_Receive_SendDomain_PeriodicTrans[iter] = Buffer_Send_SendDomain_PeriodicTrans[iter]; + Buffer_Receive_SendDomain_PeriodicReceptor[iter] = Buffer_Send_SendDomain_PeriodicReceptor[iter]; + } + + for (iter = 0; iter < Buffer_Send_nTotalReceivedDomain_Periodic; iter++) { + Buffer_Receive_ReceivedDomain_Periodic[iter] = Buffer_Send_ReceivedDomain_Periodic[iter]; + Buffer_Receive_ReceivedDomain_PeriodicTrans[iter] = Buffer_Send_ReceivedDomain_PeriodicTrans[iter]; + Buffer_Receive_ReceivedDomain_PeriodicDonor[iter] = Buffer_Send_ReceivedDomain_PeriodicDonor[iter]; + } + + } + + delete[] Buffer_Send_BoundLine; + delete[] Buffer_Send_BoundTriangle; + delete[] Buffer_Send_BoundQuadrilateral; + delete[] Buffer_Send_Local2Global_Marker; + + delete[] Buffer_Send_SendDomain_Periodic; + delete[] Buffer_Send_SendDomain_PeriodicTrans; + delete[] Buffer_Send_SendDomain_PeriodicReceptor; + delete[] Buffer_Send_ReceivedDomain_Periodic; + delete[] Buffer_Send_ReceivedDomain_PeriodicTrans; + delete[] Buffer_Send_ReceivedDomain_PeriodicDonor; + + } + + //cout << " Rank " << rank << " about to recv of bound elems " << endl; + + if ((unsigned long)rank == iDomain) { + + if (rank != MASTER_NODE) { + + /*--- Receive the buffers with the geometrical information ---*/ + +#ifdef HAVE_MPI + + MPI_Probe(MASTER_NODE, 0, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(Buffer_Receive_BoundLine, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 0, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 1, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(Buffer_Receive_BoundTriangle, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 1, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 2, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(Buffer_Receive_BoundQuadrilateral, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 2, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 3, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(Buffer_Receive_Local2Global_Marker, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 3, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 4, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(Buffer_Receive_SendDomain_Periodic, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 4, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 5, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(Buffer_Receive_SendDomain_PeriodicTrans, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 5, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 6, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(Buffer_Receive_SendDomain_PeriodicReceptor, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 6, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 7, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(Buffer_Receive_ReceivedDomain_Periodic, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 7, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 8, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(Buffer_Receive_ReceivedDomain_PeriodicTrans, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 8, MPI_COMM_WORLD, &status); + + MPI_Probe(MASTER_NODE, 9, MPI_COMM_WORLD, &status); + MPI_Get_count(&status, MPI_UNSIGNED_LONG, &recv_count); + SU2_MPI::Recv(Buffer_Receive_ReceivedDomain_PeriodicDonor, recv_count, MPI_UNSIGNED_LONG, + MASTER_NODE, 9, MPI_COMM_WORLD, &status); + +#endif + + } + + /*--- Create the domain structures for the boundaries ---*/ + + nMarker = nMarkerDomain; + nElem_Bound = new unsigned long[nMarker_Max]; + Local_to_Global_Marker = new unsigned short[nMarker_Max]; + Tag_to_Marker = new string[nMarker_Max]; + string *TagBound_Copy = new string[nMarker_Max]; + short *SendRecv_Copy = new short[nMarker_Max]; + + for (iMarker = 0; iMarker < nMarker; iMarker++) + nElem_Bound[iMarker] = nVertexDomain[iMarker]; + + bound = new CPrimalGrid**[nMarker+(overhead*nDomain)]; + for (iMarker = 0; iMarker < nMarker; iMarker++) + bound[iMarker] = new CPrimalGrid*[nElem_Bound[iMarker]]; + + /*--- Initialize boundary element counters ---*/ + iBoundLineTotal = 0; + iBoundTriangleTotal = 0; + iBoundQuadrilateralTotal = 0; + + /*--- Store the boundary element connectivity. Note here that we have + communicated the global index values for the elements, so we need to + convert this to the local index when instantiating the element. ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + iVertexDomain = 0; + + for (iBoundLine = 0; iBoundLine < nBoundLine[iMarker]; iBoundLine++) { + bound[iMarker][iVertexDomain] = new CLine(Global_to_local_Point_recv[Buffer_Receive_BoundLine[iBoundLineTotal*2+0]], + Global_to_local_Point_recv[Buffer_Receive_BoundLine[iBoundLineTotal*2+1]], 2); + iVertexDomain++; iBoundLineTotal++; + } + for (iBoundTriangle = 0; iBoundTriangle < nBoundTriangle[iMarker]; iBoundTriangle++) { + bound[iMarker][iVertexDomain] = new CTriangle(Global_to_local_Point_recv[Buffer_Receive_BoundTriangle[iBoundTriangleTotal*3+0]], + Global_to_local_Point_recv[Buffer_Receive_BoundTriangle[iBoundTriangleTotal*3+1]], + Global_to_local_Point_recv[Buffer_Receive_BoundTriangle[iBoundTriangleTotal*3+2]], 3); + iVertexDomain++; iBoundTriangleTotal++; + } + for (iBoundQuadrilateral = 0; iBoundQuadrilateral < nBoundQuadrilateral[iMarker]; iBoundQuadrilateral++) { + bound[iMarker][iVertexDomain] = new CQuadrilateral(Global_to_local_Point_recv[Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+0]], + Global_to_local_Point_recv[Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+1]], + Global_to_local_Point_recv[Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+2]], + Global_to_local_Point_recv[Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+3]], 3); + iVertexDomain++; iBoundQuadrilateralTotal++; + } + + Local_to_Global_Marker[iMarker] = Buffer_Receive_Local2Global_Marker[iMarker]; + + /*--- Now each domain has the right information ---*/ + + string Grid_Marker = config->GetMarker_All_TagBound(Local_to_Global_Marker[iMarker]); + short SendRecv = config->GetMarker_All_SendRecv(Local_to_Global_Marker[iMarker]); + TagBound_Copy[iMarker] = Grid_Marker; + SendRecv_Copy[iMarker] = SendRecv; + + } + + /*--- Store total number of each boundary element type ---*/ + + nelem_edge_bound = iBoundLineTotal; + nelem_triangle_bound = iBoundTriangleTotal; + nelem_quad_bound = iBoundQuadrilateralTotal; + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + config->SetMarker_All_TagBound(iMarker, TagBound_Copy[iMarker]); + config->SetMarker_All_SendRecv(iMarker, SendRecv_Copy[iMarker]); + } + + /*--- Add the new periodic markers to the domain ---*/ + +// iTotalSendDomain_Periodic = 0; +// iTotalReceivedDomain_Periodic = 0; + + for (jDomain = 0; jDomain < nDomain; jDomain++) { + + if (nSendDomain_Periodic[jDomain] != 0) { + nVertexDomain[nMarker] = 0; + bound[nMarker] = new CPrimalGrid* [nSendDomain_Periodic[jDomain]]; + + iVertex = 0; + for (iTotalSendDomain_Periodic = 0; iTotalSendDomain_Periodic < nTotalSendDomain_Periodic; iTotalSendDomain_Periodic++) { + if (Buffer_Receive_SendDomain_PeriodicReceptor[iTotalSendDomain_Periodic] == jDomain) { + bound[nMarker][iVertex] = new CVertexMPI(Global_to_local_Point_recv[Buffer_Receive_SendDomain_Periodic[iTotalSendDomain_Periodic]], nDim); + bound[nMarker][iVertex]->SetRotation_Type(Buffer_Receive_SendDomain_PeriodicTrans[iTotalSendDomain_Periodic]); + nVertexDomain[nMarker]++; iVertex++; + } + } + + Marker_All_SendRecv[nMarker] = jDomain+1; + nElem_Bound[nMarker] = nVertexDomain[nMarker]; + nMarker++; + } + + if (nReceivedDomain_Periodic[jDomain] != 0) { + nVertexDomain[nMarker] = 0; + bound[nMarker] = new CPrimalGrid* [nReceivedDomain_Periodic[jDomain]]; + + iVertex = 0; + for (iTotalReceivedDomain_Periodic = 0; iTotalReceivedDomain_Periodic < nTotalReceivedDomain_Periodic; iTotalReceivedDomain_Periodic++) { + if (Buffer_Receive_ReceivedDomain_PeriodicDonor[iTotalReceivedDomain_Periodic] == jDomain) { + bound[nMarker][iVertex] = new CVertexMPI(Global_to_local_Point_recv[Buffer_Receive_ReceivedDomain_Periodic[iTotalReceivedDomain_Periodic]], nDim); + bound[nMarker][iVertex]->SetRotation_Type(Buffer_Receive_ReceivedDomain_PeriodicTrans[iTotalReceivedDomain_Periodic]); + nVertexDomain[nMarker]++; iVertex++; + } + } + + Marker_All_SendRecv[nMarker] = -(jDomain+1); + nElem_Bound[nMarker] = nVertexDomain[nMarker]; + nMarker++; + } + + } + + delete[] TagBound_Copy; + delete[] SendRecv_Copy; + + delete[] Buffer_Receive_BoundLine; + delete[] Buffer_Receive_BoundTriangle; + delete[] Buffer_Receive_BoundQuadrilateral; + delete[] Buffer_Receive_Local2Global_Marker; + + delete[] Buffer_Receive_SendDomain_Periodic; + delete[] Buffer_Receive_SendDomain_PeriodicTrans; + delete[] Buffer_Receive_SendDomain_PeriodicReceptor; + delete[] Buffer_Receive_ReceivedDomain_Periodic; + delete[] Buffer_Receive_ReceivedDomain_PeriodicTrans; + delete[] Buffer_Receive_ReceivedDomain_PeriodicDonor; + + } + + + } + + /*--- The MASTER should wait for the sends above to complete ---*/ + +#ifdef HAVE_MPI + MPI_Barrier(MPI_COMM_WORLD); +#endif + + /*--- Set the value of Marker_All_SendRecv and Marker_All_TagBound in the config structure ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + config->SetMarker_All_SendRecv(iMarker, Marker_All_SendRecv[iMarker]); + } + + /*--- Set the value of Global_nPoint and Global_nPointDomain ---*/ + + unsigned long Local_nPoint = nPoint; + unsigned long Local_nPointDomain = nPointDomain; + +#ifdef HAVE_MPI + SU2_MPI::Allreduce(&Local_nPoint, &Global_nPoint, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&Local_nPointDomain, &Global_nPointDomain, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); +#else + Global_nPoint = Local_nPoint; + Global_nPointDomain = Local_nPointDomain; +#endif + + if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) + cout << Global_nPoint << " vertices including ghost points. " << endl; + + /*--- Release all of the temporary memory ---*/ + + delete [] nDim_s; + delete [] nDim_r; + + delete [] nPointTotal_s; + delete [] nPointDomainTotal_s; + delete [] nPointGhost_s; + delete [] nPointPeriodic_s; + delete [] nElemTotal_s; + delete [] nElemTriangle_s; + delete [] nElemQuadrilateral_s; + delete [] nElemTetrahedron_s; + delete [] nElemHexahedron_s; + delete [] nElemPrism_s; + delete [] nElemPyramid_s; + delete [] nZone_s; + + delete [] nPointTotal_r; + delete [] nPointDomainTotal_r; + delete [] nPointGhost_r; + delete [] nPointPeriodic_r; + delete [] nElemTotal_r; + delete [] nElemTriangle_r; + delete [] nElemQuadrilateral_r; + delete [] nElemTetrahedron_r; + delete [] nElemHexahedron_r; + delete [] nElemPrism_r; + delete [] nElemPyramid_r; + delete [] nZone_r; + + if (rank == MASTER_NODE) { + delete [] MarkerIn; + delete [] Buffer_Send_Center; + delete [] Buffer_Send_Rotation; + delete [] Buffer_Send_Translate; + delete [] Buffer_Send_nSendDomain_Periodic; + delete [] Buffer_Send_nReceivedDomain_Periodic; + delete [] Marker_All_SendRecv_Copy; + delete [] Marker_All_TagBound_Copy; + delete [] PointIn; + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) + delete [] VertexIn[iMarker]; + delete[] VertexIn; + } + + delete [] Marker_All_TagBound; + delete [] Buffer_Send_Marker_All_TagBound; + + delete [] nSendDomain_Periodic; + delete [] nReceivedDomain_Periodic; + delete [] nVertexDomain; + delete [] nBoundLine; + delete [] nBoundTriangle; + delete [] nBoundQuadrilateral; + delete [] Buffer_Send_nVertexDomain; + delete [] Buffer_Send_nBoundLine; + delete [] Buffer_Send_nBoundTriangle; + delete [] Buffer_Send_nBoundQuadrilateral; + delete [] Buffer_Send_Marker_All_SendRecv; + +#ifdef HAVE_MPI + delete [] send_stat; + delete [] recv_stat; + delete [] send_req; + delete [] recv_req; +#endif + +} + + +CPhysicalGeometry::~CPhysicalGeometry(void) { + + if (Global_to_Local_Point != NULL) delete [] Global_to_Local_Point; + if (Local_to_Global_Point != NULL) delete [] Local_to_Global_Point; + if (Global_to_Local_Marker != NULL) delete [] Global_to_Local_Marker; + if (Local_to_Global_Marker != NULL) delete [] Local_to_Global_Marker; + +} + + + +void CPhysicalGeometry::SetSendReceive(CConfig *config) { + + unsigned short Counter_Send, Counter_Receive, iMarkerSend, iMarkerReceive; + unsigned long iVertex, LocalNode; + unsigned short nMarker_Max = config->GetnMarker_Max(); + unsigned long iPoint, jPoint, iElem; + unsigned long *nVertexDomain = new unsigned long[nMarker_Max]; + unsigned short nDomain, iNode, iDomain, jDomain, jNode; + vector::iterator it; + + vector > SendTransfLocal; /*!< \brief Vector to store the type of transformation for this send point. */ + vector > ReceivedTransfLocal; /*!< \brief Vector to store the type of transformation for this received point. */ + vector > SendDomainLocal; /*!< \brief SendDomain[from domain][to domain] and return the point index of the node that must me sended. */ + vector > ReceivedDomainLocal; /*!< \brief SendDomain[from domain][to domain] and return the point index of the node that must me sended. */ + + int rank = MASTER_NODE; + int size = SINGLE_NODE; + +#ifdef HAVE_MPI + /*--- MPI initialization ---*/ + MPI_Comm_size(MPI_COMM_WORLD, &size); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + if (rank == MASTER_NODE && size > SINGLE_NODE) + cout << "Establishing MPI communication patterns." << endl; + + nDomain = size; + + SendTransfLocal.resize(nDomain); + ReceivedTransfLocal.resize(nDomain); + SendDomainLocal.resize(nDomain); + ReceivedDomainLocal.resize(nDomain); + + /*--- Loop over the all the points of the element + to find the points with different colours, and create the send/received list ---*/ + for (iElem = 0; iElem < nElem; iElem++) { + for (iNode = 0; iNode < elem[iElem]->GetnNodes(); iNode++) { + iPoint = elem[iElem]->GetNode(iNode); + iDomain = node[iPoint]->GetColor(); + + if (iDomain == rank) { + for (jNode = 0; jNode < elem[iElem]->GetnNodes(); jNode++) { + jPoint = elem[iElem]->GetNode(jNode); + jDomain = node[jPoint]->GetColor(); + + /*--- If different color and connected by an edge, then we add them to the list ---*/ + if (iDomain != jDomain) { + + /*--- We send from iDomain to jDomain the value of iPoint, we save the + global value becuase we need to sort the lists ---*/ + SendDomainLocal[jDomain].push_back(Local_to_Global_Point[iPoint]); + /*--- We send from jDomain to iDomain the value of jPoint, we save the + global value becuase we need to sort the lists ---*/ + ReceivedDomainLocal[jDomain].push_back(Local_to_Global_Point[jPoint]); + + } + } + } + } + } + + /*--- Sort the points that must be sended and delete repeated points, note + that the sorting should be done with the global point (not the local) ---*/ + for (iDomain = 0; iDomain < nDomain; iDomain++) { + sort( SendDomainLocal[iDomain].begin(), SendDomainLocal[iDomain].end()); + it = unique( SendDomainLocal[iDomain].begin(), SendDomainLocal[iDomain].end()); + SendDomainLocal[iDomain].resize( it - SendDomainLocal[iDomain].begin() ); + } + + /*--- Sort the points that must be received and delete repeated points, note + that the sorting should be done with the global point (not the local) ---*/ + for (iDomain = 0; iDomain < nDomain; iDomain++) { + sort( ReceivedDomainLocal[iDomain].begin(), ReceivedDomainLocal[iDomain].end()); + it = unique( ReceivedDomainLocal[iDomain].begin(), ReceivedDomainLocal[iDomain].end()); + ReceivedDomainLocal[iDomain].resize( it - ReceivedDomainLocal[iDomain].begin() ); + } + + /*--- Create Global to Local Point array, note that the array is smaller (Max_GlobalPoint) than the total + number of points in the simulation ---*/ + Max_GlobalPoint = 0; + for (iPoint = 0; iPoint < nPoint; iPoint++) { + if (Local_to_Global_Point[iPoint] > (long)Max_GlobalPoint) + Max_GlobalPoint = Local_to_Global_Point[iPoint]; + } + Global_to_Local_Point = new long[Max_GlobalPoint+1]; // +1 to include the bigger point. + + /*--- Initialization of the array with -1 this is important for the FFD ---*/ + for (iPoint = 0; iPoint < Max_GlobalPoint+1; iPoint++) + Global_to_Local_Point[iPoint] = -1; + + /*--- Set the value of some of the points ---*/ + for (iPoint = 0; iPoint < nPoint; iPoint++) + Global_to_Local_Point[Local_to_Global_Point[iPoint]] = iPoint; + + /*--- Add the new MPI send receive boundaries, reset the transformation, and save the local value ---*/ + for (iDomain = 0; iDomain < nDomain; iDomain++) { + if (SendDomainLocal[iDomain].size() != 0) { + nVertexDomain[nMarker] = SendDomainLocal[iDomain].size(); + for (iVertex = 0; iVertex < nVertexDomain[nMarker]; iVertex++) { + SendDomainLocal[iDomain][iVertex] = Global_to_Local_Point[SendDomainLocal[iDomain][iVertex]]; + SendTransfLocal[iDomain].push_back(0); + } + nElem_Bound[nMarker] = nVertexDomain[nMarker]; + bound[nMarker] = new CPrimalGrid*[nElem_Bound[nMarker]]; + nMarker++; + } + } + + /*--- Add the new MPI receive boundaries, reset the transformation, and save the local value ---*/ + for (iDomain = 0; iDomain < nDomain; iDomain++) { + if (ReceivedDomainLocal[iDomain].size() != 0) { + nVertexDomain[nMarker] = ReceivedDomainLocal[iDomain].size(); + for (iVertex = 0; iVertex < nVertexDomain[nMarker]; iVertex++) { + ReceivedDomainLocal[iDomain][iVertex] = Global_to_Local_Point[ReceivedDomainLocal[iDomain][iVertex]]; + ReceivedTransfLocal[iDomain].push_back(0); + } + nElem_Bound[nMarker] = nVertexDomain[nMarker]; + bound[nMarker] = new CPrimalGrid*[nElem_Bound[nMarker]]; + nMarker++; + } + } + + /*--- First compute the Send/Receive boundaries ---*/ + Counter_Send = 0; Counter_Receive = 0; + for (iDomain = 0; iDomain < nDomain; iDomain++) + if (SendDomainLocal[iDomain].size() != 0) Counter_Send++; + + for (iDomain = 0; iDomain < nDomain; iDomain++) + if (ReceivedDomainLocal[iDomain].size() != 0) Counter_Receive++; + + iMarkerSend = nMarker - Counter_Send - Counter_Receive; + iMarkerReceive = nMarker - Counter_Receive; + + /*--- First we do the send ---*/ + for (iDomain = 0; iDomain < nDomain; iDomain++) { + if (SendDomainLocal[iDomain].size() != 0) { + for (iVertex = 0; iVertex < GetnElem_Bound(iMarkerSend); iVertex++) { + LocalNode = SendDomainLocal[iDomain][iVertex]; + bound[iMarkerSend][iVertex] = new CVertexMPI(LocalNode, nDim); + bound[iMarkerSend][iVertex]->SetRotation_Type(SendTransfLocal[iDomain][iVertex]); + } + Marker_All_SendRecv[iMarkerSend] = iDomain+1; + iMarkerSend++; + } + } + + /*--- Second we do the receive ---*/ + for (iDomain = 0; iDomain < nDomain; iDomain++) { + if (ReceivedDomainLocal[iDomain].size() != 0) { + for (iVertex = 0; iVertex < GetnElem_Bound(iMarkerReceive); iVertex++) { + LocalNode = ReceivedDomainLocal[iDomain][iVertex]; + bound[iMarkerReceive][iVertex] = new CVertexMPI(LocalNode, nDim); + bound[iMarkerReceive][iVertex]->SetRotation_Type(ReceivedTransfLocal[iDomain][iVertex]); + } + Marker_All_SendRecv[iMarkerReceive] = -(iDomain+1); + iMarkerReceive++; + } + } + + /*--- Free memory ---*/ + delete [] nVertexDomain; +} + + +void CPhysicalGeometry::SetBoundaries(CConfig *config) { + + unsigned long iElem_Bound, TotalElem, *nElem_Bound_Copy, iVertex_; + string Grid_Marker; + unsigned short iDomain, nDomain, iMarkersDomain, iLoop, *DomainCount, nMarker_Physical, Duplicate_SendReceive, *DomainSendCount, **DomainSendMarkers, *DomainReceiveCount, **DomainReceiveMarkers, nMarker_SendRecv, iMarker, iMarker_; + CPrimalGrid*** bound_Copy; + short *Marker_All_SendRecv_Copy; + bool CheckStart; + + int size = SINGLE_NODE; + +#ifdef HAVE_MPI + /*--- MPI initialization ---*/ + MPI_Comm_size(MPI_COMM_WORLD, &size); +#endif + + nDomain = size+1; + + /*--- Count the number of physical markers + in the boundaries ---*/ + + nMarker_Physical = 0; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (bound[iMarker][0]->GetVTK_Type() != VERTEX) { + nMarker_Physical++; + } + } + + /*--- Identify if there are markers that send/received with the same domain, + they should be together---*/ + + Duplicate_SendReceive = 0; + for (iLoop = 0; iLoop < 2; iLoop++) { + + DomainCount = new unsigned short [nDomain]; + + for (iDomain = 0; iDomain < nDomain; iDomain++) + DomainCount[iDomain] = 0; + + if (iLoop == 0) { + for (iDomain = 0; iDomain < nDomain; iDomain++) + for (iMarker = 0; iMarker < nMarker; iMarker++) + if (bound[iMarker][0]->GetVTK_Type() == VERTEX) + if (Marker_All_SendRecv[iMarker] == iDomain) DomainCount[iDomain]++; + } + else { + for (iDomain = 0; iDomain < nDomain; iDomain++) + for (iMarker = 0; iMarker < nMarker; iMarker++) + if (bound[iMarker][0]->GetVTK_Type() == VERTEX) + if (Marker_All_SendRecv[iMarker] == -iDomain) DomainCount[iDomain]++; + } + + for (iDomain = 0; iDomain < nDomain; iDomain++) + if (DomainCount[iDomain] > 1) Duplicate_SendReceive++; + + delete [] DomainCount; + + } + + DomainSendCount = new unsigned short [nDomain]; + DomainSendMarkers = new unsigned short *[nDomain]; + DomainReceiveCount = new unsigned short [nDomain]; + DomainReceiveMarkers = new unsigned short *[nDomain]; + + for (iDomain = 0; iDomain < nDomain; iDomain++) { + DomainSendCount[iDomain] = 0; + DomainSendMarkers[iDomain] = new unsigned short [nMarker]; + + DomainReceiveCount[iDomain] = 0; + DomainReceiveMarkers[iDomain] = new unsigned short [nMarker]; + } + + for (iDomain = 0; iDomain < nDomain; iDomain++) { + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (bound[iMarker][0]->GetVTK_Type() == VERTEX) { + if (Marker_All_SendRecv[iMarker] == iDomain) { + DomainSendMarkers[iDomain][DomainSendCount[iDomain]] = iMarker; + DomainSendCount[iDomain]++; + } + if (Marker_All_SendRecv[iMarker] == -iDomain) { + DomainReceiveMarkers[iDomain][DomainReceiveCount[iDomain]] = iMarker; + DomainReceiveCount[iDomain]++; + } + } + } + } + + /*--- Create an structure to store the Send/Receive + boundaries, because they require some reorganization ---*/ + + nMarker_SendRecv = nMarker - nMarker_Physical - Duplicate_SendReceive; + bound_Copy = new CPrimalGrid**[nMarker_Physical + nMarker_SendRecv]; + nElem_Bound_Copy = new unsigned long [nMarker_Physical + nMarker_SendRecv]; + Marker_All_SendRecv_Copy = new short [nMarker_Physical + nMarker_SendRecv]; + iMarker_ = nMarker_Physical; + iVertex_ = 0; + CheckStart = false; + + /*--- Copy and allocate the physical markers in the data structure ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (bound[iMarker][0]->GetVTK_Type() != VERTEX) { + + nElem_Bound_Copy[iMarker] = nElem_Bound[iMarker]; + bound_Copy[iMarker] = new CPrimalGrid* [nElem_Bound[iMarker]]; + + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + if (bound[iMarker][iElem_Bound]->GetVTK_Type() == LINE) + bound_Copy[iMarker][iElem_Bound] = new CLine(bound[iMarker][iElem_Bound]->GetNode(0), + bound[iMarker][iElem_Bound]->GetNode(1), 2); + if (bound[iMarker][iElem_Bound]->GetVTK_Type() == TRIANGLE) + + bound_Copy[iMarker][iElem_Bound] = new CTriangle(bound[iMarker][iElem_Bound]->GetNode(0), + bound[iMarker][iElem_Bound]->GetNode(1), + bound[iMarker][iElem_Bound]->GetNode(2), 3); + if (bound[iMarker][iElem_Bound]->GetVTK_Type() == QUADRILATERAL) + bound_Copy[iMarker][iElem_Bound] = new CQuadrilateral(bound[iMarker][iElem_Bound]->GetNode(0), + bound[iMarker][iElem_Bound]->GetNode(1), + bound[iMarker][iElem_Bound]->GetNode(2), + bound[iMarker][iElem_Bound]->GetNode(3), 3); + } + } + } + + + for (iDomain = 0; iDomain < nDomain; iDomain++) { + + /*--- Compute the total number of elements (adding all the + boundaries with the same Send/Receive ---*/ + + if (DomainSendCount[iDomain] != 0) { + TotalElem = 0; + for (iMarkersDomain = 0; iMarkersDomain < DomainSendCount[iDomain]; iMarkersDomain++) { + iMarker = DomainSendMarkers[iDomain][iMarkersDomain]; + TotalElem += nElem_Bound[iMarker]; + } + if (CheckStart) iMarker_++; + CheckStart = true; + iVertex_ = 0; + nElem_Bound_Copy[iMarker_] = TotalElem; + bound_Copy[iMarker_] = new CPrimalGrid*[TotalElem]; + } + + for (iMarkersDomain = 0; iMarkersDomain < DomainSendCount[iDomain]; iMarkersDomain++) { + iMarker = DomainSendMarkers[iDomain][iMarkersDomain]; + Marker_All_SendRecv_Copy[iMarker_] = Marker_All_SendRecv[iMarker]; + + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + bound_Copy[iMarker_][iVertex_] = new CVertexMPI(bound[iMarker][iElem_Bound]->GetNode(0), nDim); + bound_Copy[iMarker_][iVertex_]->SetRotation_Type(bound[iMarker][iElem_Bound]->GetRotation_Type()); + iVertex_++; + } + + } + + /*--- Compute the total number of elements (adding all the + boundaries with the same Send/Receive ---*/ + + if (DomainReceiveCount[iDomain] != 0) { + TotalElem = 0; + for (iMarkersDomain = 0; iMarkersDomain < DomainReceiveCount[iDomain]; iMarkersDomain++) { + iMarker = DomainReceiveMarkers[iDomain][iMarkersDomain]; + TotalElem += nElem_Bound[iMarker]; + } + if (CheckStart) iMarker_++; + CheckStart = true; + iVertex_ = 0; + nElem_Bound_Copy[iMarker_] = TotalElem; + bound_Copy[iMarker_] = new CPrimalGrid*[TotalElem]; + + } + + for (iMarkersDomain = 0; iMarkersDomain < DomainReceiveCount[iDomain]; iMarkersDomain++) { + iMarker = DomainReceiveMarkers[iDomain][iMarkersDomain]; + Marker_All_SendRecv_Copy[iMarker_] = Marker_All_SendRecv[iMarker]; + + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + bound_Copy[iMarker_][iVertex_] = new CVertexMPI(bound[iMarker][iElem_Bound]->GetNode(0), nDim); + bound_Copy[iMarker_][iVertex_]->SetRotation_Type(bound[iMarker][iElem_Bound]->GetRotation_Type()); + iVertex_++; + } + + } + + } + + delete [] DomainSendCount; + for (iDomain = 0; iDomain < nDomain; iDomain++) + delete [] DomainSendMarkers[iDomain]; + delete[] DomainSendMarkers; + + delete [] DomainReceiveCount; + for (iDomain = 0; iDomain < nDomain; iDomain++) + delete [] DomainReceiveMarkers[iDomain]; + delete[] DomainReceiveMarkers; + + /*--- Deallocate the bound variables ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) + delete [] bound[iMarker]; + delete [] bound; + + /*--- Allocate the new bound variables, and set the number of markers ---*/ + + bound = bound_Copy; + nMarker = nMarker_Physical + nMarker_SendRecv; + + config->SetnMarker_All(nMarker); + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + nElem_Bound[iMarker] = nElem_Bound_Copy[iMarker]; + } + for (iMarker = nMarker_Physical; iMarker < nMarker; iMarker++) { + Marker_All_SendRecv[iMarker] = Marker_All_SendRecv_Copy[iMarker]; + config->SetMarker_All_SendRecv(iMarker, Marker_All_SendRecv[iMarker]); + config->SetMarker_All_TagBound(iMarker, "SEND_RECEIVE"); + } + + /*--- Update config information storing the boundary information in the right place ---*/ + + for (iMarker = 0 ; iMarker < nMarker; iMarker++) { + + string Marker_Tag = config->GetMarker_All_TagBound(iMarker); + + if (Marker_Tag != "SEND_RECEIVE") { + + /*--- Update config information storing the boundary information in the right place ---*/ + + Tag_to_Marker[config->GetMarker_CfgFile_TagBound(Marker_Tag)] = Marker_Tag; + config->SetMarker_All_KindBC(iMarker, config->GetMarker_CfgFile_KindBC(Marker_Tag)); + config->SetMarker_All_Monitoring(iMarker, config->GetMarker_CfgFile_Monitoring(Marker_Tag)); + config->SetMarker_All_GeoEval(iMarker, config->GetMarker_CfgFile_GeoEval(Marker_Tag)); + config->SetMarker_All_Designing(iMarker, config->GetMarker_CfgFile_Designing(Marker_Tag)); + config->SetMarker_All_Plotting(iMarker, config->GetMarker_CfgFile_Plotting(Marker_Tag)); + config->SetMarker_All_FSIinterface(iMarker, config->GetMarker_CfgFile_FSIinterface(Marker_Tag)); + config->SetMarker_All_DV(iMarker, config->GetMarker_CfgFile_DV(Marker_Tag)); + config->SetMarker_All_Moving(iMarker, config->GetMarker_CfgFile_Moving(Marker_Tag)); + config->SetMarker_All_PerBound(iMarker, config->GetMarker_CfgFile_PerBound(Marker_Tag)); + config->SetMarker_All_Out_1D(iMarker, config->GetMarker_CfgFile_Out_1D(Marker_Tag)); + + } + + /*--- Send-Receive boundaries definition ---*/ + + else { + + config->SetMarker_All_KindBC(iMarker, SEND_RECEIVE); + config->SetMarker_All_Monitoring(iMarker, NO); + config->SetMarker_All_GeoEval(iMarker, NO); + config->SetMarker_All_Designing(iMarker, NO); + config->SetMarker_All_Plotting(iMarker, NO); + config->SetMarker_All_FSIinterface(iMarker, NO); + config->SetMarker_All_DV(iMarker, NO); + config->SetMarker_All_Moving(iMarker, NO); + config->SetMarker_All_PerBound(iMarker, NO); + config->SetMarker_All_Out_1D(iMarker, NO); + + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + if (config->GetMarker_All_SendRecv(iMarker) < 0) + node[bound[iMarker][iElem_Bound]->GetNode(0)]->SetDomain(false); + } + + } + + /*--- Loop over the surface element to set the boundaries ---*/ + + unsigned long Point_Surface, iElem_Surface; + unsigned short iNode_Surface; + + for (iElem_Surface = 0; iElem_Surface < nElem_Bound[iMarker]; iElem_Surface++) { + for (iNode_Surface = 0; iNode_Surface < bound[iMarker][iElem_Surface]->GetnNodes(); iNode_Surface++) { + Point_Surface = bound[iMarker][iElem_Surface]->GetNode(iNode_Surface); + node[Point_Surface]->SetBoundary(nMarker); + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE && + config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY && + config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY && + config->GetMarker_All_KindBC(iMarker) != PERIODIC_BOUNDARY) + node[Point_Surface]->SetPhysicalBoundary(true); + + if (config->GetMarker_All_KindBC(iMarker) == EULER_WALL && + config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX && + config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) + node[Point_Surface]->SetSolidBoundary(true); + } + } + + } + +} + +void CPhysicalGeometry::Read_SU2_Format_Parallel(CConfig *config, string val_mesh_filename, unsigned short val_iZone, unsigned short val_nZone) { + + string text_line, Marker_Tag; + ifstream mesh_file; + unsigned short nMarker_Max = config->GetnMarker_Max(); + unsigned long VTK_Type, iMarker, iChar; + unsigned long iCount = 0; + unsigned long iElem_Bound = 0, iPoint = 0, ielem_div = 0, ielem = 0; + unsigned long vnodes_edge[2], vnodes_triangle[3], vnodes_quad[4]; + unsigned long vnodes_tetra[4], vnodes_hexa[8], vnodes_prism[6], + vnodes_pyramid[5], dummyLong, GlobalIndex; + unsigned long i, j; + char cstr[200]; + su2double Coord_2D[2], Coord_3D[3]; + string::size_type position; + int rank = MASTER_NODE, size = SINGLE_NODE; + bool domain_flag = false; + bool found_transform = false; + bool time_spectral = config->GetUnsteady_Simulation() == TIME_SPECTRAL; + nZone = val_nZone; + + /*--- Initialize some additional counters for the parallel partitioning ---*/ + + unsigned long total_pt_accounted = 0; + unsigned long rem_points = 0; + unsigned long element_count = 0; + unsigned long boundary_marker_count = 0; + unsigned long node_count = 0; + unsigned long loc_element_count = 0; + bool elem_reqd = false; + + /*--- Initialize counters for local/global points & elements ---*/ +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + unsigned long LocalIndex; +#endif + Global_nPoint = 0; Global_nPointDomain = 0; Global_nElem = 0; + nelem_edge = 0; Global_nelem_edge = 0; + nelem_triangle = 0; Global_nelem_triangle = 0; + nelem_quad = 0; Global_nelem_quad = 0; + nelem_tetra = 0; Global_nelem_tetra = 0; + nelem_hexa = 0; Global_nelem_hexa = 0; + nelem_prism = 0; Global_nelem_prism = 0; + nelem_pyramid = 0; Global_nelem_pyramid = 0; + + /*--- Allocate memory for the linear partition of the mesh. These + arrays are the size of the number of ranks. ---*/ + + starting_node = new unsigned long[size]; + ending_node = new unsigned long[size]; + npoint_procs = new unsigned long[size]; + + /*--- Open grid file ---*/ + + strcpy (cstr, val_mesh_filename.c_str()); + mesh_file.open(cstr, ios::in); + + /*--- Check the grid ---*/ + + if (mesh_file.fail()) { + cout << "There is no mesh file (CPhysicalGeometry)!! " << cstr << endl; +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + } + + /*--- If more than one, find the zone in the mesh file ---*/ + + if (val_nZone > 1 || time_spectral) { + if (time_spectral) { + if (rank == MASTER_NODE) cout << "Reading time spectral instance " << val_iZone+1 << ":" << endl; + } else { + while (getline (mesh_file,text_line)) { + /*--- Search for the current domain ---*/ + position = text_line.find ("IZONE=",0); + if (position != string::npos) { + text_line.erase (0,6); + unsigned short jDomain = atoi(text_line.c_str()); + if (jDomain == val_iZone+1) { + if (rank == MASTER_NODE) cout << "Reading zone " << val_iZone+1 << " points:" << endl; + break; + } + } + } + } + } + + /*--- Read grid file with format SU2 ---*/ + + while (getline (mesh_file, text_line)) { + + /*--- Read the dimension of the problem ---*/ + + position = text_line.find ("NDIME=",0); + if (position != string::npos) { + if (domain_flag == false) { + text_line.erase (0,6); nDim = atoi(text_line.c_str()); + if (rank == MASTER_NODE) { + if (nDim == 2) cout << "Two dimensional problem." << endl; + if (nDim == 3) cout << "Three dimensional problem." << endl; + } + domain_flag = true; + } else { break; } + } + + /*--- Read number of points ---*/ + + position = text_line.find ("NPOIN=",0); + if (position != string::npos) { + text_line.erase (0,6); + + /*--- Check for ghost points. ---*/ + stringstream test_line(text_line); + while (test_line >> dummyLong) + iCount++; + + /*--- Now read and store the number of points and possible ghost points. ---*/ + + stringstream stream_line(text_line); + if (iCount == 2) { + stream_line >> nPoint; + stream_line >> nPointDomain; + + /*--- Set some important point information for parallel simulations. ---*/ + + Global_nPoint = nPoint; + Global_nPointDomain = nPointDomain; + if (rank == MASTER_NODE && size > SINGLE_NODE) { + cout << Global_nPointDomain << " points and " << Global_nPoint-Global_nPointDomain; + cout << " ghost points before parallel partitioning." << endl; + } else if (rank == MASTER_NODE) { + cout << Global_nPointDomain << " points and " << Global_nPoint-Global_nPointDomain; + cout << " ghost points." << endl; + } + + } else if (iCount == 1) { + stream_line >> nPoint; + nPointDomain = nPoint; + Global_nPointDomain = nPoint; + Global_nPoint = nPoint; + if (rank == MASTER_NODE && size > SINGLE_NODE) { + cout << nPoint << " points before parallel partitioning." << endl; + } else if (rank == MASTER_NODE) { + cout << nPoint << " points." << endl; + } + } + else { + cout << "NPOIN improperly specified!!" << endl; +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + } + + if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) + cout << "Performing linear partitioning of the grid nodes." << endl; + + /*--- Compute the number of points that will be on each processor. + This is a linear partitioning with the addition of a simple load + balancing for any remainder points. ---*/ + + total_pt_accounted = 0; + for (i = 0; i < (unsigned long)size; i++) { + npoint_procs[i] = nPoint/size; + total_pt_accounted = total_pt_accounted + npoint_procs[i]; + } + + /*--- Get the number of remainder points after the even division ---*/ + rem_points = nPoint-total_pt_accounted; + for (i = 0; i= starting_node[rank]) && (node_count < ending_node[rank])) { + switch(nDim) { + case 2: + GlobalIndex = node_count; +#ifndef HAVE_MPI + point_line >> Coord_2D[0]; point_line >> Coord_2D[1]; +#else + if (size > SINGLE_NODE) { point_line >> Coord_2D[0]; point_line >> Coord_2D[1]; point_line >> LocalIndex; point_line >> GlobalIndex; } + else { point_line >> Coord_2D[0]; point_line >> Coord_2D[1]; LocalIndex = iPoint; GlobalIndex = node_count; } +#endif + node[iPoint] = new CPoint(Coord_2D[0], Coord_2D[1], GlobalIndex, config); + iPoint++; break; + case 3: + GlobalIndex = node_count; +#ifndef HAVE_MPI + point_line >> Coord_3D[0]; point_line >> Coord_3D[1]; point_line >> Coord_3D[2]; +#else + if (size > SINGLE_NODE) { point_line >> Coord_3D[0]; point_line >> Coord_3D[1]; point_line >> Coord_3D[2]; point_line >> LocalIndex; point_line >> GlobalIndex; } + else { point_line >> Coord_3D[0]; point_line >> Coord_3D[1]; point_line >> Coord_3D[2]; LocalIndex = iPoint; GlobalIndex = node_count; } +#endif + node[iPoint] = new CPoint(Coord_3D[0], Coord_3D[1], Coord_3D[2], GlobalIndex, config); + iPoint++; break; + } + } + node_count++; + } + } + } + + mesh_file.close(); + strcpy (cstr, val_mesh_filename.c_str()); + + /*--- Initialize some arrays for the adjacency information (ParMETIS). ---*/ + +// unsigned long *adj_counter = new unsigned long[local_node]; +// unsigned long **adjacent_elem = new unsigned long*[local_node]; + + adj_counter = new unsigned long[local_node]; + adjacent_elem = new unsigned long*[local_node]; + + for (iPoint = 0; iPoint < local_node; iPoint++) { + adjacent_elem[iPoint] = new unsigned long[2000]; + adj_counter[iPoint] = 0; + } + + mesh_file.open(cstr, ios::in); + + /*--- If more than one, find the zone in the mesh file ---*/ + + if (val_nZone > 1 && !time_spectral) { + while (getline (mesh_file,text_line)) { + /*--- Search for the current domain ---*/ + position = text_line.find ("IZONE=",0); + if (position != string::npos) { + text_line.erase (0,6); + unsigned short jDomain = atoi(text_line.c_str()); + if (jDomain == val_iZone+1) { + if (rank == MASTER_NODE) cout << "Reading zone " << val_iZone+1 << " elements:" << endl; + break; + } + } + } + } + + while (getline (mesh_file, text_line)) { + + /*--- Read the information about inner elements ---*/ + + position = text_line.find ("NELEM=",0); + if (position != string::npos) { + text_line.erase (0,6); nElem = atoi(text_line.c_str()); + + /*--- Store total number of elements in the original mesh ---*/ + + Global_nElem = nElem; + if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) + cout << Global_nElem << " interior elements before parallel partitioning." << endl; + + /*--- Allocate space for elements ---*/ + + elem = new CPrimalGrid*[nElem]; + for (unsigned long iElem = 0; iElem < nElem; iElem++) elem[iElem] = NULL; + + + /*--- Set up the global to local element mapping. ---*/ + Global_to_local_elem = new long[nElem]; + for (i = 0; i SINGLE_NODE)) + cout << "Distributing elements across all ranks." << endl; + + /*--- Loop over all the volumetric elements and store any element that + contains at least one of an owned node for this rank (i.e., there will + be element redundancy, since multiple ranks will store the same elems + on the boundaries of the initial linear partitioning. ---*/ + + // TO DO: remove redundant edges (quads have extra diagonals for instance) + + element_count=0; loc_element_count=0; ielem_div=0; + while (ielem_div < nElem) { + getline(mesh_file, text_line); + istringstream elem_line(text_line); + + elem_line >> VTK_Type; + elem_reqd = false; + + /*--- Decide whether this rank needs each element. If so, build the + adjacency arrays needed by ParMETIS and store the element connectivity. + Note that every proc starts it's node indexing from zero. ---*/ + + switch(VTK_Type) { + + case TRIANGLE: + + elem_line >> vnodes_triangle[0]; elem_line >> vnodes_triangle[1]; elem_line >> vnodes_triangle[2]; + for (i = 0; i < N_POINTS_TRIANGLE; i++) { + if ((vnodes_triangle[i]>=starting_node[rank])&&(vnodes_triangle[i]> vnodes_quad[0]; elem_line >> vnodes_quad[1]; elem_line >> vnodes_quad[2]; elem_line >> vnodes_quad[3]; + for (i = 0; i < N_POINTS_QUADRILATERAL; i++) { + if ((vnodes_quad[i]>=starting_node[rank])&&(vnodes_quad[i]> vnodes_tetra[0]; elem_line >> vnodes_tetra[1]; elem_line >> vnodes_tetra[2]; elem_line >> vnodes_tetra[3]; + for (i = 0; i < N_POINTS_TETRAHEDRON; i++) { + if ((vnodes_tetra[i]>=starting_node[rank])&&(vnodes_tetra[i]> vnodes_hexa[0]; elem_line >> vnodes_hexa[1]; elem_line >> vnodes_hexa[2]; + elem_line >> vnodes_hexa[3]; elem_line >> vnodes_hexa[4]; elem_line >> vnodes_hexa[5]; + elem_line >> vnodes_hexa[6]; elem_line >> vnodes_hexa[7]; + for (i = 0; i < N_POINTS_HEXAHEDRON; i++) { + if ((vnodes_hexa[i]>=starting_node[rank])&&(vnodes_hexa[i]> vnodes_prism[0]; elem_line >> vnodes_prism[1]; elem_line >> vnodes_prism[2]; + elem_line >> vnodes_prism[3]; elem_line >> vnodes_prism[4]; elem_line >> vnodes_prism[5]; + for (i = 0; i < N_POINTS_PRISM; i++) { + if ((vnodes_prism[i]>=starting_node[rank])&&(vnodes_prism[i]> vnodes_pyramid[0]; elem_line >> vnodes_pyramid[1]; elem_line >> vnodes_pyramid[2]; + elem_line >> vnodes_pyramid[3]; elem_line >> vnodes_pyramid[4]; + for (i = 0; i < N_POINTS_PYRAMID; i++) { + if ((vnodes_pyramid[i]>=starting_node[rank])&&(vnodes_pyramid[i] SINGLE_NODE)) + cout << "Calling the partitioning functions." << endl; + + /*--- Store the number of local elements on each rank after determining + which elements must be kept in the loop above. ---*/ + + no_of_local_elements = loc_element_count; + + /*--- Post process the adjacency information in order to get it into the + proper format before sending the data to ParMETIS. We need to remove + repeats and adjust the size of the array for each local node. ---*/ + + if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) + cout << "Building the graph adjacency structure." << endl; + + unsigned long loc_adjc_size=0; + vector adjac_vec; + unsigned long adj_elem_size; + vector::iterator it; + local_elem=loc_element_count; + + xadj = new unsigned long [npoint_procs[rank]+1]; + xadj[0]=0; + vector temp_adjacency; + unsigned long local_count=0; + + for (unsigned long i = 0; i < local_node; i++) { + + for (j = 0; j 1 && !time_spectral) { + while (getline (mesh_file,text_line)) { + /*--- Search for the current domain ---*/ + position = text_line.find ("IZONE=",0); + if (position != string::npos) { + text_line.erase (0,6); + unsigned short jDomain = atoi(text_line.c_str()); + if (jDomain == val_iZone+1) { + if (rank == MASTER_NODE) cout << "Reading zone " << val_iZone+1 << " markers:" << endl; + break; + } + } + } + } + + if (rank == MASTER_NODE) { + + while (getline (mesh_file, text_line)) { + /*--- Read number of markers ---*/ + position = text_line.find ("NMARK=",0); + boundary_marker_count = 0; + if (position != string::npos) { + text_line.erase (0,6); nMarker = atoi(text_line.c_str()); + if (rank == MASTER_NODE) cout << nMarker << " surface markers." << endl; + config->SetnMarker_All(nMarker); + bound = new CPrimalGrid**[nMarker]; + nElem_Bound = new unsigned long [nMarker]; + Tag_to_Marker = new string [nMarker_Max]; + + for (iMarker = 0 ; iMarker < nMarker; iMarker++) { + getline (mesh_file, text_line); + text_line.erase (0,11); + string::size_type position; + for (iChar = 0; iChar < 20; iChar++) { + position = text_line.find( " ", 0 ); + if (position != string::npos) text_line.erase (position,1); + position = text_line.find( "\r", 0 ); + if (position != string::npos) text_line.erase (position,1); + position = text_line.find( "\n", 0 ); + if (position != string::npos) text_line.erase (position,1); + } + Marker_Tag = text_line.c_str(); + + /*--- Physical boundaries definition ---*/ + if (Marker_Tag != "SEND_RECEIVE") { + getline (mesh_file, text_line); + text_line.erase (0,13); nElem_Bound[iMarker] = atoi(text_line.c_str()); + if (rank == MASTER_NODE) + cout << nElem_Bound[iMarker] << " boundary elements in index "<< iMarker <<" (Marker = " <> VTK_Type; + switch(VTK_Type) { + case LINE: + + if (nDim == 3) { + cout << "Please remove line boundary conditions from the mesh file!" << endl; +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + } + + bound_line >> vnodes_edge[0]; bound_line >> vnodes_edge[1]; + bound[iMarker][ielem] = new CLine(vnodes_edge[0], vnodes_edge[1],2); + ielem++; nelem_edge_bound++; break; + + case TRIANGLE: + bound_line >> vnodes_triangle[0]; bound_line >> vnodes_triangle[1]; bound_line >> vnodes_triangle[2]; + bound[iMarker][ielem] = new CTriangle(vnodes_triangle[0], vnodes_triangle[1], vnodes_triangle[2],3); + ielem++; nelem_triangle_bound++; break; + + case QUADRILATERAL: + + bound_line >> vnodes_quad[0]; bound_line >> vnodes_quad[1]; bound_line >> vnodes_quad[2]; bound_line >> vnodes_quad[3]; + + bound[iMarker][ielem] = new CQuadrilateral(vnodes_quad[0], vnodes_quad[1], vnodes_quad[2], vnodes_quad[3],3); + ielem++; nelem_quad_bound++; + + break; + + + } + } + + /*--- Update config information storing the boundary information in the right place ---*/ + + Tag_to_Marker[config->GetMarker_CfgFile_TagBound(Marker_Tag)] = Marker_Tag; + config->SetMarker_All_TagBound(iMarker, Marker_Tag); + config->SetMarker_All_KindBC(iMarker, config->GetMarker_CfgFile_KindBC(Marker_Tag)); + config->SetMarker_All_Monitoring(iMarker, config->GetMarker_CfgFile_Monitoring(Marker_Tag)); + config->SetMarker_All_GeoEval(iMarker, config->GetMarker_CfgFile_GeoEval(Marker_Tag)); + config->SetMarker_All_Designing(iMarker, config->GetMarker_CfgFile_Designing(Marker_Tag)); + config->SetMarker_All_Plotting(iMarker, config->GetMarker_CfgFile_Plotting(Marker_Tag)); + config->SetMarker_All_FSIinterface(iMarker, config->GetMarker_CfgFile_FSIinterface(Marker_Tag)); + config->SetMarker_All_DV(iMarker, config->GetMarker_CfgFile_DV(Marker_Tag)); + config->SetMarker_All_Moving(iMarker, config->GetMarker_CfgFile_Moving(Marker_Tag)); + config->SetMarker_All_PerBound(iMarker, config->GetMarker_CfgFile_PerBound(Marker_Tag)); + config->SetMarker_All_SendRecv(iMarker, NONE); + config->SetMarker_All_Out_1D(iMarker, config->GetMarker_CfgFile_Out_1D(Marker_Tag)); + + } + + /*--- Send-Receive boundaries definition ---*/ + + else { + unsigned long nelem_vertex = 0, vnodes_vertex; + unsigned short transform; + getline (mesh_file, text_line); + text_line.erase (0,13); nElem_Bound[iMarker] = atoi(text_line.c_str()); + bound[iMarker] = new CPrimalGrid* [nElem_Bound[iMarker]]; + + nelem_vertex = 0; ielem = 0; + getline (mesh_file, text_line); text_line.erase (0,8); + config->SetMarker_All_KindBC(iMarker, SEND_RECEIVE); + config->SetMarker_All_SendRecv(iMarker, atoi(text_line.c_str())); + + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + getline(mesh_file, text_line); + istringstream bound_line(text_line); + bound_line >> VTK_Type; bound_line >> vnodes_vertex; bound_line >> transform; + + bound[iMarker][ielem] = new CVertexMPI(vnodes_vertex, nDim); + bound[iMarker][ielem]->SetRotation_Type(transform); + ielem++; nelem_vertex++; + } + + } + boundary_marker_count++; + } + if (boundary_marker_count == nMarker) break; + } + } + + while (getline (mesh_file, text_line)) { + + /*--- Read periodic transformation info (center, rotation, translation) ---*/ + + position = text_line.find ("NPERIODIC=",0); + if (position != string::npos) { + unsigned short nPeriodic, iPeriodic, iIndex; + + /*--- Set bool signifying that periodic transormations were found ---*/ + found_transform = true; + + /*--- Read and store the number of transformations. ---*/ + text_line.erase (0,10); nPeriodic = atoi(text_line.c_str()); + if (rank == MASTER_NODE) { + if (nPeriodic - 1 != 0) + cout << nPeriodic - 1 << " periodic transformations." << endl; + } + config->SetnPeriodicIndex(nPeriodic); + + /*--- Store center, rotation, & translation in that order for each. ---*/ + for (iPeriodic = 0; iPeriodic < nPeriodic; iPeriodic++) { + getline (mesh_file, text_line); + position = text_line.find ("PERIODIC_INDEX=",0); + if (position != string::npos) { + text_line.erase (0,15); iIndex = atoi(text_line.c_str()); + if (iIndex != iPeriodic) { + cout << "PERIODIC_INDEX out of order in SU2 file!!" << endl; +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + } + } + su2double* center = new su2double[3]; + su2double* rotation = new su2double[3]; + su2double* translate = new su2double[3]; + getline (mesh_file, text_line); + istringstream cent(text_line); + cent >> center[0]; cent >> center[1]; cent >> center[2]; + config->SetPeriodicCenter(iPeriodic, center); + getline (mesh_file, text_line); + istringstream rot(text_line); + rot >> rotation[0]; rot >> rotation[1]; rot >> rotation[2]; + config->SetPeriodicRotation(iPeriodic, rotation); + getline (mesh_file, text_line); + istringstream tran(text_line); + tran >> translate[0]; tran >> translate[1]; tran >> translate[2]; + config->SetPeriodicTranslate(iPeriodic, translate); + + } + } + } + + /*--- If no periodic transormations were found, store default zeros ---*/ + + if (!found_transform) { + unsigned short nPeriodic = 1, iPeriodic = 0; + config->SetnPeriodicIndex(nPeriodic); + su2double* center = new su2double[3]; + su2double* rotation = new su2double[3]; + su2double* translate = new su2double[3]; + for (unsigned short iDim = 0; iDim < 3; iDim++) { + center[iDim] = 0.0; rotation[iDim] = 0.0; translate[iDim] = 0.0; + } + config->SetPeriodicCenter(iPeriodic, center); + config->SetPeriodicRotation(iPeriodic, rotation); + config->SetPeriodicTranslate(iPeriodic, translate); + } + } + + /*--- Close the input file ---*/ + + mesh_file.close(); + + +} + +void CPhysicalGeometry::Read_CGNS_Format_Parallel(CConfig *config, string val_mesh_filename, unsigned short val_iZone, unsigned short val_nZone) { + + /*--- Original CGNS reader implementation by Thomas D. Economon, + Francisco Palacios. Improvements for mixed-element meshes generated + by ICEM added by Martin Spel (3D) & Shlomy Shitrit (2D), April 2014. + Parallel version by Thomas D. Economon, February 2015. ---*/ + +#ifdef HAVE_CGNS + + string text_line, Marker_Tag; + ifstream mesh_file; + unsigned short VTK_Type = 0, iMarker = 0; + unsigned short nMarker_Max = config->GetnMarker_Max(); + unsigned long iPoint = 0, iProcessor = 0, ielem = 0, GlobalIndex = 0; + unsigned long globalOffset = 0; + int rank = MASTER_NODE, size = SINGLE_NODE; + nZone = val_nZone; + + /*--- Local variables needed when calling the CGNS mid-level API. ---*/ + + unsigned long vnodes_cgns[8] = {0,0,0,0,0,0,0,0}; + su2double Coord_cgns[3] = {0.0,0.0,0.0}; + int fn, nbases = 0, nzones = 0, ngrids = 0, ncoords = 0, nsections = 0; + int *vertices = NULL, *cells = NULL, nMarkers = 0, *boundVerts = NULL, npe; + int interiorElems = 0, totalVerts = 0; + int cell_dim = 0, phys_dim = 0, nbndry, parent_flag, file_type; + char basename[CGNS_STRING_SIZE], zonename[CGNS_STRING_SIZE]; + char coordname[CGNS_STRING_SIZE]; + cgsize_t* cgsize; cgsize = new cgsize_t[3]; + ZoneType_t zonetype; + DataType_t datatype; + su2double** coordArray = NULL; + su2double*** gridCoords = NULL; + ElementType_t elemType; + cgsize_t range_min, range_max, startE, endE; + range_min = 1; + string currentElem; + int** elemTypeVTK = NULL; + int** elemIndex = NULL; + int** elemBegin = NULL; + int** elemEnd = NULL; + int** nElems = NULL; + cgsize_t**** connElems = NULL; + cgsize_t* connElemCGNS = NULL; + cgsize_t* connElemTemp = NULL; + cgsize_t ElementDataSize = 0; + cgsize_t* parentData = NULL; + int** dataSize = NULL; + bool** isInternal = NULL; + char*** sectionNames = NULL; + //int indexMax; // check memory issue + + /*--- Initialize counters for local/global points & elements ---*/ + +#ifdef HAVE_MPI + unsigned long Local_nElem; + unsigned long Local_nElemTri, Local_nElemQuad, Local_nElemTet; + unsigned long Local_nElemHex, Local_nElemPrism, Local_nElemPyramid; + + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + + MPI_Request *send_req, *recv_req; + MPI_Status status; + int ind; +#endif + + /*--- Initialize counters for local/global points & elements ---*/ + + Global_nPoint = 0; Global_nPointDomain = 0; Global_nElem = 0; + nelem_edge = 0; Global_nelem_edge = 0; + nelem_triangle = 0; Global_nelem_triangle = 0; + nelem_quad = 0; Global_nelem_quad = 0; + nelem_tetra = 0; Global_nelem_tetra = 0; + nelem_hexa = 0; Global_nelem_hexa = 0; + nelem_prism = 0; Global_nelem_prism = 0; + nelem_pyramid = 0; Global_nelem_pyramid = 0; + + /*--- Initialize some additional counters for the parallel partitioning ---*/ + + unsigned long total_pt_accounted = 0; + unsigned long rem_points = 0; + unsigned long element_count = 0; + unsigned long element_remainder = 0; + unsigned long total_elems = 0; + + /*--- Allocate memory for the linear partitioning of the mesh. These + arrays are the size of the number of ranks. ---*/ + + starting_node = new unsigned long[size]; + ending_node = new unsigned long[size]; + npoint_procs = new unsigned long[size]; + + unsigned long *nPoint_Linear = new unsigned long[size+1]; + unsigned long *nElem_Linear = new unsigned long[size]; + + unsigned long *elemB = new unsigned long[size]; + unsigned long *elemE = new unsigned long[size]; + + unsigned long *elemGlobalID = NULL; + + unsigned short *nPoinPerElem = NULL; + unsigned short *elemTypes = NULL; + + bool *isMixed = NULL; + + unsigned short connSize = 10; + + /*--- Check whether the supplied file is truly a CGNS file. ---*/ + if (cg_is_cgns(val_mesh_filename.c_str(), &file_type) != CG_OK) { + if (rank == MASTER_NODE) { + printf( "\n\n !!! Error !!!\n" ); + printf( " %s is not a CGNS file.\n", val_mesh_filename.c_str()); + printf( " Now exiting...\n\n"); + } +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + } + + /*--- Open the CGNS file for reading. The value of fn returned + is the specific index number for this file and will be + repeatedly used in the function calls. ---*/ + + if (cg_open(val_mesh_filename.c_str(), CG_MODE_READ, &fn)) cg_error_exit(); + if (rank == MASTER_NODE) { + cout << "Reading the CGNS file: "; + cout << val_mesh_filename.c_str() << "." << endl; + } + + /*--- Get the number of databases. This is the highest node + in the CGNS heirarchy. ---*/ + + if ( cg_nbases(fn, &nbases) ) cg_error_exit(); + if (rank == MASTER_NODE) + cout << "CGNS file contains " << nbases << " database(s)." << endl; + + /*--- Check if there is more than one database. Throw an + error if there is because this reader can currently + only handle one database. ---*/ + + if ( nbases > 1 ) { + if (rank == MASTER_NODE) { + printf("\n\n !!! Error !!!\n" ); + printf("CGNS reader currently incapable of handling more than 1 database."); + printf("Now exiting...\n\n"); + } +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + } + + /*--- Read the databases. Note that the CGNS indexing starts at 1. ---*/ + + for (int i = 1; i <= nbases; i++) { + + if (cg_base_read(fn, i, basename, &cell_dim, &phys_dim)) cg_error_exit(); + + /*--- Get the number of zones for this base. ---*/ + + if ( cg_nzones(fn, i, &nzones) ) cg_error_exit(); + if (rank == MASTER_NODE) { + cout << "Database " << i << ", " << basename << ": " << nzones; + cout << " zone(s), cell dimension of " << cell_dim << ", physical "; + cout << "dimension of " << phys_dim << "." << endl; + } + + /*--- Check if there is more than one zone. Throw an + error if there is, because this reader can currently + only handle one zone. This could be extended in the future. ---*/ + + if ( nzones > 1 ) { + if (rank == MASTER_NODE) { + printf("\n\n !!! Error !!!\n" ); + printf("CGNS reader currently incapable of handling more than 1 zone."); + printf("Now exiting...\n\n"); + } +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + } + + /*--- Initialize some data structures for all zones. ---*/ + + vertices = new int[nzones]; + cells = new int[nzones]; + boundVerts = new int[nzones]; + coordArray = new su2double*[nzones]; + gridCoords = new su2double**[nzones]; + elemTypeVTK = new int*[nzones]; + elemIndex = new int*[nzones]; + elemBegin = new int*[nzones]; + elemEnd = new int*[nzones]; + nElems = new int*[nzones]; + dataSize = new int*[nzones]; + isInternal = new bool*[nzones]; + nMarkers = 0; + sectionNames = new char**[nzones]; + connElems = new cgsize_t***[nzones]; + + /*--- Loop over all zones in this base. Again, indexing starts at 1. ---*/ + + for (int j = 1; j <= nzones; j++) { + + /*--- Read the basic information for this zone, including + the name and the number of vertices, cells, and + boundary cells which are stored in the cgsize variable. ---*/ + + if (cg_zone_read(fn, i, j, zonename, cgsize)) cg_error_exit(); + + /*--- Rename the zone size information for clarity. + NOTE: The number of cells here may be only the number of + interior elements or it may be the total. This needs to + be counted explicitly later. ---*/ + + vertices[j-1] = cgsize[0]; + cells[j-1] = cgsize[1]; + boundVerts[j-1] = cgsize[2]; + + /*--- Increment the total number of vertices from all zones. ---*/ + + nPoint = vertices[j-1]; + nPointDomain = vertices[j-1]; + + Global_nPoint = vertices[j-1]; + Global_nPointDomain = vertices[j-1]; + + totalVerts += vertices[j-1]; + + /*--- Print some information about the current zone. ---*/ + + if (cg_zone_type(fn, i, j, &zonetype)) cg_error_exit(); + if (rank == MASTER_NODE) { + cout << "Zone " << j << ", " << zonename << ": " << vertices[j-1]; + cout << " vertices, " << cells[j-1] << " cells, " << boundVerts[j-1]; + cout << " boundary vertices." << endl; + } + + /*--- Retrieve the number of grids in this zone. For now, we know + this is one, but to be more general, this will need to check and + allow for a loop over all grids. ---*/ + + if (cg_ngrids(fn, i, j, &ngrids)) cg_error_exit(); + if (ngrids > 1) { + if (rank == MASTER_NODE) { + printf("\n\n !!! Error !!!\n" ); + printf("CGNS reader currently handles only 1 grid per zone."); + printf("Now exiting...\n\n"); + } +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + } + + /*--- Check the number of coordinate arrays stored in this zone. + Should be 2 for 2-D grids and 3 for 3-D grids. ---*/ + + if (cg_ncoords( fn, i, j, &ncoords)) cg_error_exit(); + if (rank == MASTER_NODE) { + cout << "Reading grid coordinates." << endl; + cout << "Number of coordinate dimensions is " << ncoords << "." << endl; + } + + /*--- Compute the number of points that will be on each processor. + This is a linear partitioning with the addition of a simple load + balancing for any remainder points. ---*/ + + total_pt_accounted = 0; + for (int ii = 0; ii < size; ii++) { + npoint_procs[ii] = vertices[j-1]/size; + total_pt_accounted = total_pt_accounted + npoint_procs[ii]; + } + + /*--- Get the number of remainder points after the even division ---*/ + + rem_points = vertices[j-1]-total_pt_accounted; + for (unsigned long ii = 0; ii < rem_points; ii++) { + npoint_procs[ii]++; + } + + /*--- Store the local number of nodes and the beginning/end index ---*/ + + local_node = npoint_procs[rank]; + starting_node[0] = 0; + ending_node[0] = starting_node[0] + npoint_procs[0]; + nPoint_Linear[0] = 0; + for (int ii = 1; ii < size; ii++) { + starting_node[ii] = ending_node[ii-1]; + ending_node[ii] = starting_node[ii] + npoint_procs[ii]; + nPoint_Linear[ii] = nPoint_Linear[ii-1] + npoint_procs[ii-1]; + } + nPoint_Linear[size] = vertices[j-1]; + + /*--- Set the value of range_max to the total number of nodes in + the unstructured mesh. Also allocate memory for the temporary array + that will hold the grid coordinates as they are extracted. Note the + +1 for CGNS convention. ---*/ + + range_min = (cgsize_t)starting_node[rank]+1; + range_max = (cgsize_t)ending_node[rank]; + coordArray[j-1] = new su2double[local_node]; + + /*--- Allocate memory for the 2-D array that will store the x, y, + & z (if required) coordinates for writing into the SU2 mesh. ---*/ + + gridCoords[j-1] = new su2double*[ncoords]; + for (int ii = 0; ii < ncoords; ii++) { + *(gridCoords[j-1]+ii) = new su2double[local_node]; + } + + /*--- Loop over each set of coordinates. Note again + that the indexing starts at 1. ---*/ + + for (int k = 1; k <= ncoords; k++) { + + /*--- Read the coordinate info. This will retrieve the + data type (either RealSingle or RealDouble) as + well as the coordname which will specifiy the + type of data that it is based in the SIDS convention. + This might be "CoordinateX," for instance. ---*/ + + if (cg_coord_info(fn, i, j, k, &datatype, coordname)) + cg_error_exit(); + if (rank == MASTER_NODE) { + cout << "Loading " << coordname; + cout << " values into linear partitions." << endl; + } + + /*--- Always retrieve the grid coords in su2double precision. ---*/ + + if (datatype != RealDouble) { + printf("\n\n !!! Error !!!\n" ); + printf(" CGNS coordinates are not su2double precision.\n"); + printf(" Now exiting...\n\n"); +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + } + if ( cg_coord_read(fn, i, j, coordname, datatype, &range_min, + &range_max, coordArray[j-1]) ) cg_error_exit(); + + /*--- Copy these coords into the array for storage until + writing the SU2 mesh. ---*/ + + for (unsigned long m = 0; m < local_node; m++ ) { + gridCoords[j-1][k-1][m] = coordArray[j-1][m]; + } + + } + + /*--- Begin section for retrieving the connectivity info. ---*/ + + if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) + cout << "Distributing connectivity across all ranks." << endl; + + /*--- First check the number of sections. ---*/ + + if ( cg_nsections(fn, i, j, &nsections) ) cg_error_exit(); + if (rank == MASTER_NODE) { + cout << "Number of connectivity sections is "; + cout << nsections << "." << endl; + } + + /*--- Allocate several data structures to hold the various + pieces of information describing each section. It is + stored in this manner so that it can be written to + SU2 memory later. ---*/ + + elemTypeVTK[j-1] = new int[nsections]; + elemIndex[j-1] = new int[nsections]; + elemBegin[j-1] = new int[nsections]; + elemEnd[j-1] = new int[nsections]; + nElems[j-1] = new int[nsections]; + dataSize[j-1] = new int[nsections]; + isInternal[j-1] = new bool[nsections]; + + sectionNames[j-1] = new char*[nsections]; + for (int ii = 0; ii < nsections; ii++) { + sectionNames[j-1][ii]= new char[CGNS_STRING_SIZE]; + } + + connElems[j-1] = new cgsize_t**[nsections]; + + /*--- Loop over each section. This will include the main + connectivity information for the grid cells, as well + as any boundaries which were labeled before export. ---*/ + + for (int s = 1; s <= nsections; s++) { + + /*--- Read the connectivity details for this section. + Store the total number of elements in this section + to be used later for memory allocation. ---*/ + + if (cg_section_read(fn, i, j, s, sectionNames[j-1][s-1], + &elemType, &startE, &endE, &nbndry, + &parent_flag)) cg_error_exit(); + + /*--- Store the beginning and ending index for this section. ---*/ + + elemBegin[j-1][s-1] = (int)startE; + elemEnd[j-1][s-1] = (int)endE; + + /*--- Compute element linear partitioning ---*/ + + element_count = (int) (endE-startE+1); + total_elems = 0; + for (int ii = 0; ii < size; ii++) { + nElem_Linear[ii] = element_count/size; + total_elems += nElem_Linear[ii]; + } + + /*--- Get the number of remainder elements after even division ---*/ + + element_remainder = element_count-total_elems; + for (unsigned long ii = 0; ii < element_remainder; ii++) { + nElem_Linear[ii]++; + } + + /*--- Store the number of elements that this rank is responsible for + in the current section. ---*/ + + nElems[j-1][s-1] = (int)nElem_Linear[rank]; + + /*--- Get starting and end element index for my rank. ---*/ + + elemB[0] = startE; + elemE[0] = startE + nElem_Linear[0] - 1; + for (unsigned long ii = 1; ii < (unsigned long)size; ii++) { + elemB[ii] = elemE[ii-1]+1; + elemE[ii] = elemB[ii] + nElem_Linear[ii] - 1; + } + + /*--- Allocate some memory for the handling the connectivity + and auxiliary data that we are need to communicate. ---*/ + + connElemCGNS = new cgsize_t[nElems[j-1][s-1]*connSize]; + nPoinPerElem = new unsigned short[nElems[j-1][s-1]]; + elemGlobalID = new unsigned long[nElems[j-1][s-1]]; + elemTypes = new unsigned short[nElems[j-1][s-1]]; + + isMixed = new bool[nElems[j-1][s-1]]; + for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) isMixed[ii] = false; + + /*--- Retrieve the connectivity information and store. Note that + we are only accessing our rank's piece of the data here in the + partial read function in the CGNS API. ---*/ + + if (cg_elements_partial_read(fn, i, j, s, (cgsize_t)elemB[rank], + (cgsize_t)elemE[rank], connElemCGNS, + parentData) != CG_OK) cg_error_exit(); + + /*--- Find the number of nodes required to represent + this type of element. ---*/ + + ElementType_t elmt_type; + if (cg_npe(elemType, &npe)) cg_error_exit(); + + /*--- Loop through all of the elements in this section to get more + information and to decide whether it has internal elements. ---*/ + + int counter = 0; + for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) { + + /*--- If we have a mixed element section, we need to check the elem + type one by one. Set the flag to true if mixed. ---*/ + + if (elemType == MIXED) { + elmt_type = ElementType_t(connElemCGNS[counter]); + cg_npe(elmt_type, &npe); + counter++; for ( int jj = 0; jj < npe; jj++ ) counter++; + isMixed[ii] = true; + } else { + elmt_type = elemType; + } + + /*--- Store the number of verts per elem for the current elem. ---*/ + + nPoinPerElem[ii] = npe; + + /*--- Store the global ID for this element. Note the -1 to move + from CGNS convention to SU2 convention. We also subtract off + an additional offset in case we have found boundary sections + prior to this one, in order to keep the internal element global + IDs indexed starting from zero. ---*/ + + elemGlobalID[ii] = elemB[rank] + ii - 1 - globalOffset; + + /*--- Need to check the element type and correctly specify the + VTK identifier for that element. SU2 recognizes elements by + their VTK number. ---*/ + + switch (elmt_type) { + case NODE: + currentElem = "Vertex"; + elemTypes[ii] = 1; + break; + case BAR_2: + currentElem = "Line"; + elemTypes[ii] = 3; + break; + case BAR_3: + currentElem = "Line"; + elemTypes[ii] = 3; + break; + case TRI_3: + currentElem = "Triangle"; + elemTypes[ii] = 5; + break; + case QUAD_4: + currentElem = "Quadrilateral"; + elemTypes[ii] = 9; + break; + case TETRA_4: + currentElem = "Tetrahedron"; + elemTypes[ii] = 10; + break; + case HEXA_8: + currentElem = "Hexahedron"; + elemTypes[ii] = 12; + break; + case PENTA_6: + currentElem = "Prism"; + elemTypes[ii] = 13; + break; + case PYRA_5: + currentElem = "Pyramid"; + elemTypes[ii] = 14; + break; + case HEXA_20: + if (rank == MASTER_NODE) { + printf("\n\n !!! Error !!!\n" ); + printf(" HEXA-20 element type not supported\n"); + printf(" Section %d, npe=%d\n", s, npe); + printf(" startE %d, endE %d\n", startE, endE); + printf(" Now exiting...\n\n"); + } +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + break; + default: + if (rank == MASTER_NODE) { + printf("\n\n !!! Error !!!\n" ); + printf(" Unknown elem: (type %d, npe=%d)\n", elemType, npe); + printf(" Section %d\n", s); + printf(" startE %d, endE %d\n", startE, endE); + printf(" Now exiting...\n\n"); + } +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + break; + } + + /*--- Check if the elements in this section are part + of the internal domain or are part of the boundary + surfaces. This will be used to separate the + internal connectivity from the boundary connectivity. + We will check for quad and tri elements for 3-D meshes + because these will be the boundaries. Similarly, line + elements will be boundaries to 2-D problems. ---*/ + + if ( cell_dim == 2 ) { + + /*--- In 2-D check for line elements, VTK type 3. ---*/ + + if (elemTypes[ii] == 3) { + isInternal[j-1][s-1] = false; + } else { + isInternal[j-1][s-1] = true; + interiorElems++; + } + + } else if (cell_dim == 3) { + + /*--- In 3-D check for tri/quad elements, VTK types 5 or 9. ---*/ + + switch (elemTypes[ii]) { + case 5: + case 9: + isInternal[j-1][s-1] = false; + break; + default: + isInternal[j-1][s-1] = true; + interiorElems++; + break; + } + + } + } + + /*--- Print some information to the console. ---*/ + + if (rank == MASTER_NODE) { + for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) + if (isMixed[ii]) {currentElem = "Mixed"; break;} + cout << "Loading section " << sectionNames[j-1][s-1]; + cout << " of element type " << currentElem << "." << endl; + } + + /*--- If we have found that this is a boundary section (we assume + that internal cells and boundary cells do not exist in the same + section together), the master node read the boundary section. + Otherwise, we have all ranks read and communicate the internals. ---*/ + + if (!isInternal[j-1][s-1]) { + + /*--- Master node should read this entire marker section. Free + the memory for the conn. from the CGNS file since we are going + to read the section again with the master. ---*/ + + delete [] connElemCGNS; + delete [] nPoinPerElem; + delete [] elemTypes; + delete [] elemGlobalID; + delete [] isMixed; + + /*--- Since we found an internal section, we should adjust the + element global ID offset by the total size of the section. ---*/ + + globalOffset += element_count; + + if (rank == MASTER_NODE) { + + /*--- First increment the markers ---*/ + + nMarkers++; + + /*--- Read the section info again ---*/ + + if ( cg_section_read(fn, i, j, s, sectionNames[j-1][s-1], + &elemType, &startE, &endE, &nbndry, + &parent_flag) ) cg_error_exit(); + + /*--- Store the number of elems (all on the master). ---*/ + + nElems[j-1][s-1] = (int) (endE-startE+1); + + /*--- Read and store the total amount of data that will be + listed when reading this section. ---*/ + + if (cg_ElementDataSize(fn, i, j, s, &ElementDataSize)) + cg_error_exit(); + dataSize[j-1][s-1] = ElementDataSize; + + /*--- Find the number of nodes required to represent + this type of element. ---*/ + + if (cg_npe(elemType, &npe)) cg_error_exit(); + elemIndex[j-1][s-1] = npe; + + /*--- Need to check the element type and correctly + specify the VTK identifier for that element. + SU2 recognizes elements by their VTK number. ---*/ + + switch (elemType) { + case NODE: + elemTypeVTK[j-1][s-1] = 1; + break; + case BAR_2: + elemTypeVTK[j-1][s-1] = 3; + break; + case BAR_3: + elemTypeVTK[j-1][s-1] = 3; + break; + case TRI_3: + elemTypeVTK[j-1][s-1] = 5; + break; + case QUAD_4: + elemTypeVTK[j-1][s-1] = 9; + break; + case TETRA_4: + elemTypeVTK[j-1][s-1] = 10; + break; + case HEXA_8: + elemTypeVTK[j-1][s-1] = 12; + break; + case PENTA_6: + elemTypeVTK[j-1][s-1] = 13; + break; + case PYRA_5: + elemTypeVTK[j-1][s-1] = 14; + break; + case HEXA_20: + printf( "\n\n !!! Error !!!\n" ); + printf( " HEXA-20 element type not supported\n"); + printf(" Section %d, npe=%d\n", s, npe); + printf(" startE %d, endE %d\n", startE, endE); + printf( " Now exiting...\n\n"); +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + break; + case MIXED: + currentElem = "Mixed"; + elemTypeVTK[j-1][s-1] = -1; + break; + default: + printf( "\n\n !!! Error !!!\n" ); + printf( " Unknown elem: (type %d, npe=%d)\n", elemType, npe); + printf(" Section %d\n", s); + printf(" startE %d, endE %d\n", startE, endE); + printf( " Now exiting...\n\n"); +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + break; + } + + /*--- In case of mixed data type, allocate place for 8 nodes + maximum (hex), plus element type. ---*/ + + if (elemTypeVTK[j-1][s-1] == -1) elemIndex[j-1][s-1] = 9; + + /*--- Allocate memory for accessing the connectivity and to + store it in the proper data structure for post-processing. ---*/ + + connElemTemp = new cgsize_t[dataSize[j-1][s-1]]; + + connElems[j-1][s-1] = new cgsize_t*[elemIndex[j-1][s-1]]; + for (int jj = 0; jj < elemIndex[j-1][s-1]; jj++) { + connElems[j-1][s-1][jj] = new cgsize_t[nElems[j-1][s-1]]; + } + + /*--- Retrieve the connectivity information and store. ---*/ + + if (cg_elements_read(fn, i, j, s, connElemTemp, parentData)) + cg_error_exit(); + + /*--- Copy these values into the larger array for + storage until writing the SU2 file. ---*/ + + if (elemTypeVTK[j-1][s-1] == -1) { + int counter = 0; + for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) { + ElementType_t elmt_type = ElementType_t(connElemTemp[counter]); + cg_npe( elmt_type, &npe); + counter++; + connElems[j-1][s-1][0][ii] = elmt_type; + for ( int jj = 0; jj < npe; jj++ ) { + connElems[j-1][s-1][jj+1][ii] = connElemTemp[counter] - 1; + counter++; + } + } + } else { + int counter = 0; + for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) { + for ( int jj = 0; jj < elemIndex[j-1][s-1]; jj++ ) { + connElems[j-1][s-1][jj][ii] = connElemTemp[counter] - 1; + counter++; + } + } + } + delete[] connElemTemp; + + } // end master + + } else { + + /*--- These are internal elems. Allocate memory on each proc. ---*/ + + connElemTemp = new cgsize_t[nElems[j-1][s-1]*connSize]; + + /*--- Copy these values into the larger array for + storage until writing the SU2 file. ---*/ + + int counterTemp = 0, counterCGNS = 0; + for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) { + + /*--- Store the conn in chunks of connSize for simplicity. ---*/ + + counterTemp = ii*connSize; + + /*--- Store the connectivity values. Note we subtract one from + the CGNS 1-based convention. We may also need to remove the first + entry is this is a mixed element section. ---*/ + + if (isMixed[ii]) counterCGNS++; + for ( int jj = 0; jj < nPoinPerElem[ii]; jj++) { + connElemTemp[counterTemp] = connElemCGNS[counterCGNS + jj] - 1; + counterTemp++; + } + counterCGNS += nPoinPerElem[ii]; + + } + + /*--- Free the memory for the conn. from the CGNS file. ---*/ + + delete [] connElemCGNS; + delete [] isMixed; + + /*--- We now have the connectivity stored in linearly partitioned + chunks. We need to loop through and decide how many elements we + must send to each rank in order to have all elements that + surround a particular "owned" node on each rank (i.e., elements + will appear on multiple ranks). First, initialize a counter + and flag. ---*/ + + int *nElem_Send = new int[size+1]; nElem_Send[0] = 0; + int *nElem_Recv = new int[size+1]; nElem_Recv[0] = 0; + int *nElem_Flag = new int[size]; + + for (int ii=0; ii < size; ii++) { + nElem_Send[ii] = 0; + nElem_Recv[ii] = 0; + nElem_Flag[ii]= -1; + } + nElem_Send[size] = 0; nElem_Recv[size] = 0; + + for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) { + for ( int jj = 0; jj < nPoinPerElem[ii]; jj++ ) { + + /*--- Get the index of the current point. ---*/ + + iPoint = connElemTemp[ii*connSize + jj]; + + /*--- Search for the processor that owns this point ---*/ + + iProcessor = iPoint/npoint_procs[0]; + if (iProcessor >= (unsigned long)size) iProcessor = (unsigned long)size-1; + if (iPoint >= nPoint_Linear[iProcessor]) + while(iPoint >= nPoint_Linear[iProcessor+1]) iProcessor++; + else + while(iPoint < nPoint_Linear[iProcessor]) iProcessor--; + + /*--- If we have not visted this element yet, increment our + number of elements that must be sent to a particular proc. ---*/ + + if (nElem_Flag[iProcessor] != ii) { + nElem_Flag[iProcessor] = ii; + nElem_Send[iProcessor+1]++; + } + + } + } + + /*--- Communicate the number of cells to be sent/recv'd amongst + all processors. After this communication, each proc knows how + many cells it will receive from each other processor. ---*/ + +#ifdef HAVE_MPI + MPI_Alltoall(&(nElem_Send[1]), 1, MPI_INT, + &(nElem_Recv[1]), 1, MPI_INT, MPI_COMM_WORLD); +#else + nElem_Recv[1] = nElem_Send[1]; +#endif + + /*--- Prepare to send connectivities. First check how many + messages we will be sending and receiving. Here we also put + the counters into cumulative storage format to make the + communications simpler. ---*/ + + int nSends = 0, nRecvs = 0; + for (int ii=0; ii < size; ii++) nElem_Flag[ii] = -1; + + for (int ii = 0; ii < size; ii++) { + + if ((ii != rank) && (nElem_Send[ii+1] > 0)) nSends++; + if ((ii != rank) && (nElem_Recv[ii+1] > 0)) nRecvs++; + + nElem_Send[ii+1] += nElem_Send[ii]; + nElem_Recv[ii+1] += nElem_Recv[ii]; + } + + /*--- Allocate memory to hold the connectivity that we are + sending. Note that we are also sending the VTK element type + in the first position and also the global ID. We have assumed + a constant message size of a hex element + 2 extra vals. ---*/ + + unsigned long *connSend = NULL; + connSend = new unsigned long[connSize*nElem_Send[size]]; + for (int ii = 0; ii < connSize*nElem_Send[size]; ii++) + connSend[ii] = 0; + + /*--- Create an index variable to keep track of our index + position as we load up the send buffer. ---*/ + + unsigned long *index = new unsigned long[size]; + for (int ii=0; ii < size; ii++) index[ii] = connSize*nElem_Send[ii]; + + /*--- Loop through our elements and load the elems and their + additional data that we will send to the other procs. ---*/ + + for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) { + for ( int jj = 0; jj < nPoinPerElem[ii]; jj++ ) { + + /*--- Get the index of the current point. ---*/ + + iPoint = connElemTemp[ii*connSize + jj]; + + /*--- Search for the processor that owns this point ---*/ + + iProcessor = iPoint/npoint_procs[0]; + if (iProcessor >= (unsigned long)size) iProcessor = (unsigned long)size-1; + if (iPoint >= nPoint_Linear[iProcessor]) + while(iPoint >= nPoint_Linear[iProcessor+1]) iProcessor++; + else + while(iPoint < nPoint_Linear[iProcessor]) iProcessor--; + + /*--- Load connectivity into the buffer for sending ---*/ + + if (nElem_Flag[iProcessor] != ii) { + + nElem_Flag[iProcessor] = ii; + unsigned long nn = index[iProcessor]; + + /*--- Load the VTK type first into the conn array, + then the connectivity vals, and last, the global ID. ---*/ + + connSend[nn] = elemTypes[ii]; nn++; + for ( int kk = 0; kk < nPoinPerElem[ii]; kk++ ) { + connSend[nn] = connElemTemp[ii*connSize + kk]; nn++; + } + connSend[nn] = (cgsize_t)elemGlobalID[ii]; + + /*--- Increment the index by the message length ---*/ + + index[iProcessor] += connSize; + + } + } + } + + /*--- Free memory after loading up the send buffer. ---*/ + + delete [] connElemTemp; + delete [] elemTypes; + delete [] nPoinPerElem; + delete [] elemGlobalID; + delete [] index; + + /*--- Allocate the memory that we need for receiving the conn + values and then cue up the non-blocking receives. Note that + we do not include our own rank in the communications. We will + directly copy our own data later. ---*/ + + unsigned long *connRecv = NULL; + connRecv = new unsigned long[connSize*nElem_Recv[size]]; + for (int ii = 0; ii < connSize*nElem_Recv[size]; ii++) + connRecv[ii] = 0; + +#ifdef HAVE_MPI + send_req = new MPI_Request[nSends]; + recv_req = new MPI_Request[nRecvs]; + unsigned long iMessage = 0; + for (int ii=0; ii nElem_Recv[ii])) { + int ll = connSize*nElem_Recv[ii]; + int kk = nElem_Recv[ii+1] - nElem_Recv[ii]; + int count = connSize*kk; + int source = ii; + int tag = ii + 1; + SU2_MPI::Irecv(&(connRecv[ll]), count, MPI_UNSIGNED_LONG, source, tag, + MPI_COMM_WORLD, &(recv_req[iMessage])); + iMessage++; + } + } + + /*--- Launch the non-blocking sends of the connectivity. ---*/ + + iMessage = 0; + for (int ii=0; ii nElem_Send[ii])) { + int ll = connSize*nElem_Send[ii]; + int kk = nElem_Send[ii+1] - nElem_Send[ii]; + int count = connSize*kk; + int dest = ii; + int tag = rank + 1; + SU2_MPI::Isend(&(connSend[ll]), count, MPI_UNSIGNED_LONG, dest, tag, + MPI_COMM_WORLD, &(send_req[iMessage])); + iMessage++; + } + } +#endif + + /*--- Copy my own rank's data into the recv buffer directly. ---*/ + + int mm = connSize*nElem_Recv[rank]; + int ll = connSize*nElem_Send[rank]; + int kk = connSize*nElem_Send[rank+1]; + + for (int nn=ll; nn SINGLE_NODE)) { + cout << nElem << " interior elements before linear partitioning." << endl; + } else if (rank == MASTER_NODE) { + cout << nElem << " interior elements." << endl; + } + + /*--- Set up the global to local element mapping. ---*/ + + Global_to_local_elem = new long[nElem]; + for (unsigned long i = 0; i < nElem; i++) { + Global_to_local_elem[i] = -1; + } + + /*--- Allocate space for elements. We allocate enough for all interior + elements globally, but we will only instantiate our local set. ---*/ + + elem = new CPrimalGrid*[nElem]; + for (unsigned long iElem = 0; iElem < nElem; iElem++) elem[iElem] = NULL; + ielem = 0; + unsigned long global_id = 0; + + /*--- Loop over all the internal, local volumetric elements. ---*/ + + for (int k = 0; k < nzones; k++) { + for (int s = 0; s < nsections; s++) { + if (isInternal[k][s]) { + for ( int i = 0; i < nElems[k][s]; i++) { + + /*--- Get the VTK type for this element. This is stored in the + first entry of the connectivity structure. ---*/ + + VTK_Type = connElems[k][s][0][i]; + + /*--- Instantiate this element and build adjacency structure. ---*/ + + switch(VTK_Type) { + case TRIANGLE: + for ( int j = 0; j < N_POINTS_TRIANGLE; j++ ) { + vnodes_cgns[j] = connElems[k][s][j+1][i]; + } + global_id = connElems[k][s][N_POINTS_TRIANGLE+1][i]; + for (unsigned short ii=0; ii=starting_node[rank])&&(vnodes_cgns[ii]=starting_node[rank])&&(vnodes_cgns[ii]=starting_node[rank])&&(vnodes_cgns[ii]=starting_node[rank])&&(vnodes_cgns[ii]=starting_node[rank])&&(vnodes_cgns[ii]=starting_node[rank])&&(vnodes_cgns[ii] SINGLE_NODE)) + cout << "Building the graph adjacency structure." << endl; + + unsigned long loc_adjc_size=0; + vector adjac_vec; + unsigned long adj_elem_size; + vector::iterator it; + local_elem=ielem; + + xadj = new unsigned long [npoint_procs[rank]+1]; + xadj[0]=0; + vector temp_adjacency; + unsigned long local_count=0; + + for (unsigned long i = 0; i < local_node; i++) { + + for (unsigned long j=0; j SINGLE_NODE)) { + cout << nPoint << " grid points before linear partitioning." << endl; + } else if (rank == MASTER_NODE) { + cout << nPoint << " grid points." << endl; + } + + iPoint = 0; + node = new CPoint*[local_node]; + GlobalIndex = starting_node[rank]; + for (int k = 0; k < nzones; k++ ) { + for (unsigned long i = 0; i < local_node; i++ ) { + for (int j = 0; j < cell_dim; j++ ) Coord_cgns[j] = gridCoords[k][j][i]; + switch(nDim) { + case 2: + node[iPoint] = new CPoint(Coord_cgns[0], Coord_cgns[1], GlobalIndex, config); + iPoint++; break; + case 3: + node[iPoint] = new CPoint(Coord_cgns[0], Coord_cgns[1], Coord_cgns[2], GlobalIndex, config); + iPoint++; break; + } + GlobalIndex++; + } + } + + /*--- For now, the master node takes care of all markers. ---*/ + + if (rank == MASTER_NODE) { + + /*--- Read number of markers ---*/ + + nMarker = nMarkers; + cout << nMarker << " surface markers." << endl; + config->SetnMarker_All(nMarker); + bound = new CPrimalGrid**[nMarker]; + nElem_Bound = new unsigned long [nMarker]; + Tag_to_Marker = new string [nMarker_Max]; + + iMarker = 0; + for ( int k = 0; k < nzones; k ++ ) { + for ( int s = 0; s < nsections; s++ ) { + if ( !isInternal[k][s] ) { + + /*--- Initialize some counter variables ---*/ + + nelem_edge_bound = 0; nelem_triangle_bound = 0; + nelem_quad_bound = 0; ielem = 0; + + Marker_Tag = sectionNames[k][s]; + + /*--- Remove whitespaces from the marker names ---*/ + Marker_Tag.erase(remove(Marker_Tag.begin(), Marker_Tag.end(),' '), Marker_Tag.end()); + + if (Marker_Tag != "SEND_RECEIVE") { + nElem_Bound[iMarker] = nElems[k][s]; + if (rank == MASTER_NODE) { + cout << nElem_Bound[iMarker] << " boundary elements in index "; + cout << iMarker <<" (Marker = " <GetMarker_CfgFile_TagBound(Marker_Tag)] = Marker_Tag; + config->SetMarker_All_TagBound(iMarker, Marker_Tag); + config->SetMarker_All_KindBC(iMarker, config->GetMarker_CfgFile_KindBC(Marker_Tag)); + config->SetMarker_All_Monitoring(iMarker, config->GetMarker_CfgFile_Monitoring(Marker_Tag)); + config->SetMarker_All_GeoEval(iMarker, config->GetMarker_CfgFile_GeoEval(Marker_Tag)); + config->SetMarker_All_Designing(iMarker, config->GetMarker_CfgFile_Designing(Marker_Tag)); + config->SetMarker_All_Plotting(iMarker, config->GetMarker_CfgFile_Plotting(Marker_Tag)); + config->SetMarker_All_FSIinterface(iMarker, config->GetMarker_CfgFile_FSIinterface(Marker_Tag)); + config->SetMarker_All_DV(iMarker, config->GetMarker_CfgFile_DV(Marker_Tag)); + config->SetMarker_All_Moving(iMarker, config->GetMarker_CfgFile_Moving(Marker_Tag)); + config->SetMarker_All_PerBound(iMarker, config->GetMarker_CfgFile_PerBound(Marker_Tag)); + config->SetMarker_All_Out_1D(iMarker, config->GetMarker_CfgFile_Out_1D(Marker_Tag)); + config->SetMarker_All_SendRecv(iMarker, NONE); + + } + iMarker++; + } + } + } + + /*--- Periodic transormations is not implement, store default zeros ---*/ + unsigned short nPeriodic = 1, iPeriodic = 0; + config->SetnPeriodicIndex(nPeriodic); + su2double* center = new su2double[3]; + su2double* rotation = new su2double[3]; + su2double* translate = new su2double[3]; + for (unsigned short iDim = 0; iDim < 3; iDim++) { + center[iDim] = 0.0; rotation[iDim] = 0.0; translate[iDim] = 0.0; + } + config->SetPeriodicCenter(iPeriodic, center); + config->SetPeriodicRotation(iPeriodic, rotation); + config->SetPeriodicTranslate(iPeriodic, translate); + + } + + /*--- Deallocate temporary memory. ---*/ + + delete[] vertices; + delete[] cells; + delete[] boundVerts; + + for ( int j = 0; j < nzones; j++) { + delete[] coordArray[j]; + delete[] elemTypeVTK[j]; + delete[] elemIndex[j]; + delete[] nElems[j]; + delete[] dataSize[j]; + delete[] isInternal[j]; + delete[] sectionNames[j]; + } + delete[] coordArray; + delete[] elemTypeVTK; + delete[] elemIndex; + delete[] nElems; + delete[] dataSize; + delete[] isInternal; + delete[] sectionNames; + + for ( int j = 0; j < nzones; j++) { + for ( int i = 0; i < ncoords; i++ ) { + delete[] gridCoords[j][i]; + } + delete[] gridCoords[j]; + } + delete[] gridCoords; + + // for ( int kk = 0; kk < nzones; kk++) { + // for (int ii = 0; ii < nsections; ii++) { + // for (int jj = 0; jj < indexMax; jj++) { + // delete[] connElems[kk][ii][jj]; + // } + // delete connElems[kk][ii]; + // } + // delete connElems[kk]; + // } + // delete[] connElems; + + delete [] nPoint_Linear; + delete [] nElem_Linear; + + delete [] elemB; + delete [] elemE; + +#else + cout << "SU2 built without CGNS support!!" << endl; + cout << "To use CGNS, remove the -DNO_CGNS directive "; + cout << "from the makefile and supply the correct path"; + cout << " to the CGNS library." << endl; + exit(EXIT_FAILURE); +#endif + +} + +void CPhysicalGeometry::Check_IntElem_Orientation(CConfig *config) { + + unsigned long Point_1, Point_2, Point_3, Point_4, Point_5, Point_6, + iElem; + su2double test_1, test_2, test_3, test_4, *Coord_1, *Coord_2, *Coord_3, *Coord_4, + *Coord_5, *Coord_6, a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}, c[3] = {0.0,0.0,0.0}, n[3] = {0.0,0.0,0.0}, test; + unsigned short iDim; + + /*--- Loop over all the elements ---*/ + + for (iElem = 0; iElem < nElem; iElem++) { + + /*--- 2D grid, triangle case ---*/ + + if (elem[iElem]->GetVTK_Type() == TRIANGLE) { + + Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); + Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); + Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); + b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); } + test = a[0]*b[1]-b[0]*a[1]; + + if (test < 0.0) elem[iElem]->Change_Orientation(); + } + + /*--- 2D grid, quadrilateral case ---*/ + + if (elem[iElem]->GetVTK_Type() == QUADRILATERAL) { + + Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); + Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); + Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); + Point_4 = elem[iElem]->GetNode(3); Coord_4 = node[Point_4]->GetCoord(); + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); + b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); } + test_1 = a[0]*b[1]-b[0]*a[1]; + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_3[iDim]-Coord_2[iDim]); + b[iDim] = 0.5*(Coord_4[iDim]-Coord_2[iDim]); } + test_2 = a[0]*b[1]-b[0]*a[1]; + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_4[iDim]-Coord_3[iDim]); + b[iDim] = 0.5*(Coord_1[iDim]-Coord_3[iDim]); } + test_3 = a[0]*b[1]-b[0]*a[1]; + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_1[iDim]-Coord_4[iDim]); + b[iDim] = 0.5*(Coord_3[iDim]-Coord_4[iDim]); } + test_4 = a[0]*b[1]-b[0]*a[1]; + + if ((test_1 < 0.0) && (test_2 < 0.0) && (test_3 < 0.0) && (test_4 < 0.0)) + elem[iElem]->Change_Orientation(); + } + + /*--- 3D grid, tetrahedron case ---*/ + + if (elem[iElem]->GetVTK_Type() == TETRAHEDRON) { + + Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); + Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); + Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); + Point_4 = elem[iElem]->GetNode(3); Coord_4 = node[Point_4]->GetCoord(); + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); + b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); + c[iDim] = Coord_4[iDim]-Coord_1[iDim]; } + n[0] = a[1]*b[2]-b[1]*a[2]; + n[1] = -(a[0]*b[2]-b[0]*a[2]); + n[2] = a[0]*b[1]-b[0]*a[1]; + + test = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; + if (test < 0.0) elem[iElem]->Change_Orientation(); + + } + + /*--- 3D grid, prism case ---*/ + + if (elem[iElem]->GetVTK_Type() == PRISM) { + + Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); + Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); + Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); + Point_4 = elem[iElem]->GetNode(3); Coord_4 = node[Point_4]->GetCoord(); + Point_5 = elem[iElem]->GetNode(4); Coord_5 = node[Point_5]->GetCoord(); + Point_6 = elem[iElem]->GetNode(5); Coord_6 = node[Point_6]->GetCoord(); + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); + b[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); + c[iDim] = (Coord_4[iDim]-Coord_1[iDim])+ + (Coord_5[iDim]-Coord_2[iDim])+ + (Coord_6[iDim]-Coord_3[iDim]); } + + /*--- The normal vector should point to the interior of the element ---*/ + + n[0] = a[1]*b[2]-b[1]*a[2]; + n[1] = -(a[0]*b[2]-b[0]*a[2]); + n[2] = a[0]*b[1]-b[0]*a[1]; + + test_1 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_5[iDim]-Coord_4[iDim]); + b[iDim] = 0.5*(Coord_6[iDim]-Coord_4[iDim]); + c[iDim] = (Coord_1[iDim]-Coord_4[iDim])+ + (Coord_2[iDim]-Coord_5[iDim])+ + (Coord_3[iDim]-Coord_6[iDim]); } + + /*--- The normal vector should point to the interior of the element ---*/ + + n[0] = a[1]*b[2]-b[1]*a[2]; + n[1] = -(a[0]*b[2]-b[0]*a[2]); + n[2] = a[0]*b[1]-b[0]*a[1]; + + test_2 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; + + if ((test_1 < 0.0) || (test_2 < 0.0)) + elem[iElem]->Change_Orientation(); + + } + + if (elem[iElem]->GetVTK_Type() == HEXAHEDRON) { + + Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); + Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); + Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); + Point_4 = elem[iElem]->GetNode(5); Coord_4 = node[Point_4]->GetCoord(); + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); + b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); + c[iDim] = Coord_4[iDim]-Coord_1[iDim]; } + n[0] = a[1]*b[2]-b[1]*a[2]; + n[1] = -(a[0]*b[2]-b[0]*a[2]); + n[2] = a[0]*b[1]-b[0]*a[1]; + + test_1 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; + + Point_1 = elem[iElem]->GetNode(2); Coord_1 = node[Point_1]->GetCoord(); + Point_2 = elem[iElem]->GetNode(3); Coord_2 = node[Point_2]->GetCoord(); + Point_3 = elem[iElem]->GetNode(0); Coord_3 = node[Point_3]->GetCoord(); + Point_4 = elem[iElem]->GetNode(7); Coord_4 = node[Point_4]->GetCoord(); + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); + b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); + c[iDim] = Coord_4[iDim]-Coord_1[iDim]; } + n[0] = a[1]*b[2]-b[1]*a[2]; + n[1] = -(a[0]*b[2]-b[0]*a[2]); + n[2] = a[0]*b[1]-b[0]*a[1]; + + test_2 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; + + Point_1 = elem[iElem]->GetNode(1); Coord_1 = node[Point_1]->GetCoord(); + Point_2 = elem[iElem]->GetNode(2); Coord_2 = node[Point_2]->GetCoord(); + Point_3 = elem[iElem]->GetNode(3); Coord_3 = node[Point_3]->GetCoord(); + Point_4 = elem[iElem]->GetNode(6); Coord_4 = node[Point_4]->GetCoord(); + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); + b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); + c[iDim] = Coord_4[iDim]-Coord_1[iDim]; } + n[0] = a[1]*b[2]-b[1]*a[2]; + n[1] = -(a[0]*b[2]-b[0]*a[2]); + n[2] = a[0]*b[1]-b[0]*a[1]; + + test_3 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; + + Point_1 = elem[iElem]->GetNode(3); Coord_1 = node[Point_1]->GetCoord(); + Point_2 = elem[iElem]->GetNode(0); Coord_2 = node[Point_2]->GetCoord(); + Point_3 = elem[iElem]->GetNode(1); Coord_3 = node[Point_3]->GetCoord(); + Point_4 = elem[iElem]->GetNode(4); Coord_4 = node[Point_4]->GetCoord(); + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); + b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); + c[iDim] = Coord_4[iDim]-Coord_1[iDim]; } + n[0] = a[1]*b[2]-b[1]*a[2]; + n[1] = -(a[0]*b[2]-b[0]*a[2]); + n[2] = a[0]*b[1]-b[0]*a[1]; + + test_4 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; + + if ((test_1 < 0.0) || (test_2 < 0.0) || (test_3 < 0.0) + || (test_4 < 0.0)) elem[iElem]->Change_Orientation(); + + } + + if (elem[iElem]->GetVTK_Type() == PYRAMID) { + + Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); + Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); + Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); + Point_4 = elem[iElem]->GetNode(4); Coord_4 = node[Point_4]->GetCoord(); + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); + b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); + c[iDim] = Coord_4[iDim]-Coord_1[iDim]; } + n[0] = a[1]*b[2]-b[1]*a[2]; + n[1] = -(a[0]*b[2]-b[0]*a[2]); + n[2] = a[0]*b[1]-b[0]*a[1]; + + test_1 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; + + Point_1 = elem[iElem]->GetNode(2); Coord_1 = node[Point_1]->GetCoord(); + Point_2 = elem[iElem]->GetNode(3); Coord_2 = node[Point_2]->GetCoord(); + Point_3 = elem[iElem]->GetNode(0); Coord_3 = node[Point_3]->GetCoord(); + Point_4 = elem[iElem]->GetNode(4); Coord_4 = node[Point_4]->GetCoord(); + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); + b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); + c[iDim] = Coord_4[iDim]-Coord_1[iDim]; } + n[0] = a[1]*b[2]-b[1]*a[2]; + n[1] = -(a[0]*b[2]-b[0]*a[2]); + n[2] = a[0]*b[1]-b[0]*a[1]; + + test_2 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; + + if ((test_1 < 0.0) || (test_2 < 0.0)) + elem[iElem]->Change_Orientation(); + + } + + } + +} + +void CPhysicalGeometry::Check_BoundElem_Orientation(CConfig *config) { + + unsigned long Point_1_Surface, Point_2_Surface, Point_3_Surface, Point_4_Surface, + iElem_Domain, Point_Domain = 0, Point_Surface, iElem_Surface; + su2double test_1, test_2, test_3, test_4, *Coord_1, *Coord_2, *Coord_3, *Coord_4, + *Coord_5, a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}, c[3] = {0.0,0.0,0.0}, n[3] = {0.0,0.0,0.0}, test; + unsigned short iDim, iMarker, iNode_Domain, iNode_Surface; + bool find; + + /*--- Surface elements ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) + for (iElem_Surface = 0; iElem_Surface < nElem_Bound[iMarker]; iElem_Surface++) { + + iElem_Domain = bound[iMarker][iElem_Surface]->GetDomainElement(); + for (iNode_Domain = 0; iNode_Domain < elem[iElem_Domain]->GetnNodes(); iNode_Domain++) { + Point_Domain = elem[iElem_Domain]->GetNode(iNode_Domain); + find = false; + for (iNode_Surface = 0; iNode_Surface < bound[iMarker][iElem_Surface]->GetnNodes(); iNode_Surface++) { + Point_Surface = bound[iMarker][iElem_Surface]->GetNode(iNode_Surface); + if (Point_Surface == Point_Domain) {find = true; break;} + } + if (!find) break; + } + + /*--- 2D grid, line case ---*/ + + if (bound[iMarker][iElem_Surface]->GetVTK_Type() == LINE) { + + Point_1_Surface = bound[iMarker][iElem_Surface]->GetNode(0); Coord_1 = node[Point_1_Surface]->GetCoord(); + Point_2_Surface = bound[iMarker][iElem_Surface]->GetNode(1); Coord_2 = node[Point_2_Surface]->GetCoord(); + Coord_3 = node[Point_Domain]->GetCoord(); + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); + b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); } + test = a[0]*b[1]-b[0]*a[1]; + + if (test < 0.0) { + bound[iMarker][iElem_Surface]->Change_Orientation(); + node[Point_1_Surface]->SetFlip_Orientation(); + node[Point_2_Surface]->SetFlip_Orientation(); + } + + } + + /*--- 3D grid, triangle case ---*/ + if (bound[iMarker][iElem_Surface]->GetVTK_Type() == TRIANGLE) { + + Point_1_Surface = bound[iMarker][iElem_Surface]->GetNode(0); Coord_1 = node[Point_1_Surface]->GetCoord(); + Point_2_Surface = bound[iMarker][iElem_Surface]->GetNode(1); Coord_2 = node[Point_2_Surface]->GetCoord(); + Point_3_Surface = bound[iMarker][iElem_Surface]->GetNode(2); Coord_3 = node[Point_3_Surface]->GetCoord(); + Coord_4 = node[Point_Domain]->GetCoord(); + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); + b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); + c[iDim] = Coord_4[iDim]-Coord_1[iDim]; } + n[0] = a[1]*b[2]-b[1]*a[2]; + n[1] = -(a[0]*b[2]-b[0]*a[2]); + n[2] = a[0]*b[1]-b[0]*a[1]; + + test = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; + if (test < 0.0) { + bound[iMarker][iElem_Surface]->Change_Orientation(); + node[Point_1_Surface]->SetFlip_Orientation(); + node[Point_2_Surface]->SetFlip_Orientation(); + node[Point_3_Surface]->SetFlip_Orientation(); + } + + } + + if (bound[iMarker][iElem_Surface]->GetVTK_Type() == QUADRILATERAL) { + + Point_1_Surface = bound[iMarker][iElem_Surface]->GetNode(0); Coord_1 = node[Point_1_Surface]->GetCoord(); + Point_2_Surface = bound[iMarker][iElem_Surface]->GetNode(1); Coord_2 = node[Point_2_Surface]->GetCoord(); + Point_3_Surface = bound[iMarker][iElem_Surface]->GetNode(2); Coord_3 = node[Point_3_Surface]->GetCoord(); + Point_4_Surface = bound[iMarker][iElem_Surface]->GetNode(3); Coord_4 = node[Point_4_Surface]->GetCoord(); + Coord_5 = node[Point_Domain]->GetCoord(); + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); + b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); + c[iDim] = Coord_5[iDim]-Coord_1[iDim]; } + n[0] = a[1]*b[2]-b[1]*a[2]; + n[1] = -(a[0]*b[2]-b[0]*a[2]); + n[2] = a[0]*b[1]-b[0]*a[1]; + test_1 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_3[iDim]-Coord_2[iDim]); + b[iDim] = 0.5*(Coord_4[iDim]-Coord_2[iDim]); + c[iDim] = Coord_5[iDim]-Coord_2[iDim]; } + n[0] = a[1]*b[2]-b[1]*a[2]; + n[1] = -(a[0]*b[2]-b[0]*a[2]); + n[2] = a[0]*b[1]-b[0]*a[1]; + test_2 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_4[iDim]-Coord_3[iDim]); + b[iDim] = 0.5*(Coord_1[iDim]-Coord_3[iDim]); + c[iDim] = Coord_5[iDim]-Coord_3[iDim]; } + n[0] = a[1]*b[2]-b[1]*a[2]; + n[1] = -(a[0]*b[2]-b[0]*a[2]); + n[2] = a[0]*b[1]-b[0]*a[1]; + test_3 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = 0.5*(Coord_1[iDim]-Coord_4[iDim]); + b[iDim] = 0.5*(Coord_3[iDim]-Coord_4[iDim]); + c[iDim] = Coord_5[iDim]-Coord_4[iDim]; } + n[0] = a[1]*b[2]-b[1]*a[2]; + n[1] = -(a[0]*b[2]-b[0]*a[2]); + n[2] = a[0]*b[1]-b[0]*a[1]; + test_4 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; + + if ((test_1 < 0.0) && (test_2 < 0.0) && (test_3 < 0.0) && (test_4 < 0.0)) { + bound[iMarker][iElem_Surface]->Change_Orientation(); + node[Point_1_Surface]->SetFlip_Orientation(); + node[Point_2_Surface]->SetFlip_Orientation(); + node[Point_3_Surface]->SetFlip_Orientation(); + node[Point_4_Surface]->SetFlip_Orientation(); + } + + } + } +} + +void CPhysicalGeometry::ComputeWall_Distance(CConfig *config) { + + su2double *coord, dist; + passivedouble dist2, diff; + unsigned short iDim, iMarker; + unsigned long iPoint, iVertex, nVertex_SolidWall, iVertex_nearestWall = 0; + + +#ifndef HAVE_MPI + + /*--- Compute the total number of nodes on no-slip boundaries ---*/ + + nVertex_SolidWall = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) ) + nVertex_SolidWall += GetnVertex(iMarker); + + /*--- Allocate an array to hold boundary node coordinates ---*/ + + su2double **Coord_bound; + Coord_bound = new su2double* [nVertex_SolidWall]; + for (iVertex = 0; iVertex < nVertex_SolidWall; iVertex++) + Coord_bound[iVertex] = new su2double [nDim]; + + /*--- Retrieve and store the coordinates of the no-slip boundary nodes ---*/ + + nVertex_SolidWall = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) ) + for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + for (iDim = 0; iDim < nDim; iDim++) + Coord_bound[nVertex_SolidWall][iDim] = node[iPoint]->GetCoord(iDim); + nVertex_SolidWall++; + } + } + + /*--- Loop over all interior mesh nodes and compute the distances to each + of the no-slip boundary nodes. Store the minimum distance to the wall for + each interior mesh node. ---*/ + + su2double dist1 = 0.0; + if (nVertex_SolidWall != 0) { + for (iPoint = 0; iPoint < GetnPoint(); iPoint++) { + coord = node[iPoint]->GetCoord(); + dist1 = 1E20; + for (iVertex = 0; iVertex < nVertex_SolidWall; iVertex++) { + dist2 = 0.0; + + /*--- The wall distance computation is done using the plain su2double datatype to just + * determine the index of the closest vertex. Otherwise we are storing a lot of + * unnecessary derivative information when using AD.---*/ + + for (iDim = 0; iDim < nDim; iDim++){ + diff = (SU2_TYPE::GetValue(coord[iDim]) + -SU2_TYPE::GetValue(Coord_bound[iVertex][iDim])); + dist2 += diff*diff; + } + if (dist2 < dist1) { + iVertex_nearestWall = iVertex; + dist1 = dist2; + } + } + dist = 0.0; + + /*--- Now we do the computation of the wall distance again using the general datatype.---*/ + + for (iDim = 0; iDim < nDim; iDim++){ + dist += (coord[iDim] - Coord_bound[iVertex_nearestWall][iDim])* + (coord[iDim] - Coord_bound[iVertex_nearestWall][iDim]); + } + node[iPoint]->SetWall_Distance(sqrt(dist)); + } + } + else { + for (iPoint = 0; iPoint < GetnPoint(); iPoint++) + node[iPoint]->SetWall_Distance(0.0); + } + + /*--- Deallocate the vector of boundary coordinates. ---*/ + + for (iVertex = 0; iVertex < nVertex_SolidWall; iVertex++) + delete[] Coord_bound[iVertex]; + delete[] Coord_bound; + + +#else + + /*--- Variables and buffers needed for MPI ---*/ + + int iProcessor, nProcessor; + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); + + unsigned long nLocalVertex_NS = 0, nGlobalVertex_NS = 0, MaxLocalVertex_NS = 0; + unsigned long *Buffer_Send_nVertex = new unsigned long [1]; + unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor]; + + /*--- Count the total number of nodes on no-slip boundaries within the + local partition. ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) ) + nLocalVertex_NS += GetnVertex(iMarker); + + /*--- Communicate to all processors the total number of no-slip boundary + nodes, the maximum number of no-slip boundary nodes on any single single + partition, and the number of no-slip nodes on each partition. ---*/ + + Buffer_Send_nVertex[0] = nLocalVertex_NS; + SU2_MPI::Allreduce(&nLocalVertex_NS, &nGlobalVertex_NS, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&nLocalVertex_NS, &MaxLocalVertex_NS, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + /*--- Create and initialize to zero some buffers to hold the coordinates + of the boundary nodes that are communicated from each partition (all-to-all). ---*/ + + su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_NS*nDim]; + su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_NS*nDim]; + unsigned long nBuffer = MaxLocalVertex_NS*nDim; + + for (iVertex = 0; iVertex < MaxLocalVertex_NS; iVertex++) + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; + + /*--- Retrieve and store the coordinates of the no-slip boundary nodes on + the local partition and broadcast them to all partitions. ---*/ + + nVertex_SolidWall = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) ) + for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[nVertex_SolidWall*nDim+iDim] = node[iPoint]->GetCoord(iDim); + nVertex_SolidWall++; + } + + SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer, MPI_DOUBLE, MPI_COMM_WORLD); + + /*--- Loop over all interior mesh nodes on the local partition and compute + the distances to each of the no-slip boundary nodes in the entire mesh. + Store the minimum distance to the wall for each interior mesh node. ---*/ + + nVertex_SolidWall = 0; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + nVertex_SolidWall += Buffer_Receive_nVertex[iProcessor]; + } + + if (nVertex_SolidWall != 0) { + for (iPoint = 0; iPoint < GetnPoint(); iPoint++) { + coord = node[iPoint]->GetCoord(); + dist = 1E20; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) + for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { + dist2 = 0.0; + + /*--- The wall distance computation is done using the plain su2double datatype to just + * determine the index of the closest vertex. Otherwise we are storing a lot of + * unnecessary derivative information when using AD.---*/ + + for (iDim = 0; iDim < nDim; iDim++){ + diff = SU2_TYPE::GetValue(coord[iDim]) - + SU2_TYPE::GetValue(Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_NS+iVertex)*nDim+iDim]); + dist2 += diff*diff; + } + if (dist2 < dist) { + iVertex_nearestWall = iProcessor*MaxLocalVertex_NS+iVertex; + dist = dist2; + } + } + + /*--- Now we do the computation of the wall distance again using the general datatype.---*/ + + dist = 0.0; + for (iDim = 0; iDim < nDim; iDim++){ + dist += (coord[iDim] - Buffer_Receive_Coord[iVertex_nearestWall*nDim+iDim])* + (coord[iDim] - Buffer_Receive_Coord[iVertex_nearestWall*nDim+iDim]); + } + node[iPoint]->SetWall_Distance(sqrt(dist)); + } + } + else { + for (iPoint = 0; iPoint < GetnPoint(); iPoint++) + node[iPoint]->SetWall_Distance(0.0); + } + + /*--- Deallocate the buffers needed for the MPI communication. ---*/ + + delete[] Buffer_Send_Coord; + delete[] Buffer_Receive_Coord; + delete[] Buffer_Send_nVertex; + delete[] Buffer_Receive_nVertex; + +#endif + +} + +void CPhysicalGeometry::SetPositive_ZArea(CConfig *config) { + unsigned short iMarker, Boundary, Monitoring; + unsigned long iVertex, iPoint; + su2double *Normal, PositiveZArea; + int rank = MASTER_NODE; + +#ifndef HAVE_MPI + + PositiveZArea = 0.0; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + Boundary = config->GetMarker_All_KindBC(iMarker); + Monitoring = config->GetMarker_All_Monitoring(iMarker); + + if (((Boundary == EULER_WALL) || + (Boundary == HEAT_FLUX) || + (Boundary == ISOTHERMAL) || + (Boundary == LOAD_BOUNDARY) || + (Boundary == DISPLACEMENT_BOUNDARY)) && (Monitoring == YES)) + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + Normal = vertex[iMarker][iVertex]->GetNormal(); + if (Normal[nDim-1] < 0) PositiveZArea -= Normal[nDim-1]; + } + } + } + +#else + + su2double TotalPositiveZArea; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + PositiveZArea = 0.0; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + Boundary = config->GetMarker_All_KindBC(iMarker); + Monitoring = config->GetMarker_All_Monitoring(iMarker); + + if (((Boundary == EULER_WALL) || + (Boundary == HEAT_FLUX) || + (Boundary == ISOTHERMAL) || + (Boundary == LOAD_BOUNDARY) || + (Boundary == DISPLACEMENT_BOUNDARY)) && (Monitoring == YES)) + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + Normal = vertex[iMarker][iVertex]->GetNormal(); + if (Normal[nDim-1] < 0) PositiveZArea -= Normal[nDim-1]; + } + } + } + SU2_MPI::Reduce(&PositiveZArea, &TotalPositiveZArea, 1, MPI_DOUBLE, MPI_SUM, MASTER_NODE, MPI_COMM_WORLD); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == MASTER_NODE) PositiveZArea = TotalPositiveZArea; + SU2_MPI::Bcast(&PositiveZArea, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + +#endif + + if (config->GetRefAreaCoeff() == 0.0) + config->SetRefAreaCoeff(PositiveZArea); + + if (rank == MASTER_NODE) { + if (nDim == 2) cout << "Area projection in the y-plane = "<< PositiveZArea << "." << endl; + else cout << "Area projection in the z-plane = "<< PositiveZArea << "." << endl; + } + +} + +void CPhysicalGeometry::SetPoint_Connectivity(void) { + + unsigned short Node_Neighbor, iNode, iNeighbor; + unsigned long jElem, Point_Neighbor, iPoint, iElem; + + /*--- Loop over all the elements ---*/ + + for (iElem = 0; iElem < nElem; iElem++) + + /*--- Loop over all the nodes of an element ---*/ + + for (iNode = 0; iNode < elem[iElem]->GetnNodes(); iNode++) { + iPoint = elem[iElem]->GetNode(iNode); + + /*--- Store the element into the point ---*/ + + node[iPoint]->SetElem(iElem); + } + + /*--- Loop over all the points ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint++) + + /*--- Loop over all elements shared by the point ---*/ + + for (iElem = 0; iElem < node[iPoint]->GetnElem(); iElem++) { + + jElem = node[iPoint]->GetElem(iElem); + + /*--- If we find the point iPoint in the surronding element ---*/ + + for (iNode = 0; iNode < elem[jElem]->GetnNodes(); iNode++) + + if (elem[jElem]->GetNode(iNode) == iPoint) + + /*--- Localize the local index of the neighbor of iPoint in the element ---*/ + + for (iNeighbor = 0; iNeighbor < elem[jElem]->GetnNeighbor_Nodes(iNode); iNeighbor++) { + Node_Neighbor = elem[jElem]->GetNeighbor_Nodes(iNode, iNeighbor); + Point_Neighbor = elem[jElem]->GetNode(Node_Neighbor); + + /*--- Store the point into the point ---*/ + + node[iPoint]->SetPoint(Point_Neighbor); + } + } + + /*--- Set the number of neighbors variable, this is + important for JST and multigrid in parallel ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint++) + node[iPoint]->SetnNeighbor(node[iPoint]->GetnPoint()); + +} + +void CPhysicalGeometry::SetRCM_Ordering(CConfig *config) { + unsigned long iPoint, AdjPoint, AuxPoint, AddPoint, iElem, iNode, jNode; + vector Queue, AuxQueue, Result; + unsigned short Degree, MinDegree, iDim, iMarker; + bool *inQueue; + + inQueue = new bool [nPoint]; + + for (iPoint = 0; iPoint < nPoint; iPoint++) + inQueue[iPoint] = false; + + /*--- Select the node with the lowest degree in the grid. ---*/ + + MinDegree = node[0]->GetnNeighbor(); AddPoint = 0; + for (iPoint = 1; iPoint < nPointDomain; iPoint++) { + Degree = node[iPoint]->GetnPoint(); + if (Degree < MinDegree) { MinDegree = Degree; AddPoint = iPoint; } + } + + /*--- Add the node in the first free position. ---*/ + + Result.push_back(AddPoint); inQueue[AddPoint] = true; + + /*--- Loop until reorganize all the nodes ---*/ + + do { + + /*--- Add to the queue all the nodes adjacent in the increasing + order of their degree, checking if the element is already + in the Queue. ---*/ + + AuxQueue.clear(); + for (iNode = 0; iNode < node[AddPoint]->GetnPoint(); iNode++) { + AdjPoint = node[AddPoint]->GetPoint(iNode); + if ((!inQueue[AdjPoint]) && (AdjPoint < nPointDomain)) { + AuxQueue.push_back(AdjPoint); + } + } + + if (AuxQueue.size() != 0) { + + /*--- Sort the auxiliar queue based on the number of neighbors ---*/ + + for (iNode = 0; iNode < AuxQueue.size(); iNode++) { + for (jNode = 0; jNode < AuxQueue.size() - 1 - iNode; jNode++) { + if (node[AuxQueue[jNode]]->GetnPoint() > node[AuxQueue[jNode+1]]->GetnPoint()) { + AuxPoint = AuxQueue[jNode]; + AuxQueue[jNode] = AuxQueue[jNode+1]; + AuxQueue[jNode+1] = AuxPoint; + } + } + } + + Queue.insert(Queue.end(), AuxQueue.begin(), AuxQueue.end()); + for (iNode = 0; iNode < AuxQueue.size(); iNode++) { + inQueue[AuxQueue[iNode]] = true; + } + + } + + /*--- Extract the first node from the queue and add it in the first free + position. ---*/ + + if (Queue.size() != 0) { + AddPoint = Queue[0]; + Result.push_back(Queue[0]); + Queue.erase (Queue.begin(), Queue.begin()+1); + } + + /*--- Add to the queue all the nodes adjacent in the increasing + order of their degree, checking if the element is already + in the Queue. ---*/ + + } while (Queue.size() != 0); + + /*--- Check that all the points have been added ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + if (inQueue[iPoint] == false) Result.push_back(iPoint); + } + + delete[] inQueue; + + reverse(Result.begin(), Result.end()); + + /*--- Add the MPI points ---*/ + + for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { + Result.push_back(iPoint); + } + + /*--- Reset old data structures ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + node[iPoint]->ResetElem(); + node[iPoint]->ResetPoint(); + node[iPoint]->ResetBoundary(); + node[iPoint]->SetPhysicalBoundary(false); + node[iPoint]->SetSolidBoundary(false); + node[iPoint]->SetDomain(true); + } + + /*--- Set the new coordinates ---*/ + + su2double **AuxCoord; + unsigned long *AuxGlobalIndex; + + AuxGlobalIndex = new unsigned long [nPoint]; + AuxCoord = new su2double* [nPoint]; + for (iPoint = 0; iPoint < nPoint; iPoint++) + AuxCoord[iPoint] = new su2double [nDim]; + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + AuxGlobalIndex[iPoint] = node[iPoint]->GetGlobalIndex(); + for (iDim = 0; iDim < nDim; iDim++) { + AuxCoord[iPoint][iDim] = node[iPoint]->GetCoord(iDim); + } + } + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + node[iPoint]->SetGlobalIndex(AuxGlobalIndex[Result[iPoint]]); + for (iDim = 0; iDim < nDim; iDim++) + node[iPoint]->SetCoord(iDim, AuxCoord[Result[iPoint]][iDim]); + } + + for (iPoint = 0; iPoint < nPoint; iPoint++) + delete[] AuxCoord[iPoint]; + delete[] AuxCoord; + delete[] AuxGlobalIndex; + + /*--- Set the new conectivities ---*/ + + unsigned long *InvResult; + InvResult = new unsigned long [nPoint]; + for (iPoint = 0; iPoint < nPoint; iPoint++) + InvResult[Result[iPoint]] = iPoint; + + for (iElem = 0; iElem < nElem; iElem++) { + for (iNode = 0; iNode < elem[iElem]->GetnNodes(); iNode++) { + iPoint = elem[iElem]->GetNode(iNode); + elem[iElem]->SetNode(iNode, InvResult[iPoint]); + } + } + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) { + + string Marker_Tag = config->GetMarker_All_TagBound(iMarker); + if (Marker_Tag == "SEND_RECEIVE") { + for (unsigned long iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + if (config->GetMarker_All_SendRecv(iMarker) < 0) + node[bound[iMarker][iElem_Bound]->GetNode(0)]->SetDomain(false); + } + } + + for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { + iPoint = bound[iMarker][iElem]->GetNode(iNode); + bound[iMarker][iElem]->SetNode(iNode, InvResult[iPoint]); + node[InvResult[iPoint]]->SetBoundary(nMarker); + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE && + config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY && + config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY && + config->GetMarker_All_KindBC(iMarker) != PERIODIC_BOUNDARY) + node[InvResult[iPoint]]->SetPhysicalBoundary(true); + + if (config->GetMarker_All_KindBC(iMarker) == EULER_WALL || + config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX || + config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) + node[InvResult[iPoint]]->SetSolidBoundary(true); + } + } + } + + + delete[] InvResult; + +} + +void CPhysicalGeometry::SetElement_Connectivity(void) { + unsigned short first_elem_face, second_elem_face, iFace, iNode, jElem; + unsigned long face_point, Test_Elem, iElem; + + /*--- Loop over all the elements, faces and nodes ---*/ + + for (iElem = 0; iElem < nElem; iElem++) + for (iFace = 0; iFace < elem[iElem]->GetnFaces(); iFace++) + for (iNode = 0; iNode < elem[iElem]->GetnNodesFace(iFace); iNode++) { + face_point = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iNode)); + + /*--- Loop over all elements sharing the face point ---*/ + + for (jElem = 0; jElem < node[face_point]->GetnElem(); jElem++) { + Test_Elem = node[face_point]->GetElem(jElem); + + /*--- If it is a new element in this face ---*/ + + if ((elem[iElem]->GetNeighbor_Elements(iFace) == -1) && (iElem < Test_Elem) && + (FindFace(iElem, Test_Elem, first_elem_face, second_elem_face))) { + + /*--- Localice which faces are sharing both elements ---*/ + + elem[iElem]->SetNeighbor_Elements(Test_Elem, first_elem_face); + + /*--- Store the element for both elements ---*/ + + elem[Test_Elem]->SetNeighbor_Elements(iElem, second_elem_face); + + } + } + } +} + +void CPhysicalGeometry::SetBoundVolume(void) { + unsigned short cont, iMarker, iElem, iNode_Domain, iNode_Surface; + unsigned long Point_Domain, Point_Surface, Point, iElem_Surface, iElem_Domain; + bool CheckVol; + + for (iMarker = 0; iMarker < nMarker; iMarker++) + for (iElem_Surface = 0; iElem_Surface < nElem_Bound[iMarker]; iElem_Surface++) { + + /*--- Choose and arbitrary point from the surface --*/ + Point = bound[iMarker][iElem_Surface]->GetNode(0); + CheckVol = false; + + for (iElem = 0; iElem < node[Point]->GetnElem(); iElem++) { + /*--- Look for elements surronding that point --*/ + cont = 0; iElem_Domain = node[Point]->GetElem(iElem); + for (iNode_Domain = 0; iNode_Domain < elem[iElem_Domain]->GetnNodes(); iNode_Domain++) { + Point_Domain = elem[iElem_Domain]->GetNode(iNode_Domain); + for (iNode_Surface = 0; iNode_Surface < bound[iMarker][iElem_Surface]->GetnNodes(); iNode_Surface++) { + Point_Surface = bound[iMarker][iElem_Surface]->GetNode(iNode_Surface); + if (Point_Surface == Point_Domain) cont++; + if (cont == bound[iMarker][iElem_Surface]->GetnNodes()) break; + } + if (cont == bound[iMarker][iElem_Surface]->GetnNodes()) break; + } + + if (cont == bound[iMarker][iElem_Surface]->GetnNodes()) { + bound[iMarker][iElem_Surface]->SetDomainElement(iElem_Domain); + CheckVol = true; + break; + } + } + if (!CheckVol) { + cout << "The surface element ("<< iMarker <<", "<< iElem_Surface << ") doesn't have an associated volume element." << endl; + exit(EXIT_FAILURE); + } + } +} + +void CPhysicalGeometry::SetVertex(CConfig *config) { + unsigned long iPoint, iVertex, iElem; + unsigned short iMarker, iNode; + + /*--- Initialize the Vertex vector for each node of the grid ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint++) + for (iMarker = 0; iMarker < nMarker; iMarker++) + node[iPoint]->SetVertex(-1, iMarker); + + /*--- Create and compute the vector with the number of vertex per marker ---*/ + + nVertex = new unsigned long [nMarker]; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + /*--- Initialize the number of Bound Vertex for each Marker ---*/ + + nVertex[iMarker] = 0; + for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) + for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { + iPoint = bound[iMarker][iElem]->GetNode(iNode); + + /*--- Set the vertex in the node information ---*/ + + if ((node[iPoint]->GetVertex(iMarker) == -1) || (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE)) { + node[iPoint]->SetVertex(nVertex[iMarker], iMarker); + nVertex[iMarker]++; + } + } + } + + /*--- Initialize the Vertex vector for each node, the previous result is deleted ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint++) + for (iMarker = 0; iMarker < nMarker; iMarker++) + node[iPoint]->SetVertex(-1, iMarker); + + /*--- Create the bound vertex structure, note that the order + is the same as in the input file, this is important for Send/Receive part ---*/ + + vertex = new CVertex**[nMarker]; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + vertex[iMarker] = new CVertex* [nVertex[iMarker]]; + nVertex[iMarker] = 0; + + /*--- Initialize the number of Bound Vertex for each Marker ---*/ + + for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) + for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { + iPoint = bound[iMarker][iElem]->GetNode(iNode); + + /*--- Set the vertex in the node information ---*/ + + if ((node[iPoint]->GetVertex(iMarker) == -1) || (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE)) { + iVertex = nVertex[iMarker]; + vertex[iMarker][iVertex] = new CVertex(iPoint, nDim); + + if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { + vertex[iMarker][iVertex]->SetRotation_Type(bound[iMarker][iElem]->GetRotation_Type()); + } + node[iPoint]->SetVertex(nVertex[iMarker], iMarker); + nVertex[iMarker]++; + } + } + } +} + +void CPhysicalGeometry::SetCoord_CG(void) { + unsigned short nNode, iDim, iMarker, iNode; + unsigned long elem_poin, edge_poin, iElem, iEdge; + su2double **Coord; + + /*--- Compute the center of gravity for elements ---*/ + + for (iElem = 0; iElemGetnNodes(); + Coord = new su2double* [nNode]; + + /*--- Store the coordinates for all the element nodes ---*/ + + for (iNode = 0; iNode < nNode; iNode++) { + elem_poin = elem[iElem]->GetNode(iNode); + Coord[iNode] = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Coord[iNode][iDim]=node[elem_poin]->GetCoord(iDim); + } + + /*--- Compute the element CG coordinates ---*/ + + elem[iElem]->SetCoord_CG(Coord); + + for (iNode = 0; iNode < nNode; iNode++) + if (Coord[iNode] != NULL) delete[] Coord[iNode]; + if (Coord != NULL) delete[] Coord; + } + + /*--- Center of gravity for face elements ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) + for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) { + nNode = bound[iMarker][iElem]->GetnNodes(); + Coord = new su2double* [nNode]; + + /*--- Store the coordinates for all the element nodes ---*/ + + for (iNode = 0; iNode < nNode; iNode++) { + elem_poin = bound[iMarker][iElem]->GetNode(iNode); + Coord[iNode] = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Coord[iNode][iDim]=node[elem_poin]->GetCoord(iDim); + } + /*--- Compute the element CG coordinates ---*/ + + bound[iMarker][iElem]->SetCoord_CG(Coord); + for (iNode = 0; iNode < nNode; iNode++) + if (Coord[iNode] != NULL) delete[] Coord[iNode]; + if (Coord != NULL) delete[] Coord; + } + + /*--- Center of gravity for edges ---*/ + + for (iEdge = 0; iEdge < nEdge; iEdge++) { + nNode = edge[iEdge]->GetnNodes(); + Coord = new su2double* [nNode]; + + /*--- Store the coordinates for all the element nodes ---*/ + + for (iNode = 0; iNode < nNode; iNode++) { + edge_poin=edge[iEdge]->GetNode(iNode); + Coord[iNode] = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Coord[iNode][iDim]=node[edge_poin]->GetCoord(iDim); + } + + /*--- Compute the edge CG coordinates ---*/ + + edge[iEdge]->SetCoord_CG(Coord); + + for (iNode = 0; iNode < nNode; iNode++) + if (Coord[iNode] != NULL) delete[] Coord[iNode]; + if (Coord != NULL) delete[] Coord; + } +} + +void CPhysicalGeometry::SetBoundControlVolume(CConfig *config, unsigned short action) { + unsigned short Neighbor_Node, iMarker, iNode, iNeighbor_Nodes, iDim; + unsigned long Neighbor_Point, iVertex, iPoint, iElem; + long iEdge; + su2double Area, *NormalFace = NULL; + + /*--- Update values of faces of the edge ---*/ + + if (action != ALLOCATE) + for (iMarker = 0; iMarker < nMarker; iMarker++) + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) + vertex[iMarker][iVertex]->SetZeroValues(); + + su2double *Coord_Edge_CG = new su2double [nDim]; + su2double *Coord_Elem_CG = new su2double [nDim]; + su2double *Coord_Vertex = new su2double [nDim]; + + /*--- Loop over all the markers ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) + + /*--- Loop over all the boundary elements ---*/ + + for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) + + /*--- Loop over all the nodes of the boundary ---*/ + + for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { + iPoint = bound[iMarker][iElem]->GetNode(iNode); + iVertex = node[iPoint]->GetVertex(iMarker); + + /*--- Loop over the neighbor nodes, there is a face for each one ---*/ + + for (iNeighbor_Nodes = 0; iNeighbor_Nodes < bound[iMarker][iElem]->GetnNeighbor_Nodes(iNode); iNeighbor_Nodes++) { + Neighbor_Node = bound[iMarker][iElem]->GetNeighbor_Nodes(iNode, iNeighbor_Nodes); + Neighbor_Point = bound[iMarker][iElem]->GetNode(Neighbor_Node); + + /*--- Shared edge by the Neighbor Point and the point ---*/ + + iEdge = FindEdge(iPoint, Neighbor_Point); + for (iDim = 0; iDim < nDim; iDim++) { + Coord_Edge_CG[iDim] = edge[iEdge]->GetCG(iDim); + Coord_Elem_CG[iDim] = bound[iMarker][iElem]->GetCG(iDim); + Coord_Vertex[iDim] = node[iPoint]->GetCoord(iDim); + } + switch (nDim) { + case 2: + + /*--- Store the 2D face ---*/ + + if (iNode == 0) vertex[iMarker][iVertex]->SetNodes_Coord(Coord_Elem_CG, Coord_Vertex); + if (iNode == 1) vertex[iMarker][iVertex]->SetNodes_Coord(Coord_Vertex, Coord_Elem_CG); + break; + case 3: + + /*--- Store the 3D face ---*/ + + if (iNeighbor_Nodes == 0) vertex[iMarker][iVertex]->SetNodes_Coord(Coord_Elem_CG, Coord_Edge_CG, Coord_Vertex); + if (iNeighbor_Nodes == 1) vertex[iMarker][iVertex]->SetNodes_Coord(Coord_Edge_CG, Coord_Elem_CG, Coord_Vertex); + break; + } + } + } + + delete[] Coord_Edge_CG; + delete[] Coord_Elem_CG; + delete[] Coord_Vertex; + + /*--- Check if there is a normal with null area ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker ++) + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + NormalFace = vertex[iMarker][iVertex]->GetNormal(); + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += NormalFace[iDim]*NormalFace[iDim]; + Area = sqrt(Area); + if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS; + } + +} + +void CPhysicalGeometry::MatchInterface(CConfig *config) { + su2double epsilon = 1.5e-1; + + unsigned short nMarker_InterfaceBound = config->GetnMarker_InterfaceBound(); + + if (nMarker_InterfaceBound != 0) { +#ifndef HAVE_MPI + + unsigned short iMarker, jMarker; + unsigned long iVertex, iPoint, jVertex, jPoint = 0, pPoint = 0; + su2double *Coord_i, *Coord_j, dist = 0.0, mindist, maxdist; + + cout << "Set Interface boundary conditions." << endl; + + maxdist = 0.0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + Coord_i = node[iPoint]->GetCoord(); + + mindist = 1E6; + for (jMarker = 0; jMarker < config->GetnMarker_All(); jMarker++) + if ((config->GetMarker_All_KindBC(jMarker) == INTERFACE_BOUNDARY) && (iMarker != jMarker)) + for (jVertex = 0; jVertex < nVertex[jMarker]; jVertex++) { + jPoint = vertex[jMarker][jVertex]->GetNode(); + Coord_j = node[jPoint]->GetCoord(); + if (nDim == 2) dist = sqrt(pow(Coord_j[0]-Coord_i[0],2.0) + pow(Coord_j[1]-Coord_i[1],2.0)); + if (nDim == 3) dist = sqrt(pow(Coord_j[0]-Coord_i[0],2.0) + pow(Coord_j[1]-Coord_i[1],2.0) + pow(Coord_j[2]-Coord_i[2],2.0)); + if (dist < mindist) {mindist = dist; pPoint = jPoint;} + } + maxdist = max(maxdist, mindist); + vertex[iMarker][iVertex]->SetDonorPoint(pPoint, MASTER_NODE); + + if (mindist > epsilon) { + cout.precision(10); + cout << endl; + cout << " Bad match for point " << iPoint << ".\tNearest"; + cout << " donor distance: " << scientific << mindist << "."; + vertex[iMarker][iVertex]->SetDonorPoint(iPoint, MASTER_NODE); + maxdist = min(maxdist, 0.0); + } + + } + cout <<"The max distance between points is: " << maxdist <<"."<< endl; + } + +#else + + unsigned short iMarker, iDim; + unsigned long iVertex, iPoint, pPoint = 0, jVertex, jPoint; + su2double *Coord_i, Coord_j[3], dist = 0.0, mindist, maxdist_local, maxdist_global; + int iProcessor, pProcessor = 0; + unsigned long nLocalVertex_Interface = 0, nGlobalVertex_Interface = 0, MaxLocalVertex_Interface = 0; + int rank, nProcessor; + + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); + + unsigned long *Buffer_Send_nVertex = new unsigned long [1]; + unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor]; + + if (rank == MASTER_NODE) cout << "Set Interface boundary conditions (if any)." << endl; + + /*--- Compute the number of vertex that have interfase boundary condition + without including the ghost nodes ---*/ + + nLocalVertex_Interface = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) + for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) nLocalVertex_Interface ++; + } + + Buffer_Send_nVertex[0] = nLocalVertex_Interface; + + /*--- Send Interface vertex information --*/ + + SU2_MPI::Allreduce(&nLocalVertex_Interface, &nGlobalVertex_Interface, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&nLocalVertex_Interface, &MaxLocalVertex_Interface, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_Interface*nDim]; + unsigned long *Buffer_Send_Point = new unsigned long [MaxLocalVertex_Interface]; + + su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_Interface*nDim]; + unsigned long *Buffer_Receive_Point = new unsigned long [nProcessor*MaxLocalVertex_Interface]; + + unsigned long nBuffer_Coord = MaxLocalVertex_Interface*nDim; + unsigned long nBuffer_Point = MaxLocalVertex_Interface; + + for (iVertex = 0; iVertex < MaxLocalVertex_Interface; iVertex++) { + Buffer_Send_Point[iVertex] = 0; + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; + } + + /*--- Copy coordinates and point to the auxiliar vector --*/ + + nLocalVertex_Interface = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) + for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + Buffer_Send_Point[nLocalVertex_Interface] = iPoint; + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[nLocalVertex_Interface*nDim+iDim] = node[iPoint]->GetCoord(iDim); + nLocalVertex_Interface++; + } + } + + SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_Point, nBuffer_Point, MPI_UNSIGNED_LONG, Buffer_Receive_Point, nBuffer_Point, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + /*--- Compute the closest point to a Near-Field boundary point ---*/ + + maxdist_local = 0.0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + + /*--- Coordinates of the boundary point ---*/ + + Coord_i = node[iPoint]->GetCoord(); mindist = 1E6; pProcessor = 0; pPoint = 0; + + /*--- Loop over all the boundaries to find the pair ---*/ + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) + for (jVertex = 0; jVertex < Buffer_Receive_nVertex[iProcessor]; jVertex++) { + jPoint = Buffer_Receive_Point[iProcessor*MaxLocalVertex_Interface+jVertex]; + + /*--- Compute the distance ---*/ + + dist = 0.0; for (iDim = 0; iDim < nDim; iDim++) { + Coord_j[iDim] = Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_Interface+jVertex)*nDim+iDim]; + dist += pow(Coord_j[iDim]-Coord_i[iDim],2.0); + } dist = sqrt(dist); + + if (((dist < mindist) && (iProcessor != rank)) || + ((dist < mindist) && (iProcessor == rank) && (jPoint != iPoint))) { + mindist = dist; pProcessor = iProcessor; pPoint = jPoint; + } + } + + /*--- Store the value of the pair ---*/ + + maxdist_local = max(maxdist_local, mindist); + vertex[iMarker][iVertex]->SetDonorPoint(pPoint, pProcessor); + + if (mindist > epsilon) { + cout.precision(10); + cout << endl; + cout << " Bad match for point " << iPoint << ".\tNearest"; + cout << " donor distance: " << scientific << mindist << "."; + vertex[iMarker][iVertex]->SetDonorPoint(iPoint, pProcessor); + maxdist_local = min(maxdist_local, 0.0); + } + + } + } + } + } + + SU2_MPI::Reduce(&maxdist_local, &maxdist_global, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, MPI_COMM_WORLD); + + if (rank == MASTER_NODE) cout <<"The max distance between points is: " << maxdist_global <<"."<< endl; + + delete[] Buffer_Send_Coord; + delete[] Buffer_Send_Point; + + delete[] Buffer_Receive_Coord; + delete[] Buffer_Receive_Point; + + delete[] Buffer_Send_nVertex; + delete[] Buffer_Receive_nVertex; + +#endif + + } + +} + +void CPhysicalGeometry::MatchNearField(CConfig *config) { + su2double epsilon = 1e-1; + + unsigned short nMarker_NearfieldBound = config->GetnMarker_NearFieldBound(); + + if (nMarker_NearfieldBound != 0) { + +#ifndef HAVE_MPI + + unsigned short iMarker, jMarker; + unsigned long iVertex, iPoint, jVertex, jPoint = 0, pPoint = 0; + su2double *Coord_i, *Coord_j, dist = 0.0, mindist, maxdist; + + cout << "Set Near-Field boundary conditions. " << endl; + + maxdist = 0.0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + Coord_i = node[iPoint]->GetCoord(); + + mindist = 1e10; + for (jMarker = 0; jMarker < config->GetnMarker_All(); jMarker++) + if ((config->GetMarker_All_KindBC(jMarker) == NEARFIELD_BOUNDARY) && (iMarker != jMarker)) + for (jVertex = 0; jVertex < nVertex[jMarker]; jVertex++) { + jPoint = vertex[jMarker][jVertex]->GetNode(); + Coord_j = node[jPoint]->GetCoord(); + if (nDim == 2) dist = sqrt(pow(Coord_j[0]-Coord_i[0],2.0) + pow(Coord_j[1]-Coord_i[1],2.0)); + if (nDim == 3) dist = sqrt(pow(Coord_j[0]-Coord_i[0],2.0) + pow(Coord_j[1]-Coord_i[1],2.0) + pow(Coord_j[2]-Coord_i[2],2.0)); + if (dist < mindist) { mindist = dist; pPoint = jPoint; } + } + maxdist = max(maxdist, mindist); + vertex[iMarker][iVertex]->SetDonorPoint(pPoint, MASTER_NODE); + + if (mindist > epsilon) { + cout.precision(10); + cout << endl; + cout << " Bad match for point " << iPoint << ".\tNearest"; + cout << " donor distance: " << scientific << mindist << "."; + vertex[iMarker][iVertex]->SetDonorPoint(iPoint, MASTER_NODE); + maxdist = min(maxdist, 0.0); + } + } + cout <<"The max distance between points is: " << maxdist <<"."<< endl; + } + +#else + + unsigned short iMarker, iDim; + unsigned long iVertex, iPoint, pPoint = 0, jVertex, jPoint; + su2double *Coord_i, Coord_j[3], dist = 0.0, mindist, maxdist_local, maxdist_global; + int iProcessor, pProcessor = 0; + unsigned long nLocalVertex_NearField = 0, nGlobalVertex_NearField = 0, MaxLocalVertex_NearField = 0; + int rank, nProcessor; + + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); + + unsigned long *Buffer_Send_nVertex = new unsigned long [1]; + unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor]; + + if (rank == MASTER_NODE) cout << "Set Near-Field boundary conditions." << endl; + + /*--- Compute the number of vertex that have nearfield boundary condition + without including the ghost nodes ---*/ + + nLocalVertex_NearField = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) + for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) nLocalVertex_NearField ++; + } + + Buffer_Send_nVertex[0] = nLocalVertex_NearField; + + /*--- Send Near-Field vertex information --*/ + + SU2_MPI::Allreduce(&nLocalVertex_NearField, &nGlobalVertex_NearField, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&nLocalVertex_NearField, &MaxLocalVertex_NearField, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_NearField*nDim]; + unsigned long *Buffer_Send_Point = new unsigned long [MaxLocalVertex_NearField]; + + su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_NearField*nDim]; + unsigned long *Buffer_Receive_Point = new unsigned long [nProcessor*MaxLocalVertex_NearField]; + + unsigned long nBuffer_Coord = MaxLocalVertex_NearField*nDim; + unsigned long nBuffer_Point = MaxLocalVertex_NearField; + + for (iVertex = 0; iVertex < MaxLocalVertex_NearField; iVertex++) { + Buffer_Send_Point[iVertex] = 0; + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; + } + + /*--- Copy coordinates and point to the auxiliar vector --*/ + + nLocalVertex_NearField = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) + for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + Buffer_Send_Point[nLocalVertex_NearField] = iPoint; + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[nLocalVertex_NearField*nDim+iDim] = node[iPoint]->GetCoord(iDim); + nLocalVertex_NearField++; + } + } + + SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_Point, nBuffer_Point, MPI_UNSIGNED_LONG, Buffer_Receive_Point, nBuffer_Point, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + /*--- Compute the closest point to a Near-Field boundary point ---*/ + + maxdist_local = 0.0; + maxdist_global = 0.0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { + + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + + /*--- Coordinates of the boundary point ---*/ + + Coord_i = node[iPoint]->GetCoord(); mindist = 1E6; pProcessor = 0; pPoint = 0; + + /*--- Loop over all the boundaries to find the pair ---*/ + + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) + for (jVertex = 0; jVertex < Buffer_Receive_nVertex[iProcessor]; jVertex++) { + jPoint = Buffer_Receive_Point[iProcessor*MaxLocalVertex_NearField+jVertex]; + + /*--- Compute the distance ---*/ + + dist = 0.0; for (iDim = 0; iDim < nDim; iDim++) { + Coord_j[iDim] = Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_NearField+jVertex)*nDim+iDim]; + dist += pow(Coord_j[iDim]-Coord_i[iDim],2.0); + } dist = sqrt(dist); + + if (((dist < mindist) && (iProcessor != rank)) || + ((dist < mindist) && (iProcessor == rank) && (jPoint != iPoint))) { + mindist = dist; pProcessor = iProcessor; pPoint = jPoint; + } + } + + /*--- Store the value of the pair ---*/ + + maxdist_local = max(maxdist_local, mindist); + vertex[iMarker][iVertex]->SetDonorPoint(pPoint, pProcessor); + + if (mindist > epsilon) { + cout.precision(10); + cout << endl; + cout << " Bad match for point " << iPoint << ".\tNearest"; + cout << " donor distance: " << scientific << mindist << "."; + vertex[iMarker][iVertex]->SetDonorPoint(iPoint, pProcessor); + maxdist_local = min(maxdist_local, 0.0); + } + + } + } + + } + } + + SU2_MPI::Reduce(&maxdist_local, &maxdist_global, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, MPI_COMM_WORLD); + + if (rank == MASTER_NODE) cout <<"The max distance between points is: " << maxdist_global <<"."<< endl; + + delete[] Buffer_Send_Coord; + delete[] Buffer_Send_Point; + + delete[] Buffer_Receive_Coord; + delete[] Buffer_Receive_Point; + + delete[] Buffer_Send_nVertex; + delete[] Buffer_Receive_nVertex; + +#endif + + } + +} + +void CPhysicalGeometry::MatchActuator_Disk(CConfig *config) { + su2double epsilon = 1e-1; + unsigned short iMarker, iDim; + unsigned long iVertex, iPoint, pPoint = 0, jVertex, jPoint; + su2double *Coord_i, Coord_j[3], dist = 0.0, mindist, maxdist_local = 0.0, maxdist_global = 0.0; + int iProcessor, pProcessor = 0; + unsigned long nLocalVertex_ActDisk = 0, MaxLocalVertex_ActDisk = 0; + int rank, nProcessor; + unsigned short Beneficiary = 0, Donor = 0, iBC; + + unsigned short nMarker_ActDisk_Inlet = config->GetnMarker_ActDisk_Inlet(); + + if (nMarker_ActDisk_Inlet != 0) { + + for (iBC = 0; iBC < 2; iBC++) { + + if (iBC == 0) { Beneficiary = ACTDISK_INLET; Donor = ACTDISK_OUTLET; } + if (iBC == 1) { Beneficiary = ACTDISK_OUTLET; Donor = ACTDISK_INLET; } + +#ifndef HAVE_MPI + rank = MASTER_NODE; + nProcessor = SINGLE_NODE; +#else + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); +#endif + + unsigned long *Buffer_Send_nVertex = new unsigned long [1]; + unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor]; + + if ((iBC == 0) && (rank == MASTER_NODE)) cout << "Set Actuator Disk inlet boundary conditions." << endl; + if ((iBC == 1) && (rank == MASTER_NODE)) cout << "Set Actuator Disk outlet boundary conditions." << endl; + + /*--- Compute the number of vertex that have an actuator disk outlet boundary condition + without including the ghost nodes ---*/ + + nLocalVertex_ActDisk = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == Donor) { + for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) nLocalVertex_ActDisk ++; + } + } + } + + Buffer_Send_nVertex[0] = nLocalVertex_ActDisk; + + /*--- Send actuator disk vertex information --*/ + +#ifndef HAVE_MPI + MaxLocalVertex_ActDisk = nLocalVertex_ActDisk; + Buffer_Receive_nVertex[0] = Buffer_Send_nVertex[0]; +#else + SU2_MPI::Allreduce(&nLocalVertex_ActDisk, &MaxLocalVertex_ActDisk, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); +#endif + + /*--- Array dimensionalization --*/ + + su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_ActDisk*nDim]; + unsigned long *Buffer_Send_Point = new unsigned long [MaxLocalVertex_ActDisk]; + + su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_ActDisk*nDim]; + unsigned long *Buffer_Receive_Point = new unsigned long [nProcessor*MaxLocalVertex_ActDisk]; + + unsigned long nBuffer_Coord = MaxLocalVertex_ActDisk*nDim; + unsigned long nBuffer_Point = MaxLocalVertex_ActDisk; + + for (iVertex = 0; iVertex < MaxLocalVertex_ActDisk; iVertex++) { + Buffer_Send_Point[iVertex] = 0; + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; + } + + /*--- Copy coordinates and point to the auxiliar vector --*/ + + nLocalVertex_ActDisk = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == Donor) { + for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + Buffer_Send_Point[nLocalVertex_ActDisk] = iPoint; + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[nLocalVertex_ActDisk*nDim+iDim] = node[iPoint]->GetCoord(iDim); + nLocalVertex_ActDisk++; + } + } + } + } + +#ifndef HAVE_MPI + for (unsigned long iBuffer_Coord = 0; iBuffer_Coord < nBuffer_Coord; iBuffer_Coord++) + Buffer_Receive_Coord[iBuffer_Coord] = Buffer_Send_Coord[iBuffer_Coord]; + for (unsigned long iBuffer_Point = 0; iBuffer_Point < nBuffer_Point; iBuffer_Point++) + Buffer_Receive_Point[iBuffer_Point] = Buffer_Send_Point[iBuffer_Point]; +#else + SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_Point, nBuffer_Point, MPI_UNSIGNED_LONG, Buffer_Receive_Point, nBuffer_Point, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); +#endif + + /*--- Compute the closest point to an actuator disk inlet point ---*/ + + maxdist_local = 0.0; + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == Beneficiary) { + + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + + /*--- Coordinates of the boundary point ---*/ + + Coord_i = node[iPoint]->GetCoord(); mindist = 1E6; pProcessor = 0; pPoint = 0; + + /*--- Loop over all the boundaries to find the pair ---*/ + + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + for (jVertex = 0; jVertex < Buffer_Receive_nVertex[iProcessor]; jVertex++) { + jPoint = Buffer_Receive_Point[iProcessor*MaxLocalVertex_ActDisk+jVertex]; + + /*--- Compute the distance ---*/ + + dist = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Coord_j[iDim] = Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_ActDisk+jVertex)*nDim+iDim]; + dist += pow(Coord_j[iDim]-Coord_i[iDim], 2.0); + } + dist = sqrt(dist); + + if (dist < mindist) { + mindist = dist; pProcessor = iProcessor; pPoint = jPoint; + if (dist == 0.0) break; + } + + } + } + + /*--- Store the value of the pair ---*/ + + maxdist_local = max(maxdist_local, mindist); + vertex[iMarker][iVertex]->SetDonorPoint(pPoint, pProcessor); + + if (mindist > epsilon) { + cout.precision(10); + cout << endl; + cout << " Bad match for point " << iPoint << ".\tNearest"; + cout << " donor distance: " << scientific << mindist << "."; + vertex[iMarker][iVertex]->SetDonorPoint(iPoint, pProcessor); + maxdist_local = min(maxdist_local, 0.0); + } + + } + } + + } + } + +#ifndef HAVE_MPI + maxdist_global = maxdist_local; +#else + SU2_MPI::Reduce(&maxdist_local, &maxdist_global, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, MPI_COMM_WORLD); +#endif + + if (rank == MASTER_NODE) cout <<"The max distance between points is: " << maxdist_global <<"."<< endl; + + delete[] Buffer_Send_Coord; + delete[] Buffer_Send_Point; + + delete[] Buffer_Receive_Coord; + delete[] Buffer_Receive_Point; + + delete[] Buffer_Send_nVertex; + delete[] Buffer_Receive_nVertex; + + } + } + +} + +void CPhysicalGeometry::MatchZone(CConfig *config, CGeometry *geometry_donor, CConfig *config_donor, + unsigned short val_iZone, unsigned short val_nZone) { + +#ifndef HAVE_MPI + + unsigned short iMarker, jMarker; + unsigned long iVertex, iPoint, jVertex, jPoint = 0, pPoint = 0; + su2double *Coord_i, *Coord_j, dist = 0.0, mindist, maxdist; + + if (val_iZone == ZONE_0) cout << "Set zone boundary conditions (if any)." << endl; + + maxdist = 0.0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + Coord_i = node[iPoint]->GetCoord(); + + mindist = 1E6; + for (jMarker = 0; jMarker < config_donor->GetnMarker_All(); jMarker++) + for (jVertex = 0; jVertex < geometry_donor->GetnVertex(jMarker); jVertex++) { + jPoint = geometry_donor->vertex[jMarker][jVertex]->GetNode(); + Coord_j = geometry_donor->node[jPoint]->GetCoord(); + if (nDim == 2) dist = sqrt(pow(Coord_j[0]-Coord_i[0],2.0) + pow(Coord_j[1]-Coord_i[1],2.0)); + if (nDim == 3) dist = sqrt(pow(Coord_j[0]-Coord_i[0],2.0) + pow(Coord_j[1]-Coord_i[1],2.0) + pow(Coord_j[2]-Coord_i[2],2.0)); + if (dist < mindist) { mindist = dist; pPoint = jPoint; } + } + + maxdist = max(maxdist, mindist); + vertex[iMarker][iVertex]->SetDonorPoint(pPoint, MASTER_NODE); + + } + } + +#else + + unsigned short iMarker, iDim; + unsigned long iVertex, iPoint, pPoint = 0, jVertex, jPoint; + su2double *Coord_i, Coord_j[3], dist = 0.0, mindist, maxdist; + int iProcessor, pProcessor = 0; + unsigned long nLocalVertex_Zone = 0, nGlobalVertex_Zone = 0, MaxLocalVertex_Zone = 0; + int rank, nProcessor; + + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); + + unsigned long *Buffer_Send_nVertex = new unsigned long [1]; + unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor]; + + if (val_iZone == ZONE_0) cout << "Set zone boundary conditions (if any)." << endl; + + nLocalVertex_Zone = 0; + for (iMarker = 0; iMarker < config_donor->GetnMarker_All(); iMarker++) + for (iVertex = 0; iVertex < geometry_donor->GetnVertex(iMarker); iVertex++) { + iPoint = geometry_donor->vertex[iMarker][iVertex]->GetNode(); + if (geometry_donor->node[iPoint]->GetDomain()) nLocalVertex_Zone ++; + } + + Buffer_Send_nVertex[0] = nLocalVertex_Zone; + + /*--- Send Interface vertex information --*/ + + SU2_MPI::Allreduce(&nLocalVertex_Zone, &nGlobalVertex_Zone, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&nLocalVertex_Zone, &MaxLocalVertex_Zone, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_Zone*nDim]; + unsigned long *Buffer_Send_Point = new unsigned long [MaxLocalVertex_Zone]; + + su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_Zone*nDim]; + unsigned long *Buffer_Receive_Point = new unsigned long [nProcessor*MaxLocalVertex_Zone]; + + unsigned long nBuffer_Coord = MaxLocalVertex_Zone*nDim; + unsigned long nBuffer_Point = MaxLocalVertex_Zone; + + for (iVertex = 0; iVertex < MaxLocalVertex_Zone; iVertex++) { + Buffer_Send_Point[iVertex] = 0; + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; + } + + /*--- Copy coordinates and point to the auxiliar vector --*/ + nLocalVertex_Zone = 0; + for (iMarker = 0; iMarker < config_donor->GetnMarker_All(); iMarker++) + for (iVertex = 0; iVertex < geometry_donor->GetnVertex(iMarker); iVertex++) { + iPoint = geometry_donor->vertex[iMarker][iVertex]->GetNode(); + if (geometry_donor->node[iPoint]->GetDomain()) { + Buffer_Send_Point[nLocalVertex_Zone] = iPoint; + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[nLocalVertex_Zone*nDim+iDim] = geometry_donor->node[iPoint]->GetCoord(iDim); + nLocalVertex_Zone++; + } + } + + SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_Point, nBuffer_Point, MPI_UNSIGNED_LONG, Buffer_Receive_Point, nBuffer_Point, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + /*--- Compute the closest point to a Near-Field boundary point ---*/ + maxdist = 0.0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + + if (node[iPoint]->GetDomain()) { + + /*--- Coordinates of the boundary point ---*/ + Coord_i = node[iPoint]->GetCoord(); mindist = 1E6; pProcessor = 0; pPoint = 0; + + /*--- Loop over all the boundaries to find the pair ---*/ + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) + for (jVertex = 0; jVertex < Buffer_Receive_nVertex[iProcessor]; jVertex++) { + jPoint = Buffer_Receive_Point[iProcessor*MaxLocalVertex_Zone+jVertex]; + + /*--- Compute the distance ---*/ + dist = 0.0; for (iDim = 0; iDim < nDim; iDim++) { + Coord_j[iDim] = Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_Zone+jVertex)*nDim+iDim]; + dist += pow(Coord_j[iDim]-Coord_i[iDim],2.0); + } dist = sqrt(dist); + + if (((dist < mindist) && (iProcessor != rank)) || + ((dist < mindist) && (iProcessor == rank) && (jPoint != iPoint))) { + mindist = dist; pProcessor = iProcessor; pPoint = jPoint; + } + } + + /*--- Store the value of the pair ---*/ + maxdist = max(maxdist, mindist); + vertex[iMarker][iVertex]->SetDonorPoint(pPoint, pProcessor); + + + } + } + } + + delete[] Buffer_Send_Coord; + delete[] Buffer_Send_Point; + + delete[] Buffer_Receive_Coord; + delete[] Buffer_Receive_Point; + + delete[] Buffer_Send_nVertex; + delete[] Buffer_Receive_nVertex; + +#endif + +} + + +void CPhysicalGeometry::SetControlVolume(CConfig *config, unsigned short action) { + unsigned long face_iPoint = 0, face_jPoint = 0, iPoint, iElem; + long iEdge; + unsigned short nEdgesFace = 1, iFace, iEdgesFace, iDim; + su2double *Coord_Edge_CG, *Coord_FaceElem_CG, *Coord_Elem_CG, *Coord_FaceiPoint, *Coord_FacejPoint, Area, + Volume, DomainVolume, my_DomainVolume, *NormalFace = NULL; + bool change_face_orientation; + int rank; + +#ifndef HAVE_MPI + rank = MASTER_NODE; +#else + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Update values of faces of the edge ---*/ + if (action != ALLOCATE) { + for (iEdge = 0; iEdge < (long)nEdge; iEdge++) + edge[iEdge]->SetZeroValues(); + for (iPoint = 0; iPoint < nPoint; iPoint++) + node[iPoint]->SetVolume (0.0); + } + + Coord_Edge_CG = new su2double [nDim]; + Coord_FaceElem_CG = new su2double [nDim]; + Coord_Elem_CG = new su2double [nDim]; + Coord_FaceiPoint = new su2double [nDim]; + Coord_FacejPoint = new su2double [nDim]; + + my_DomainVolume = 0.0; + for (iElem = 0; iElem < nElem; iElem++) + for (iFace = 0; iFace < elem[iElem]->GetnFaces(); iFace++) { + + /*--- In 2D all the faces have only one edge ---*/ + if (nDim == 2) nEdgesFace = 1; + /*--- In 3D the number of edges per face is the same as the number of point per face ---*/ + if (nDim == 3) nEdgesFace = elem[iElem]->GetnNodesFace(iFace); + + /*-- Loop over the edges of a face ---*/ + for (iEdgesFace = 0; iEdgesFace < nEdgesFace; iEdgesFace++) { + + /*--- In 2D only one edge (two points) per edge ---*/ + if (nDim == 2) { + face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0)); + face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,1)); + } + + /*--- In 3D there are several edges in each face ---*/ + if (nDim == 3) { + face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iEdgesFace)); + if (iEdgesFace != nEdgesFace-1) + face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iEdgesFace+1)); + else + face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0)); + } + + /*--- We define a direction (from the smalest index to the greatest) --*/ + change_face_orientation = false; + if (face_iPoint > face_jPoint) change_face_orientation = true; + iEdge = FindEdge(face_iPoint, face_jPoint); + + for (iDim = 0; iDim < nDim; iDim++) { + Coord_Edge_CG[iDim] = edge[iEdge]->GetCG(iDim); + Coord_Elem_CG[iDim] = elem[iElem]->GetCG(iDim); + Coord_FaceElem_CG[iDim] = elem[iElem]->GetFaceCG(iFace, iDim); + Coord_FaceiPoint[iDim] = node[face_iPoint]->GetCoord(iDim); + Coord_FacejPoint[iDim] = node[face_jPoint]->GetCoord(iDim); + } + + switch (nDim) { + case 2: + /*--- Two dimensional problem ---*/ + if (change_face_orientation) edge[iEdge]->SetNodes_Coord(Coord_Elem_CG, Coord_Edge_CG); + else edge[iEdge]->SetNodes_Coord(Coord_Edge_CG, Coord_Elem_CG); + Area = edge[iEdge]->GetVolume(Coord_FaceiPoint, Coord_Edge_CG, Coord_Elem_CG); + node[face_iPoint]->AddVolume(Area); my_DomainVolume +=Area; + Area = edge[iEdge]->GetVolume(Coord_FacejPoint, Coord_Edge_CG, Coord_Elem_CG); + node[face_jPoint]->AddVolume(Area); my_DomainVolume +=Area; + break; + case 3: + /*--- Three dimensional problem ---*/ + if (change_face_orientation) edge[iEdge]->SetNodes_Coord(Coord_FaceElem_CG, Coord_Edge_CG, Coord_Elem_CG); + else edge[iEdge]->SetNodes_Coord(Coord_Edge_CG, Coord_FaceElem_CG, Coord_Elem_CG); + Volume = edge[iEdge]->GetVolume(Coord_FaceiPoint, Coord_Edge_CG, Coord_FaceElem_CG, Coord_Elem_CG); + node[face_iPoint]->AddVolume(Volume); my_DomainVolume +=Volume; + Volume = edge[iEdge]->GetVolume(Coord_FacejPoint, Coord_Edge_CG, Coord_FaceElem_CG, Coord_Elem_CG); + node[face_jPoint]->AddVolume(Volume); my_DomainVolume +=Volume; + break; + } + } + } + + /*--- Check if there is a normal with null area ---*/ + for (iEdge = 0; iEdge < (long)nEdge; iEdge++) { + NormalFace = edge[iEdge]->GetNormal(); + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += NormalFace[iDim]*NormalFace[iDim]; + Area = sqrt(Area); + if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS; + } + + +#ifdef HAVE_MPI + SU2_MPI::Allreduce(&my_DomainVolume, &DomainVolume, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); +#else + DomainVolume = my_DomainVolume; +#endif + + if ((rank == MASTER_NODE) && (action == ALLOCATE)) { + if (nDim == 2) cout <<"Area of the computational grid: "<< DomainVolume <<"."<< endl; + if (nDim == 3) cout <<"Volume of the computational grid: "<< DomainVolume <<"."<< endl; + } + + config->SetDomainVolume(DomainVolume); + + delete[] Coord_Edge_CG; + delete[] Coord_FaceElem_CG; + delete[] Coord_Elem_CG; + delete[] Coord_FaceiPoint; + delete[] Coord_FacejPoint; +} + +void CPhysicalGeometry::VisualizeControlVolume(CConfig *config, unsigned short action) { + + /*--- This routine is only meant for visualization in serial currently ---*/ +#ifndef HAVE_MPI + + unsigned long face_iPoint = 0, face_jPoint = 0, iElem, iPoint_Viz; + long iEdge; + unsigned short nEdgesFace = 1, iFace, iEdgesFace, iDim; + su2double *Coord_Edge_CG, *Coord_FaceElem_CG, *Coord_Elem_CG, *Coord_FaceiPoint, + *Coord_FacejPoint; + int counter = 0; + char cstr[MAX_STRING_SIZE], buffer[50]; + ofstream Tecplot_File; + string mesh_filename; + vector X, Y, Z, X_n, Y_n, Z_n; + su2double r1[3], r2[3], CrossProduct[3]; + + /*--- Access the point number for control volume we want to vizualize ---*/ + + iPoint_Viz = config->GetVisualize_CV(); + + /*--- Allocate some structures for building the dual CVs ---*/ + + Coord_Edge_CG = new su2double [nDim]; + Coord_FaceElem_CG = new su2double [nDim]; + Coord_Elem_CG = new su2double [nDim]; + Coord_FaceiPoint = new su2double [nDim]; + Coord_FacejPoint = new su2double [nDim]; + + /*--- Loop over each face of each element ---*/ + + CrossProduct[0] = 0.0; CrossProduct[1] = 0.0; CrossProduct[2] = 0.0; + + for (iElem = 0; iElem < nElem; iElem++) { + + for (iFace = 0; iFace < elem[iElem]->GetnFaces(); iFace++) { + + /*--- In 2D all the faces have only one edge ---*/ + if (nDim == 2) nEdgesFace = 1; + /*--- In 3D the number of edges per face is the same as the number of point per face ---*/ + if (nDim == 3) nEdgesFace = elem[iElem]->GetnNodesFace(iFace); + + /*-- Loop over the edges of a face ---*/ + for (iEdgesFace = 0; iEdgesFace < nEdgesFace; iEdgesFace++) { + + /*--- In 2D only one edge (two points) per edge ---*/ + if (nDim == 2) { + face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0)); + face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,1)); + } + + /*--- In 3D there are several edges in each face ---*/ + if (nDim == 3) { + face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iEdgesFace)); + if (iEdgesFace != nEdgesFace-1) + face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iEdgesFace+1)); + else + face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0)); + } + + /*--- We define a direction (from the smallest index to the greatest) --*/ + iEdge = FindEdge(face_iPoint, face_jPoint); + + for (iDim = 0; iDim < nDim; iDim++) { + Coord_Edge_CG[iDim] = edge[iEdge]->GetCG(iDim); + Coord_Elem_CG[iDim] = elem[iElem]->GetCG(iDim); + Coord_FaceElem_CG[iDim] = elem[iElem]->GetFaceCG(iFace, iDim); + Coord_FaceiPoint[iDim] = node[face_iPoint]->GetCoord(iDim); + Coord_FacejPoint[iDim] = node[face_jPoint]->GetCoord(iDim); + } + + /*--- Print out the coordinates for a set of triangles making + up a single dual control volume for visualization. ---*/ + + if (face_iPoint == iPoint_Viz || face_jPoint == iPoint_Viz) { + + if (nDim == 2) { + X.push_back(Coord_Elem_CG[0]); X.push_back(Coord_Edge_CG[0]); + Y.push_back(Coord_Elem_CG[1]); Y.push_back(Coord_Edge_CG[1]); + } else if (nDim == 3) { + X.push_back(Coord_FaceElem_CG[0]); X.push_back(Coord_Edge_CG[0]); X.push_back(Coord_Elem_CG[0]); + Y.push_back(Coord_FaceElem_CG[1]); Y.push_back(Coord_Edge_CG[1]); Y.push_back(Coord_Elem_CG[1]); + Z.push_back(Coord_FaceElem_CG[2]); Z.push_back(Coord_Edge_CG[2]); Z.push_back(Coord_Elem_CG[2]); + + for (iDim = 0; iDim < nDim; iDim++) { + r1[iDim] = Coord_FaceElem_CG[iDim]-Coord_Elem_CG[iDim]; + r2[iDim] = Coord_Edge_CG[iDim]-Coord_Elem_CG[iDim]; + } + CrossProduct[0] += 0.5*(r1[1]*r2[2] - r1[2]*r2[1]); + CrossProduct[1] += 0.5*(r1[2]*r2[0] - r1[0]*r2[2]); + CrossProduct[2] += 0.5*(r1[0]*r2[1] - r1[1]*r2[0]); + } + counter++; + } + } + } + } + + /*--- Write a Tecplot file to visualize the CV ---*/ + + strcpy(cstr,"dual_cv"); + SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(iPoint_Viz)); + strcat(cstr, buffer); + + Tecplot_File.open(cstr, ios::out); + Tecplot_File << "TITLE= \"Visualization of the control volume\"" << endl; + + if (nDim == 2) { + Tecplot_File << "VARIABLES = \"x\",\"y\" " << endl; + Tecplot_File << "ZONE NODES= "<< counter*2 <<", ELEMENTS= "; + Tecplot_File << counter <<", DATAPACKING=POINT, ZONETYPE=FEQUADRILATERAL"<< endl; + } if (nDim == 3) { + Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\" " << endl; + Tecplot_File << "ZONE NODES= "<< counter*3 <<", ELEMENTS= "; + Tecplot_File << counter <<", DATAPACKING=POINT, ZONETYPE=FEBRICK"<< endl; + } + + /*--- Write coordinates for the nodes in the order that they were found + for each of the edges/triangles making up a dual control volume. ---*/ + + for (vector::size_type i = 0; i != X.size(); i++) { + Tecplot_File << X[i] << "\t" << Y[i]; + if (nDim == 3) Tecplot_File << "\t" << Z[i]; + Tecplot_File << "\n"; + } + + /*--- Create a new connectivity table in the order the faces were found ---*/ + + int j; + for (int i= 0; i < counter; i++) { + if (nDim == 2) { + j = i*2; + Tecplot_File << j+1 <<"\t"<GetNode(iNodes); + output_file << "\t"<GetCoord(iDim) ; +#ifndef HAVE_MPI + output_file << "\t" << iPoint << endl; +#else + output_file << "\t" << iPoint << "\t" << node[iPoint]->GetGlobalIndex() << endl; +#endif + + } + + /*--- Loop through and write the boundary info ---*/ + + output_file << "NMARK= " << nMarker << endl; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + /*--- Ignore SEND_RECEIVE for the moment ---*/ + if (bound[iMarker][0]->GetVTK_Type() != VERTEX) { + + Grid_Marker = config->GetMarker_All_TagBound(iMarker); + output_file << "MARKER_TAG= " << Grid_Marker << endl; + output_file << "MARKER_ELEMS= " << nElem_Bound[iMarker]<< endl; + + if (nDim == 2) { + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ; + for (iNodes = 0; iNodes < bound[iMarker][iElem_Bound]->GetnNodes(); iNodes++) + output_file << bound[iMarker][iElem_Bound]->GetNode(iNodes) << "\t" ; + output_file << iElem_Bound << endl; + } + } + + if (nDim == 3) { + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ; + for (iNodes = 0; iNodes < bound[iMarker][iElem_Bound]->GetnNodes(); iNodes++) + output_file << bound[iMarker][iElem_Bound]->GetNode(iNodes) << "\t" ; + output_file << iElem_Bound << endl; + } + } + + } else if (bound[iMarker][0]->GetVTK_Type() == VERTEX) { + output_file << "MARKER_TAG= SEND_RECEIVE" << endl; + output_file << "MARKER_ELEMS= " << nElem_Bound[iMarker]<< endl; + if (config->GetMarker_All_SendRecv(iMarker) > 0) output_file << "SEND_TO= " << config->GetMarker_All_SendRecv(iMarker) << endl; + if (config->GetMarker_All_SendRecv(iMarker) < 0) output_file << "SEND_TO= " << config->GetMarker_All_SendRecv(iMarker) << endl; + + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" << + bound[iMarker][iElem_Bound]->GetNode(0) << "\t" << + bound[iMarker][iElem_Bound]->GetRotation_Type() << endl; + } + + } + } + + /*--- Get the total number of periodic transformations ---*/ + + nPeriodic = config->GetnPeriodicIndex(); + output_file << "NPERIODIC= " << nPeriodic << endl; + + /*--- From iPeriodic obtain the iMarker ---*/ + + for (iPeriodic = 0; iPeriodic < nPeriodic; iPeriodic++) { + + /*--- Retrieve the supplied periodic information. ---*/ + + center = config->GetPeriodicCenter(iPeriodic); + angles = config->GetPeriodicRotation(iPeriodic); + transl = config->GetPeriodicTranslate(iPeriodic); + + output_file << "PERIODIC_INDEX= " << iPeriodic << endl; + output_file << center[0] << "\t" << center[1] << "\t" << center[2] << endl; + output_file << angles[0] << "\t" << angles[1] << "\t" << angles[2] << endl; + output_file << transl[0] << "\t" << transl[1] << "\t" << transl[2] << endl; + + } + + + output_file.close(); +} + +void CPhysicalGeometry::SetCoord_Smoothing (unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config) { + unsigned short iSmooth, nneigh, iMarker; + su2double *Coord_Old, *Coord_Sum, *Coord, *Coord_i, *Coord_j, Position_Plane = 0.0; + unsigned long iEdge, iPoint, jPoint, iVertex; + su2double eps = 1E-6; + bool NearField = false; + + Coord = new su2double [nDim]; + + for (iPoint = 0; iPoint < GetnPoint(); iPoint++) { + su2double *Coord = node[iPoint]->GetCoord(); + node[iPoint]->SetCoord_Old(Coord); + } + + /*--- Jacobi iterations ---*/ + for (iSmooth = 0; iSmooth < val_nSmooth; iSmooth++) { + + for (iPoint = 0; iPoint < nPoint; iPoint++) + node[iPoint]->SetCoord_SumZero(); + + + /*--- Loop over Interior edges ---*/ + for (iEdge = 0; iEdge < nEdge; iEdge++) { + iPoint = edge[iEdge]->GetNode(0); + Coord_i = node[iPoint]->GetCoord(); + + jPoint = edge[iEdge]->GetNode(1); + Coord_j = node[jPoint]->GetCoord(); + + /*--- Accumulate nearest neighbor Coord to Res_sum for each variable ---*/ + node[iPoint]->AddCoord_Sum(Coord_j); + node[jPoint]->AddCoord_Sum(Coord_i); + + } + + /*--- Loop over all mesh points (Update Coords with averaged sum) ---*/ + for (iPoint = 0; iPoint < nPoint; iPoint++) { + nneigh = node[iPoint]->GetnPoint(); + Coord_Sum = node[iPoint]->GetCoord_Sum(); + Coord_Old = node[iPoint]->GetCoord_Old(); + + if (nDim == 2) { + Coord[0] =(Coord_Old[0] + val_smooth_coeff*Coord_Sum[0]) /(1.0 + val_smooth_coeff*su2double(nneigh)); + Coord[1] =(Coord_Old[1] + val_smooth_coeff*Coord_Sum[1]) /(1.0 + val_smooth_coeff*su2double(nneigh)); + if ((NearField) && ((Coord_Old[1] > Position_Plane-eps) && (Coord_Old[1] < Position_Plane+eps))) + Coord[1] = Coord_Old[1]; + } + + if (nDim == 3) { + Coord[0] =(Coord_Old[0] + val_smooth_coeff*Coord_Sum[0]) /(1.0 + val_smooth_coeff*su2double(nneigh)); + Coord[1] =(Coord_Old[1] + val_smooth_coeff*Coord_Sum[1]) /(1.0 + val_smooth_coeff*su2double(nneigh)); + Coord[2] =(Coord_Old[2] + val_smooth_coeff*Coord_Sum[2]) /(1.0 + val_smooth_coeff*su2double(nneigh)); + if ((NearField) && ((Coord_Old[2] > Position_Plane-eps) && (Coord_Old[2] < Position_Plane+eps))) + Coord[2] = Coord_Old[2]; + } + + node[iPoint]->SetCoord(Coord); + } + + /*--- Copy boundary values ---*/ + for (iMarker = 0; iMarker < nMarker; iMarker++) + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + Coord_Old = node[iPoint]->GetCoord_Old(); + node[iPoint]->SetCoord(Coord_Old); + } + } + + delete[] Coord; +} + +bool CPhysicalGeometry::FindFace(unsigned long first_elem, unsigned long second_elem, unsigned short &face_first_elem, + unsigned short &face_second_elem) { + + /*--- Find repeated nodes between two elements to identify the common face ---*/ + unsigned long iPoint = 0, jPoint = 0; + unsigned short face_node, iFace, iNode, jNode, nNodesFace; + vector CommonPoints, PointFaceFirst, PointFaceSecond; + vector::iterator IterPoint; + pair::iterator, vector ::iterator> mypair; + bool face_first_found = false, face_second_found =false; + + if (first_elem == second_elem) return false; + + for (iNode = 0; iNode < elem[first_elem]->GetnNodes(); iNode++) { + iPoint = elem[first_elem]->GetNode(iNode); + for (jNode = 0; jNode < elem[second_elem]->GetnNodes(); jNode++) { + jPoint = elem[second_elem]->GetNode(jNode); + if (iPoint == jPoint) { + CommonPoints.push_back(iPoint); + break; + } + } + } + + /*--- Sort point in face and check that the list is unique ---*/ + sort( CommonPoints.begin(), CommonPoints.end()); + IterPoint = unique( CommonPoints.begin(), CommonPoints.end()); + CommonPoints.resize( distance(CommonPoints.begin(), IterPoint) ); + + /*--- In 2D, the two elements must share two points that make up + an edge, as all "faces" are edges in 2D. In 3D, we need to find + exactly 3 (tri) or 4 (quad) common points. Return immediately to + avoid a memory issue due to vectors of different lengths below. ---*/ + + if ((nDim == 2) && (CommonPoints.size() != 2)) return false; + if ((nDim == 3) && ((CommonPoints.size() != 3) && + (CommonPoints.size() != 4))) return false; + + /*--- Search the sequence in the first element ---*/ + for (iFace = 0; iFace < elem[first_elem]->GetnFaces(); iFace++) { + nNodesFace = elem[first_elem]->GetnNodesFace(iFace); + + if (nNodesFace == CommonPoints.size()) { + for (iNode = 0; iNode < nNodesFace; iNode++) { + face_node = elem[first_elem]->GetFaces(iFace, iNode); + PointFaceFirst.push_back(elem[first_elem]->GetNode(face_node)); + } + + /*--- Sort face_poin to perform comparison ---*/ + sort( PointFaceFirst.begin(), PointFaceFirst.end()); + + /*--- List comparison ---*/ + mypair = mismatch (PointFaceFirst.begin(), PointFaceFirst.end(), CommonPoints.begin()); + if (mypair.first == PointFaceFirst.end()) { + face_first_elem = iFace; + face_first_found = true; + break; + } + + PointFaceFirst.erase (PointFaceFirst.begin(), PointFaceFirst.end()); + } + } + + /*--- Search the secuence in the second element ---*/ + for (iFace = 0; iFace < elem[second_elem]->GetnFaces(); iFace++) { + nNodesFace = elem[second_elem]->GetnNodesFace(iFace); + + if (nNodesFace == CommonPoints.size()) { + for (iNode = 0; iNode < nNodesFace; iNode++) { + face_node = elem[second_elem]->GetFaces(iFace, iNode); + PointFaceSecond.push_back(elem[second_elem]->GetNode(face_node)); + } + + /*--- Sort face_poin to perform comparison ---*/ + sort( PointFaceSecond.begin(), PointFaceSecond.end()); + + /*--- List comparison ---*/ + mypair = mismatch (PointFaceSecond.begin(), PointFaceSecond.end(), CommonPoints.begin()); + if (mypair.first == PointFaceSecond.end()) { + face_second_elem = iFace; + face_second_found = true; + break; + } + + PointFaceSecond.erase (PointFaceSecond.begin(), PointFaceSecond.end()); + } + } + + if (face_first_found && face_second_found) return true; + else return false; + +} + +void CPhysicalGeometry::SetTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file) { + + unsigned long iElem, iPoint; + unsigned short iDim; + ofstream Tecplot_File; + + /*--- Open the tecplot file and write the header ---*/ + + if (new_file) { + Tecplot_File.open(mesh_filename, ios::out); + Tecplot_File << "TITLE= \"Visualization of the volumetric grid\"" << endl; + if (nDim == 2) Tecplot_File << "VARIABLES = \"x\",\"y\" " << endl; + if (nDim == 3) Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\" " << endl; + } + else Tecplot_File.open(mesh_filename, ios::out | ios::app); + + Tecplot_File << "ZONE T= "; + if (new_file) Tecplot_File << "\"Original grid\", C=BLACK, "; + else Tecplot_File << "\"Deformed grid\", C=RED, "; + Tecplot_File << "NODES= "<< nPoint <<", ELEMENTS= "<< nElem <<", DATAPACKING= POINT"; + if (nDim == 2) Tecplot_File << ", ZONETYPE= FEQUADRILATERAL"<< endl; + if (nDim == 3) Tecplot_File << ", ZONETYPE= FEBRICK"<< endl; + + /*--- Adding coordinates ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + for (iDim = 0; iDim < nDim; iDim++) + Tecplot_File << scientific << node[iPoint]->GetCoord(iDim) << "\t"; + Tecplot_File << "\n"; + } + + /*--- Adding conectivity ---*/ + + for (iElem = 0; iElem < nElem; iElem++) { + if (elem[iElem]->GetVTK_Type() == TRIANGLE) { + Tecplot_File << + elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< + elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(2)+1 << endl; + } + if (elem[iElem]->GetVTK_Type() == QUADRILATERAL) { + Tecplot_File << + elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< + elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 << endl; + } + if (elem[iElem]->GetVTK_Type() == TETRAHEDRON) { + Tecplot_File << + elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< + elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(2)+1 <<" "<< + elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<< + elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(3)+1 << endl; + } + if (elem[iElem]->GetVTK_Type() == HEXAHEDRON) { + Tecplot_File << + elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< + elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<< + elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(5)+1 <<" "<< + elem[iElem]->GetNode(6)+1 <<" "<< elem[iElem]->GetNode(7)+1 << endl; + } + if (elem[iElem]->GetVTK_Type() == PYRAMID) { + Tecplot_File << + elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< + elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<< + elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(4)+1 <<" "<< + elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(4)+1 << endl; + } + if (elem[iElem]->GetVTK_Type() == PRISM) { + Tecplot_File << + elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< + elem[iElem]->GetNode(1)+1 <<" "<< elem[iElem]->GetNode(2)+1 <<" "<< + elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(4)+1 <<" "<< + elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(5)+1 << endl; + } + } + + Tecplot_File.close(); +} + +void CPhysicalGeometry::SetBoundTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file, CConfig *config) { + + ofstream Tecplot_File; + unsigned long iPoint, Total_nElem_Bound, iElem, *PointSurface = NULL, nPointSurface = 0; + unsigned short Coord_i, iMarker; + + /*--- It is important to do a renumbering to don't add points + that do not belong to the surfaces ---*/ + + PointSurface = new unsigned long[nPoint]; + for (iPoint = 0; iPoint < nPoint; iPoint++) + if (node[iPoint]->GetBoundary()) { + PointSurface[iPoint] = nPointSurface; + nPointSurface++; + } + + /*--- Compute the total number of elements ---*/ + + Total_nElem_Bound = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_Plotting(iMarker) == YES) { + Total_nElem_Bound += nElem_Bound[iMarker]; + } + } + + /*--- Open the tecplot file and write the header ---*/ + + if (new_file) { + Tecplot_File.open(mesh_filename, ios::out); + Tecplot_File << "TITLE= \"Visualization of the surface grid\"" << endl; + if (nDim == 2) Tecplot_File << "VARIABLES = \"x\",\"y\" " << endl; + if (nDim == 3) Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\" " << endl; + } + else Tecplot_File.open(mesh_filename, ios::out | ios::app); + + if (Total_nElem_Bound != 0) { + + /*--- Write the header of the file ---*/ + + Tecplot_File << "ZONE T= "; + if (new_file) Tecplot_File << "\"Original grid\", C=BLACK, "; + else Tecplot_File << "\"Deformed grid\", C=RED, "; + Tecplot_File << "NODES= "<< nPointSurface <<", ELEMENTS= "<< Total_nElem_Bound <<", DATAPACKING= POINT"; + if (nDim == 2) Tecplot_File << ", ZONETYPE= FELINESEG"<< endl; + if (nDim == 3) Tecplot_File << ", ZONETYPE= FEQUADRILATERAL"<< endl; + + /*--- Only write the coordiantes of the points that are on the surfaces ---*/ + + if (nDim == 3) { + for (iPoint = 0; iPoint < nPoint; iPoint++) + if (node[iPoint]->GetBoundary()) { + for (Coord_i = 0; Coord_i < nDim-1; Coord_i++) + Tecplot_File << node[iPoint]->GetCoord(Coord_i) << " "; + Tecplot_File << node[iPoint]->GetCoord(nDim-1) << "\n"; + } + } + else { + for (iPoint = 0; iPoint < nPoint; iPoint++) + if (node[iPoint]->GetBoundary()) { + for (Coord_i = 0; Coord_i < nDim; Coord_i++) + Tecplot_File << node[iPoint]->GetCoord(Coord_i) << " "; + Tecplot_File << "\n"; + } + } + + /*--- Write the cells using the new numbering ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_Plotting(iMarker) == YES) + for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) { + if (nDim == 2) { + Tecplot_File << PointSurface[bound[iMarker][iElem]->GetNode(0)]+1 << " " + << PointSurface[bound[iMarker][iElem]->GetNode(1)]+1 << endl; + } + if (nDim == 3) { + if (bound[iMarker][iElem]->GetnNodes() == 3) { + Tecplot_File << PointSurface[bound[iMarker][iElem]->GetNode(0)]+1 << " " + << PointSurface[bound[iMarker][iElem]->GetNode(1)]+1 << " " + << PointSurface[bound[iMarker][iElem]->GetNode(2)]+1 << " " + << PointSurface[bound[iMarker][iElem]->GetNode(2)]+1 << endl; + } + if (bound[iMarker][iElem]->GetnNodes() == 4) { + Tecplot_File << PointSurface[bound[iMarker][iElem]->GetNode(0)]+1 << " " + << PointSurface[bound[iMarker][iElem]->GetNode(1)]+1 << " " + << PointSurface[bound[iMarker][iElem]->GetNode(2)]+1 << " " + << PointSurface[bound[iMarker][iElem]->GetNode(3)]+1 << endl; + } + } + } + } + else { + + /*--- No elements in the surface ---*/ + + if (nDim == 2) { + Tecplot_File << "ZONE NODES= 1, ELEMENTS= 1, DATAPACKING=POINT, ZONETYPE=FELINESEG"<< endl; + Tecplot_File << "0.0 0.0"<< endl; + Tecplot_File << "1 1"<< endl; + } + if (nDim == 3) { + Tecplot_File << "ZONE NODES= 1, ELEMENTS= 1, DATAPACKING=POINT, ZONETYPE=FEQUADRILATERAL"<< endl; + Tecplot_File << "0.0 0.0 0.0"<< endl; + Tecplot_File << "1 1 1 1"<< endl; + } + } + + /*--- Dealocate memory and close the file ---*/ + + delete[] PointSurface; + Tecplot_File.close(); + +} + +void CPhysicalGeometry::SetBoundSTL(char mesh_filename[MAX_STRING_SIZE], bool new_file, CConfig *config) { + + ofstream STL_File; + unsigned long this_node, iNode, nNode, iElem; + unsigned short iDim, iMarker; + su2double p[3] = {0.0,0.0,0.0}, u[3] = {0.0,0.0,0.0}, v[3] = {0.0,0.0,0.0}, n[3] = {0.0,0.0,0.0}, a; + + /*--- STL format: + solid NAME + ... + facet normal 0.00 0.00 1.00 + outer loop + vertex 2.00 2.00 0.00 + vertex -1.00 1.00 0.00 + vertex 0.00 -1.00 0.00 + endloop + endfacet + ... + end solid + ---*/ + + /*--- Open the STL file ---*/ + + if (new_file) STL_File.open(mesh_filename, ios::out); + else STL_File.open(mesh_filename, ios::out | ios::app); + + /*--- Write the header of the file ---*/ + + STL_File << "solid surface_mesh" << endl; + + /*--- Write facets of surface markers ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_Plotting(iMarker) == YES) + for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) { + + /*--- number of nodes for this elemnt ---*/ + + nNode = bound[iMarker][iElem]->GetnNodes(); + + /*--- Calculate Normal Vector ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + p[0] = node[bound[iMarker][iElem]->GetNode(0)] ->GetCoord(iDim); + p[1] = node[bound[iMarker][iElem]->GetNode(1)] ->GetCoord(iDim); + p[2] = node[bound[iMarker][iElem]->GetNode(nNode-1)]->GetCoord(iDim); + u[iDim] = p[1]-p[0]; + v[iDim] = p[2]-p[0]; + } + + n[0] = u[1]*v[2]-u[2]*v[1]; + n[1] = u[2]*v[0]-u[0]*v[2]; + n[2] = u[0]*v[1]-u[1]*v[0]; + a = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]); + + /*--- Print normal vector ---*/ + + STL_File << " facet normal "; + for (iDim = 0; iDim < nDim; iDim++) { + STL_File << n[iDim]/a << " "; + } + STL_File << endl; + + /*--- STL Facet Loop --*/ + + STL_File << " outer loop" << endl; + + /*--- Print Nodes for Facet ---*/ + + for (iNode = 0; iNode < nNode; iNode++) { + this_node = bound[iMarker][iElem]->GetNode(iNode); + STL_File << " vertex "; + for (iDim = 0; iDim < nDim; iDim++) + STL_File << node[this_node]->GetCoord(iDim) << " "; + if (nDim==2) + STL_File << 0.0 << " "; + STL_File << endl; + } + STL_File << " endloop" << endl; + STL_File << " endfacet" << endl; + } + + /*--- Done with Surface Mesh ---*/ + + STL_File << "endsolid" << endl; + + /*--- Close the file ---*/ + + STL_File.close(); + +} + +void CPhysicalGeometry::SetColorGrid(CConfig *config) { + +#ifdef HAVE_MPI +#ifdef HAVE_METIS + + unsigned long iPoint, iElem, iElem_Triangle, iElem_Tetrahedron, nElem_Triangle, + nElem_Tetrahedron; + idx_t ne = 0, nn, *elmnts = NULL, *epart = NULL, *npart = NULL, nparts, edgecut, *eptr; + int rank, size; + + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + + if (size != SINGLE_ZONE) + cout << endl <<"---------------------------- Grid partitioning --------------------------" << endl; + + unsigned short nDomain = size; + + nElem_Triangle = 0; + nElem_Tetrahedron = 0; + for (iElem = 0; iElem < GetnElem(); iElem++) { + if (elem[iElem]->GetVTK_Type() == TRIANGLE) nElem_Triangle = nElem_Triangle + 1; + if (elem[iElem]->GetVTK_Type() == QUADRILATERAL) nElem_Triangle = nElem_Triangle + 2; + if (elem[iElem]->GetVTK_Type() == TETRAHEDRON) nElem_Tetrahedron = nElem_Tetrahedron + 1; + if (elem[iElem]->GetVTK_Type() == HEXAHEDRON) nElem_Tetrahedron = nElem_Tetrahedron + 5; + if (elem[iElem]->GetVTK_Type() == PYRAMID) nElem_Tetrahedron = nElem_Tetrahedron + 2; + if (elem[iElem]->GetVTK_Type() == PRISM) nElem_Tetrahedron = nElem_Tetrahedron + 3; + } + + if (GetnDim() == 2) { + ne = nElem_Triangle; + elmnts = new idx_t [ne*3]; + } + if (GetnDim() == 3) { + ne = nElem_Tetrahedron; + elmnts = new idx_t [ne*4]; + } + + nn = nPoint; + nparts = nDomain; + epart = new idx_t [ne]; + npart = new idx_t [nn]; + eptr = new idx_t[ne+1]; + + /*--- Initialize the color vector ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint++) + node[iPoint]->SetColor(0); + + if (nparts > 1) { + + iElem_Triangle = 0; iElem_Tetrahedron = 0; + for (iElem = 0; iElem < GetnElem(); iElem++) { + if (elem[iElem]->GetVTK_Type() == TRIANGLE) { + elmnts[3*iElem_Triangle+0]= elem[iElem]->GetNode(0); + elmnts[3*iElem_Triangle+1]= elem[iElem]->GetNode(1); + elmnts[3*iElem_Triangle+2]= elem[iElem]->GetNode(2); + eptr[iElem_Triangle] = 3*iElem_Triangle; + iElem_Triangle++; + } + if (elem[iElem]->GetVTK_Type() == QUADRILATERAL) { + elmnts[3*iElem_Triangle+0]= elem[iElem]->GetNode(0); + elmnts[3*iElem_Triangle+1]= elem[iElem]->GetNode(1); + elmnts[3*iElem_Triangle+2]= elem[iElem]->GetNode(2); + eptr[iElem_Triangle] = 3*iElem_Triangle; + iElem_Triangle++; + elmnts[3*iElem_Triangle+0]= elem[iElem]->GetNode(0); + elmnts[3*iElem_Triangle+1]= elem[iElem]->GetNode(2); + elmnts[3*iElem_Triangle+2]= elem[iElem]->GetNode(3); + eptr[iElem_Triangle] = 3*iElem_Triangle; + iElem_Triangle++; + } + if (elem[iElem]->GetVTK_Type() == TETRAHEDRON) { + elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); + elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(1); + elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(2); + elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(3); + eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; + iElem_Tetrahedron++; + } + if (elem[iElem]->GetVTK_Type() == HEXAHEDRON) { + elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); + elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(1); + elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(2); + elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(5); + eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; + iElem_Tetrahedron++; + elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); + elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(2); + elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(3); + elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(7); + eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; + iElem_Tetrahedron++; + elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); + elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(5); + elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(7); + elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(4); + eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; + iElem_Tetrahedron++; + elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(2); + elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(7); + elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(5); + elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(6); + eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; + iElem_Tetrahedron++; + elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); + elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(2); + elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(7); + elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(5); + eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; + iElem_Tetrahedron++; + } + if (elem[iElem]->GetVTK_Type() == PYRAMID) { + elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); + elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(1); + elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(2); + elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(4); + eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; + iElem_Tetrahedron++; + elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); + elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(2); + elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(3); + elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(4); + eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; + iElem_Tetrahedron++; + } + if (elem[iElem]->GetVTK_Type() == PRISM) { + elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); + elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(1); + elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(4); + elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(2); + eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; + iElem_Tetrahedron++; + elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0); + elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(2); + elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(3); + elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(4); + eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; + iElem_Tetrahedron++; + elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(3); + elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(4); + elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(5); + elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(2); + eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron; + iElem_Tetrahedron++; + } + } + + /*--- Add final value to element pointer array ---*/ + + if (GetnDim() == 2) eptr[ne] = 3*ne; + else eptr[ne] = 4*ne; + + METIS_PartMeshNodal(&ne, &nn, eptr, elmnts, NULL, NULL, &nparts, NULL, NULL, &edgecut, epart, npart); + + cout << "Finished partitioning using METIS. (" << edgecut << " edge cuts)." << endl; + + for (iPoint = 0; iPoint < nPoint; iPoint++) + node[iPoint]->SetColor(npart[iPoint]); + } + + delete[] epart; + delete[] npart; + delete[] elmnts; + delete[] eptr; + +#endif + +#endif + +} + +void CPhysicalGeometry::SetColorGrid_Parallel(CConfig *config) { + + /*--- Initialize the color vector ---*/ + + for (unsigned long iPoint = 0; iPoint < local_node; iPoint++) + node[iPoint]->SetColor(0); + + /*--- This routine should only ever be called if we have parallel support + with MPI and have the ParMETIS library compiled and linked. ---*/ + +#ifdef HAVE_MPI +#ifdef HAVE_PARMETIS + + unsigned long iPoint; + int rank, size; + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + + /*--- Only call ParMETIS if we have more than one rank to avoid errors ---*/ + + if (size > SINGLE_NODE) { + + /*--- Create some structures that ParMETIS needs for partitioning. ---*/ + + idx_t numflag, nparts, edgecut, wgtflag, ncon; + idx_t *vtxdist = new idx_t[size+1]; + idx_t *xadj_l = new idx_t[xadj_size]; + idx_t *adjacency_l = new idx_t[adjacency_size]; + idx_t *elmwgt = new idx_t[local_node]; + idx_t *part = new idx_t[local_node]; + + real_t ubvec; + real_t *tpwgts = new real_t[size]; + + /*--- Some recommended defaults for the various ParMETIS options. ---*/ + + wgtflag = 0; + numflag = 0; + ncon = 1; + ubvec = 1.05; + nparts = (idx_t)size; + idx_t options[METIS_NOPTIONS]; + METIS_SetDefaultOptions(options); + options[1] = 0; + + /*--- Fill the necessary ParMETIS data arrays. Note that xadj_size and + adjacency_size are class data members that have been defined and set + earlier in the partitioning process. ---*/ + + for (int i = 0; i < size; i++) { + tpwgts[i] = 1.0/((real_t)size); + } + + vtxdist[0] = 0; + for (int i = 0; i < size; i++) { + vtxdist[i+1] = (idx_t)ending_node[i]; + } + + for (unsigned long i = 0; i < xadj_size; i++) { + xadj_l[i] = (idx_t)xadj[i]; + } + + for (unsigned long i = 0; i < adjacency_size; i++) { + adjacency_l[i] = (idx_t)adjacency[i]; + } + + /*--- Calling ParMETIS ---*/ + if (rank == MASTER_NODE) cout << "Calling ParMETIS..." << endl; + ParMETIS_V3_PartKway(vtxdist,xadj_l, adjacency_l, NULL, NULL, &wgtflag, + &numflag, &ncon, &nparts, tpwgts, &ubvec, options, + &edgecut, part, &comm); + if (rank == MASTER_NODE) { + cout << "Finished partitioning using ParMETIS ("; + cout << edgecut << " edge cuts)." << endl; + } + + /*--- Store the results of the partitioning (note that this is local + since each processor is calling ParMETIS in parallel and storing the + results for its initial piece of the grid. ---*/ + + for (iPoint = 0; iPoint < local_node; iPoint++) { + node[iPoint]->SetColor(part[iPoint]); + } + + /*--- Free all memory needed for the ParMETIS structures ---*/ + + delete [] vtxdist; + delete [] xadj_l; + delete [] adjacency_l; + delete [] elmwgt; + delete [] part; + delete [] tpwgts; + + } + + /*--- Delete the memory from the geometry class that carried the + adjacency structure. ---*/ + + delete [] xadj; + delete [] adjacency; + +#endif +#endif + +} + +void CPhysicalGeometry::GetQualityStatistics(su2double *statistics) { + unsigned long jPoint, Point_2, Point_3, iElem; + su2double *Coord_j, *Coord_2, *Coord_3; + unsigned short iDim; + + statistics[0] = 1e06; + statistics[1] = 0; + + /*--- Loop interior edges ---*/ + for (iElem = 0; iElem < this->GetnElem(); iElem++) { + + if ((this->GetnDim() == 2) && (elem[iElem]->GetVTK_Type() == TRIANGLE)) { + + jPoint = elem[iElem]->GetNode(0); Coord_j = node[jPoint]->GetCoord(); + Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); + Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); + + /*--- Compute sides of the triangle ---*/ + su2double a = 0, b = 0, c = 0; + for (iDim = 0; iDim < nDim; iDim++) { + a += (Coord_2[iDim]-Coord_j[iDim])*(Coord_2[iDim]-Coord_j[iDim]); + b += (Coord_3[iDim]-Coord_j[iDim])*(Coord_3[iDim]-Coord_j[iDim]); + c += (Coord_3[iDim]-Coord_2[iDim])*(Coord_3[iDim]-Coord_2[iDim]); + } + a = sqrt(a); b = sqrt(b); c = sqrt(c); + + /*--- Compute semiperimeter (s) and area ---*/ + su2double s = 0.5*(a + b + c); + su2double Area = sqrt(s*(s-a)*(s-b)*(s-c)); + + /*--- Compute radius of the circumcircle (R) and of the incircle (r) ---*/ + su2double R = (a*b*c) / (4.0*Area); + su2double r = Area / s; + su2double roR = r / R; + + /*--- Update statistics ---*/ + if (roR < statistics[0]) + statistics[0] = roR; + statistics[1] += roR; + + } + } + statistics[1] /= this->GetnElem(); + +} + +void CPhysicalGeometry::SetRotationalVelocity(CConfig *config, unsigned short val_iZone) { + + unsigned long iPoint; + su2double RotVel[3], Distance[3], *Coord, Center[3], Omega[3], L_Ref; + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Center of rotation & angular velocity vector from config ---*/ + + Center[0] = config->GetMotion_Origin_X(val_iZone); + Center[1] = config->GetMotion_Origin_Y(val_iZone); + Center[2] = config->GetMotion_Origin_Z(val_iZone); + Omega[0] = config->GetRotation_Rate_X(val_iZone)/config->GetOmega_Ref(); + Omega[1] = config->GetRotation_Rate_Y(val_iZone)/config->GetOmega_Ref(); + Omega[2] = config->GetRotation_Rate_Z(val_iZone)/config->GetOmega_Ref(); + L_Ref = config->GetLength_Ref(); + + /*--- Print some information to the console ---*/ + + if (rank == MASTER_NODE) { + cout << " Rotational origin (x, y, z): ( " << Center[0] << ", " << Center[1]; + cout << ", " << Center[2] << " )" << endl; + cout << " Angular velocity about x, y, z axes: ( " << Omega[0] << ", "; + cout << Omega[1] << ", " << Omega[2] << " ) rad/s" << endl; + } + + /*--- Loop over all nodes and set the rotational velocity ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + + /*--- Get the coordinates of the current node ---*/ + + Coord = node[iPoint]->GetCoord(); + + /*--- Calculate the non-dim. distance from the rotation center ---*/ + + Distance[0] = (Coord[0]-Center[0])/L_Ref; + Distance[1] = (Coord[1]-Center[1])/L_Ref; + Distance[2] = (Coord[2]-Center[2])/L_Ref; + + /*--- Calculate the angular velocity as omega X r ---*/ + + RotVel[0] = Omega[1]*(Distance[2]) - Omega[2]*(Distance[1]); + RotVel[1] = Omega[2]*(Distance[0]) - Omega[0]*(Distance[2]); + RotVel[2] = Omega[0]*(Distance[1]) - Omega[1]*(Distance[0]); + + /*--- Store the grid velocity at this node ---*/ + + node[iPoint]->SetGridVel(RotVel); + + } + +} + +void CPhysicalGeometry::SetTranslationalVelocity(CConfig *config) { + + unsigned short iDim; + unsigned long iPoint; + su2double xDot[3] = {0.0,0.0,0.0}; + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Get the translational velocity vector from config ---*/ + + xDot[0] = config->GetTranslation_Rate_X(ZONE_0)/config->GetVelocity_Ref(); + xDot[1] = config->GetTranslation_Rate_Y(ZONE_0)/config->GetVelocity_Ref(); + xDot[2] = config->GetTranslation_Rate_Z(ZONE_0)/config->GetVelocity_Ref(); + + /*--- Print some information to the console ---*/ + + if (rank == MASTER_NODE) { + cout << " Non-dim. translational velocity: (" << xDot[0] << ", " << xDot[1]; + cout << ", " << xDot[2] << ")." << endl; + } + + /*--- Loop over all nodes and set the translational velocity ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + + /*--- Store the grid velocity at this node ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + node[iPoint]->SetGridVel(iDim,xDot[iDim]); + } + + } + +} + +void CPhysicalGeometry::SetGridVelocity(CConfig *config, unsigned long iter) { + + /*--- Local variables ---*/ + + su2double *Coord_nP1 = NULL, *Coord_n = NULL, *Coord_nM1 = NULL; + su2double TimeStep, GridVel = 0.0; + unsigned long iPoint; + unsigned short iDim; + + /*--- Compute the velocity of each node in the volume mesh ---*/ + + for (iPoint = 0; iPoint < GetnPoint(); iPoint++) { + + /*--- Coordinates of the current point at n+1, n, & n-1 time levels ---*/ + + Coord_nM1 = node[iPoint]->GetCoord_n1(); + Coord_n = node[iPoint]->GetCoord_n(); + Coord_nP1 = node[iPoint]->GetCoord(); + + /*--- Unsteady time step ---*/ + + TimeStep = config->GetDelta_UnstTimeND(); + + /*--- Compute mesh velocity with 1st or 2nd-order approximation ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + GridVel = ( Coord_nP1[iDim] - Coord_n[iDim] ) / TimeStep; + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + GridVel = ( 3.0*Coord_nP1[iDim] - 4.0*Coord_n[iDim] + + 1.0*Coord_nM1[iDim] ) / (2.0*TimeStep); + + /*--- Store grid velocity for this point ---*/ + + node[iPoint]->SetGridVel(iDim, GridVel); + } + } + +} + +void CPhysicalGeometry::Set_MPI_Coord(CConfig *config) { + + unsigned short iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, *Buffer_Receive_Coord = NULL, *Buffer_Send_Coord = NULL, *Coord = NULL, *newCoord = NULL; + + newCoord = new su2double[nDim]; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = nVertex[MarkerS]; nVertexR = nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nDim; nBufferR_Vector = nVertexR*nDim; + + /*--- Allocate Receive and send buffers ---*/ + + Buffer_Receive_Coord = new su2double [nBufferR_Vector]; + Buffer_Send_Coord = new su2double[nBufferS_Vector]; + + /*--- Copy the coordinates that should be sended ---*/ + + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = vertex[MarkerS][iVertex]->GetNode(); + Coord = node[iPoint]->GetCoord(); + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[iDim*nVertexS+iVertex] = Coord[iDim]; + } + +#ifdef HAVE_MPI + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Coord, nBufferS_Vector, MPI_DOUBLE, send_to,0, + Buffer_Receive_Coord, nBufferR_Vector, MPI_DOUBLE, receive_from,0, MPI_COMM_WORLD, &status); +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Receive_Coord[iDim*nVertexR+iVertex] = Buffer_Send_Coord[iDim*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + + delete [] Buffer_Send_Coord; + + /*--- Do the coordinate transformation ---*/ + + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + + iPoint = vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy coordinates before performing transformation. ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + newCoord[iDim] = Buffer_Receive_Coord[iDim*nVertexR+iVertex]; + + /*--- Rotate the coordinates. ---*/ + + if (nDim == 2) { + newCoord[0] = (rotMatrix[0][0]*Buffer_Receive_Coord[0*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_Coord[1*nVertexR+iVertex]); + newCoord[1] = (rotMatrix[1][0]*Buffer_Receive_Coord[0*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_Coord[1*nVertexR+iVertex]); + } + else { + newCoord[0] = (rotMatrix[0][0]*Buffer_Receive_Coord[0*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_Coord[1*nVertexR+iVertex] + + rotMatrix[0][2]*Buffer_Receive_Coord[2*nVertexR+iVertex]); + newCoord[1] = (rotMatrix[1][0]*Buffer_Receive_Coord[0*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_Coord[1*nVertexR+iVertex] + + rotMatrix[1][2]*Buffer_Receive_Coord[2*nVertexR+iVertex]); + newCoord[2] = (rotMatrix[2][0]*Buffer_Receive_Coord[0*nVertexR+iVertex] + + rotMatrix[2][1]*Buffer_Receive_Coord[1*nVertexR+iVertex] + + rotMatrix[2][2]*Buffer_Receive_Coord[2*nVertexR+iVertex]); + } + + /*--- Copy transformed coordinates back into buffer. ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + node[iPoint]->SetCoord(iDim, newCoord[iDim]); + + } + + /*--- Deallocate receive buffer. ---*/ + + delete [] Buffer_Receive_Coord; + + } + + } + + delete [] newCoord; + +} + +void CPhysicalGeometry::Set_MPI_GridVel(CConfig *config) { + + unsigned short iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, *Buffer_Receive_GridVel = NULL, *Buffer_Send_GridVel = NULL, *GridVel = NULL, *newGridVel = NULL; + + newGridVel = new su2double[nDim]; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = nVertex[MarkerS]; nVertexR = nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nDim; nBufferR_Vector = nVertexR*nDim; + + /*--- Allocate Receive and send buffers ---*/ + + Buffer_Receive_GridVel = new su2double [nBufferR_Vector]; + Buffer_Send_GridVel = new su2double[nBufferS_Vector]; + + /*--- Copy the grid velocity that should be sended ---*/ + + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = vertex[MarkerS][iVertex]->GetNode(); + GridVel = node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_GridVel[iDim*nVertexS+iVertex] = GridVel[iDim]; + } + +#ifdef HAVE_MPI + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_GridVel, nBufferS_Vector, MPI_DOUBLE, send_to,0, + Buffer_Receive_GridVel, nBufferR_Vector, MPI_DOUBLE, receive_from,0, MPI_COMM_WORLD, &status); +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Receive_GridVel[iDim*nVertexR+iVertex] = Buffer_Send_GridVel[iDim*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + + delete [] Buffer_Send_GridVel; + + /*--- Do the coordinate transformation ---*/ + + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + + iPoint = vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy grid velocity before performing transformation. ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + newGridVel[iDim] = Buffer_Receive_GridVel[iDim*nVertexR+iVertex]; + + if (nDim == 2) { + newGridVel[0] = (rotMatrix[0][0]*Buffer_Receive_GridVel[0*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_GridVel[1*nVertexR+iVertex]); + newGridVel[1] = (rotMatrix[1][0]*Buffer_Receive_GridVel[0*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_GridVel[1*nVertexR+iVertex]); + } + else { + newGridVel[0] = (rotMatrix[0][0]*Buffer_Receive_GridVel[0*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_GridVel[1*nVertexR+iVertex] + + rotMatrix[0][2]*Buffer_Receive_GridVel[2*nVertexR+iVertex]); + newGridVel[1] = (rotMatrix[1][0]*Buffer_Receive_GridVel[0*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_GridVel[1*nVertexR+iVertex] + + rotMatrix[1][2]*Buffer_Receive_GridVel[2*nVertexR+iVertex]); + newGridVel[2] = (rotMatrix[2][0]*Buffer_Receive_GridVel[0*nVertexR+iVertex] + + rotMatrix[2][1]*Buffer_Receive_GridVel[1*nVertexR+iVertex] + + rotMatrix[2][2]*Buffer_Receive_GridVel[2*nVertexR+iVertex]); + } + + /*--- Copy transformed grid velocity back into buffer. ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + node[iPoint]->SetGridVel(iDim, newGridVel[iDim]); + + } + + /*--- Deallocate receive buffer ---*/ + + delete [] Buffer_Receive_GridVel; + + } + + } + + delete [] newGridVel; + +} + +void CPhysicalGeometry::SetPeriodicBoundary(CConfig *config) { + + unsigned short iMarker, jMarker, kMarker = 0, iPeriodic, iDim, nPeriodic = 0, VTK_Type; + unsigned long iNode, iIndex, iVertex, iPoint, iElem, kElem; + unsigned long jElem, kPoint = 0, jVertex = 0, jPoint = 0, pPoint = 0, nPointPeriodic, newNodes[4] = {0,0,0,0}; + vector::iterator IterElem, IterPoint[MAX_NUMBER_PERIODIC][2]; + su2double *center, *angles, rotMatrix[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}, + translation[3], *trans, theta, phi, psi, cosTheta, sinTheta, cosPhi, sinPhi, cosPsi, sinPsi, + dx, dy, dz, rotCoord[3], epsilon = 1e-10, mindist = 1e6, *Coord_i, *Coord_j, dist = 0.0; + bool isBadMatch = false; + + /*--- Check this dimensionalization ---*/ + + vector OldBoundaryElems[100]; + vector::iterator IterNewElem[100]; + + /*--- We only create the mirror structure for the second boundary ---*/ + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) { + /*--- Evaluate the number of periodic boundary conditions ---*/ + nPeriodic++; + } + } + bool *CreateMirror = new bool[nPeriodic+1]; + CreateMirror[0] = false; + for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { + if (iPeriodic <= nPeriodic/2) CreateMirror[iPeriodic] = false; + else CreateMirror[iPeriodic] = true; + } + + /*--- Send an initial message to the console. ---*/ + cout << "Setting the periodic boundary conditions." << endl; + + /*--- Loop through each marker to find any periodic boundaries. ---*/ + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) { + + /*--- Get marker index of the periodic donor boundary. ---*/ + jMarker = config->GetMarker_Periodic_Donor(config->GetMarker_All_TagBound(iMarker)); + + /*--- Write some info to the console. ---*/ + cout << "Checking " << config->GetMarker_All_TagBound(iMarker); + cout << " boundary against periodic donor, " << config->GetMarker_All_TagBound(jMarker) << ". "; + + /*--- Retrieve the supplied periodic information. ---*/ + center = config->GetPeriodicRotCenter(config->GetMarker_All_TagBound(iMarker)); + angles = config->GetPeriodicRotAngles(config->GetMarker_All_TagBound(iMarker)); + trans = config->GetPeriodicTranslation(config->GetMarker_All_TagBound(iMarker)); + + /*--- Store (center+trans) as it is constant and will be added on. ---*/ + translation[0] = center[0] + trans[0]; + translation[1] = center[1] + trans[1]; + translation[2] = center[2] + trans[2]; + + /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ + theta = angles[0]; + phi = angles[1]; + psi = angles[2]; + + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; + rotMatrix[1][0] = cosPhi*sinPsi; + rotMatrix[2][0] = -sinPhi; + + rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; + rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; + rotMatrix[2][1] = sinTheta*cosPhi; + + rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Loop through all vertices and find/set the periodic point. ---*/ + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + + /*--- Retrieve node information for this boundary point. ---*/ + iPoint = vertex[iMarker][iVertex]->GetNode(); + Coord_i = node[iPoint]->GetCoord(); + + /*--- Get the position vector from rot center to point. ---*/ + dx = Coord_i[0] - center[0]; + dy = Coord_i[1] - center[1]; + if (nDim == 3) { + dz = Coord_i[2] - center[2]; + } else { + dz = 0.0; + } + + /*--- Compute transformed point coordinates. ---*/ + rotCoord[0] = rotMatrix[0][0]*dx + + rotMatrix[0][1]*dy + + rotMatrix[0][2]*dz + translation[0]; + + rotCoord[1] = rotMatrix[1][0]*dx + + rotMatrix[1][1]*dy + + rotMatrix[1][2]*dz + translation[1]; + + rotCoord[2] = rotMatrix[2][0]*dx + + rotMatrix[2][1]*dy + + rotMatrix[2][2]*dz + translation[2]; + + /*--- Perform a search to find the closest donor point. ---*/ + mindist = 1e10; + for (jVertex = 0; jVertex < nVertex[jMarker]; jVertex++) { + + /*--- Retrieve information for this jPoint. ---*/ + jPoint = vertex[jMarker][jVertex]->GetNode(); + Coord_j = node[jPoint]->GetCoord(); + + /*--- Check the distance between the computed periodic + location and this jPoint. ---*/ + dist = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + dist += (Coord_j[iDim]-rotCoord[iDim])*(Coord_j[iDim]-rotCoord[iDim]); + } + dist = sqrt(dist); + + /*--- Store vertex information if this is the closest + point found thus far. ---*/ + if (dist < mindist) { mindist = dist; pPoint = jPoint; } + } + + /*--- Set the periodic point for this iPoint. ---*/ + vertex[iMarker][iVertex]->SetDonorPoint(pPoint, MASTER_NODE); + + /*--- Print warning if the nearest point was not within + the specified tolerance. Computation will continue. ---*/ + if (mindist > epsilon) { + isBadMatch = true; + cout.precision(10); + cout << endl; + cout << " Bad match for point " << iPoint << ".\tNearest"; + cout << " donor distance: " << scientific << mindist << "."; + } + } + + /*--- Print final warning when finding bad matches. ---*/ + if (isBadMatch) { + cout << endl; + cout << "\n !!! Warning !!!" << endl; + cout << "Bad matches found. Computation will continue, but be cautious.\n"; + } + cout << endl; + isBadMatch = false; + + } + + /*--- Create a vector to identify the points that belong to each periodic boundary condition ---*/ + bool *PeriodicBC = new bool [nPoint]; + for (iPoint = 0; iPoint < nPoint; iPoint++) PeriodicBC[iPoint] = false; + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + PeriodicBC[iPoint] = true; + } + + /*--- Determine the new points that must be added to each periodic boundary, + note that only one of the boundaries require the extra data ---*/ + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) { + iPeriodic = config->GetMarker_All_PerBound(iMarker); + + /*--- An integer identify the periodic boundary condition --*/ + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + + /*--- iPoint is the original point on the surface and jPoint is the + equivalent point in the other periodic surface ---*/ + iPoint = vertex[iMarker][iVertex]->GetNode(); + jPoint = vertex[iMarker][iVertex]->GetDonorPoint(); + + /*--- First the case in which it is necessary to create a mirror set of elements ---*/ + if (CreateMirror[iPeriodic]) { + /*--- Now we must determine the neighbor points (including indirect ones) to the periodic points + and store all the information (in this list we do not include the points + that already belong to the periodic boundary), we also add the elements that + share a point with the periodic boundary condition ---*/ + for (iIndex = 0; iIndex < node[jPoint]->GetnElem(); iIndex++) { + iElem = node[jPoint]->GetElem(iIndex); + PeriodicElem[iPeriodic].push_back(iElem); + for (unsigned short iNode = 0; iNode < elem[iElem]->GetnNodes(); iNode ++) { + kPoint = elem[iElem]->GetNode(iNode); + if (!PeriodicBC[kPoint]) PeriodicPoint[iPeriodic][0].push_back(kPoint); + } + } + } + /*--- Second the case where no new element is added, neither points ---*/ + else { + PeriodicPoint[iPeriodic][0].push_back(jPoint); + PeriodicPoint[iPeriodic][1].push_back(iPoint); + } + } + } + } + + /*--- Sort the points that must be sended and delete repeated points ---*/ + for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { + if (CreateMirror[iPeriodic]) { + sort( PeriodicPoint[iPeriodic][0].begin(), PeriodicPoint[iPeriodic][0].end()); + IterPoint[iPeriodic][0] = unique( PeriodicPoint[iPeriodic][0].begin(), PeriodicPoint[iPeriodic][0].end()); + PeriodicPoint[iPeriodic][0].resize( IterPoint[iPeriodic][0] - PeriodicPoint[iPeriodic][0].begin() ); + } + } + + /*--- Create a list of the points that receive the values (only the new points) ---*/ + nPointPeriodic = nPoint; + for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { + if (CreateMirror[iPeriodic]) { + for (iPoint = 0; iPoint < PeriodicPoint[iPeriodic][0].size(); iPoint++) { + PeriodicPoint[iPeriodic][1].push_back(nPointPeriodic); + nPointPeriodic++; + } + } + } + + /*--- Sort the elements that must be replicated in the periodic boundary + and delete the repeated elements ---*/ + for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { + if (CreateMirror[iPeriodic]) { + sort( PeriodicElem[iPeriodic].begin(), PeriodicElem[iPeriodic].end()); + IterElem = unique( PeriodicElem[iPeriodic].begin(), PeriodicElem[iPeriodic].end()); + PeriodicElem[iPeriodic].resize( IterElem - PeriodicElem[iPeriodic].begin() ); + } + } + + /*--- Check all SEND points to see if they also lie on another boundary. ---*/ + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + + /*--- iPoint is a node that lies on the current marker. ---*/ + iPoint = vertex[iMarker][iVertex]->GetNode(); + + /*--- Search through SEND points to check for iPoint. ---*/ + for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { + if (CreateMirror[iPeriodic]) { + + /*--- jPoint is the SEND point. ---*/ + for (iElem = 0; iElem < PeriodicPoint[iPeriodic][0].size(); iElem++) { + jPoint = PeriodicPoint[iPeriodic][0][iElem]; + + /*--- If the two match, then jPoint lies on this boundary. + However, we are concerned with the new points, so we + will store kPoint instead. ---*/ + if (iPoint == jPoint) { +// kPoint = PeriodicPoint[iPeriodic][1][iElem]; + + /*--- We also want the type of boundary element that this point + was within, so that we know what type of element to add + built from the new points. ---*/ + bool isJPoint, isPeriodic; + for (jElem = 0; jElem < nElem_Bound[iMarker]; jElem++) { + isJPoint = false; isPeriodic = false; + for (iNode = 0; iNode < bound[iMarker][jElem]->GetnNodes(); iNode++) { + if (bound[iMarker][jElem]->GetNode(iNode) == jPoint) isJPoint = true; + if (PeriodicBC[bound[iMarker][jElem]->GetNode(iNode)]) isPeriodic = true; + } + + /*--- If both points were found, store this element. ---*/ + if (isJPoint && isPeriodic) { + OldBoundaryElems[iMarker].push_back(jElem); + } + + } + + } + } + } + } + } + } + + /*--- Sort the elements that must be added and remove duplicates. ---*/ + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + sort( OldBoundaryElems[iMarker].begin(), OldBoundaryElems[iMarker].end()); + IterNewElem[iMarker] = unique( OldBoundaryElems[iMarker].begin(), OldBoundaryElems[iMarker].end()); + OldBoundaryElems[iMarker].resize( IterNewElem[iMarker] - OldBoundaryElems[iMarker].begin() ); + } + + /*--- Create the new boundary elements. Points making up these new + elements must either be SEND/RECEIVE or periodic points. ---*/ + nNewElem_Bound = new unsigned long[nMarker]; + newBound = new CPrimalGrid**[nMarker]; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + nNewElem_Bound[iMarker] = OldBoundaryElems[iMarker].size(); + newBound[iMarker] = new CPrimalGrid*[nNewElem_Bound[iMarker]]; + + /*--- Loop through all new elements to be added. ---*/ + for (iElem = 0; iElem < nNewElem_Bound[iMarker]; iElem++) { + jElem = OldBoundaryElems[iMarker][iElem]; + + /*--- Loop through all nodes of this element. ---*/ + for (iNode = 0; iNode < bound[iMarker][jElem]->GetnNodes(); iNode++) { + pPoint = bound[iMarker][jElem]->GetNode(iNode); + + /*--- Check if this node is a send point. If so, the corresponding + receive point will be used in making the new boundary element. ---*/ + for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { + for (kElem = 0; kElem < PeriodicPoint[iPeriodic][0].size(); kElem++) { + if (pPoint == PeriodicPoint[iPeriodic][0][kElem]) newNodes[iNode] = PeriodicPoint[iPeriodic][1][kElem]; + } + } + + /*--- Check if this node is a periodic point. If so, the corresponding + periodic point will be used in making the new boundary element. ---*/ + if (PeriodicBC[pPoint]) { + + /*--- Find the corresponding periodic point. ---*/ + for (jMarker = 0; jMarker < config->GetnMarker_All(); jMarker++) { + if (config->GetMarker_All_KindBC(jMarker) == PERIODIC_BOUNDARY) { + for (iVertex = 0; iVertex < nVertex[jMarker]; iVertex++) { + if (pPoint == vertex[jMarker][iVertex]->GetNode()) {kMarker = jMarker; jVertex = iVertex;} + } + } + } + newNodes[iNode] = vertex[kMarker][jVertex]->GetDonorPoint(); + } + } + + /*--- Now instantiate the new element. ---*/ + VTK_Type = bound[iMarker][jElem]->GetVTK_Type(); + switch(VTK_Type) { + case LINE: + newBound[iMarker][iElem] = new CLine(newNodes[0], newNodes[1],2); + break; + case TRIANGLE: + newBound[iMarker][iElem] = new CTriangle(newNodes[0], newNodes[1], newNodes[2],3); + break; + case QUADRILATERAL: + newBound[iMarker][iElem] = new CQuadrilateral(newNodes[0], newNodes[1], newNodes[2], newNodes[3],3); + break; + } + + } + } + + delete [] PeriodicBC; + delete [] CreateMirror; + +} + +void CPhysicalGeometry::FindNormal_Neighbor(CConfig *config) { + su2double cos_max, scalar_prod, norm_vect, norm_Normal, cos_alpha, diff_coord, *Normal; + unsigned long Point_Normal, jPoint; + unsigned short iNeigh, iMarker, iDim; + unsigned long iPoint, iVertex; + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE && + config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY && + config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY ) { + + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + + iPoint = vertex[iMarker][iVertex]->GetNode(); + Normal = vertex[iMarker][iVertex]->GetNormal(); + + /*--- Compute closest normal neighbor, note that the normal are oriented inwards ---*/ + Point_Normal = 0; cos_max = -1.0; + for (iNeigh = 0; iNeigh < node[iPoint]->GetnPoint(); iNeigh++) { + jPoint = node[iPoint]->GetPoint(iNeigh); + scalar_prod = 0.0; norm_vect = 0.0; norm_Normal = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + diff_coord = node[jPoint]->GetCoord(iDim)-node[iPoint]->GetCoord(iDim); + scalar_prod += diff_coord*Normal[iDim]; + norm_vect += diff_coord*diff_coord; + norm_Normal += Normal[iDim]*Normal[iDim]; + } + norm_vect = sqrt(norm_vect); + norm_Normal = sqrt(norm_Normal); + cos_alpha = scalar_prod/(norm_vect*norm_Normal); + + /*--- Get maximum cosine ---*/ + if (cos_alpha >= cos_max) { + Point_Normal = jPoint; + cos_max = cos_alpha; + } + } + vertex[iMarker][iVertex]->SetNormal_Neighbor(Point_Normal); + } + } + } +} + +void CPhysicalGeometry::SetGeometryPlanes(CConfig *config) { + + bool loop_on; + unsigned short iMarker = 0; + su2double auxXCoord, auxYCoord, auxZCoord, *Face_Normal = NULL, auxArea, *Xcoord = NULL, *Ycoord = NULL, *Zcoord = NULL, *FaceArea = NULL; + unsigned long jVertex, iVertex, ixCoord, iPoint, iVertex_Wall, nVertex_Wall = 0; + + /*--- Compute the total number of points on the near-field ---*/ + nVertex_Wall = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) || + (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ) + nVertex_Wall += nVertex[iMarker]; + + + /*--- Create an array with all the coordinates, points, pressures, face area, + equivalent area, and nearfield weight ---*/ + Xcoord = new su2double[nVertex_Wall]; + Ycoord = new su2double[nVertex_Wall]; + if (nDim == 3) Zcoord = new su2double[nVertex_Wall]; + FaceArea = new su2double[nVertex_Wall]; + + /*--- Copy the boundary information to an array ---*/ + iVertex_Wall = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) || + (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ) + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + Xcoord[iVertex_Wall] = node[iPoint]->GetCoord(0); + Ycoord[iVertex_Wall] = node[iPoint]->GetCoord(1); + if (nDim==3) Zcoord[iVertex_Wall] = node[iPoint]->GetCoord(2); + Face_Normal = vertex[iMarker][iVertex]->GetNormal(); + FaceArea[iVertex_Wall] = fabs(Face_Normal[nDim-1]); + iVertex_Wall ++; + } + + + //vector XCoordList; + vector::iterator IterXCoordList; + + for (iVertex = 0; iVertex < nVertex_Wall; iVertex++) + XCoordList.push_back(Xcoord[iVertex]); + + sort( XCoordList.begin(), XCoordList.end()); + IterXCoordList = unique( XCoordList.begin(), XCoordList.end()); + XCoordList.resize( IterXCoordList - XCoordList.begin() ); + + /*--- Create vectors and distribute the values among the different PhiAngle queues ---*/ + Xcoord_plane.resize(XCoordList.size()); + Ycoord_plane.resize(XCoordList.size()); + if (nDim==3) Zcoord_plane.resize(XCoordList.size()); + FaceArea_plane.resize(XCoordList.size()); + Plane_points.resize(XCoordList.size()); + + + su2double dist_ratio; + unsigned long iCoord; + + /*--- Distribute the values among the different PhiAngles ---*/ + for (iPoint = 0; iPoint < nPoint; iPoint++) { + if (node[iPoint]->GetDomain()) { + loop_on = true; + for (ixCoord = 0; ixCoord < XCoordList.size()-1 && loop_on; ixCoord++) { + dist_ratio = (node[iPoint]->GetCoord(0) - XCoordList[ixCoord])/(XCoordList[ixCoord+1]- XCoordList[ixCoord]); + if (dist_ratio >= 0 && dist_ratio <= 1.0) { + if (dist_ratio <= 0.5) iCoord = ixCoord; + else iCoord = ixCoord+1; + Xcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(0) ); + Ycoord_plane[iCoord].push_back(node[iPoint]->GetCoord(1) ); + if (nDim==3) Zcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(2) ); + FaceArea_plane[iCoord].push_back(node[iPoint]->GetVolume()); ///// CHECK AREA CALCULATION + Plane_points[iCoord].push_back(iPoint ); + loop_on = false; + } + } + } + } + + unsigned long auxPoint; + /*--- Order the arrays in ascending values of y ---*/ + for (ixCoord = 0; ixCoord < XCoordList.size(); ixCoord++) + for (iVertex = 0; iVertex < Xcoord_plane[ixCoord].size(); iVertex++) + for (jVertex = 0; jVertex < Xcoord_plane[ixCoord].size() - 1 - iVertex; jVertex++) + if (Ycoord_plane[ixCoord][jVertex] > Ycoord_plane[ixCoord][jVertex+1]) { + auxXCoord = Xcoord_plane[ixCoord][jVertex]; Xcoord_plane[ixCoord][jVertex] = Xcoord_plane[ixCoord][jVertex+1]; Xcoord_plane[ixCoord][jVertex+1] = auxXCoord; + auxYCoord = Ycoord_plane[ixCoord][jVertex]; Ycoord_plane[ixCoord][jVertex] = Ycoord_plane[ixCoord][jVertex+1]; Ycoord_plane[ixCoord][jVertex+1] = auxYCoord; + auxPoint = Plane_points[ixCoord][jVertex]; Plane_points[ixCoord][jVertex] = Plane_points[ixCoord][jVertex+1]; Plane_points[ixCoord][jVertex+1] = auxPoint; + if (nDim==3) { + auxZCoord = Zcoord_plane[ixCoord][jVertex]; Zcoord_plane[ixCoord][jVertex] = Zcoord_plane[ixCoord][jVertex+1]; Zcoord_plane[ixCoord][jVertex+1] = auxZCoord; + } + auxArea = FaceArea_plane[ixCoord][jVertex]; FaceArea_plane[ixCoord][jVertex] = FaceArea_plane[ixCoord][jVertex+1]; FaceArea_plane[ixCoord][jVertex+1] = auxArea; + } + + /*--- Delete structures ---*/ + delete[] Xcoord; delete[] Ycoord; + if (nDim==3) delete[] Zcoord; + delete[] FaceArea; +} + +void CPhysicalGeometry::SetBoundSensitivity(CConfig *config) { + unsigned short iMarker, icommas; + unsigned long iVertex, iPoint, (*Point2Vertex)[2], nPointLocal = 0, nPointGlobal = 0; + su2double Sensitivity; + bool *PointInDomain; + +#ifdef HAVE_MPI + int rank = MASTER_NODE; + int size = SINGLE_NODE; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); +#endif + + nPointLocal = nPoint; +#ifdef HAVE_MPI + SU2_MPI::Allreduce(&nPointLocal, &nPointGlobal, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); +#else + nPointGlobal = nPointLocal; +#endif + + Point2Vertex = new unsigned long[nPointGlobal][2]; + PointInDomain = new bool[nPointGlobal]; + + for (iPoint = 0; iPoint < nPointGlobal; iPoint ++) + PointInDomain[iPoint] = false; + + for (iMarker = 0; iMarker < nMarker; iMarker++) + if (config->GetMarker_All_DV(iMarker) == YES) + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + + /*--- The sensitivity file uses the global numbering ---*/ + iPoint = node[vertex[iMarker][iVertex]->GetNode()]->GetGlobalIndex(); + + if (vertex[iMarker][iVertex]->GetNode() < GetnPointDomain()) { + Point2Vertex[iPoint][0] = iMarker; + Point2Vertex[iPoint][1] = iVertex; + PointInDomain[iPoint] = true; + vertex[iMarker][iVertex]->SetAuxVar(0.0); + } + } + + /*--- Time-average any unsteady surface sensitivities ---*/ + + unsigned long iExtIter, nExtIter; + su2double delta_T, total_T; + if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { + nExtIter = config->GetUnst_AdjointIter(); + delta_T = config->GetDelta_UnstTimeND(); + total_T = (su2double)nExtIter*delta_T; + } else if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { + + /*--- Compute period of oscillation & compute time interval using nTimeInstances ---*/ + + su2double period = config->GetTimeSpectral_Period(); + nExtIter = config->GetnTimeInstances(); + delta_T = period/(su2double)nExtIter; + total_T = period; + + } else { + nExtIter = 1; + delta_T = 1.0; + total_T = 1.0; + } + + for (iExtIter = 0; iExtIter < nExtIter; iExtIter++) { + + /*--- Prepare to read surface sensitivity files (CSV) ---*/ + + string text_line; + ifstream Surface_file; + char buffer[50]; + char cstr[MAX_STRING_SIZE]; + string surfadj_filename = config->GetSurfAdjCoeff_FileName(); + strcpy (cstr, surfadj_filename.c_str()); + + /*--- Write file name with extension if unsteady or steady ---*/ + + if ((config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) || + (config->GetUnsteady_Simulation() == TIME_SPECTRAL)) { + if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(iExtIter)); + if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(iExtIter)); + } + else + SPRINTF (buffer, ".csv"); + + strcat (cstr, buffer); + + /*--- Read the sensitivity file ---*/ + + string::size_type position; + + Surface_file.open(cstr, ios::in); + getline(Surface_file, text_line); + + while (getline(Surface_file, text_line)) { + for (icommas = 0; icommas < 50; icommas++) { + position = text_line.find( ",", 0 ); + if (position!=string::npos) text_line.erase (position,1); + } + stringstream point_line(text_line); + point_line >> iPoint >> Sensitivity; + + if (PointInDomain[iPoint]) { + + /*--- Find the vertex for the Point and Marker ---*/ + + iMarker = Point2Vertex[iPoint][0]; + iVertex = Point2Vertex[iPoint][1]; + + /*--- Increment the auxiliary variable with the contribution of + this unsteady timestep. For steady problems, this reduces to + a single sensitivity value multiplied by 1.0. ---*/ + + vertex[iMarker][iVertex]->AddAuxVar(Sensitivity*(delta_T/total_T)); + } + + } + Surface_file.close(); + } + + delete[] Point2Vertex; +} + +void CPhysicalGeometry::SetSensitivity(CConfig *config){ + + ifstream restart_file; + string filename = config->GetSolution_AdjFileName(); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool sst = config->GetKind_Turb_Model() == SST; + bool sa = config->GetKind_Turb_Model() == SA; + bool grid_movement = config->GetGrid_Movement(); + su2double Sens, dull_val; + //su2double delta_T, total_T; + unsigned short nExtIter, iDim, iExtIter; + unsigned long iPoint, index; + + Sensitivity = new su2double[nPoint*nDim]; + + if (config->GetUnsteady_Simulation()){ + nExtIter = config->GetUnst_AdjointIter(); + // delta_T = config->GetDelta_UnstTimeND(); + // delta_T = 1.0; + //total_T = (su2double)nExtIter*delta_T; + }else{ + //total_T = 1.0; + nExtIter = 1; + } + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + #endif + + unsigned short skipVar = nDim; + + if (incompressible) { skipVar += nDim+1; } + if (freesurface) { skipVar += nDim+2; } + if (compressible) { skipVar += nDim+2; } + if (sst) { skipVar += 2;} + if (sa) { skipVar += 1;} + + if (grid_movement) {skipVar += nDim;} + + /*--- Sensitivity in normal direction ---*/ + + skipVar += 1; + + /*--- In case this is a parallel simulation, we need to perform the + Global2Local index transformation first. ---*/ + long *Global2Local = new long[Global_nPointDomain]; + + /*--- First, set all indices to a negative value by default ---*/ + for(iPoint = 0; iPoint < Global_nPointDomain; iPoint++) + Global2Local[iPoint] = -1; + + /*--- Now fill array with the transform values only for local points ---*/ + for(iPoint = 0; iPoint < nPointDomain; iPoint++) + Global2Local[node[iPoint]->GetGlobalIndex()] = iPoint; + + /*--- Read all lines in the restart file ---*/ + long iPoint_Local; unsigned long iPoint_Global = 0; string text_line; + + + for (iPoint = 0; iPoint < nPoint; iPoint++){ + for (iDim = 0; iDim < nDim; iDim++){ + Sensitivity[iPoint*nDim+iDim] = 0.0; + } + } + + for (iExtIter = 0; iExtIter < nExtIter; iExtIter++){ + + iPoint_Global = 0; + + filename = config->GetSolution_AdjFileName(); + + filename = config->GetObjFunc_Extension(filename); + + if (config->GetUnsteady_Simulation()){ + filename = config->GetUnsteady_FileName(filename, iExtIter); + } + + restart_file.open(filename.data(), ios::in); + if (restart_file.fail()) { + cout << "There is no adjoint restart file!! " << filename.data() << "."<< endl; + exit(EXIT_FAILURE); + } + + if (rank == MASTER_NODE) + cout << "Reading in sensitivity at iteration " << iExtIter << "."<< endl; + /*--- The first line is the header ---*/ + getline (restart_file, text_line); + + while (getline (restart_file, text_line)) { + istringstream point_line(text_line); + + /*--- Retrieve local index. If this node from the restart file lives + on a different processor, the value of iPoint_Local will be -1. + Otherwise, the local index for this node on the current processor + will be returned and used to instantiate the vars. ---*/ + iPoint_Local = Global2Local[iPoint_Global]; + + if (iPoint_Local >= 0){ + point_line >> index; + for (iDim = 0; iDim < skipVar; iDim++){ point_line >> dull_val;} + for (iDim = 0; iDim < nDim; iDim++){ + point_line >> Sens; + // Sensitivity[iPoint_Local*nDim+iDim] += Sens*delta_T/total_T; + Sensitivity[iPoint_Local*nDim+iDim] += Sens; + + } + } + iPoint_Global++; + } + restart_file.close(); + } +} + +su2double CPhysicalGeometry::Compute_MaxThickness(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { + unsigned long iVertex, jVertex, n, Trailing_Point, Leading_Point; + su2double Normal[3], Tangent[3], BiNormal[3], auxXCoord, auxYCoord, auxZCoord, zp1, zpn, MaxThickness_Value = 0, Thickness, Length, Xcoord_Trailing, Ycoord_Trailing, Zcoord_Trailing, ValCos, ValSin, XValue, ZValue, MaxDistance, Distance, AoA; + vector Xcoord, Ycoord, Zcoord, Z2coord, Xcoord_Normal, Ycoord_Normal, Zcoord_Normal, Xcoord_Airfoil_, Ycoord_Airfoil_, Zcoord_Airfoil_; + + /*--- Find the leading and trailing edges and compute the angle of attack ---*/ + + MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0; + for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) { + Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) + + pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) + + pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0)); + + if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; } + } + + AoA = atan((Zcoord_Airfoil[Leading_Point] - Zcoord_Airfoil[Trailing_Point]) / (Xcoord_Airfoil[Trailing_Point] - Xcoord_Airfoil[Leading_Point]))*180/PI_NUMBER; + + /*--- Translate to the origin ---*/ + + Xcoord_Trailing = Xcoord_Airfoil[0]; + Ycoord_Trailing = Ycoord_Airfoil[0]; + Zcoord_Trailing = Zcoord_Airfoil[0]; + + for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { + Xcoord_Airfoil_.push_back(Xcoord_Airfoil[iVertex] - Xcoord_Trailing); + Ycoord_Airfoil_.push_back(Ycoord_Airfoil[iVertex] - Ycoord_Trailing); + Zcoord_Airfoil_.push_back(Zcoord_Airfoil[iVertex] - Zcoord_Trailing); + } + + /*--- Rotate the airfoil ---*/ + + ValCos = cos(AoA*PI_NUMBER/180.0); + ValSin = sin(AoA*PI_NUMBER/180.0); + + for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { + XValue = Xcoord_Airfoil_[iVertex]; + ZValue = Zcoord_Airfoil_[iVertex]; + + Xcoord_Airfoil_[iVertex] = XValue*ValCos - ZValue*ValSin; + Zcoord_Airfoil_[iVertex] = ZValue*ValCos + XValue*ValSin; + + } + + /*--- Identify upper and lower side, and store the value of the normal --*/ + + for (iVertex = 1; iVertex < Xcoord_Airfoil_.size(); iVertex++) { + Tangent[0] = Xcoord_Airfoil_[iVertex] - Xcoord_Airfoil_[iVertex-1]; + Tangent[1] = Ycoord_Airfoil_[iVertex] - Ycoord_Airfoil_[iVertex-1]; + Tangent[2] = Zcoord_Airfoil_[iVertex] - Zcoord_Airfoil_[iVertex-1]; + Length = sqrt(pow(Tangent[0], 2.0) + pow(Tangent[1], 2.0) + pow(Tangent[2], 2.0)); + Tangent[0] /= Length; Tangent[1] /= Length; Tangent[2] /= Length; + + BiNormal[0] = Plane_Normal[0]; + BiNormal[1] = Plane_Normal[1]; + BiNormal[2] = Plane_Normal[2]; + Length = sqrt(pow(BiNormal[0], 2.0) + pow(BiNormal[1], 2.0) + pow(BiNormal[2], 2.0)); + BiNormal[0] /= Length; BiNormal[1] /= Length; BiNormal[2] /= Length; + + Normal[0] = Tangent[1]*BiNormal[2] - Tangent[2]*BiNormal[1]; + Normal[1] = Tangent[2]*BiNormal[0] - Tangent[0]*BiNormal[2]; + Normal[2] = Tangent[0]*BiNormal[1] - Tangent[1]*BiNormal[0]; + + Xcoord_Normal.push_back(Normal[0]); Ycoord_Normal.push_back(Normal[1]); Zcoord_Normal.push_back(Normal[2]); + + unsigned short index = 2; + if ((config->GetAxis_Orientation() == Z_AXIS) && (nDim == 3)) index = 0; + + if (Normal[index] >= 0.0) { + Xcoord.push_back(Xcoord_Airfoil_[iVertex]); + Ycoord.push_back(Ycoord_Airfoil_[iVertex]); + Zcoord.push_back(Zcoord_Airfoil_[iVertex]); + } + + } + + /*--- Order the arrays using the X component ---*/ + + for (iVertex = 0; iVertex < Xcoord.size(); iVertex++) { + for (jVertex = 0; jVertex < Xcoord.size() - 1 - iVertex; jVertex++) { + if (Xcoord[jVertex] > Xcoord[jVertex+1]) { + auxXCoord = Xcoord[jVertex]; Xcoord[jVertex] = Xcoord[jVertex+1]; Xcoord[jVertex+1] = auxXCoord; + auxYCoord = Ycoord[jVertex]; Ycoord[jVertex] = Ycoord[jVertex+1]; Ycoord[jVertex+1] = auxYCoord; + auxZCoord = Zcoord[jVertex]; Zcoord[jVertex] = Zcoord[jVertex+1]; Zcoord[jVertex+1] = auxZCoord; + } + } + } + + n = Xcoord.size(); + zp1 = (Zcoord[1]-Zcoord[0])/(Xcoord[1]-Xcoord[0]); + zpn = (Zcoord[n-1]-Zcoord[n-2])/(Xcoord[n-1]-Xcoord[n-2]); + Z2coord.resize(n+1); + SetSpline(Xcoord, Zcoord, n, zp1, zpn, Z2coord); + + /*--- Compute the thickness (we add a fabs because we can not guarantee the + right sorting of the points and the upper and/or lower part of the airfoil is not well defined) ---*/ + + MaxThickness_Value = 0.0; + for (iVertex = 0; iVertex < Xcoord_Airfoil_.size(); iVertex++) { + if (Zcoord_Normal[iVertex] < 0.0) { + Thickness = fabs(Zcoord_Airfoil_[iVertex] - GetSpline(Xcoord, Zcoord, Z2coord, n, Xcoord_Airfoil_[iVertex])); + if (Thickness > MaxThickness_Value) { MaxThickness_Value = Thickness; } + } + } + + return MaxThickness_Value; + +} + +su2double CPhysicalGeometry::Compute_AoA(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { + unsigned long iVertex, Trailing_Point, Leading_Point; + su2double MaxDistance, Distance, AoA = 0.0; + + /*--- Find the leading and trailing edges and compute the angle of attack ---*/ + MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0; + for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) { + Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) + + pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) + + pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0)); + + if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; } + } + + AoA = atan((Zcoord_Airfoil[Leading_Point] - Zcoord_Airfoil[Trailing_Point]) / (Xcoord_Airfoil[Trailing_Point] - Xcoord_Airfoil[Leading_Point]))*180/PI_NUMBER; + + return AoA; + +} + +su2double CPhysicalGeometry::Compute_Chord(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { + unsigned long iVertex, Trailing_Point; + su2double MaxDistance, Distance, Chord = 0.0; + + /*--- Find the leading and trailing edges and compute the angle of attack ---*/ + MaxDistance = 0.0; Trailing_Point = 0; + for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) { + + Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) + + pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) + + pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0)); + + if (MaxDistance < Distance) { MaxDistance = Distance; } + } + + Chord = MaxDistance; + + return Chord; + +} + +su2double CPhysicalGeometry::Compute_Thickness(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, su2double Location, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { + unsigned long iVertex, jVertex, n_Upper, n_Lower, Trailing_Point, Leading_Point; + su2double Thickness_Location, Normal[3], Tangent[3], BiNormal[3], auxXCoord, auxYCoord, auxZCoord, Thickness_Value = 0.0, Length, Xcoord_Trailing, Ycoord_Trailing, Zcoord_Trailing, ValCos, ValSin, XValue, ZValue, zp1, zpn, Chord, MaxDistance, Distance, AoA; + vector Xcoord_Upper, Ycoord_Upper, Zcoord_Upper, Z2coord_Upper, Xcoord_Lower, Ycoord_Lower, Zcoord_Lower, Z2coord_Lower, Z2coord, Xcoord_Normal, Ycoord_Normal, Zcoord_Normal, Xcoord_Airfoil_, Ycoord_Airfoil_, Zcoord_Airfoil_; + + /*--- Find the leading and trailing edges and compute the angle of attack ---*/ + + MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0; + for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) { + Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) + + pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) + + pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0)); + + if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; } + } + + AoA = atan((Zcoord_Airfoil[Leading_Point] - Zcoord_Airfoil[Trailing_Point]) / (Xcoord_Airfoil[Trailing_Point] - Xcoord_Airfoil[Leading_Point]))*180/PI_NUMBER; + Chord = MaxDistance; + + /*--- Translate to the origin ---*/ + + Xcoord_Trailing = Xcoord_Airfoil[0]; + Ycoord_Trailing = Ycoord_Airfoil[0]; + Zcoord_Trailing = Zcoord_Airfoil[0]; + + for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { + Xcoord_Airfoil_.push_back(Xcoord_Airfoil[iVertex] - Xcoord_Trailing); + Ycoord_Airfoil_.push_back(Ycoord_Airfoil[iVertex] - Ycoord_Trailing); + Zcoord_Airfoil_.push_back(Zcoord_Airfoil[iVertex] - Zcoord_Trailing); + } + + /*--- Rotate the airfoil ---*/ + + ValCos = cos(AoA*PI_NUMBER/180.0); + ValSin = sin(AoA*PI_NUMBER/180.0); + + for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { + XValue = Xcoord_Airfoil_[iVertex]; + ZValue = Zcoord_Airfoil_[iVertex]; + + Xcoord_Airfoil_[iVertex] = XValue*ValCos - ZValue*ValSin; + Zcoord_Airfoil_[iVertex] = ZValue*ValCos + XValue*ValSin; + } + + /*--- Identify upper and lower side, and store the value of the normal --*/ + + for (iVertex = 1; iVertex < Xcoord_Airfoil_.size(); iVertex++) { + Tangent[0] = Xcoord_Airfoil_[iVertex] - Xcoord_Airfoil_[iVertex-1]; + Tangent[1] = Ycoord_Airfoil_[iVertex] - Ycoord_Airfoil_[iVertex-1]; + Tangent[2] = Zcoord_Airfoil_[iVertex] - Zcoord_Airfoil_[iVertex-1]; + Length = sqrt(pow(Tangent[0], 2.0) + pow(Tangent[1], 2.0) + pow(Tangent[2], 2.0)); + Tangent[0] /= Length; Tangent[1] /= Length; Tangent[2] /= Length; + + BiNormal[0] = Plane_Normal[0]; + BiNormal[1] = Plane_Normal[1]; + BiNormal[2] = Plane_Normal[2]; + Length = sqrt(pow(BiNormal[0], 2.0) + pow(BiNormal[1], 2.0) + pow(BiNormal[2], 2.0)); + BiNormal[0] /= Length; BiNormal[1] /= Length; BiNormal[2] /= Length; + + Normal[0] = Tangent[1]*BiNormal[2] - Tangent[2]*BiNormal[1]; + Normal[1] = Tangent[2]*BiNormal[0] - Tangent[0]*BiNormal[2]; + Normal[2] = Tangent[0]*BiNormal[1] - Tangent[1]*BiNormal[0]; + + Xcoord_Normal.push_back(Normal[0]); Ycoord_Normal.push_back(Normal[1]); Zcoord_Normal.push_back(Normal[2]); + + unsigned short index = 2; + if ((config->GetAxis_Orientation() == Z_AXIS) && (nDim == 3)) index = 0; + + if (Normal[index] >= 0.0) { + Xcoord_Upper.push_back(Xcoord_Airfoil_[iVertex]); + Ycoord_Upper.push_back(Ycoord_Airfoil_[iVertex]); + Zcoord_Upper.push_back(Zcoord_Airfoil_[iVertex]); + } + else { + Xcoord_Lower.push_back(Xcoord_Airfoil_[iVertex]); + Ycoord_Lower.push_back(Ycoord_Airfoil_[iVertex]); + Zcoord_Lower.push_back(Zcoord_Airfoil_[iVertex]); + } + + } + + /*--- Order the arrays using the X component ---*/ + + for (iVertex = 0; iVertex < Xcoord_Upper.size(); iVertex++) { + for (jVertex = 0; jVertex < Xcoord_Upper.size() - 1 - iVertex; jVertex++) { + if (Xcoord_Upper[jVertex] > Xcoord_Upper[jVertex+1]) { + auxXCoord = Xcoord_Upper[jVertex]; Xcoord_Upper[jVertex] = Xcoord_Upper[jVertex+1]; Xcoord_Upper[jVertex+1] = auxXCoord; + auxYCoord = Ycoord_Upper[jVertex]; Ycoord_Upper[jVertex] = Ycoord_Upper[jVertex+1]; Ycoord_Upper[jVertex+1] = auxYCoord; + auxZCoord = Zcoord_Upper[jVertex]; Zcoord_Upper[jVertex] = Zcoord_Upper[jVertex+1]; Zcoord_Upper[jVertex+1] = auxZCoord; + } + } + } + + /*--- Order the arrays using the X component ---*/ + + for (iVertex = 0; iVertex < Xcoord_Lower.size(); iVertex++) { + for (jVertex = 0; jVertex < Xcoord_Lower.size() - 1 - iVertex; jVertex++) { + if (Xcoord_Lower[jVertex] > Xcoord_Lower[jVertex+1]) { + auxXCoord = Xcoord_Lower[jVertex]; Xcoord_Lower[jVertex] = Xcoord_Lower[jVertex+1]; Xcoord_Lower[jVertex+1] = auxXCoord; + auxYCoord = Ycoord_Lower[jVertex]; Ycoord_Lower[jVertex] = Ycoord_Lower[jVertex+1]; Ycoord_Lower[jVertex+1] = auxYCoord; + auxZCoord = Zcoord_Lower[jVertex]; Zcoord_Lower[jVertex] = Zcoord_Lower[jVertex+1]; Zcoord_Lower[jVertex+1] = auxZCoord; + } + } + } + + n_Upper = Xcoord_Upper.size(); + zp1 = (Zcoord_Upper[1]-Zcoord_Upper[0])/(Xcoord_Upper[1]-Xcoord_Upper[0]); + zpn = (Zcoord_Upper[n_Upper-1]-Zcoord_Upper[n_Upper-2])/(Xcoord_Upper[n_Upper-1]-Xcoord_Upper[n_Upper-2]); + Z2coord_Upper.resize(n_Upper+1); + SetSpline(Xcoord_Upper, Zcoord_Upper, n_Upper, zp1, zpn, Z2coord_Upper); + + n_Lower = Xcoord_Lower.size(); + zp1 = (Zcoord_Lower[1]-Zcoord_Lower[0])/(Xcoord_Lower[1]-Xcoord_Lower[0]); + zpn = (Zcoord_Lower[n_Lower-1]-Zcoord_Lower[n_Lower-2])/(Xcoord_Lower[n_Lower-1]-Xcoord_Lower[n_Lower-2]); + Z2coord_Lower.resize(n_Lower+1); + SetSpline(Xcoord_Lower, Zcoord_Lower, n_Lower, zp1, zpn, Z2coord_Lower); + + /*--- Compute the thickness (we add a fabs because we can not guarantee the + right sorting of the points and the upper and/or lower part of the airfoil is not well defined) ---*/ + + Thickness_Location = - Chord*(1.0-Location); + + Thickness_Value = fabs(GetSpline(Xcoord_Upper, Zcoord_Upper, Z2coord_Upper, n_Upper, Thickness_Location) - GetSpline(Xcoord_Lower, Zcoord_Lower, Z2coord_Lower, n_Lower, Thickness_Location)); + + return Thickness_Value; + +} + +su2double CPhysicalGeometry::Compute_Area(su2double *Plane_P0, su2double *Plane_Normal, unsigned short iSection, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, bool original_surface) { + unsigned long iVertex, jVertex; + su2double Normal[3], Tangent[3], BiNormal[3], auxXCoord, auxYCoord, auxZCoord, Area_Value = 0.0, Area_Value_Upper = 0.0, Area_Value_Lower = 0.0, Length, Xcoord_Trailing, Ycoord_Trailing, Zcoord_Trailing, ValCos, ValSin, XValue, ZValue; + vector Xcoord_Upper, Ycoord_Upper, Zcoord_Upper, Xcoord_Lower, Ycoord_Lower, Zcoord_Lower, Z2coord, Xcoord_Normal, Ycoord_Normal, Zcoord_Normal, Xcoord_Airfoil_, Ycoord_Airfoil_, Zcoord_Airfoil_; + unsigned long Trailing_Point, Leading_Point; + su2double MaxDistance, Distance, AoA; + + /*--- Find the leading and trailing edges and compute the angle of attack ---*/ + + MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0; + for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) { + Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) + + pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) + + pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0)); + + if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; } + } + + AoA = atan((Zcoord_Airfoil[Leading_Point] - Zcoord_Airfoil[Trailing_Point]) / (Xcoord_Airfoil[Trailing_Point] - Xcoord_Airfoil[Leading_Point]))*180/PI_NUMBER; + + /*--- Translate to the origin ---*/ + + Xcoord_Trailing = Xcoord_Airfoil[0]; + Ycoord_Trailing = Ycoord_Airfoil[0]; + Zcoord_Trailing = Zcoord_Airfoil[0]; + + for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { + Xcoord_Airfoil_.push_back(Xcoord_Airfoil[iVertex] - Xcoord_Trailing); + Ycoord_Airfoil_.push_back(Ycoord_Airfoil[iVertex] - Ycoord_Trailing); + Zcoord_Airfoil_.push_back(Zcoord_Airfoil[iVertex] - Zcoord_Trailing); + } + + /*--- Rotate the airfoil ---*/ + + ValCos = cos(AoA*PI_NUMBER/180.0); + ValSin = sin(AoA*PI_NUMBER/180.0); + + for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { + XValue = Xcoord_Airfoil_[iVertex]; + ZValue = Zcoord_Airfoil_[iVertex]; + + Xcoord_Airfoil_[iVertex] = XValue*ValCos - ZValue*ValSin; + Zcoord_Airfoil_[iVertex] = ZValue*ValCos + XValue*ValSin; + + } + + /*--- Identify upper and lower side, and store the value of the normal --*/ + + for (iVertex = 1; iVertex < Xcoord_Airfoil_.size(); iVertex++) { + Tangent[0] = Xcoord_Airfoil_[iVertex] - Xcoord_Airfoil_[iVertex-1]; + Tangent[1] = Ycoord_Airfoil_[iVertex] - Ycoord_Airfoil_[iVertex-1]; + Tangent[2] = Zcoord_Airfoil_[iVertex] - Zcoord_Airfoil_[iVertex-1]; + Length = sqrt(pow(Tangent[0], 2.0) + pow(Tangent[1], 2.0) + pow(Tangent[2], 2.0)); + Tangent[0] /= Length; Tangent[1] /= Length; Tangent[2] /= Length; + + BiNormal[0] = Plane_Normal[0]; + BiNormal[1] = Plane_Normal[1]; + BiNormal[2] = Plane_Normal[2]; + Length = sqrt(pow(BiNormal[0], 2.0) + pow(BiNormal[1], 2.0) + pow(BiNormal[2], 2.0)); + BiNormal[0] /= Length; BiNormal[1] /= Length; BiNormal[2] /= Length; + + Normal[0] = Tangent[1]*BiNormal[2] - Tangent[2]*BiNormal[1]; + Normal[1] = Tangent[2]*BiNormal[0] - Tangent[0]*BiNormal[2]; + Normal[2] = Tangent[0]*BiNormal[1] - Tangent[1]*BiNormal[0]; + + Xcoord_Normal.push_back(Normal[0]); Ycoord_Normal.push_back(Normal[1]); Zcoord_Normal.push_back(Normal[2]); + + unsigned short index = 2; + if ((config->GetAxis_Orientation() == Z_AXIS) && (nDim == 3)) index = 0; + + if (Normal[index] >= 0.0) { + Xcoord_Upper.push_back(Xcoord_Airfoil_[iVertex]); + Ycoord_Upper.push_back(Ycoord_Airfoil_[iVertex]); + Zcoord_Upper.push_back(Zcoord_Airfoil_[iVertex]); + } + else { + Xcoord_Lower.push_back(Xcoord_Airfoil_[iVertex]); + Ycoord_Lower.push_back(Ycoord_Airfoil_[iVertex]); + Zcoord_Lower.push_back(Zcoord_Airfoil_[iVertex]); + } + + } + + /*--- Order the arrays using the X component ---*/ + + for (iVertex = 0; iVertex < Xcoord_Upper.size(); iVertex++) { + for (jVertex = 0; jVertex < Xcoord_Upper.size() - 1 - iVertex; jVertex++) { + if (Xcoord_Upper[jVertex] > Xcoord_Upper[jVertex+1]) { + auxXCoord = Xcoord_Upper[jVertex]; Xcoord_Upper[jVertex] = Xcoord_Upper[jVertex+1]; Xcoord_Upper[jVertex+1] = auxXCoord; + auxYCoord = Ycoord_Upper[jVertex]; Ycoord_Upper[jVertex] = Ycoord_Upper[jVertex+1]; Ycoord_Upper[jVertex+1] = auxYCoord; + auxZCoord = Zcoord_Upper[jVertex]; Zcoord_Upper[jVertex] = Zcoord_Upper[jVertex+1]; Zcoord_Upper[jVertex+1] = auxZCoord; + } + } + } + + /*--- Order the arrays using the X component ---*/ + + for (iVertex = 0; iVertex < Xcoord_Lower.size(); iVertex++) { + for (jVertex = 0; jVertex < Xcoord_Lower.size() - 1 - iVertex; jVertex++) { + if (Xcoord_Lower[jVertex] > Xcoord_Lower[jVertex+1]) { + auxXCoord = Xcoord_Lower[jVertex]; Xcoord_Lower[jVertex] = Xcoord_Lower[jVertex+1]; Xcoord_Lower[jVertex+1] = auxXCoord; + auxYCoord = Ycoord_Lower[jVertex]; Ycoord_Lower[jVertex] = Ycoord_Lower[jVertex+1]; Ycoord_Lower[jVertex+1] = auxYCoord; + auxZCoord = Zcoord_Lower[jVertex]; Zcoord_Lower[jVertex] = Zcoord_Lower[jVertex+1]; Zcoord_Lower[jVertex+1] = auxZCoord; + } + } + } + + /*--- Compute total area ---*/ + + Area_Value_Upper = 0.0; + Area_Value_Lower = 0.0; + + for (iVertex = 0; iVertex < Xcoord_Upper.size()-1; iVertex++) + Area_Value_Upper += (Xcoord_Upper[iVertex+1] - Xcoord_Upper[iVertex]) * 0.5*(Zcoord_Upper[iVertex+1] + Zcoord_Upper[iVertex]); + for (iVertex = 0; iVertex < Xcoord_Lower.size()-1; iVertex++) + Area_Value_Lower += (Xcoord_Lower[iVertex+1] - Xcoord_Lower[iVertex]) * 0.5*(Zcoord_Lower[iVertex+1] + Zcoord_Lower[iVertex]); + + Area_Value = fabs(Area_Value_Upper - Area_Value_Lower); + return Area_Value; + +} + +su2double CPhysicalGeometry::Compute_Volume(CConfig *config, bool original_surface) { + + int rank = MASTER_NODE; + + /*--- MPI initialization ---*/ + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + unsigned short iPlane, nPlane = 0; + su2double Volume = 0.0, MinPlane, MaxPlane, MinXCoord, MaxXCoord, dPlane, *Area; + vector *Xcoord_Airfoil, *Ycoord_Airfoil, *Zcoord_Airfoil, *Variable_Airfoil; + + /*--- Make a large number of section cuts for approximating volume ---*/ + + nPlane = config->GetnVolSections(); + + /*--- Allocate memory for the section cutting ---*/ + + Area = new su2double [nPlane]; + + su2double **Plane_P0 = new su2double*[nPlane]; + for (iPlane = 0; iPlane < nPlane; iPlane++ ) + Plane_P0[iPlane] = new su2double[nDim]; + + su2double **Plane_Normal = new su2double*[nPlane]; + for (iPlane = 0; iPlane < nPlane; iPlane++ ) + Plane_Normal[iPlane] = new su2double[nDim]; + + + MinPlane = config->GetSection_Location(0); MaxPlane = config->GetSection_Location(1); + MinXCoord = -1E6; MaxXCoord = 1E6; + dPlane = fabs((MaxPlane - MinPlane)/su2double(nPlane-1)); + for (iPlane = 0; iPlane < nPlane; iPlane++) { + Plane_Normal[iPlane][0] = 0.0; Plane_P0[iPlane][0] = 0.0; + Plane_Normal[iPlane][1] = 0.0; Plane_P0[iPlane][1] = 0.0; + Plane_Normal[iPlane][2] = 0.0; Plane_P0[iPlane][2] = 0.0; + Plane_Normal[iPlane][config->GetAxis_Orientation()] = 1.0; + Plane_P0[iPlane][config->GetAxis_Orientation()] = MinPlane + iPlane*dPlane; + } + + /*--- Allocate some vectors for storing airfoil coordinates ---*/ + + Xcoord_Airfoil = new vector[nPlane]; + Ycoord_Airfoil = new vector[nPlane]; + Zcoord_Airfoil = new vector[nPlane]; + Variable_Airfoil = new vector[nPlane]; + + /*--- Create the section slices through the geometry ---*/ + + for (iPlane = 0; iPlane < nPlane; iPlane++) { + ComputeAirfoil_Section(Plane_P0[iPlane], Plane_Normal[iPlane], + MinXCoord, MaxXCoord, NULL, Xcoord_Airfoil[iPlane], + Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane], + Variable_Airfoil[iPlane], original_surface, config); + } + + /*--- Compute the area at each section ---*/ + + if (rank == MASTER_NODE) { + + for (iPlane = 0; iPlane < nPlane; iPlane++) { + Area[iPlane] = 0.0; + if (Xcoord_Airfoil[iPlane].size() != 0) { + Area[iPlane] = Compute_Area(Plane_P0[iPlane], Plane_Normal[iPlane], + iPlane, config, Xcoord_Airfoil[iPlane], + Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane], + original_surface); + } + } + + /*--- Compute the volume using a composite Simpson's rule ---*/ + + Volume = 0.0; + for (iPlane = 0; iPlane < nPlane-2; iPlane+=2) { + if (Xcoord_Airfoil[iPlane].size() != 0) { + Volume += (1.0/3.0)*dPlane*(Area[iPlane] + 4.0*Area[iPlane+1] + Area[iPlane+2]); + } + } + + } + + /*--- Free memory for the section cuts ---*/ + + delete [] Xcoord_Airfoil; + delete [] Ycoord_Airfoil; + delete [] Zcoord_Airfoil; + delete [] Variable_Airfoil; + + for (iPlane = 0; iPlane < nPlane; iPlane++) + delete [] Plane_P0[iPlane]; + delete [] Plane_P0; + + for (iPlane = 0; iPlane < nPlane; iPlane++) + delete [] Plane_Normal[iPlane]; + delete [] Plane_Normal; + + delete [] Area; + + /*--- Return the volume and exit ---*/ + + return Volume; +} + +CMultiGridGeometry::CMultiGridGeometry(CGeometry ***geometry, CConfig **config_container, unsigned short iMesh, unsigned short iZone) : CGeometry() { + + /*--- CGeometry & CConfig pointers to the fine grid level for clarity. We may + need access to the other zones in the mesh for zone boundaries. ---*/ + + CGeometry *fine_grid = geometry[iZone][iMesh-1]; + CConfig *config = config_container[iZone]; + + /*--- Local variables ---*/ + + unsigned long iPoint, Index_CoarseCV, CVPoint, iElem, iVertex, jPoint, iteration, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector, iParent, jVertex, *Buffer_Receive_Parent = NULL, *Buffer_Send_Parent = NULL, *Buffer_Receive_Children = NULL, *Buffer_Send_Children = NULL, *Parent_Remote = NULL, *Children_Remote = NULL, *Parent_Local = NULL, *Children_Local = NULL, Local_nPointCoarse, Local_nPointFine, Global_nPointCoarse, Global_nPointFine;; + short marker_seed; + bool agglomerate_seed = true; + unsigned short nChildren, iNode, counter, iMarker, jMarker, priority, MarkerS, MarkerR, *nChildren_MPI; + vector Suitable_Indirect_Neighbors, Aux_Parent; + vector::iterator it; + int rank; + + unsigned short nMarker_Max = config->GetnMarker_Max(); + + unsigned short *copy_marker = new unsigned short [nMarker_Max]; + +#ifndef HAVE_MPI + rank = MASTER_NODE; +#else + int send_to, receive_from; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Status status; +#endif + + nDim = fine_grid->GetnDim(); // Write the number of dimensions of the coarse grid. + + /*--- Create a queue system to deo the agglomeration + 1st) More than two markers ---> Vertices (never agglomerate) + 2nd) Two markers ---> Edges (agglomerate if same BC, never agglomerate if different BC) + 3rd) One marker ---> Surface (always agglomarate) + 4th) No marker ---> Internal Volume (always agglomarate) ---*/ + + /*--- Set a marker to indicate indirect agglomeration ---*/ + + if (iMesh == MESH_1) { + + for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) + fine_grid->node[iPoint]->SetAgglomerate_Indirect(false); + + for (iElem = 0; iElem < fine_grid->GetnElem(); iElem++) { + if ((fine_grid->elem[iElem]->GetVTK_Type() == HEXAHEDRON) || + (fine_grid->elem[iElem]->GetVTK_Type() == QUADRILATERAL)) { + for (iNode = 0; iNode < fine_grid->elem[iElem]->GetnNodes(); iNode++) { + iPoint = fine_grid->elem[iElem]->GetNode(iNode); + fine_grid->node[iPoint]->SetAgglomerate_Indirect(true); + } + } + } + + } + + /*--- Create the coarse grid structure using as baseline the fine grid ---*/ + + CMultiGridQueue MGQueue_InnerCV(fine_grid->GetnPoint()); + + node = new CPoint*[fine_grid->GetnPoint()]; + for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) { + + /*--- Create node structure ---*/ + + node[iPoint] = new CPoint(nDim, iPoint, config); + + /*--- Set the indirect agglomeration to false ---*/ + + node[iPoint]->SetAgglomerate_Indirect(false); + } + + Index_CoarseCV = 0; + + /*--- The first step is the boundary agglomeration. ---*/ + + for (iMarker = 0; iMarker < fine_grid->GetnMarker(); iMarker++) { + + for (iVertex = 0; iVertex < fine_grid->GetnVertex(iMarker); iVertex++) { + iPoint = fine_grid->vertex[iMarker][iVertex]->GetNode(); + + /*--- If the element has not being previously agglomerated and it belongs + to the physical domain, then the agglomeration is studied ---*/ + + if ((fine_grid->node[iPoint]->GetAgglomerate() == false) && + (fine_grid->node[iPoint]->GetDomain()) && + (GeometricalCheck(iPoint, fine_grid, config))) { + + nChildren = 1; + + /*--- We set an index for the parent control volume ---*/ + + fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV); + + /*--- We add the seed point (child) to the parent control volume ---*/ + + node[Index_CoarseCV]->SetChildren_CV(0, iPoint); + agglomerate_seed = true; counter = 0; marker_seed = iMarker; + + /*--- For a particular point in the fine grid we save all the markers + that are in that point ---*/ + + for (jMarker = 0; jMarker < fine_grid->GetnMarker(); jMarker ++) + if (fine_grid->node[iPoint]->GetVertex(jMarker) != -1) { + copy_marker[counter] = jMarker; + counter++; + } + + /*--- To aglomerate a vertex it must have only one physical bc!! + This can be improved. If there is only a marker, it is a good + candidate for agglomeration ---*/ + + if (counter == 1) agglomerate_seed = true; + + /*--- If there are two markers, we will aglomerate if one of the + marker is SEND_RECEIVE ---*/ + + if (counter == 2) { + if ((config->GetMarker_All_KindBC(copy_marker[0]) == SEND_RECEIVE) || + (config->GetMarker_All_KindBC(copy_marker[1]) == SEND_RECEIVE)) agglomerate_seed = true; + else agglomerate_seed = false; + } + + /*--- If there are more than 2 markers, the aglomeration will be discarted ---*/ + + if (counter > 2) agglomerate_seed = false; + + /*--- If the seed can be agglomerated, we try to agglomerate more points ---*/ + + if (agglomerate_seed) { + + /*--- Now we do a sweep over all the nodes that surround the seed point ---*/ + + for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { + + CVPoint = fine_grid->node[iPoint]->GetPoint(iNode); + + /*--- The new point can be agglomerated ---*/ + + if (SetBoundAgglomeration(CVPoint, marker_seed, fine_grid, config)) { + + /*--- We set the value of the parent ---*/ + + fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV); + + /*--- We set the value of the child ---*/ + + node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint); + nChildren++; + } + + } + + Suitable_Indirect_Neighbors.clear(); + + if (fine_grid->node[iPoint]->GetAgglomerate_Indirect()) + SetSuitableNeighbors(&Suitable_Indirect_Neighbors, iPoint, Index_CoarseCV, fine_grid); + + /*--- Now we do a sweep over all the indirect nodes that can be added ---*/ + + for (iNode = 0; iNode < Suitable_Indirect_Neighbors.size(); iNode ++) { + + CVPoint = Suitable_Indirect_Neighbors[iNode]; + + /*--- The new point can be agglomerated ---*/ + + if (SetBoundAgglomeration(CVPoint, marker_seed, fine_grid, config)) { + + /*--- We set the value of the parent ---*/ + + fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV); + + /*--- We set the indirect agglomeration information ---*/ + + if (fine_grid->node[CVPoint]->GetAgglomerate_Indirect()) + node[Index_CoarseCV]->SetAgglomerate_Indirect(true); + + /*--- We set the value of the child ---*/ + + node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint); + nChildren++; + } + } + + + } + + /*--- Update the number of child of the control volume ---*/ + + node[Index_CoarseCV]->SetnChildren_CV(nChildren); + Index_CoarseCV++; + } + } + } + + /*--- Agglomerate all the nodes that have more than one physical boundary condition, + Maybe here we can add the posibility of merging the vertex that have the same number, + and kind of markers---*/ + + for (iMarker = 0; iMarker < fine_grid->GetnMarker(); iMarker++) + for (iVertex = 0; iVertex < fine_grid->GetnVertex(iMarker); iVertex++) { + iPoint = fine_grid->vertex[iMarker][iVertex]->GetNode(); + if ((fine_grid->node[iPoint]->GetAgglomerate() == false) && + (fine_grid->node[iPoint]->GetDomain())) { + fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV); + node[Index_CoarseCV]->SetChildren_CV(0, iPoint); + node[Index_CoarseCV]->SetnChildren_CV(1); + Index_CoarseCV++; + } + } + + /*--- Update the queue with the results from the boundary agglomeration ---*/ + + for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) { + + /*--- The CV has been agglomerated, remove form the list ---*/ + + if (fine_grid->node[iPoint]->GetAgglomerate() == true) { + + MGQueue_InnerCV.RemoveCV(iPoint); + + } + + else { + + /*--- Count the number of agglomerated neighbors, and modify the queue ---*/ + + priority = 0; + for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { + jPoint = fine_grid->node[iPoint]->GetPoint(iNode); + if (fine_grid->node[jPoint]->GetAgglomerate() == true) priority++; + } + MGQueue_InnerCV.MoveCV(iPoint, priority); + } + } + + /*--- Agglomerate the domain nodes ---*/ + + iteration = 0; + while (!MGQueue_InnerCV.EmptyQueue() && (iteration < fine_grid->GetnPoint())) { + + iPoint = MGQueue_InnerCV.NextCV(); + iteration ++; + + /*--- If the element has not being previously agglomerated, belongs to the physical domain, + and satisfies several geometrical criteria then the seed CV is acepted for agglomeration ---*/ + + if ((fine_grid->node[iPoint]->GetAgglomerate() == false) && + (fine_grid->node[iPoint]->GetDomain()) && + (GeometricalCheck(iPoint, fine_grid, config))) { + + nChildren = 1; + + /*--- We set an index for the parent control volume ---*/ + + fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV); + + /*--- We add the seed point (child) to the parent control volume ---*/ + + node[Index_CoarseCV]->SetChildren_CV(0, iPoint); + + /*--- Update the queue with the seed point (remove the seed and + increase the priority of the neighbors) ---*/ + + MGQueue_InnerCV.Update(iPoint, fine_grid); + + /*--- Now we do a sweep over all the nodes that surround the seed point ---*/ + + for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { + + CVPoint = fine_grid->node[iPoint]->GetPoint(iNode); + + /*--- Determine if the CVPoint can be agglomerated ---*/ + + if ((fine_grid->node[CVPoint]->GetAgglomerate() == false) && + (fine_grid->node[CVPoint]->GetDomain()) && + (GeometricalCheck(CVPoint, fine_grid, config))) { + + /*--- We set the value of the parent ---*/ + + fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV); + + /*--- We set the value of the child ---*/ + + node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint); + nChildren++; + + /*--- Update the queue with the new control volume (remove the CV and + increase the priority of the neighbors) ---*/ + + MGQueue_InnerCV.Update(CVPoint, fine_grid); + + } + + } + + /*--- Subrotuine to identify the indirect neighbors ---*/ + + Suitable_Indirect_Neighbors.clear(); + if (fine_grid->node[iPoint]->GetAgglomerate_Indirect()) + SetSuitableNeighbors(&Suitable_Indirect_Neighbors, iPoint, Index_CoarseCV, fine_grid); + + /*--- Now we do a sweep over all the indirect nodes that can be added ---*/ + + for (iNode = 0; iNode < Suitable_Indirect_Neighbors.size(); iNode ++) { + + CVPoint = Suitable_Indirect_Neighbors[iNode]; + + /*--- The new point can be agglomerated ---*/ + + if ((fine_grid->node[CVPoint]->GetAgglomerate() == false) && + (fine_grid->node[CVPoint]->GetDomain())) { + + /*--- We set the value of the parent ---*/ + + fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV); + + /*--- We set the indirect agglomeration information ---*/ + + if (fine_grid->node[CVPoint]->GetAgglomerate_Indirect()) + node[Index_CoarseCV]->SetAgglomerate_Indirect(true); + + /*--- We set the value of the child ---*/ + + node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint); + nChildren++; + + /*--- Update the queue with the new control volume (remove the CV and + increase the priority of the neighbors) ---*/ + + MGQueue_InnerCV.Update(CVPoint, fine_grid); + + } + } + + /*--- Update the number of control of childrens ---*/ + + node[Index_CoarseCV]->SetnChildren_CV(nChildren); + Index_CoarseCV++; + } + else { + + /*--- The seed point can not be agglomerated because of size, domain, streching, etc. + move the point to the lowest priority ---*/ + + MGQueue_InnerCV.MoveCV(iPoint, -1); + } + + } + + /*--- Add all the elements that have not being agglomerated, in the previous stage ---*/ + + for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) { + if ((fine_grid->node[iPoint]->GetAgglomerate() == false) && (fine_grid->node[iPoint]->GetDomain())) { + + nChildren = 1; + fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV); + if (fine_grid->node[iPoint]->GetAgglomerate_Indirect()) + node[Index_CoarseCV]->SetAgglomerate_Indirect(true); + node[Index_CoarseCV]->SetChildren_CV(0, iPoint); + node[Index_CoarseCV]->SetnChildren_CV(nChildren); + Index_CoarseCV++; + + } + } + + nPointDomain = Index_CoarseCV; + + /*--- Check that there are no hanging nodes ---*/ + + unsigned long iFinePoint, iFinePoint_Neighbor, iCoarsePoint, iCoarsePoint_Complete; + unsigned short iChildren; + + /*--- Find the point surrounding a point ---*/ + + for (iCoarsePoint = 0; iCoarsePoint < nPointDomain; iCoarsePoint ++) { + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + for (iNode = 0; iNode < fine_grid->node[iFinePoint]->GetnPoint(); iNode ++) { + iFinePoint_Neighbor = fine_grid->node[iFinePoint]->GetPoint(iNode); + iParent = fine_grid->node[iFinePoint_Neighbor]->GetParent_CV(); + if (iParent != iCoarsePoint) node[iCoarsePoint]->SetPoint(iParent); + } + } + } + + /*--- Detect isolated points and merge them with its correct neighbor ---*/ + + for (iCoarsePoint = 0; iCoarsePoint < nPointDomain; iCoarsePoint ++) { + + if (node[iCoarsePoint]->GetnPoint() == 1) { + + /*--- Find the neighbor of the isolated point. This neighbor is the right control volume ---*/ + + iCoarsePoint_Complete = node[iCoarsePoint]->GetPoint(0); + + /*--- Add the children to the connected control volume (and modify it parent indexing). + Identify the child CV from the finest grid and added to the correct control volume. + Set the parent CV of iFinePoint. Instead of using the original + (iCoarsePoint) one use the new one (iCoarsePoint_Complete) ---*/ + + nChildren = node[iCoarsePoint_Complete]->GetnChildren_CV(); + + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + node[iCoarsePoint_Complete]->SetChildren_CV(nChildren, iFinePoint); + nChildren++; + fine_grid->node[iFinePoint]->SetParent_CV(iCoarsePoint_Complete); + } + + /*--- Update the number of children control volumes ---*/ + + node[iCoarsePoint_Complete]->SetnChildren_CV(nChildren); + node[iCoarsePoint]->SetnChildren_CV(0); + + } + } + + // unsigned long iPointFree = nPointDomain-1; + // iCoarsePoint = 0; + // + // do { + // + // if (node[iCoarsePoint]->GetnChildren_CV() == 0) { + // + // while (node[iPointFree]->GetnChildren_CV() == 0) { + // Index_CoarseCV--; + // iPointFree--; + // } + // + // nChildren = node[iPointFree]->GetnChildren_CV(); + // for (iChildren = 0; iChildren < nChildren; iChildren ++) { + // iFinePoint = node[iPointFree]->GetChildren_CV(iChildren); + // node[iCoarsePoint]->SetChildren_CV(iChildren, iFinePoint); + // fine_grid->node[iFinePoint]->SetParent_CV(iCoarsePoint); + // } + // node[iCoarsePoint]->SetnChildren_CV(nChildren); + // node[iPointFree]->SetnChildren_CV(0); + // + // Index_CoarseCV--; + // iPointFree--; + // + // } + // + // iCoarsePoint++; + // + // } while ((iCoarsePoint-1) < Index_CoarseCV); + // + // nPointDomain = Index_CoarseCV; + + /*--- Reset the point surrounding a point ---*/ + + for (iCoarsePoint = 0; iCoarsePoint < nPointDomain; iCoarsePoint ++) { + node[iCoarsePoint]->ResetPoint(); + } + + /*--- Dealing with MPI parallelization, the objective is that the received nodes must be agglomerated + in the same way as the donor nodes. Send the node agglomeration information of the donor + (parent and children), Sending only occurs with MPI ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = fine_grid->nVertex[MarkerS]; nVertexR = fine_grid->nVertex[MarkerR]; + nBufferS_Vector = nVertexS; nBufferR_Vector = nVertexR; + + /*--- Allocate Receive and send buffers ---*/ + + Buffer_Receive_Children = new unsigned long [nBufferR_Vector]; + Buffer_Send_Children = new unsigned long [nBufferS_Vector]; + + Buffer_Receive_Parent = new unsigned long [nBufferR_Vector]; + Buffer_Send_Parent = new unsigned long [nBufferS_Vector]; + + /*--- Copy the information that should be sended ---*/ + + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = fine_grid->vertex[MarkerS][iVertex]->GetNode(); + Buffer_Send_Children[iVertex] = iPoint; + Buffer_Send_Parent[iVertex] = fine_grid->node[iPoint]->GetParent_CV(); + } + +#ifdef HAVE_MPI + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Children, nBufferS_Vector, MPI_UNSIGNED_LONG, send_to,0, + Buffer_Receive_Children, nBufferR_Vector, MPI_UNSIGNED_LONG, receive_from,0, MPI_COMM_WORLD, &status); + SU2_MPI::Sendrecv(Buffer_Send_Parent, nBufferS_Vector, MPI_UNSIGNED_LONG, send_to,1, + Buffer_Receive_Parent, nBufferR_Vector, MPI_UNSIGNED_LONG, receive_from,1, MPI_COMM_WORLD, &status); +#else + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + Buffer_Receive_Children[iVertex] = Buffer_Send_Children[iVertex]; + Buffer_Receive_Parent[iVertex] = Buffer_Send_Parent[iVertex]; + } +#endif + + /*--- Deallocate send buffer ---*/ + + delete [] Buffer_Send_Children; + delete [] Buffer_Send_Parent; + + /*--- Create a list of the parent nodes without repeated parents ---*/ + + Aux_Parent.clear(); + for (iVertex = 0; iVertex < nVertexR; iVertex++) + Aux_Parent.push_back (Buffer_Receive_Parent[iVertex]); + + sort(Aux_Parent.begin(), Aux_Parent.end()); + it = unique(Aux_Parent.begin(), Aux_Parent.end()); + Aux_Parent.resize(it - Aux_Parent.begin()); + + /*--- Allocate some structures ---*/ + + Parent_Remote = new unsigned long[nVertexR]; + Children_Remote = new unsigned long[nVertexR]; + Parent_Local = new unsigned long[nVertexR]; + Children_Local = new unsigned long[nVertexR]; + + /*--- Create the local vector and remote for the parents and the children ---*/ + + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + Parent_Remote[iVertex] = Buffer_Receive_Parent[iVertex]; + + /*--- We use the same sorting as in the donor domain ---*/ + + for (jVertex = 0; jVertex < Aux_Parent.size(); jVertex++) { + if (Parent_Remote[iVertex] == Aux_Parent[jVertex]) { + Parent_Local[iVertex] = jVertex + Index_CoarseCV; + break; + } + } + + Children_Remote[iVertex] = Buffer_Receive_Children[iVertex]; + Children_Local[iVertex] = fine_grid->vertex[MarkerR][iVertex]->GetNode(); + + } + + Index_CoarseCV += Aux_Parent.size(); + + nChildren_MPI = new unsigned short [Index_CoarseCV]; + for (iParent = 0; iParent < Index_CoarseCV; iParent++) + nChildren_MPI[iParent] = 0; + + /*--- Create the final structure ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Be careful, it is possible that a node change the agglomeration configuration, the priority + is always, when receive the information ---*/ + + fine_grid->node[Children_Local[iVertex]]->SetParent_CV(Parent_Local[iVertex]); + node[Parent_Local[iVertex]]->SetChildren_CV(nChildren_MPI[Parent_Local[iVertex]], Children_Local[iVertex]); + nChildren_MPI[Parent_Local[iVertex]]++; + node[Parent_Local[iVertex]]->SetnChildren_CV(nChildren_MPI[Parent_Local[iVertex]]); + node[Parent_Local[iVertex]]->SetDomain(false); + + } + + /*--- Deallocate auxiliar structures ---*/ + + delete[] nChildren_MPI; + delete[] Parent_Remote; + delete[] Children_Remote; + delete[] Parent_Local; + delete[] Children_Local; + + /*--- Deallocate receive buffer ---*/ + + delete [] Buffer_Receive_Children; + delete [] Buffer_Receive_Parent; + + } + + } + + /*--- Update the number of points after the MPI agglomeration ---*/ + + nPoint = Index_CoarseCV; + + /*--- Console output with the summary of the agglomeration ---*/ + + Local_nPointCoarse = nPoint; + Local_nPointFine = fine_grid->GetnPoint(); + +#ifdef HAVE_MPI + SU2_MPI::Allreduce(&Local_nPointCoarse, &Global_nPointCoarse, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&Local_nPointFine, &Global_nPointFine, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); +#else + Global_nPointCoarse = Local_nPointCoarse; + Global_nPointFine = Local_nPointFine; +#endif + + su2double Coeff = 1.0, CFL = 0.0, factor = 1.5; + + if (iMesh != MESH_0) { + if (nDim == 2) Coeff = pow(su2double(Global_nPointFine)/su2double(Global_nPointCoarse), 1./2.); + if (nDim == 3) Coeff = pow(su2double(Global_nPointFine)/su2double(Global_nPointCoarse), 1./3.); + CFL = factor*config->GetCFL(iMesh-1)/Coeff; + config->SetCFL(iMesh, CFL); + } + + su2double ratio = su2double(Global_nPointFine)/su2double(Global_nPointCoarse); + + if (((nDim == 2) && (ratio < 2.5)) || + ((nDim == 3) && (ratio < 2.5))) { + config->SetMGLevels(iMesh-1); + } + else { + if (rank == MASTER_NODE) { + if (iMesh == 1) cout <<"MG level: "<< iMesh-1 <<" -> CVs: " << Global_nPointFine << ". Agglomeration rate 1/1.00. CFL "<< config->GetCFL(iMesh-1) <<"." << endl; + cout <<"MG level: "<< iMesh <<" -> CVs: " << Global_nPointCoarse << ". Agglomeration rate 1/" << ratio <<". CFL "<< CFL <<"." << endl; + } + } + + delete [] copy_marker; + +} + + +CMultiGridGeometry::~CMultiGridGeometry(void) { + +} + +bool CMultiGridGeometry::SetBoundAgglomeration(unsigned long CVPoint, short marker_seed, CGeometry *fine_grid, CConfig *config) { + + bool agglomerate_CV = false; + unsigned short counter, jMarker; + + unsigned short nMarker_Max = config->GetnMarker_Max(); + + unsigned short *copy_marker = new unsigned short [nMarker_Max]; + + /*--- Basic condition, the element has not being previously agglomerated, it belongs to the domain, + and has passed some basic geometrical check ---*/ + + if ((fine_grid->node[CVPoint]->GetAgglomerate() == false) && + (fine_grid->node[CVPoint]->GetDomain()) && + (GeometricalCheck(CVPoint, fine_grid, config))) { + + /*--- If the element belong to the boundary, we must be careful ---*/ + + if (fine_grid->node[CVPoint]->GetBoundary()) { + + /*--- Identify the markers of the vertex that we want to agglomerate ---*/ + + counter = 0; + for (jMarker = 0; jMarker < fine_grid->GetnMarker(); jMarker ++) + if (fine_grid->node[CVPoint]->GetVertex(jMarker) != -1) { + copy_marker[counter] = jMarker; + counter++; + } + + /*--- The basic condition is that the aglomerated vertex must have the same physical marker, + but eventually a send-receive condition ---*/ + + /*--- Only one marker in the vertex that is going to be aglomerated ---*/ + + if (counter == 1) { + + /*--- We agglomerate if there is only a marker and is the same marker as the seed marker ---*/ + + if (copy_marker[0] == marker_seed) + agglomerate_CV = true; + + /*--- If there is only a marker, but the marker is the SEND_RECEIVE ---*/ + + if (config->GetMarker_All_KindBC(copy_marker[0]) == SEND_RECEIVE) + agglomerate_CV = true; + + } + + /*--- If there are two markers in the vertex that is going to be aglomerated ---*/ + + if (counter == 2) { + + /*--- First we verify that the seed is a physical boundary ---*/ + + if (config->GetMarker_All_KindBC(marker_seed) != SEND_RECEIVE) { + + /*--- Then we check that one of the marker is equal to the seed marker, and the other is send/receive ---*/ + + if (((copy_marker[0] == marker_seed) && (config->GetMarker_All_KindBC(copy_marker[1]) == SEND_RECEIVE)) || + ((config->GetMarker_All_KindBC(copy_marker[0]) == SEND_RECEIVE) && (copy_marker[1] == marker_seed))) + agglomerate_CV = true; + } + + } + + } + + /*--- If the element belong to the domain, it is allways aglomerated ---*/ + + else { agglomerate_CV = true; } + + } + + delete [] copy_marker; + + return agglomerate_CV; + +} + + +bool CMultiGridGeometry::GeometricalCheck(unsigned long iPoint, CGeometry *fine_grid, CConfig *config) { + + su2double max_dimension = 1.2; + + /*--- Evaluate the total size of the element ---*/ + + bool Volume = true; + su2double ratio = pow(fine_grid->node[iPoint]->GetVolume(), 1.0/su2double(nDim))*max_dimension; + su2double limit = pow(config->GetDomainVolume(), 1.0/su2double(nDim)); + if ( ratio > limit ) Volume = false; + + /*--- Evaluate the stretching of the element ---*/ + + bool Stretching = true; + + /* unsigned short iNode, iDim; + unsigned long jPoint; + su2double *Coord_i = fine_grid->node[iPoint]->GetCoord(); + su2double max_dist = 0.0 ; su2double min_dist = 1E20; + for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { + jPoint = fine_grid->node[iPoint]->GetPoint(iNode); + su2double *Coord_j = fine_grid->node[jPoint]->GetCoord(); + su2double distance = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + distance += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); + distance = sqrt(distance); + max_dist = max(distance, max_dist); + min_dist = min(distance, min_dist); + } + if ( max_dist/min_dist > 100.0 ) Stretching = false;*/ + + return (Stretching && Volume); + +} + +void CMultiGridGeometry::SetSuitableNeighbors(vector *Suitable_Indirect_Neighbors, unsigned long iPoint, + unsigned long Index_CoarseCV, CGeometry *fine_grid) { + + unsigned long jPoint, kPoint, lPoint; + unsigned short iNode, jNode, iNeighbor, jNeighbor, kNode; + bool SecondNeighborSeed, ThirdNeighborSeed; + vector::iterator it; + + /*--- Create a list with the first neighbors, including the seed ---*/ + + vector First_Neighbor_Points; + First_Neighbor_Points.push_back(iPoint); + for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { + jPoint = fine_grid->node[iPoint]->GetPoint(iNode); + First_Neighbor_Points.push_back(jPoint); + } + + /*--- Create a list with the second neighbors, without first, and seed neighbors ---*/ + + vector Second_Neighbor_Points, Second_Origin_Points, Suitable_Second_Neighbors; + + for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { + jPoint = fine_grid->node[iPoint]->GetPoint(iNode); + + for (jNode = 0; jNode < fine_grid->node[jPoint]->GetnPoint(); jNode ++) { + kPoint = fine_grid->node[jPoint]->GetPoint(jNode); + + /*--- Check that the second neighbor do not belong to the first neighbor or the seed ---*/ + + SecondNeighborSeed = true; + for (iNeighbor = 0; iNeighbor < First_Neighbor_Points.size(); iNeighbor ++) + if (kPoint == First_Neighbor_Points[iNeighbor]) { + SecondNeighborSeed = false; break; + } + + if (SecondNeighborSeed) { + Second_Neighbor_Points.push_back(kPoint); + Second_Origin_Points.push_back(jPoint); + } + + } + } + + /*--- Identify those second neighbors that are repeated (candidate to be added) ---*/ + + for (iNeighbor = 0; iNeighbor < Second_Neighbor_Points.size(); iNeighbor ++) + + for (jNeighbor = 0; jNeighbor < Second_Neighbor_Points.size(); jNeighbor ++) + + /*--- Repeated second neighbor with different origin ---*/ + + if ((Second_Neighbor_Points[iNeighbor] == Second_Neighbor_Points[jNeighbor]) && + (Second_Origin_Points[iNeighbor] != Second_Origin_Points[jNeighbor]) && + (iNeighbor < jNeighbor)) { + + Suitable_Indirect_Neighbors->push_back(Second_Neighbor_Points[iNeighbor]); + + /*--- Create alist with the suitable second neighbor, that we will use + to compute the third neighbors --*/ + + Suitable_Second_Neighbors.push_back(Second_Neighbor_Points[iNeighbor]); + + } + + + /*--- Remove repeated from the suitable second neighbors ---*/ + + sort(Suitable_Second_Neighbors.begin(), Suitable_Second_Neighbors.end()); + it = unique(Suitable_Second_Neighbors.begin(), Suitable_Second_Neighbors.end()); + Suitable_Second_Neighbors.resize(it - Suitable_Second_Neighbors.begin()); + + /*--- Remove repeated from first neighbors ---*/ + + sort(First_Neighbor_Points.begin(), First_Neighbor_Points.end()); + it = unique(First_Neighbor_Points.begin(), First_Neighbor_Points.end()); + First_Neighbor_Points.resize(it - First_Neighbor_Points.begin()); + + /*--- Create a list with the third neighbors, without first, second, and seed neighbors ---*/ + + vector Third_Neighbor_Points, Third_Origin_Points; + + for (jNode = 0; jNode < Suitable_Second_Neighbors.size(); jNode ++) { + kPoint = Suitable_Second_Neighbors[jNode]; + + for (kNode = 0; kNode < fine_grid->node[kPoint]->GetnPoint(); kNode ++) { + lPoint = fine_grid->node[kPoint]->GetPoint(kNode); + + /*--- Check that the third neighbor do not belong to the first neighbors or the seed ---*/ + + ThirdNeighborSeed = true; + + for (iNeighbor = 0; iNeighbor < First_Neighbor_Points.size(); iNeighbor ++) + if (lPoint == First_Neighbor_Points[iNeighbor]) { + ThirdNeighborSeed = false; + break; + } + + /*--- Check that the third neighbor do not belong to the second neighbors ---*/ + + for (iNeighbor = 0; iNeighbor < Suitable_Second_Neighbors.size(); iNeighbor ++) + if (lPoint == Suitable_Second_Neighbors[iNeighbor]) { + ThirdNeighborSeed = false; + break; + } + + if (ThirdNeighborSeed) { + Third_Neighbor_Points.push_back(lPoint); + Third_Origin_Points.push_back(kPoint); + } + + } + } + + /*--- Identify those third neighbors that are repeated (candidate to be added) ---*/ + + for (iNeighbor = 0; iNeighbor < Third_Neighbor_Points.size(); iNeighbor ++) + for (jNeighbor = 0; jNeighbor < Third_Neighbor_Points.size(); jNeighbor ++) + + /*--- Repeated second neighbor with different origin ---*/ + + if ((Third_Neighbor_Points[iNeighbor] == Third_Neighbor_Points[jNeighbor]) && + (Third_Origin_Points[iNeighbor] != Third_Origin_Points[jNeighbor]) && + (iNeighbor < jNeighbor)) { + + Suitable_Indirect_Neighbors->push_back(Third_Neighbor_Points[iNeighbor]); + + } + + /*--- Remove repeated from Suitable Indirect Neighbors List ---*/ + + sort(Suitable_Indirect_Neighbors->begin(), Suitable_Indirect_Neighbors->end()); + it = unique(Suitable_Indirect_Neighbors->begin(), Suitable_Indirect_Neighbors->end()); + Suitable_Indirect_Neighbors->resize(it - Suitable_Indirect_Neighbors->begin()); + +} + +void CMultiGridGeometry::SetPoint_Connectivity(CGeometry *fine_grid) { + + unsigned long iFinePoint, iFinePoint_Neighbor, iParent, iCoarsePoint; + unsigned short iChildren, iNode; + + /*--- Set the point surrounding a point ---*/ + + for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) { + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + for (iNode = 0; iNode < fine_grid->node[iFinePoint]->GetnPoint(); iNode ++) { + iFinePoint_Neighbor = fine_grid->node[iFinePoint]->GetPoint(iNode); + iParent = fine_grid->node[iFinePoint_Neighbor]->GetParent_CV(); + if (iParent != iCoarsePoint) node[iCoarsePoint]->SetPoint(iParent); + } + } + } + + /*--- Set the number of neighbors variable, this is + important for JST and multigrid in parallel ---*/ + + for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) + node[iCoarsePoint]->SetnNeighbor(node[iCoarsePoint]->GetnPoint()); + +} + +void CMultiGridGeometry::SetVertex(CGeometry *fine_grid, CConfig *config) { + unsigned long iVertex, iFinePoint, iCoarsePoint; + unsigned short iMarker, iMarker_Tag, iChildren; + + nMarker = fine_grid->GetnMarker(); + unsigned short nMarker_Max = config->GetnMarker_Max(); + + /*--- If any children node belong to the boundary then the entire control + volume will belong to the boundary ---*/ + for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + if (fine_grid->node[iFinePoint]->GetBoundary()) { + node[iCoarsePoint]->SetBoundary(nMarker); + break; + } + } + + vertex = new CVertex**[nMarker]; + nVertex = new unsigned long [nMarker]; + + Tag_to_Marker = new string [nMarker_Max]; + for (iMarker_Tag = 0; iMarker_Tag < nMarker_Max; iMarker_Tag++) + Tag_to_Marker[iMarker_Tag] = fine_grid->GetMarker_Tag(iMarker_Tag); + + /*--- Compute the number of vertices to do the dimensionalization ---*/ + for (iMarker = 0; iMarker < nMarker; iMarker++) nVertex[iMarker] = 0; + + + for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) { + if (node[iCoarsePoint]->GetBoundary()) { + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + for (iMarker = 0; iMarker < nMarker; iMarker ++) { + if ((fine_grid->node[iFinePoint]->GetVertex(iMarker) != -1) && (node[iCoarsePoint]->GetVertex(iMarker) == -1)) { + iVertex = nVertex[iMarker]; + node[iCoarsePoint]->SetVertex(iVertex, iMarker); + nVertex[iMarker]++; + } + } + } + } + } + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + vertex[iMarker] = new CVertex* [fine_grid->GetnVertex(iMarker)+1]; + nVertex[iMarker] = 0; + } + + for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) + if (node[iCoarsePoint]->GetBoundary()) + for (iMarker = 0; iMarker < nMarker; iMarker ++) + node[iCoarsePoint]->SetVertex(-1, iMarker); + + for (iMarker = 0; iMarker < nMarker; iMarker++) nVertex[iMarker] = 0; + + for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) + if (node[iCoarsePoint]->GetBoundary()) + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + for (iMarker = 0; iMarker < fine_grid->GetnMarker(); iMarker ++) { + if ((fine_grid->node[iFinePoint]->GetVertex(iMarker) != -1) && (node[iCoarsePoint]->GetVertex(iMarker) == -1)) { + iVertex = nVertex[iMarker]; + vertex[iMarker][iVertex] = new CVertex(iCoarsePoint, nDim); + node[iCoarsePoint]->SetVertex(iVertex, iMarker); + + /*--- Set the transformation to apply ---*/ + unsigned long ChildVertex = fine_grid->node[iFinePoint]->GetVertex(iMarker); + unsigned short RotationKind = fine_grid->vertex[iMarker][ChildVertex]->GetRotation_Type(); + vertex[iMarker][iVertex]->SetRotation_Type(RotationKind); + nVertex[iMarker]++; + } + } + } +} + +void CMultiGridGeometry::MatchNearField(CConfig *config) { + + unsigned short iMarker; + unsigned long iVertex, iPoint; + int iProcessor; + +#ifndef HAVE_MPI + iProcessor = MASTER_NODE; +#else + MPI_Comm_rank(MPI_COMM_WORLD, &iProcessor); +#endif + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + vertex[iMarker][iVertex]->SetDonorPoint(iPoint, iProcessor); + } + } + } + } + +} + +void CMultiGridGeometry::MatchActuator_Disk(CConfig *config) { + + unsigned short iMarker; + unsigned long iVertex, iPoint; + int iProcessor; + +#ifndef HAVE_MPI + iProcessor = MASTER_NODE; +#else + MPI_Comm_rank(MPI_COMM_WORLD, &iProcessor); +#endif + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_KindBC(iMarker) == ACTDISK_INLET) || + (config->GetMarker_All_KindBC(iMarker) == ACTDISK_OUTLET)) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + vertex[iMarker][iVertex]->SetDonorPoint(iPoint, iProcessor); + } + } + } + } + +} + +void CMultiGridGeometry::MatchInterface(CConfig *config) { + + unsigned short iMarker; + unsigned long iVertex, iPoint; + int iProcessor; + +#ifndef HAVE_MPI + iProcessor = MASTER_NODE; +#else + MPI_Comm_rank(MPI_COMM_WORLD, &iProcessor); +#endif + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + vertex[iMarker][iVertex]->SetDonorPoint(iPoint, iProcessor); + } + } + } + } + +} + + +void CMultiGridGeometry::SetControlVolume(CConfig *config, CGeometry *fine_grid, unsigned short action) { + + unsigned long iFinePoint, iFinePoint_Neighbor, iCoarsePoint, iEdge, iParent; + long FineEdge, CoarseEdge; + unsigned short iChildren, iNode, iDim; + bool change_face_orientation; + su2double *Normal, Coarse_Volume, Area, *NormalFace = NULL; + Normal = new su2double [nDim]; + + /*--- Compute the area of the coarse volume ---*/ + for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) { + node[iCoarsePoint]->SetVolume(0.0); + Coarse_Volume = 0.0; + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + Coarse_Volume += fine_grid->node[iFinePoint]->GetVolume(); + } + node[iCoarsePoint]->SetVolume(Coarse_Volume); + } + + /*--- Update or not the values of faces at the edge ---*/ + if (action != ALLOCATE) { + for (iEdge=0; iEdge < nEdge; iEdge++) + edge[iEdge]->SetZeroValues(); + } + + for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + + for (iNode = 0; iNode < fine_grid->node[iFinePoint]->GetnPoint(); iNode ++) { + iFinePoint_Neighbor = fine_grid->node[iFinePoint]->GetPoint(iNode); + iParent = fine_grid->node[iFinePoint_Neighbor]->GetParent_CV(); + if ((iParent != iCoarsePoint) && (iParent < iCoarsePoint)) { + + FineEdge = fine_grid->FindEdge(iFinePoint, iFinePoint_Neighbor); + + change_face_orientation = false; + if (iFinePoint < iFinePoint_Neighbor) change_face_orientation = true; + + CoarseEdge = FindEdge(iParent, iCoarsePoint); + + fine_grid->edge[FineEdge]->GetNormal(Normal); + + if (change_face_orientation) { + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + edge[CoarseEdge]->AddNormal(Normal); + } + else { + edge[CoarseEdge]->AddNormal(Normal); + } + } + } + } + delete[] Normal; + + /*--- Check if there is a normal with null area ---*/ + + for (iEdge = 0; iEdge < nEdge; iEdge++) { + NormalFace = edge[iEdge]->GetNormal(); + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += NormalFace[iDim]*NormalFace[iDim]; + Area = sqrt(Area); + if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS; + } + +} + +void CMultiGridGeometry::SetBoundControlVolume(CConfig *config, CGeometry *fine_grid, unsigned short action) { + unsigned long iCoarsePoint, iFinePoint, FineVertex, iVertex; + unsigned short iMarker, iChildren, iDim; + su2double *Normal, Area, *NormalFace = NULL; + + Normal = new su2double [nDim]; + + if (action != ALLOCATE) { + for (iMarker = 0; iMarker < nMarker; iMarker++) + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) + vertex[iMarker][iVertex]->SetZeroValues(); + } + + for (iMarker = 0; iMarker < nMarker; iMarker ++) + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iCoarsePoint = vertex[iMarker][iVertex]->GetNode(); + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + if (fine_grid->node[iFinePoint]->GetVertex(iMarker)!=-1) { + FineVertex = fine_grid->node[iFinePoint]->GetVertex(iMarker); + fine_grid->vertex[iMarker][FineVertex]->GetNormal(Normal); + vertex[iMarker][iVertex]->AddNormal(Normal); + } + } + } + + delete[] Normal; + + /*--- Check if there is a normal with null area ---*/ + for (iMarker = 0; iMarker < nMarker; iMarker ++) + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + NormalFace = vertex[iMarker][iVertex]->GetNormal(); + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += NormalFace[iDim]*NormalFace[iDim]; + Area = sqrt(Area); + if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS; + } + +} + +void CMultiGridGeometry::SetCoord(CGeometry *geometry) { + unsigned long Point_Fine, Point_Coarse; + unsigned short iChildren, iDim; + su2double Area_Parent, Area_Children; + su2double *Coordinates_Fine, *Coordinates; + Coordinates = new su2double[nDim]; + + for (Point_Coarse = 0; Point_Coarse < GetnPoint(); Point_Coarse++) { + Area_Parent = node[Point_Coarse]->GetVolume(); + for (iDim = 0; iDim < nDim; iDim++) Coordinates[iDim] = 0.0; + for (iChildren = 0; iChildren < node[Point_Coarse]->GetnChildren_CV(); iChildren++) { + Point_Fine = node[Point_Coarse]->GetChildren_CV(iChildren); + Area_Children = geometry->node[Point_Fine]->GetVolume(); + Coordinates_Fine = geometry->node[Point_Fine]->GetCoord(); + for (iDim = 0; iDim < nDim; iDim++) + Coordinates[iDim] += Coordinates_Fine[iDim]*Area_Children/Area_Parent; + } + for (iDim = 0; iDim < nDim; iDim++) + node[Point_Coarse]->SetCoord(iDim, Coordinates[iDim]); + } + delete[] Coordinates; +} + +void CMultiGridGeometry::SetRotationalVelocity(CConfig *config, unsigned short val_iZone) { + + unsigned long iPoint_Coarse; + su2double *RotVel, Distance[3] = {0.0,0.0,0.0}, *Coord; + su2double Center[3] = {0.0,0.0,0.0}, Omega[3] = {0.0,0.0,0.0}, L_Ref; + RotVel = new su2double [3]; + + /*--- Center of rotation & angular velocity vector from config. ---*/ + + Center[0] = config->GetMotion_Origin_X(val_iZone); + Center[1] = config->GetMotion_Origin_Y(val_iZone); + Center[2] = config->GetMotion_Origin_Z(val_iZone); + Omega[0] = config->GetRotation_Rate_X(val_iZone)/config->GetOmega_Ref(); + Omega[1] = config->GetRotation_Rate_Y(val_iZone)/config->GetOmega_Ref(); + Omega[2] = config->GetRotation_Rate_Z(val_iZone)/config->GetOmega_Ref(); + L_Ref = config->GetLength_Ref(); + + /*--- Loop over all nodes and set the rotational velocity. ---*/ + + for (iPoint_Coarse = 0; iPoint_Coarse < GetnPoint(); iPoint_Coarse++) { + + /*--- Get the coordinates of the current node ---*/ + + Coord = node[iPoint_Coarse]->GetCoord(); + + /*--- Calculate the non-dim. distance from the rotation center ---*/ + + Distance[0] = (Coord[0]-Center[0])/L_Ref; + Distance[1] = (Coord[1]-Center[1])/L_Ref; + Distance[2] = (Coord[2]-Center[2])/L_Ref; + + /*--- Calculate the angular velocity as omega X r ---*/ + + RotVel[0] = Omega[1]*(Distance[2]) - Omega[2]*(Distance[1]); + RotVel[1] = Omega[2]*(Distance[0]) - Omega[0]*(Distance[2]); + RotVel[2] = Omega[0]*(Distance[1]) - Omega[1]*(Distance[0]); + + /*--- Store the grid velocity at this node ---*/ + + node[iPoint_Coarse]->SetGridVel(RotVel); + + } + + delete [] RotVel; + +} + +void CMultiGridGeometry::SetTranslationalVelocity(CConfig *config) { + + unsigned iDim; + unsigned long iPoint_Coarse; + su2double xDot[3]; + + /*--- Get the translational velocity vector from config ---*/ + + xDot[0] = config->GetTranslation_Rate_X(ZONE_0)/config->GetVelocity_Ref(); + xDot[1] = config->GetTranslation_Rate_Y(ZONE_0)/config->GetVelocity_Ref(); + xDot[2] = config->GetTranslation_Rate_Z(ZONE_0)/config->GetVelocity_Ref(); + + /*--- Loop over all nodes and set the translational velocity ---*/ + + for (iPoint_Coarse = 0; iPoint_Coarse < nPoint; iPoint_Coarse++) { + + /*--- Store the grid velocity at this node ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + node[iPoint_Coarse]->SetGridVel(iDim,xDot[iDim]); + + } + +} + +void CMultiGridGeometry::SetGridVelocity(CConfig *config, unsigned long iter) { + + /*--- Local variables ---*/ + + su2double *Coord_nP1 = NULL, *Coord_n = NULL, *Coord_nM1 = NULL; + su2double TimeStep, GridVel = 0.0; + unsigned long Point_Coarse; + unsigned short iDim; + + /*--- Compute the velocity of each node in the volume mesh ---*/ + + for (Point_Coarse = 0; Point_Coarse < GetnPoint(); Point_Coarse++) { + + /*--- Coordinates of the current point at n+1, n, & n-1 time levels ---*/ + + Coord_nM1 = node[Point_Coarse]->GetCoord_n1(); + Coord_n = node[Point_Coarse]->GetCoord_n(); + Coord_nP1 = node[Point_Coarse]->GetCoord(); + + /*--- Unsteady time step ---*/ + + TimeStep = config->GetDelta_UnstTimeND(); + + /*--- Compute mesh velocity with 1st or 2nd-order approximation ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + GridVel = ( Coord_nP1[iDim] - Coord_n[iDim] ) / TimeStep; + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + GridVel = ( 3.0*Coord_nP1[iDim] - 4.0*Coord_n[iDim] + + 1.0*Coord_nM1[iDim] ) / (2.0*TimeStep); + + /*--- Store grid velocity for this point ---*/ + + node[Point_Coarse]->SetGridVel(iDim, GridVel); + + } + } +} + +void CMultiGridGeometry::SetRestricted_GridVelocity(CGeometry *fine_mesh, CConfig *config) { + + /*--- Local variables ---*/ + unsigned short iDim, iChild; + unsigned long Point_Coarse, Point_Fine; + su2double Area_Parent, Area_Child, Grid_Vel[3], *Grid_Vel_Fine; + + /*--- Loop over all coarse mesh points ---*/ + for (Point_Coarse = 0; Point_Coarse < GetnPoint(); Point_Coarse++) { + Area_Parent = node[Point_Coarse]->GetVolume(); + + /*--- Zero out the grid velocity ---*/ + for (iDim = 0; iDim < nDim; iDim++) + Grid_Vel[iDim] = 0.0; + + /*--- Loop over all of the children for this coarse CV and compute + a grid velocity based on the values in the child CVs (fine mesh). ---*/ + for (iChild = 0; iChild < node[Point_Coarse]->GetnChildren_CV(); iChild++) { + Point_Fine = node[Point_Coarse]->GetChildren_CV(iChild); + Area_Child = fine_mesh->node[Point_Fine]->GetVolume(); + Grid_Vel_Fine = fine_mesh->node[Point_Fine]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + Grid_Vel[iDim] += Grid_Vel_Fine[iDim]*Area_Child/Area_Parent; + } + + /*--- Set the grid velocity for this coarse node. ---*/ + for (iDim = 0; iDim < nDim; iDim++) + node[Point_Coarse]->SetGridVel(iDim, Grid_Vel[iDim]); + } +} + + +void CMultiGridGeometry::FindNormal_Neighbor(CConfig *config) { + + unsigned short iMarker, iDim; + unsigned long iPoint, iVertex; + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE && + config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY && + config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY ) { + + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + + iPoint = vertex[iMarker][iVertex]->GetNode(); + + /*--- If the node belong to the domain ---*/ + if (node[iPoint]->GetDomain()) { + + /*--- Compute closest normal neighbor ---*/ + su2double cos_max, scalar_prod, norm_vect, norm_Normal, cos_alpha, diff_coord; + unsigned long Point_Normal = 0, jPoint; + unsigned short iNeigh; + su2double *Normal = vertex[iMarker][iVertex]->GetNormal(); + cos_max = -1.0; + for (iNeigh = 0; iNeigh < node[iPoint]->GetnPoint(); iNeigh++) { + jPoint = node[iPoint]->GetPoint(iNeigh); + scalar_prod = 0.0; norm_vect = 0.0; norm_Normal = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + diff_coord = node[jPoint]->GetCoord(iDim)-node[iPoint]->GetCoord(iDim); + scalar_prod += diff_coord*Normal[iDim]; + norm_vect += diff_coord*diff_coord; + norm_Normal += Normal[iDim]*Normal[iDim]; + } + norm_vect = sqrt(norm_vect); + norm_Normal = sqrt(norm_Normal); + cos_alpha = scalar_prod/(norm_vect*norm_Normal); + + /*--- Get maximum cosine (not minimum because normals are oriented inwards) ---*/ + if (cos_alpha >= cos_max) { + Point_Normal = jPoint; + cos_max = cos_alpha; + } + } + vertex[iMarker][iVertex]->SetNormal_Neighbor(Point_Normal); + } + } + } + } +} + + +void CMultiGridGeometry::SetGeometryPlanes(CConfig *config) { + bool loop_on; + unsigned short iMarker = 0; + su2double auxXCoord, auxYCoord, auxZCoord, *Face_Normal = NULL, auxArea, *Xcoord = NULL, *Ycoord = NULL, *Zcoord = NULL, *FaceArea = NULL; + unsigned long jVertex, iVertex, ixCoord, iPoint, iVertex_Wall, nVertex_Wall = 0; + + /*--- Compute the total number of points on the near-field ---*/ + nVertex_Wall = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) || + (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ) + nVertex_Wall += nVertex[iMarker]; + + + /*--- Create an array with all the coordinates, points, pressures, face area, + equivalent area, and nearfield weight ---*/ + Xcoord = new su2double[nVertex_Wall]; + Ycoord = new su2double[nVertex_Wall]; + if (nDim == 3) Zcoord = new su2double[nVertex_Wall]; + FaceArea = new su2double[nVertex_Wall]; + + /*--- Copy the boundary information to an array ---*/ + iVertex_Wall = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) || + (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ) + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + Xcoord[iVertex_Wall] = node[iPoint]->GetCoord(0); + Ycoord[iVertex_Wall] = node[iPoint]->GetCoord(1); + if (nDim==3) Zcoord[iVertex_Wall] = node[iPoint]->GetCoord(2); + Face_Normal = vertex[iMarker][iVertex]->GetNormal(); + FaceArea[iVertex_Wall] = fabs(Face_Normal[nDim-1]); + iVertex_Wall ++; + } + + + //vector XCoordList; + vector::iterator IterXCoordList; + + for (iVertex = 0; iVertex < nVertex_Wall; iVertex++) + XCoordList.push_back(Xcoord[iVertex]); + + sort( XCoordList.begin(), XCoordList.end()); + IterXCoordList = unique( XCoordList.begin(), XCoordList.end()); + XCoordList.resize( IterXCoordList - XCoordList.begin() ); + + /*--- Create vectors and distribute the values among the different PhiAngle queues ---*/ + Xcoord_plane.resize(XCoordList.size()); + Ycoord_plane.resize(XCoordList.size()); + if (nDim==3) Zcoord_plane.resize(XCoordList.size()); + FaceArea_plane.resize(XCoordList.size()); + Plane_points.resize(XCoordList.size()); + + + su2double dist_ratio; + unsigned long iCoord; + + /*--- Distribute the values among the different PhiAngles ---*/ + for (iPoint = 0; iPoint < nPoint; iPoint++) { + if (node[iPoint]->GetDomain()) { + loop_on = true; + for (ixCoord = 0; ixCoord < XCoordList.size()-1 && loop_on; ixCoord++) { + dist_ratio = (node[iPoint]->GetCoord(0) - XCoordList[ixCoord])/(XCoordList[ixCoord+1]- XCoordList[ixCoord]); + if (dist_ratio >= 0 && dist_ratio <= 1.0) { + if (dist_ratio <= 0.5) iCoord = ixCoord; + else iCoord = ixCoord+1; + Xcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(0) ); + Ycoord_plane[iCoord].push_back(node[iPoint]->GetCoord(1) ); + if (nDim==3) Zcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(2) ); + FaceArea_plane[iCoord].push_back(node[iPoint]->GetVolume()); ///// CHECK AREA CALCULATION + Plane_points[iCoord].push_back(iPoint ); + loop_on = false; + } + } + } + } + + unsigned long auxPoint; + /*--- Order the arrays in ascending values of y ---*/ + for (ixCoord = 0; ixCoord < XCoordList.size(); ixCoord++) + for (iVertex = 0; iVertex < Xcoord_plane[ixCoord].size(); iVertex++) + for (jVertex = 0; jVertex < Xcoord_plane[ixCoord].size() - 1 - iVertex; jVertex++) + if (Ycoord_plane[ixCoord][jVertex] > Ycoord_plane[ixCoord][jVertex+1]) { + auxXCoord = Xcoord_plane[ixCoord][jVertex]; Xcoord_plane[ixCoord][jVertex] = Xcoord_plane[ixCoord][jVertex+1]; Xcoord_plane[ixCoord][jVertex+1] = auxXCoord; + auxYCoord = Ycoord_plane[ixCoord][jVertex]; Ycoord_plane[ixCoord][jVertex] = Ycoord_plane[ixCoord][jVertex+1]; Ycoord_plane[ixCoord][jVertex+1] = auxYCoord; + auxPoint = Plane_points[ixCoord][jVertex]; Plane_points[ixCoord][jVertex] = Plane_points[ixCoord][jVertex+1]; Plane_points[ixCoord][jVertex+1] = auxPoint; + if (nDim==3) { + auxZCoord = Zcoord_plane[ixCoord][jVertex]; Zcoord_plane[ixCoord][jVertex] = Zcoord_plane[ixCoord][jVertex+1]; Zcoord_plane[ixCoord][jVertex+1] = auxZCoord; + } + auxArea = FaceArea_plane[ixCoord][jVertex]; FaceArea_plane[ixCoord][jVertex] = FaceArea_plane[ixCoord][jVertex+1]; FaceArea_plane[ixCoord][jVertex+1] = auxArea; + } + + /*--- Delete structures ---*/ + delete[] Xcoord; delete[] Ycoord; + if (nDim==3) delete[] Zcoord; + delete[] FaceArea; +} + +CPeriodicGeometry::CPeriodicGeometry(CGeometry *geometry, CConfig *config) { + unsigned long nElem_new, nPoint_new, jPoint, iPoint, iElem, jElem, iVertex, + nelem_triangle = 0, nelem_quad = 0, nelem_tetra = 0, nelem_hexa = 0, nelem_prism = 0, + nelem_pyramid = 0, iIndex, newElementsBound = 0; + unsigned short iMarker, nPeriodic = 0, iPeriodic; + su2double *center, *angles, rotMatrix[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}, + translation[3], *trans, theta, phi, psi, cosTheta, sinTheta, cosPhi, sinPhi, cosPsi, sinPsi, + dx, dy, dz, rotCoord[3], *Coord_i; + unsigned short nMarker_Max = config->GetnMarker_Max(); + + /*--- We only create the mirror structure for the second boundary ---*/ + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) { + /*--- Evaluate the number of periodic boundary conditions ---*/ + nPeriodic++; + } + } + bool *CreateMirror = new bool[nPeriodic+1]; + CreateMirror[0] = false; + for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { + if (iPeriodic <= nPeriodic/2) CreateMirror[iPeriodic] = false; + else CreateMirror[iPeriodic] = true; + } + + /*--- Write the number of dimensions of the problem ---*/ + nDim = geometry->GetnDim(); + + /*--- Copy the new boundary element information from the geometry class. + Be careful, as these are pointers to vectors/objects. ---*/ + nNewElem_BoundPer = geometry->nNewElem_Bound; + newBoundPer = geometry->newBound; + + /*--- Count the number of new boundary elements. ---*/ + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + newElementsBound += nNewElem_BoundPer[iMarker]; + + /*--- Loop over the original grid to perform the dimensionalizaton of the new vectors ---*/ + nElem_new = 0; nPoint_new = 0; + for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { + if (CreateMirror[iPeriodic]) { + nElem_new += geometry->PeriodicElem[iPeriodic].size(); + nPoint_new += geometry->PeriodicPoint[iPeriodic][0].size(); + } + } + + cout << "Number of new points: " << nPoint_new << "." << endl; + cout << "Number of new interior elements: " << nElem_new << "." << endl; + cout << "Number of new boundary elements added to preexisting markers: " << newElementsBound << "." << endl; + + /*--- Create a copy of the original grid ---*/ + elem = new CPrimalGrid*[geometry->GetnElem() + nElem_new]; + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + switch(geometry->elem[iElem]->GetVTK_Type()) { + case TRIANGLE: + elem[iElem] = new CTriangle(geometry->elem[iElem]->GetNode(0), + geometry->elem[iElem]->GetNode(1), + geometry->elem[iElem]->GetNode(2), 2); + nelem_triangle++; + break; + + case QUADRILATERAL: + elem[iElem] = new CQuadrilateral(geometry->elem[iElem]->GetNode(0), + geometry->elem[iElem]->GetNode(1), + geometry->elem[iElem]->GetNode(2), + geometry->elem[iElem]->GetNode(3), 2); + nelem_quad++; + break; + + case TETRAHEDRON: + elem[iElem] = new CTetrahedron(geometry->elem[iElem]->GetNode(0), + geometry->elem[iElem]->GetNode(1), + geometry->elem[iElem]->GetNode(2), + geometry->elem[iElem]->GetNode(3)); + nelem_tetra++; + break; + + case HEXAHEDRON: + elem[iElem] = new CHexahedron(geometry->elem[iElem]->GetNode(0), + geometry->elem[iElem]->GetNode(1), + geometry->elem[iElem]->GetNode(2), + geometry->elem[iElem]->GetNode(3), + geometry->elem[iElem]->GetNode(4), + geometry->elem[iElem]->GetNode(5), + geometry->elem[iElem]->GetNode(6), + geometry->elem[iElem]->GetNode(7)); + nelem_hexa++; + break; + + case PRISM: + elem[iElem] = new CPrism(geometry->elem[iElem]->GetNode(0), + geometry->elem[iElem]->GetNode(1), + geometry->elem[iElem]->GetNode(2), + geometry->elem[iElem]->GetNode(3), + geometry->elem[iElem]->GetNode(4), + geometry->elem[iElem]->GetNode(5)); + nelem_prism++; + break; + + case PYRAMID: + elem[iElem] = new CPyramid(geometry->elem[iElem]->GetNode(0), + geometry->elem[iElem]->GetNode(1), + geometry->elem[iElem]->GetNode(2), + geometry->elem[iElem]->GetNode(3), + geometry->elem[iElem]->GetNode(4)); + nelem_pyramid++; + break; + + } + } + + /*--- Create a list with all the points and the new index ---*/ + unsigned long *Index = new unsigned long [geometry->GetnPoint()]; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) Index[iPoint] = 0; + + for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { + if (CreateMirror[iPeriodic]) { + for (iIndex = 0; iIndex < geometry->PeriodicPoint[iPeriodic][0].size(); iIndex++) { + iPoint = geometry->PeriodicPoint[iPeriodic][0][iIndex]; + Index[iPoint] = geometry->PeriodicPoint[iPeriodic][1][iIndex]; + } + } + } + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) + if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + jPoint = geometry->vertex[iMarker][iVertex]->GetDonorPoint(); + Index[iPoint] = jPoint; + } + + /*--- Add the new elements due to the periodic boundary condtion ---*/ + iElem = geometry->GetnElem(); + + for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { + if (CreateMirror[iPeriodic]) { + for (iIndex = 0; iIndex < geometry->PeriodicElem[iPeriodic].size(); iIndex++) { + jElem = geometry->PeriodicElem[iPeriodic][iIndex]; + + switch(geometry->elem[jElem]->GetVTK_Type()) { + case TRIANGLE: + elem[iElem] = new CTriangle(Index[geometry->elem[jElem]->GetNode(0)], + Index[geometry->elem[jElem]->GetNode(1)], + Index[geometry->elem[jElem]->GetNode(2)], 2); + iElem++; nelem_triangle++; + break; + + case QUADRILATERAL: + elem[iElem] = new CQuadrilateral(Index[geometry->elem[jElem]->GetNode(0)], + Index[geometry->elem[jElem]->GetNode(1)], + Index[geometry->elem[jElem]->GetNode(2)], + Index[geometry->elem[jElem]->GetNode(3)], 2); + iElem++; nelem_quad++; + break; + + case TETRAHEDRON: + elem[iElem] = new CTetrahedron(Index[geometry->elem[jElem]->GetNode(0)], + Index[geometry->elem[jElem]->GetNode(1)], + Index[geometry->elem[jElem]->GetNode(2)], + Index[geometry->elem[jElem]->GetNode(3)]); + iElem++; nelem_tetra++; + break; + + case HEXAHEDRON: + elem[iElem] = new CHexahedron(Index[geometry->elem[jElem]->GetNode(0)], + Index[geometry->elem[jElem]->GetNode(1)], + Index[geometry->elem[jElem]->GetNode(2)], + Index[geometry->elem[jElem]->GetNode(3)], + Index[geometry->elem[jElem]->GetNode(4)], + Index[geometry->elem[jElem]->GetNode(5)], + Index[geometry->elem[jElem]->GetNode(6)], + Index[geometry->elem[jElem]->GetNode(7)]); + iElem++; nelem_hexa++; + break; + + case PRISM: + elem[iElem] = new CPrism(Index[geometry->elem[jElem]->GetNode(0)], + Index[geometry->elem[jElem]->GetNode(1)], + Index[geometry->elem[jElem]->GetNode(2)], + Index[geometry->elem[jElem]->GetNode(3)], + Index[geometry->elem[jElem]->GetNode(4)], + Index[geometry->elem[jElem]->GetNode(5)]); + iElem++; nelem_prism++; + break; + + case PYRAMID: + elem[iElem] = new CPyramid(Index[geometry->elem[jElem]->GetNode(0)], + Index[geometry->elem[jElem]->GetNode(1)], + Index[geometry->elem[jElem]->GetNode(2)], + Index[geometry->elem[jElem]->GetNode(3)], + Index[geometry->elem[jElem]->GetNode(4)]); + iElem++; nelem_pyramid++; + break; + + } + } + } + } + + nElem = geometry->GetnElem() + nElem_new; + + /*--- Add the old points ---*/ + node = new CPoint*[geometry->GetnPoint() + nPoint_new]; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { + if (geometry->GetnDim() == 2) + node[iPoint] = new CPoint(geometry->node[iPoint]->GetCoord(0), + geometry->node[iPoint]->GetCoord(1), iPoint, config); + if (geometry->GetnDim() == 3) + node[iPoint] = new CPoint(geometry->node[iPoint]->GetCoord(0), + geometry->node[iPoint]->GetCoord(1), + geometry->node[iPoint]->GetCoord(2), iPoint, config); + } + + /*--- Add the new points due to the periodic boundary condtion (only in the mirror part) ---*/ + for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { + if (CreateMirror[iPeriodic]) { + for (iIndex = 0; iIndex < geometry->PeriodicPoint[iPeriodic][0].size(); iIndex++) { + + /*--- From iPeriodic obtain the iMarker ---*/ + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) + if (iPeriodic == config->GetMarker_All_PerBound(iMarker)) break; + + /*--- Retrieve the supplied periodic information. ---*/ + center = config->GetPeriodicRotCenter(config->GetMarker_All_TagBound(iMarker)); + angles = config->GetPeriodicRotAngles(config->GetMarker_All_TagBound(iMarker)); + trans = config->GetPeriodicTranslation(config->GetMarker_All_TagBound(iMarker)); + + /*--- Store center - trans as it is constant and will be added on. + Note the subtraction, as this is the inverse translation. ---*/ + translation[0] = center[0] - trans[0]; + translation[1] = center[1] - trans[1]; + translation[2] = center[2] - trans[2]; + + /*--- Store angles separately for clarity. Compute sines/cosines. + Note the negative sign, as this is the inverse rotation. ---*/ + theta = -angles[0]; + phi = -angles[1]; + psi = -angles[2]; + + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; + rotMatrix[1][0] = cosPhi*sinPsi; + rotMatrix[2][0] = -sinPhi; + + rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; + rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; + rotMatrix[2][1] = sinTheta*cosPhi; + + rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Retrieve node information for this boundary point. ---*/ + iPoint = geometry->PeriodicPoint[iPeriodic][0][iIndex]; + jPoint = geometry->PeriodicPoint[iPeriodic][1][iIndex]; + Coord_i = geometry->node[iPoint]->GetCoord(); + + /*--- Get the position vector from rot center to point. ---*/ + dx = Coord_i[0] - center[0]; + dy = Coord_i[1] - center[1]; + if (nDim == 3) { + dz = Coord_i[2] - center[2]; + } else { + dz = 0.0; + } + + /*--- Compute transformed point coordinates. ---*/ + rotCoord[0] = rotMatrix[0][0]*dx + rotMatrix[0][1]*dy + rotMatrix[0][2]*dz + translation[0]; + rotCoord[1] = rotMatrix[1][0]*dx + rotMatrix[1][1]*dy + rotMatrix[1][2]*dz + translation[1]; + rotCoord[2] = rotMatrix[2][0]*dx + rotMatrix[2][1]*dy + rotMatrix[2][2]*dz + translation[2]; + + /*--- Save the new points with the new coordinates. ---*/ + if (geometry->GetnDim() == 2) + node[jPoint] = new CPoint(rotCoord[0], rotCoord[1], jPoint, config); + if (geometry->GetnDim() == 3) + node[jPoint] = new CPoint(rotCoord[0], rotCoord[1], rotCoord[2], jPoint, config); + + } + } + } + + nPoint = geometry->GetnPoint() + nPoint_new; + + /*--- Add the old boundary, reserving space for two new bc (send/recive periodic bc) ---*/ + nMarker = geometry->GetnMarker() + 2; + nElem_Bound = new unsigned long [nMarker]; + bound = new CPrimalGrid**[nMarker]; + Tag_to_Marker = new string [nMarker_Max]; + config->SetnMarker_All(nMarker); + + /*--- Copy the olf boundary ---*/ + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + + bound[iMarker] = new CPrimalGrid* [geometry->GetnElem_Bound(iMarker)]; + + for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { + if (geometry->bound[iMarker][iVertex]->GetVTK_Type() == LINE) + bound[iMarker][iVertex] = new CLine(geometry->bound[iMarker][iVertex]->GetNode(0), + geometry->bound[iMarker][iVertex]->GetNode(1), 2); + if (geometry->bound[iMarker][iVertex]->GetVTK_Type() == TRIANGLE) + bound[iMarker][iVertex] = new CTriangle(geometry->bound[iMarker][iVertex]->GetNode(0), + geometry->bound[iMarker][iVertex]->GetNode(1), + geometry->bound[iMarker][iVertex]->GetNode(2), 3); + if (geometry->bound[iMarker][iVertex]->GetVTK_Type() == QUADRILATERAL) + bound[iMarker][iVertex] = new CQuadrilateral(geometry->bound[iMarker][iVertex]->GetNode(0), + geometry->bound[iMarker][iVertex]->GetNode(1), + geometry->bound[iMarker][iVertex]->GetNode(2), + geometry->bound[iMarker][iVertex]->GetNode(3), 3); + } + + nElem_Bound[iMarker] = geometry->GetnElem_Bound(iMarker); + Tag_to_Marker[iMarker] = geometry->GetMarker_Tag(iMarker); + + } + + delete [] Index; + delete [] CreateMirror; + +} + +CPeriodicGeometry::~CPeriodicGeometry(void) { + unsigned long iElem_Bound; + unsigned short iMarker; + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + if (newBoundPer[iMarker][iElem_Bound] != NULL) delete [] newBoundPer[iMarker][iElem_Bound]; + } + } + if (newBoundPer != NULL) delete[] newBoundPer; + + if (nNewElem_BoundPer != NULL) delete[] nNewElem_BoundPer; + +} + +void CPeriodicGeometry::SetPeriodicBoundary(CGeometry *geometry, CConfig *config) { + unsigned short iMarker, iPeriodic, nPeriodic = 0, iMarkerSend, iMarkerReceive; + unsigned long iVertex, Counter_Send = 0, Counter_Receive = 0, iIndex; + + /*--- Compute the number of periodic bc on the geometry ---*/ + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) + nPeriodic++; + + /*--- First compute the Send/Receive boundaries, count the number of points ---*/ + Counter_Send = 0; Counter_Receive = 0; + for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { + if (geometry->PeriodicPoint[iPeriodic][0].size() != 0) + Counter_Send += geometry->PeriodicPoint[iPeriodic][0].size(); + if (geometry->PeriodicPoint[iPeriodic][1].size() != 0) + Counter_Receive += geometry->PeriodicPoint[iPeriodic][1].size(); + } + + /*--- Adimensionalization of the new boundaries ---*/ + iMarkerSend = nMarker - 2; iMarkerReceive = nMarker - 1; + config->SetMarker_All_SendRecv(iMarkerSend,1); + config->SetMarker_All_SendRecv(iMarkerReceive,-1); + nElem_Bound[iMarkerSend] = Counter_Send; + nElem_Bound[iMarkerReceive] = Counter_Receive; + bound[iMarkerSend] = new CPrimalGrid* [Counter_Send]; + bound[iMarkerReceive] = new CPrimalGrid* [Counter_Receive]; + + /*--- First we do the send ---*/ + iVertex = 0; + for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) + if (geometry->PeriodicPoint[iPeriodic][0].size() != 0) + for (iIndex = 0; iIndex < geometry->PeriodicPoint[iPeriodic][0].size(); iIndex++) { + bound[iMarkerSend][iVertex] = new CVertexMPI(geometry->PeriodicPoint[iPeriodic][0][iIndex], nDim); + bound[iMarkerSend][iVertex]->SetRotation_Type(iPeriodic); + iVertex++; + } + + /*--- Second we do the receive ---*/ + iVertex = 0; + for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) + if (geometry->PeriodicPoint[iPeriodic][1].size() != 0) + for (iIndex = 0; iIndex < geometry->PeriodicPoint[iPeriodic][1].size(); iIndex++) { + bound[iMarkerReceive][iVertex] = new CVertexMPI(geometry->PeriodicPoint[iPeriodic][1][iIndex], nDim); + bound[iMarkerReceive][iVertex]->SetRotation_Type(iPeriodic); + iVertex++; + } + +} + +void CPeriodicGeometry::SetMeshFile(CGeometry *geometry, CConfig *config, string val_mesh_out_filename) { + unsigned long iElem, iPoint, iElem_Bound, GhostPoints; + unsigned short iMarker, iNodes, iDim; + unsigned short iMarkerReceive, iPeriodic, nPeriodic = 0; + ofstream output_file; + string Grid_Marker; + char *cstr; + su2double *center, *angles, *transl; + + cstr = new char [val_mesh_out_filename.size()+1]; + strcpy (cstr, val_mesh_out_filename.c_str()); + + /*--- Open .su2 grid file ---*/ + output_file.precision(15); + output_file.open(cstr, ios::out); + + /*--- Ghost points, look at the nodes in the send receive ---*/ + iMarkerReceive = nMarker - 1; + GhostPoints = nElem_Bound[iMarkerReceive]; + + /*--- Change the numbering to guarantee that the all the receive + points are at the end of the file ---*/ + unsigned long OldnPoint = geometry->GetnPoint(); + unsigned long *NewSort = new unsigned long[nPoint]; + for (iPoint = 0; iPoint < nPoint; iPoint++) { + NewSort[iPoint] = iPoint; + } + + unsigned long Index = OldnPoint-1; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (bound[iMarker][0]->GetVTK_Type() == VERTEX) { + if (config->GetMarker_All_SendRecv(iMarker) < 0) { + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + if (bound[iMarker][iElem_Bound]->GetNode(0) < geometry->GetnPoint()) { + NewSort[bound[iMarker][iElem_Bound]->GetNode(0)] = Index; + NewSort[Index] = bound[iMarker][iElem_Bound]->GetNode(0); + Index--; + } + } + } + } + } + + + /*--- Write dimension, number of elements and number of points ---*/ + output_file << "NDIME= " << nDim << endl; + output_file << "NELEM= " << nElem << endl; + for (iElem = 0; iElem < nElem; iElem++) { + output_file << elem[iElem]->GetVTK_Type(); + for (iNodes = 0; iNodes < elem[iElem]->GetnNodes(); iNodes++) + output_file << "\t" << NewSort[elem[iElem]->GetNode(iNodes)]; + output_file << "\t"<GetCoord(iDim) ; + output_file << "\t" << iPoint << endl; + } + + output_file << "NMARK= " << nMarker << endl; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (bound[iMarker][0]->GetVTK_Type() != VERTEX) { + + Grid_Marker = config->GetMarker_All_TagBound(iMarker); + output_file << "MARKER_TAG= " << Grid_Marker << endl; + output_file << "MARKER_ELEMS= " << nElem_Bound[iMarker] + nNewElem_BoundPer[iMarker] << endl; + + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ; + for (iNodes = 0; iNodes < bound[iMarker][iElem_Bound]->GetnNodes()-1; iNodes++) + output_file << NewSort[bound[iMarker][iElem_Bound]->GetNode(iNodes)] << "\t" ; + iNodes = bound[iMarker][iElem_Bound]->GetnNodes()-1; + output_file << NewSort[bound[iMarker][iElem_Bound]->GetNode(iNodes)] << endl; + } + + /*--- Write any new elements at the end of the list. ---*/ + if (nNewElem_BoundPer[iMarker] > 0) { + for (iElem_Bound = 0; iElem_Bound < nNewElem_BoundPer[iMarker]; iElem_Bound++) { + output_file << newBoundPer[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ; + for (iNodes = 0; iNodes < newBoundPer[iMarker][iElem_Bound]->GetnNodes()-1; iNodes++) + output_file << NewSort[newBoundPer[iMarker][iElem_Bound]->GetNode(iNodes)] << "\t" ; + iNodes = newBoundPer[iMarker][iElem_Bound]->GetnNodes()-1; + output_file << NewSort[newBoundPer[iMarker][iElem_Bound]->GetNode(iNodes)] << endl; + } + } + + } + + if (bound[iMarker][0]->GetVTK_Type() == VERTEX) { + output_file << "MARKER_TAG= SEND_RECEIVE" << endl; + output_file << "MARKER_ELEMS= " << nElem_Bound[iMarker]<< endl; + if (config->GetMarker_All_SendRecv(iMarker) > 0) output_file << "SEND_TO= " << config->GetMarker_All_SendRecv(iMarker) << endl; + if (config->GetMarker_All_SendRecv(iMarker) < 0) output_file << "SEND_TO= " << config->GetMarker_All_SendRecv(iMarker) << endl; + + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" << + NewSort[bound[iMarker][iElem_Bound]->GetNode(0)] << "\t" << + bound[iMarker][iElem_Bound]->GetRotation_Type() << endl; + } + } + } + + /*--- Compute the number of periodic bc on the geometry ---*/ + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) + nPeriodic++; + + output_file << "NPERIODIC= " << nPeriodic + 1 << endl; + + /*--- Periodic 0 correspond with no movement of the surface ---*/ + output_file << "PERIODIC_INDEX= 0" << endl; + output_file << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << endl; + output_file << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << endl; + output_file << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << endl; + + /*--- From iPeriodic obtain the iMarker ---*/ + for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) { + for (iMarker = 0; iMarker < nMarker; iMarker++) + if (iPeriodic == config->GetMarker_All_PerBound(iMarker)) break; + + /*--- Retrieve the supplied periodic information. ---*/ + center = config->GetPeriodicRotCenter(config->GetMarker_All_TagBound(iMarker)); + angles = config->GetPeriodicRotAngles(config->GetMarker_All_TagBound(iMarker)); + transl = config->GetPeriodicTranslation(config->GetMarker_All_TagBound(iMarker)); + + output_file << "PERIODIC_INDEX= " << iPeriodic << endl; + output_file << center[0] << "\t" << center[1] << "\t" << center[2] << endl; + output_file << angles[0] << "\t" << angles[1] << "\t" << angles[2] << endl; + output_file << transl[0] << "\t" << transl[1] << "\t" << transl[2] << endl; + + } + + + output_file.close(); + + /*--- Free memory ---*/ + delete [] NewSort; + +} + +void CPeriodicGeometry::SetTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file) { + + unsigned long iElem, iPoint; + unsigned short iDim; + ofstream Tecplot_File; + + Tecplot_File.open(mesh_filename, ios::out); + Tecplot_File << "TITLE= \"Visualization of the volumetric grid\"" << endl; + + if (nDim == 2) { + Tecplot_File << "VARIABLES = \"x\",\"y\" " << endl; + Tecplot_File << "ZONE NODES= "<< nPoint <<", ELEMENTS= "<< nElem <<", DATAPACKING=POINT, ZONETYPE=FEQUADRILATERAL"<< endl; + } + if (nDim == 3) { + Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\" " << endl; + Tecplot_File << "ZONE NODES= "<< nPoint <<", ELEMENTS= "<< nElem <<", DATAPACKING=POINT, ZONETYPE=FEBRICK"<< endl; + } + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + for (iDim = 0; iDim < nDim; iDim++) + Tecplot_File << scientific << node[iPoint]->GetCoord(iDim) << "\t"; + Tecplot_File << "\n"; + } + + for (iElem = 0; iElem < nElem; iElem++) { + if (elem[iElem]->GetVTK_Type() == TRIANGLE) { + Tecplot_File << + elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< + elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(2)+1 << endl; + } + if (elem[iElem]->GetVTK_Type() == QUADRILATERAL) { + Tecplot_File << + elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< + elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 << endl; + } + if (elem[iElem]->GetVTK_Type() == TETRAHEDRON) { + Tecplot_File << + elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< + elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(2)+1 <<" "<< + elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<< + elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(3)+1 << endl; + } + if (elem[iElem]->GetVTK_Type() == HEXAHEDRON) { + Tecplot_File << + elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< + elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<< + elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(5)+1 <<" "<< + elem[iElem]->GetNode(6)+1 <<" "<< elem[iElem]->GetNode(7)+1 << endl; + } + if (elem[iElem]->GetVTK_Type() == PYRAMID) { + Tecplot_File << + elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< + elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<< + elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(4)+1 <<" "<< + elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(4)+1 << endl; + } + if (elem[iElem]->GetVTK_Type() == PRISM) { + Tecplot_File << + elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<< + elem[iElem]->GetNode(1)+1 <<" "<< elem[iElem]->GetNode(2)+1 <<" "<< + elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(4)+1 <<" "<< + elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(5)+1 << endl; + } + } + + Tecplot_File.close(); +} + +CMultiGridQueue::CMultiGridQueue(unsigned long val_npoint) { + unsigned long iPoint; + + nPoint = val_npoint; + Priority = new short[nPoint]; + RightCV = new bool[nPoint]; + + QueueCV.resize(1); + + /*--- Queue initialization with all the points in the finer grid ---*/ + for (iPoint = 0; iPoint < nPoint; iPoint ++) { + QueueCV[0].push_back(iPoint); + Priority[iPoint] = 0; + RightCV[iPoint] = true; + } + +} + +CMultiGridQueue::~CMultiGridQueue(void) { + + delete[] Priority; + delete[] RightCV; + +} + +void CMultiGridQueue::AddCV(unsigned long val_new_point, unsigned short val_number_neighbors) { + + unsigned short Max_Neighbors = QueueCV.size()-1; + + /*--- Basic check ---*/ + if (val_new_point > nPoint) { + cout << "The index of the CV is greater than the size of the priority list." << endl; + exit(EXIT_FAILURE); + } + + /*--- Resize the list ---*/ + if (val_number_neighbors > Max_Neighbors) + QueueCV.resize(val_number_neighbors+1); + + /*--- Find the point in the queue ---*/ + bool InQueue = false; + if (Priority[val_new_point] == val_number_neighbors) InQueue = true; + + if (!InQueue) { + /*--- Add the control volume, and update the priority list ---*/ + QueueCV[val_number_neighbors].push_back(val_new_point); + Priority[val_new_point] = val_number_neighbors; + } + +} + +void CMultiGridQueue::RemoveCV(unsigned long val_remove_point) { + unsigned short iPoint; + bool check; + + /*--- Basic check ---*/ + if (val_remove_point > nPoint) { + cout << "The index of the CV is greater than the size of the priority list." << endl; + exit(EXIT_FAILURE); + } + + /*--- Find priority of the Control Volume ---*/ + short Number_Neighbors = Priority[val_remove_point]; + if (Number_Neighbors == -1) { + cout << "The CV "<< val_remove_point <<" is not in the priority list. (RemoveCV)" << endl; + exit(EXIT_FAILURE); + } + + /*--- Find the point in the queue ---*/ + vector::iterator ItQueue = find(QueueCV[Number_Neighbors].begin(), + QueueCV[Number_Neighbors].end(), + val_remove_point); + if ( ItQueue != QueueCV[Number_Neighbors].end() ) QueueCV[Number_Neighbors].erase(ItQueue); + + Priority[val_remove_point] = -1; + + /*--- Check that the size of the queue is the right one ---*/ + unsigned short Size_QueueCV = 0; + check = false; + for (iPoint = 0; iPoint < QueueCV.size(); iPoint ++) + if (QueueCV[iPoint].size() != 0) { Size_QueueCV = iPoint; check = true;} + + /*--- Resize the queue, if check = false, the queue is empty, at least + we need one element in the queue ---*/ + if (check) QueueCV.resize(Size_QueueCV+1); + else QueueCV.resize(1); + +} + +void CMultiGridQueue::MoveCV(unsigned long val_move_point, short val_number_neighbors) { + + if (val_number_neighbors < 0) { + val_number_neighbors = 0; + RightCV[val_move_point] = false; + } + else { + RightCV[val_move_point] = true; + } + + /*--- Remove the control volume ---*/ + RemoveCV(val_move_point); + + /*--- Add a new control volume ---*/ + AddCV(val_move_point, val_number_neighbors); + +} + +void CMultiGridQueue::IncrPriorityCV(unsigned long val_incr_point) { + + /*--- Find the priority list ---*/ + short Number_Neighbors = Priority[val_incr_point]; + if (Number_Neighbors == -1) { + cout << "The CV "<< val_incr_point <<" is not in the priority list. (IncrPriorityCV)" << endl; + exit(EXIT_FAILURE); + } + + /*--- Remove the control volume ---*/ + RemoveCV(val_incr_point); + + /*--- Increase the priority ---*/ + AddCV(val_incr_point, Number_Neighbors+1); + +} + +void CMultiGridQueue::RedPriorityCV(unsigned long val_red_point) { + + /*--- Find the priority list ---*/ + short Number_Neighbors = Priority[val_red_point]; + if (Number_Neighbors == -1) { + cout << "The CV "<< val_red_point <<" is not in the priority list. (RedPriorityCV)" << endl; + exit(EXIT_FAILURE); + } + + if (Number_Neighbors != 0) { + + /*--- Remove the control volume ---*/ + RemoveCV(val_red_point); + + /*--- Increase the priority ---*/ + AddCV(val_red_point, Number_Neighbors-1); + + } + +} + +void CMultiGridQueue::VisualizeQueue(void) { + unsigned short iPoint; + unsigned long jPoint; + + cout << endl; + for (iPoint = 0; iPoint < QueueCV.size(); iPoint ++) { + cout << "Number of neighbors " << iPoint <<": "; + for (jPoint = 0; jPoint < QueueCV[iPoint].size(); jPoint ++) { + cout << QueueCV[iPoint][jPoint] << " "; + } + cout << endl; + } + +} + +void CMultiGridQueue::VisualizePriority(void) { + unsigned long iPoint; + + for (iPoint = 0; iPoint < nPoint; iPoint ++) + cout << "Control Volume: " << iPoint <<" Priority: " << Priority[iPoint] << endl; + +} + +long CMultiGridQueue::NextCV(void) { + if (QueueCV.size() != 0) return QueueCV[QueueCV.size()-1][0]; + else return -1; +} + +bool CMultiGridQueue::EmptyQueue(void) { + unsigned short iPoint; + + /*--- In case there is only the no agglomerated elements, + check if they can be agglomerated or we have already finished ---*/ + bool check = true; + + if ( QueueCV.size() == 1 ) { + for (iPoint = 0; iPoint < QueueCV[0].size(); iPoint ++) { + if (RightCV[QueueCV[0][iPoint]]) { check = false; break; } + } + } + else { + for (iPoint = 1; iPoint < QueueCV.size(); iPoint ++) + if (QueueCV[iPoint].size() != 0) { check = false; break;} + } + + return check; +} + +unsigned long CMultiGridQueue::TotalCV(void) { + unsigned short iPoint; + unsigned long TotalCV; + + TotalCV = 0; + for (iPoint = 0; iPoint < QueueCV.size(); iPoint ++) + if (QueueCV[iPoint].size() != 0) { TotalCV += QueueCV[iPoint].size(); } + + return TotalCV; +} + +void CMultiGridQueue::Update(unsigned long iPoint, CGeometry *fine_grid) { + unsigned short iNode; + unsigned long jPoint; + + RemoveCV(iPoint); + for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { + jPoint = fine_grid->node[iPoint]->GetPoint(iNode); + if (fine_grid->node[jPoint]->GetAgglomerate() == false) + IncrPriorityCV(jPoint); + } + +} diff --git a/Common/src/grid_adaptation_structure.cpp b/Common/src/grid_adaptation_structure.cpp index d1cb8c3e898..d9ec5c75509 100644 --- a/Common/src/grid_adaptation_structure.cpp +++ b/Common/src/grid_adaptation_structure.cpp @@ -1,3631 +1,3631 @@ -/*! - * \file grid_adaptation_structure.cpp - * \brief Main subroutines for grid adaptation - * \author F. Palacios - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#include "../include/grid_adaptation_structure.hpp" -#include - -CGridAdaptation::CGridAdaptation(CGeometry *geometry, CConfig *config) { - - unsigned long iPoint; - - nDim = geometry->GetnDim(); - - switch (config->GetKind_Solver()) { - - case POISSON_EQUATION: - nVar = 1; - break; - - default: - nVar = geometry->GetnDim()+2; - break; - } - - ConsVar_Sol = new su2double* [geometry->GetnPoint()]; - AdjVar_Sol = new su2double* [geometry->GetnPoint()]; - LinVar_Sol = new su2double* [geometry->GetnPoint()]; - ConsVar_Res = new su2double* [geometry->GetnPoint()]; - AdjVar_Res = new su2double* [geometry->GetnPoint()]; - LinVar_Res = new su2double* [geometry->GetnPoint()]; - Gradient = new su2double* [geometry->GetnPoint()]; - Gradient_Flow = new su2double* [geometry->GetnPoint()]; - Gradient_Adj = new su2double* [geometry->GetnPoint()]; - - Index = new su2double [geometry->GetnPoint()]; - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { - ConsVar_Sol[iPoint] = new su2double [nVar]; - AdjVar_Sol[iPoint] = new su2double [nVar]; - LinVar_Sol[iPoint] = new su2double [nVar]; - ConsVar_Res[iPoint] = new su2double [nVar]; - LinVar_Res[iPoint] = new su2double [nVar]; - AdjVar_Res[iPoint] = new su2double [nVar]; - Gradient[iPoint] = new su2double [nDim]; - Gradient_Flow[iPoint] = new su2double [nDim]; - Gradient_Adj[iPoint] = new su2double [nDim]; - } - -} - -CGridAdaptation::~CGridAdaptation(void) { - - unsigned short iVar, iDim; - - for (iVar = 0; iVar < nVar; iVar++) { - delete [] ConsVar_Adapt[iVar]; - delete [] ConsVar_Sol[iVar]; - delete [] ConsVar_Res[iVar]; - delete [] AdjVar_Adapt[iVar]; - delete [] AdjVar_Sol[iVar]; - delete [] AdjVar_Res[iVar]; - delete [] LinVar_Adapt[iVar]; - delete [] LinVar_Sol[iVar]; - delete [] LinVar_Res[iVar]; - } - - for (iDim = 0; iDim < nDim; iDim++) { - delete [] Gradient[iDim]; - delete [] Gradient_Flow[iDim]; - delete [] Gradient_Adj[iDim]; - } - delete [] ConsVar_Adapt; - delete [] ConsVar_Sol; - delete [] ConsVar_Res; - delete [] AdjVar_Adapt; - delete [] AdjVar_Sol; - delete [] AdjVar_Res; - delete [] LinVar_Adapt; - delete [] LinVar_Sol; - delete [] LinVar_Res; - delete [] Gradient; - delete [] Gradient_Flow; - delete [] Gradient_Adj; - delete [] Index; -} - -void CGridAdaptation::GetFlowSolution(CGeometry *geometry, CConfig *config) { - unsigned long iPoint, index; - unsigned short iVar; - su2double dummy; - - string text_line; - - string mesh_filename = config->GetSolution_FlowFileName(); - ifstream restart_file; - - char *cstr = new char [mesh_filename.size()+1]; - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - strcpy (cstr, mesh_filename.c_str()); - restart_file.open(cstr, ios::in); - if (restart_file.fail()) { - if (rank == MASTER_NODE) - cout << "There is no flow restart file!!" << endl; - exit(EXIT_FAILURE); } - - /*--- Read the header of the file ---*/ - getline(restart_file, text_line); - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - getline(restart_file, text_line); - istringstream point_line(text_line); - - point_line >> index; - - if (nDim == 2) point_line >> dummy >> dummy; - else point_line >> dummy >> dummy >> dummy; - - for (iVar = 0; iVar < nVar; iVar ++) - point_line >> ConsVar_Sol[iPoint][iVar]; - } - restart_file.close(); -} - -void CGridAdaptation::GetFlowResidual(CGeometry *geometry, CConfig *config) { - unsigned long iPoint, index; - unsigned short iVar; - -// su2double dummy[5]; - su2double dummy; - string text_line; - - string mesh_filename = config->GetSolution_FlowFileName(); - ifstream restart_file; - - char *cstr = new char [mesh_filename.size()+1]; - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - strcpy (cstr, mesh_filename.c_str()); - restart_file.open(cstr, ios::in); - if (restart_file.fail()) { - if (rank == MASTER_NODE) - cout << "There is no flow restart file!!" << endl; - exit(EXIT_FAILURE); } - - /*--- Read the header of the file ---*/ - getline(restart_file, text_line); - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - getline(restart_file, text_line); - istringstream point_line(text_line); - - point_line >> index; - - if (nDim == 2) point_line >> dummy >> dummy; - else point_line >> dummy >> dummy >> dummy; - - for (iVar = 0; iVar < nVar; iVar++) - point_line >> dummy; - for (iVar = 0; iVar < nVar; iVar++) - point_line >> ConsVar_Res[iPoint][iVar]; - } - restart_file.close(); -} - -void CGridAdaptation::GetAdjSolution(CGeometry *geometry, CConfig *config) { - unsigned long iPoint, index; - unsigned short iVar; - su2double dummy; - string text_line; - - string copy, mesh_filename; - ifstream restart_file; - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Get the adjoint solution file name ---*/ - mesh_filename = config->GetSolution_AdjFileName(); - mesh_filename = config->GetObjFunc_Extension(mesh_filename); - - restart_file.open(mesh_filename.c_str(), ios::in); - if (restart_file.fail()) { - if (rank == MASTER_NODE) - cout << "There is no adjoint restart file!!" << endl; - exit(EXIT_FAILURE); } - - /*--- Read the header of the file ---*/ - getline(restart_file, text_line); - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - getline(restart_file, text_line); - istringstream point_line(text_line); - - point_line >> index; - - if (nDim == 2) point_line >> dummy >> dummy; - else point_line >> dummy >> dummy >> dummy; - - for (iVar = 0; iVar < nVar; iVar ++) - point_line >> AdjVar_Sol[iPoint][iVar]; - } - - restart_file.close(); -} - -void CGridAdaptation::GetAdjResidual(CGeometry *geometry, CConfig *config) { - unsigned long iPoint, index; - string text_line; - su2double dummy; - - string mesh_filename, copy; - ifstream restart_file; - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - char buffer[50], cstr[MAX_STRING_SIZE]; - mesh_filename = config->GetSolution_AdjFileName(); - copy.assign(mesh_filename); - unsigned short lastindex = copy.find_last_of("."); - copy = copy.substr(0, lastindex); - strcpy (cstr, copy.c_str()); - if (config->GetKind_ObjFunc() == DRAG_COEFFICIENT) SPRINTF (buffer, "_cd.dat"); - if (config->GetKind_ObjFunc() == LIFT_COEFFICIENT) SPRINTF (buffer, "_cl.dat"); - if (config->GetKind_ObjFunc() == SIDEFORCE_COEFFICIENT) SPRINTF (buffer, "_csf.dat"); - if (config->GetKind_ObjFunc() == INVERSE_DESIGN_PRESSURE) SPRINTF (buffer, "_invpress.dat"); - if (config->GetKind_ObjFunc() == INVERSE_DESIGN_HEATFLUX) SPRINTF (buffer, "_invheat.dat"); - if (config->GetKind_ObjFunc() == MOMENT_X_COEFFICIENT) SPRINTF (buffer, "_cmx.dat"); - if (config->GetKind_ObjFunc() == MOMENT_Y_COEFFICIENT) SPRINTF (buffer, "_cmy.dat"); - if (config->GetKind_ObjFunc() == MOMENT_Z_COEFFICIENT) SPRINTF (buffer, "_cmz.dat"); - if (config->GetKind_ObjFunc() == EFFICIENCY) SPRINTF (buffer, "_eff.dat"); - if (config->GetKind_ObjFunc() == FORCE_X_COEFFICIENT) SPRINTF (buffer, "_cfx.dat"); - if (config->GetKind_ObjFunc() == FORCE_Y_COEFFICIENT) SPRINTF (buffer, "_cfy.dat"); - if (config->GetKind_ObjFunc() == FORCE_Z_COEFFICIENT) SPRINTF (buffer, "_cfz.dat"); - if (config->GetKind_ObjFunc() == TOTAL_HEATFLUX) SPRINTF (buffer, "_totheat.dat"); - if (config->GetKind_ObjFunc() == MAXIMUM_HEATFLUX) SPRINTF (buffer, "_maxheat.dat"); - if (config->GetKind_ObjFunc() == AVG_TOTAL_PRESSURE) SPRINTF (buffer, "_pt.dat"); - if (config->GetKind_ObjFunc() == AVG_OUTLET_PRESSURE) SPRINTF (buffer, "_pe.dat"); - if (config->GetKind_ObjFunc() == MASS_FLOW_RATE) SPRINTF (buffer, "_mfr.dat"); - if (config->GetKind_ObjFunc() == OUTLET_CHAIN_RULE) SPRINTF (buffer, "_chn.dat"); - - strcat(cstr, buffer); - - restart_file.open(cstr, ios::in); - - if (restart_file.fail()) { - if (rank == MASTER_NODE) - cout << "There is no flow restart file!!" << endl; - exit(EXIT_FAILURE); } - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - getline(restart_file, text_line); - istringstream point_line(text_line); - - point_line >> index; - - if (nDim == 2) point_line >> dummy >> dummy; - else point_line >> dummy >> dummy >> dummy; - - if (nVar == 1) point_line >> dummy >> AdjVar_Res[iPoint][0]; - if (nVar == 4) point_line >> dummy >> dummy >> dummy >> dummy >> - AdjVar_Res[iPoint][0] >> AdjVar_Res[iPoint][1] >> AdjVar_Res[iPoint][2] >> - AdjVar_Res[iPoint][3]; - if (nVar == 5) point_line >> dummy >> dummy >> dummy >> dummy >> dummy >> - AdjVar_Res[iPoint][0] >> AdjVar_Res[iPoint][1] >> AdjVar_Res[iPoint][2] >> - AdjVar_Res[iPoint][3] >> AdjVar_Res[iPoint][4]; - } - restart_file.close(); -} - -void CGridAdaptation::SetComplete_Refinement(CGeometry *geometry, unsigned short strength) { - unsigned long iElem; - - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - geometry->elem[iElem]->SetDivide (true); - } -} - -void CGridAdaptation::SetNo_Refinement(CGeometry *geometry, unsigned short strength) { - unsigned long iElem; - - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - geometry->elem[iElem]->SetDivide (false); - } -} - -void CGridAdaptation::SetWake_Refinement(CGeometry *geometry, unsigned short strength) { - unsigned long iElem, iPoint; - unsigned short iNode; - su2double Coordx, Coordy, dist, wake = 0.5; - - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { - iPoint = geometry->elem[iElem]->GetNode(iNode); - Coordx = geometry->node[iPoint]->GetCoord(0); - Coordy = geometry->node[iPoint]->GetCoord(1); - dist = sqrt(Coordx*Coordx+Coordy*Coordy); - if (dist < wake) { - geometry->elem[iElem]->SetDivide (true); - } - if ((Coordx > 0) && ((Coordy > -wake) && (Coordy < wake))) { - geometry->elem[iElem]->SetDivide (true); - } - } -} - -void CGridAdaptation::SetSupShock_Refinement(CGeometry *geometry, CConfig *config) { - unsigned long iElem, iPoint; - unsigned short iNode; - su2double Coordx, Coordy; - su2double mu_1 = asin(1/config->GetMach()-0.1); - su2double mu_2 = asin(1/(config->GetMach()-0.7)); - - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { - iPoint = geometry->elem[iElem]->GetNode(iNode); - Coordx = geometry->node[iPoint]->GetCoord(0); - Coordy = geometry->node[iPoint]->GetCoord(1); - if (Coordy < 0.0) - if ((Coordx > fabs(Coordy/tan(mu_2))-0.25) && (Coordx < fabs(Coordy/tan(mu_1))+1.25)) { - geometry->elem[iElem]->SetDivide (true); - } - } -} - -long CGridAdaptation::CheckRectCode(bool *AdaptCode) { - - int Code = -1; - - // Default - - if ((AdaptCode[0] == true) || (AdaptCode[1] == true) || (AdaptCode[2] == true) || (AdaptCode[3] == true)) { Code = 0; } - - // Combination 1:4 - - if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == true)) {Code = 1; return Code;} - - // Combination 1:2 - - if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == false)) {Code = 2; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == true)) {Code = 3; return Code;} - - return Code; - -} - -long CGridAdaptation::CheckRectExtCode(bool *AdaptCode) { - - int Code = -1; - - if ((AdaptCode[0] == true) || (AdaptCode[1] == true) || (AdaptCode[2] == true) || (AdaptCode[3] == true)) {Code = 0;} - - // Combination 1R -> 3T - - if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == false)) {Code = 2; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == false)) {Code = 3; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == false)) {Code = 4; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == true)) {Code = 5; return Code;} - - // Combination 1R -> 4T - - if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == false)) {Code = 6; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == false)) {Code = 7; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == true)) {Code = 8; return Code;} - - if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == true)) {Code = 9; return Code;} - - // Combination 1R -> 1R+3T - - if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == false)) {Code = 12; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == true)) {Code = 13; return Code;} - - if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == true)) {Code = 14; return Code;} - - if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == true)) {Code = 15; return Code;} - - return Code; - -} - -long CGridAdaptation::CheckTriangleCode(bool *AdaptCode) { - - int Code = -1; - - if ((AdaptCode[0] == true) || (AdaptCode[1] == true) || (AdaptCode[2] == true)) {Code = 0;} - - // Combination 1T -> 3T - - if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == true)) {Code = 1; return Code;} - - // Combination 1T -> 2T - - if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == false)) {Code = 2; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == false)) {Code = 3; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == true)) {Code = 4; return Code;} - - // Combination 1T -> 1R+1T (2D) or 3T (3D) - - if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == false)) {Code = 5; return Code;} - - if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == true)) {Code = 6; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == true)) {Code = 7; return Code;} - - return Code; - -} - -long CGridAdaptation::CheckTetraCode(bool *AdaptCode) { - - int Code = -1; - unsigned short nDivEdges, iVar; - - // Default - - if ((AdaptCode[0] == true) || (AdaptCode[1] == true) || (AdaptCode[2] == true) || (AdaptCode[3] == true) || (AdaptCode[4] == true) || - (AdaptCode[5] == true) ) { Code = 0; } - - // Combination 1:8 - - if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == true) && (AdaptCode[4] == true) && - (AdaptCode[5] == true) ) {Code = 1; return Code;} - - // Combination 1:4 - - if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == false) && (AdaptCode[4] == true) && - (AdaptCode[5] == false) ) {Code = 2; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == true) && (AdaptCode[4] == true) && - (AdaptCode[5] == true) ) {Code = 3; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == false) && (AdaptCode[4] == false) && - (AdaptCode[5] == true) ) {Code = 4; return Code;} - - if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == true) && (AdaptCode[4] == false) && - (AdaptCode[5] == false) ) {Code = 5; return Code;} - - // Combinations with 1, 2, and 3 (no regular) divided edges. - - nDivEdges = 0; - for (iVar = 0; iVar < 6; iVar ++) - if (AdaptCode[iVar] == true) nDivEdges++; - - if ((nDivEdges == 1) || (nDivEdges == 2) || (nDivEdges == 3)) {Code = 6; return Code;} - - return Code; - -} - -long CGridAdaptation::CheckHexaCode(bool *AdaptCode) { - - int Code = -1; - - // Default - - if ((AdaptCode[0] == true) || (AdaptCode[1] == true) || (AdaptCode[2] == true) || (AdaptCode[3] == true) || (AdaptCode[4] == true) || - (AdaptCode[5] == true) || (AdaptCode[6] == true) || (AdaptCode[7] == true) || (AdaptCode[8] == true) || (AdaptCode[9] == true) || - (AdaptCode[10] == true) || (AdaptCode[11] == true)) { Code = 0; } - - // Combination 1:8 - - if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == true) && (AdaptCode[4] == true) && - (AdaptCode[5] == true) && (AdaptCode[6] == true) && (AdaptCode[7] == true) && (AdaptCode[8] == true) && (AdaptCode[9] == true) && - (AdaptCode[10] == true) && (AdaptCode[11] == true)) {Code = 1; return Code;} - - // Combination 1:4 - - if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == false) && (AdaptCode[4] == true) && - (AdaptCode[5] == false) && (AdaptCode[6] == true) && (AdaptCode[7] == false) && (AdaptCode[8] == true) && (AdaptCode[9] == true) && - (AdaptCode[10] == true) && (AdaptCode[11] == true)) {Code = 2; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == true) && (AdaptCode[4] == false) && - (AdaptCode[5] == true) && (AdaptCode[6] == false) && (AdaptCode[7] == true) && (AdaptCode[8] == true) && (AdaptCode[9] == true) && - (AdaptCode[10] == true) && (AdaptCode[11] == true)) {Code = 3; return Code;} - - if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == true) && (AdaptCode[4] == true) && - (AdaptCode[5] == true) && (AdaptCode[6] == true) && (AdaptCode[7] == true) && (AdaptCode[8] == false) && (AdaptCode[9] == false) && - (AdaptCode[10] == false) && (AdaptCode[11] == false)) {Code = 4; return Code;} - - // Combination 1:2 - - if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == false) && (AdaptCode[4] == false) && - (AdaptCode[5] == false) && (AdaptCode[6] == false) && (AdaptCode[7] == false) && (AdaptCode[8] == true) && (AdaptCode[9] == true) && - (AdaptCode[10] == true) && (AdaptCode[11] == true)) {Code = 5; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == true) && (AdaptCode[4] == false) && - (AdaptCode[5] == true) && (AdaptCode[6] == false) && (AdaptCode[7] == true) && (AdaptCode[8] == false) && (AdaptCode[9] == false) && - (AdaptCode[10] == false) && (AdaptCode[11] == false)) {Code = 6; return Code;} - - if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == false) && (AdaptCode[4] == true) && - (AdaptCode[5] == false) && (AdaptCode[6] == true) && (AdaptCode[7] == false) && (AdaptCode[8] == false) && (AdaptCode[9] == false) && - (AdaptCode[10] == false) && (AdaptCode[11] == false)) {Code = 7; return Code; } - - return Code; - -} - -long CGridAdaptation::CheckPyramCode(bool *AdaptCode) { - - int Code = -1; - - if ((AdaptCode[0] == true) || (AdaptCode[1] == true) || (AdaptCode[2] == true) || (AdaptCode[3] == true)) {Code = 0;} - - // Combination 1P -> 1P - - if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == false)) {Code = 1; return Code;} - - // Combination 1P -> 3T - - if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == false)) {Code = 2; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == false)) {Code = 3; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == false)) {Code = 4; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == true)) {Code = 5; return Code;} - - // Combination 1P -> 4T - - if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == false)) {Code = 6; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == false)) {Code = 7; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == true)) {Code = 8; return Code;} - - if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == true)) {Code = 9; return Code;} - - // Combination 1P -> 2P - - if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == false)) {Code = 10; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == true)) {Code = 11; return Code;} - - // Combination 1P -> 1P+3T - - if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == false)) {Code = 12; return Code;} - - if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == true)) {Code = 13; return Code;} - - if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == true)) {Code = 14; return Code;} - - if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == true)) {Code = 15; return Code;} - - - // Combination 1P -> 4P - - if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == true)) {Code = 16; return Code;} - - return Code; - -} - -void CGridAdaptation::RectDivision(long code , long *nodes, long **Division, long *nPart) { - - if (code == 1) { - - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[8]; Division[0][2] = nodes[7]; Division[0][3] = nodes[0]; Division[0][4] = nodes[4]; - - Division[1][1] = nodes[8]; Division[1][2] = nodes[4]; Division[1][3] = nodes[1]; Division[1][4] = nodes[5]; - - Division[2][1] = nodes[8]; Division[2][2] = nodes[5]; Division[2][3] = nodes[2]; Division[2][4] = nodes[6]; - - Division[3][1] = nodes[8]; Division[3][2] = nodes[6]; Division[3][3] = nodes[3]; Division[3][4] = nodes[7]; - - } - - if (code == 2) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 5; - *nPart = 2; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[4]; Division[0][3] = nodes[6]; Division[0][4] = nodes[3]; - - Division[1][1] = nodes[4]; Division[1][2] = nodes[1]; Division[1][3] = nodes[2]; Division[1][4] = nodes[6]; - - } - - if (code == 3) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 5; - *nPart = 2; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[5]; Division[0][4] = nodes[7]; - - Division[1][1] = nodes[5]; Division[1][2] = nodes[2]; Division[1][3] = nodes[3]; Division[1][4] = nodes[7]; - - } - -} - -void CGridAdaptation::RectExtDivision(long code , long *nodes, long **Division, long *nPart) { - - if (code == 2) { - // number of nodes at each new element - Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; - *nPart = 3; - - // nodes that compose each element - Division[0][1] = nodes[4]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; - - Division[1][1] = nodes[4]; Division[1][2] = nodes[2]; Division[1][3] = nodes[3]; - - Division[2][1] = nodes[4]; Division[2][2] = nodes[3]; Division[2][3] = nodes[0]; - - } - - if (code == 3) { - // number of nodes at each new element - Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; - *nPart = 3; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[5]; - - Division[1][1] = nodes[0]; Division[1][2] = nodes[5]; Division[1][3] = nodes[3]; - - Division[2][1] = nodes[3]; Division[2][2] = nodes[5]; Division[2][3] = nodes[2]; - - } - - if (code == 4) { - // number of nodes at each new element - Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; - *nPart = 3; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[6]; - - Division[1][1] = nodes[1]; Division[1][2] = nodes[2]; Division[1][3] = nodes[6]; - - Division[2][1] = nodes[0]; Division[2][2] = nodes[6]; Division[2][3] = nodes[3]; - - } - - if (code == 5) { - // number of nodes at each new element - Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; - *nPart = 3; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[7]; - - Division[1][1] = nodes[1]; Division[1][2] = nodes[2]; Division[1][3] = nodes[7]; - - Division[2][1] = nodes[7]; Division[2][2] = nodes[2]; Division[2][3] = nodes[3]; - - } - - if (code == 6) { - // number of nodes at each new element - Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[4]; Division[0][3] = nodes[3]; - - Division[1][1] = nodes[4]; Division[1][2] = nodes[1]; Division[1][3] = nodes[5]; - - Division[2][1] = nodes[4]; Division[2][2] = nodes[5]; Division[2][3] = nodes[3]; - - Division[3][1] = nodes[5]; Division[3][2] = nodes[2]; Division[3][3] = nodes[3]; - - } - - if (code == 7) { - // number of nodes at each new element - Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[5]; - - Division[1][1] = nodes[0]; Division[1][2] = nodes[5]; Division[1][3] = nodes[6]; - - Division[2][1] = nodes[5]; Division[2][2] = nodes[2]; Division[2][3] = nodes[6]; - - Division[3][1] = nodes[0]; Division[3][2] = nodes[6]; Division[3][3] = nodes[3]; - - } - - if (code == 8) { - // number of nodes at each new element - Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[7]; - - Division[1][1] = nodes[7]; Division[1][2] = nodes[1]; Division[1][3] = nodes[6]; - - Division[2][1] = nodes[1]; Division[2][2] = nodes[2]; Division[2][3] = nodes[6]; - - Division[3][1] = nodes[7]; Division[3][2] = nodes[6]; Division[3][3] = nodes[3]; - - } - - if (code == 9) { - // number of nodes at each new element - Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[4]; Division[0][3] = nodes[7]; - - Division[1][1] = nodes[4]; Division[1][2] = nodes[1]; Division[1][3] = nodes[2]; - - Division[2][1] = nodes[7]; Division[2][2] = nodes[4]; Division[2][3] = nodes[2]; - - Division[3][1] = nodes[7]; Division[3][2] = nodes[2]; Division[3][3] = nodes[3]; - - } - - if (code == 12) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[4]; Division[0][3] = nodes[6]; Division[0][4] = nodes[3]; - - Division[1][1] = nodes[4]; Division[1][2] = nodes[1]; Division[1][3] = nodes[5]; - - Division[2][1] = nodes[4]; Division[2][2] = nodes[5]; Division[2][3] = nodes[6]; - - Division[3][1] = nodes[5]; Division[3][2] = nodes[2]; Division[3][3] = nodes[6]; - - } - - if (code == 13) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[5]; Division[0][4] = nodes[7]; - - Division[1][1] = nodes[5]; Division[1][2] = nodes[2]; Division[1][3] = nodes[6]; - - Division[2][1] = nodes[7]; Division[2][2] = nodes[5]; Division[2][3] = nodes[6]; - - Division[3][1] = nodes[7]; Division[3][2] = nodes[6]; Division[3][3] = nodes[3]; - - } - - if (code == 14) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[4]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; Division[0][4] = nodes[6]; - - Division[1][1] = nodes[0]; Division[1][2] = nodes[4]; Division[1][3] = nodes[7]; - - Division[2][1] = nodes[7]; Division[2][2] = nodes[4]; Division[2][3] = nodes[6]; - - Division[3][1] = nodes[7]; Division[3][2] = nodes[6]; Division[3][3] = nodes[3]; - - } - - if (code == 15) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[7]; Division[0][2] = nodes[5]; Division[0][3] = nodes[2]; Division[0][4] = nodes[3]; - - Division[1][1] = nodes[0]; Division[1][2] = nodes[4]; Division[1][3] = nodes[7]; - - Division[2][1] = nodes[4]; Division[2][2] = nodes[1]; Division[2][3] = nodes[5]; - - Division[3][1] = nodes[4]; Division[3][2] = nodes[5]; Division[3][3] = nodes[7]; - - } - -} - -void CGridAdaptation::TriangleDivision(long code , long *nodes, long *edges, long **Division, long *nPart) { - - if (code == 1) { - // number of nodes at each new element - Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[3]; Division[0][3] = nodes[5]; - - Division[1][1] = nodes[3]; Division[1][2] = nodes[1]; Division[1][3] = nodes[4]; - - Division[2][1] = nodes[5]; Division[2][2] = nodes[4]; Division[2][3] = nodes[2]; - - Division[3][1] = nodes[3]; Division[3][2] = nodes[4]; Division[3][3] = nodes[5]; - return; - } - - if (code == 2) { - // number of nodes at each new element - Division[0][0] = 4; Division[1][0] = 4; - *nPart = 2; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[3]; Division[0][3] = nodes[2]; - - Division[1][1] = nodes[3]; Division[1][2] = nodes[1]; Division[1][3] = nodes[2]; - return; - - } - - if (code == 3) { - // number of nodes at each new element - Division[0][0] = 4; Division[1][0] = 4; - *nPart = 2; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[4]; - - Division[1][1] = nodes[0]; Division[1][2] = nodes[4]; Division[1][3] = nodes[2]; - return; - - } - - if (code == 4) { - // number of nodes at each new element - Division[0][0] = 4; Division[1][0] = 4; - *nPart = 2; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[5]; - - Division[1][1] = nodes[5]; Division[1][2] = nodes[1]; Division[1][3] = nodes[2]; - return; - - } - - if (edges == NULL) { - - if (code == 5) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 4; - *nPart = 2; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[3]; Division[0][3] = nodes[4]; Division[0][4] = nodes[2]; - - Division[1][1] = nodes[3]; Division[1][2] = nodes[1]; Division[1][3] = nodes[4]; - return; - - } - - if (code == 6) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 4; - *nPart = 2; - - // nodes that compose each element - Division[0][1] = nodes[3]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; Division[0][4] = nodes[5]; - - Division[1][1] = nodes[0]; Division[1][2] = nodes[3]; Division[1][3] = nodes[5]; - return; - - } - - if (code == 7) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 4; - *nPart = 2; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[4]; Division[0][4] = nodes[5]; - - Division[1][1] = nodes[5]; Division[1][2] = nodes[4]; Division[1][3] = nodes[2]; - return; - - } - - } - else { - - unsigned short iDiv, nDiv, edge_div[6][3], max_iVar, iVar, nElem, iElem, iNode, iTriangle; - bool set_0, set_1, new_div, new_triangle[8][10]; - long max_edge; - - nDiv = 0; - do { new_div = false; - - // Compute the greatest edge index - max_edge = 0; max_iVar = 0; - for (iVar = 0; iVar < 3; iVar ++) { - max_edge = max(max_edge, edges[iVar]); - if ( max_edge == edges[iVar] ) max_iVar = iVar; - } - - // If the edge is divided compose the vector with the information of the division - if (edges[max_iVar] >= 0) { - if (max_iVar == 0) { edge_div[nDiv][0] = 3; edge_div[nDiv][1] = 0; edge_div[nDiv][2] = 1; } - if (max_iVar == 1) { edge_div[nDiv][0] = 4; edge_div[nDiv][1] = 0; edge_div[nDiv][2] = 2; } - if (max_iVar == 2) { edge_div[nDiv][0] = 5; edge_div[nDiv][1] = 1; edge_div[nDiv][2] = 2; } - nDiv++; new_div = true; - } - // In order to do not repeat the egde, restart the code - edges[max_iVar] = -1; - } while (new_div); - - - // Inicializa - for (iVar = 0; iVar < 3; iVar ++) new_triangle[0][iVar] = true; - for (iVar = 3; iVar < 6; iVar ++) new_triangle[0][iVar] = false; - - nElem = 1; - for (iDiv = 0; iDiv < nDiv; iDiv++) { - short target_elem = -1; - - for (iElem = 0; iElem < nElem; iElem++) { - set_0 = false; set_1 = false; - if (new_triangle[iElem][edge_div[iDiv][1]]) set_0 = true; - if (new_triangle[iElem][edge_div[iDiv][2]]) set_1 = true; - if (set_0 && set_1) target_elem = iElem; - } - - if (target_elem != -1) { - for (iNode = 0; iNode < 6; iNode++) - new_triangle[nElem][iNode] = new_triangle[target_elem][iNode]; - new_triangle[target_elem][edge_div[iDiv][0]] = true; - new_triangle[target_elem][edge_div[iDiv][2]] = false; - new_triangle[nElem][edge_div[iDiv][0]] = true; - new_triangle[nElem][edge_div[iDiv][1]] = false; - nElem++; - } - } - - *nPart = nElem; - - for (iTriangle = 0; iTriangle < nElem; iTriangle++) { - Division[iTriangle][0] = 3; - iVar = 1; - for (iNode = 0; iNode < 6; iNode++) - if (new_triangle[iTriangle][iNode] == true) { - if (iNode == 0) Division[iTriangle][iVar] = nodes[0]; - if (iNode == 1) Division[iTriangle][iVar] = nodes[1]; - if (iNode == 2) Division[iTriangle][iVar] = nodes[2]; - if (iNode == 3) Division[iTriangle][iVar] = nodes[3]; - if (iNode == 4) Division[iTriangle][iVar] = nodes[4]; - if (iNode == 5) Division[iTriangle][iVar] = nodes[5]; - iVar++; - } - - } - - } -} - -void CGridAdaptation::TetraDivision(long code , long *nodes, long *edges, long **Division, long *nPart) { - - - if (code == 1) { - - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; - Division[4][0] = 5; Division[5][0] = 5; Division[6][0] = 5; Division[7][0] = 5; - *nPart = 8; - - // nodes that compose each element - Division[0][1] = nodes[6]; Division[0][2] = nodes[5]; Division[0][3] = nodes[4]; Division[0][4] = nodes[0]; - Division[1][1] = nodes[8]; Division[1][2] = nodes[4]; Division[1][3] = nodes[7]; Division[1][4] = nodes[1]; - Division[2][1] = nodes[6]; Division[2][2] = nodes[8]; Division[2][3] = nodes[9]; Division[2][4] = nodes[3]; - Division[3][1] = nodes[9]; Division[3][2] = nodes[7]; Division[3][3] = nodes[5]; Division[3][4] = nodes[2]; - Division[4][1] = nodes[6]; Division[4][2] = nodes[8]; Division[4][3] = nodes[7]; Division[4][4] = nodes[9]; - Division[5][1] = nodes[6]; Division[5][2] = nodes[7]; Division[5][3] = nodes[5]; Division[5][4] = nodes[9]; - Division[6][1] = nodes[7]; Division[6][2] = nodes[8]; Division[6][3] = nodes[6]; Division[6][4] = nodes[4]; - Division[7][1] = nodes[5]; Division[7][2] = nodes[7]; Division[7][3] = nodes[6]; Division[7][4] = nodes[4]; - - } - - if (code == 2) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[4]; Division[0][3] = nodes[6]; Division[0][4] = nodes[2]; - Division[1][1] = nodes[6]; Division[1][2] = nodes[4]; Division[1][3] = nodes[8]; Division[1][4] = nodes[2]; - Division[2][1] = nodes[6]; Division[2][2] = nodes[8]; Division[2][3] = nodes[3]; Division[2][4] = nodes[2]; - Division[3][1] = nodes[4]; Division[3][2] = nodes[1]; Division[3][3] = nodes[8]; Division[3][4] = nodes[2]; - - } - - if (code == 3) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[2]; Division[0][2] = nodes[7]; Division[0][3] = nodes[9]; Division[0][4] = nodes[0]; - Division[1][1] = nodes[7]; Division[1][2] = nodes[8]; Division[1][3] = nodes[9]; Division[1][4] = nodes[0]; - Division[2][1] = nodes[7]; Division[2][2] = nodes[1]; Division[2][3] = nodes[8]; Division[2][4] = nodes[0]; - Division[3][1] = nodes[9]; Division[3][2] = nodes[8]; Division[3][3] = nodes[3]; Division[3][4] = nodes[0]; - - } - - if (code == 4) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[2]; Division[0][2] = nodes[5]; Division[0][3] = nodes[9]; Division[0][4] = nodes[1]; - Division[1][1] = nodes[9]; Division[1][2] = nodes[5]; Division[1][3] = nodes[6]; Division[1][4] = nodes[1]; - Division[2][1] = nodes[5]; Division[2][2] = nodes[0]; Division[2][3] = nodes[6]; Division[2][4] = nodes[1]; - Division[3][1] = nodes[9]; Division[3][2] = nodes[6]; Division[3][3] = nodes[3]; Division[3][4] = nodes[1]; - - } - - if (code == 5) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[4]; Division[0][3] = nodes[5]; Division[0][4] = nodes[3]; - Division[1][1] = nodes[5]; Division[1][2] = nodes[4]; Division[1][3] = nodes[7]; Division[1][4] = nodes[3]; - Division[2][1] = nodes[2]; Division[2][2] = nodes[5]; Division[2][3] = nodes[7]; Division[2][4] = nodes[3]; - Division[3][1] = nodes[7]; Division[3][2] = nodes[4]; Division[3][3] = nodes[1]; Division[3][4] = nodes[3]; - - } - - if (code == 6) { - - unsigned short iDiv, nDiv, edge_div[6][3], max_iVar, iVar, nElem, iElem, iNode, iTetra; - bool set_0, set_1, new_div, new_tetra[8][10]; - long max_edge; - - nDiv = 0; - do { new_div = false; - - // Compute the greatest node at the divided edge - max_edge = 0; max_iVar = 0; - for (iVar = 0; iVar < 6; iVar ++) { - max_edge = max(max_edge, edges[iVar]); - if ( max_edge == edges[iVar] ) max_iVar = iVar; - } - - // If the edge is divided compose the vector with the information of the division - if (edges[max_iVar] >= 0) { - if (max_iVar == 0) { edge_div[nDiv][0] = 4; edge_div[nDiv][1] = 0; edge_div[nDiv][2] = 1; } - if (max_iVar == 1) { edge_div[nDiv][0] = 5; edge_div[nDiv][1] = 0; edge_div[nDiv][2] = 2; } - if (max_iVar == 2) { edge_div[nDiv][0] = 6; edge_div[nDiv][1] = 0; edge_div[nDiv][2] = 3; } - if (max_iVar == 3) { edge_div[nDiv][0] = 7; edge_div[nDiv][1] = 1; edge_div[nDiv][2] = 2; } - if (max_iVar == 4) { edge_div[nDiv][0] = 8; edge_div[nDiv][1] = 1; edge_div[nDiv][2] = 3; } - if (max_iVar == 5) { edge_div[nDiv][0] = 9; edge_div[nDiv][1] = 2; edge_div[nDiv][2] = 3; } - nDiv++; new_div = true; - } - // In order to do not repeat the egde, restart the code - edges[max_iVar] = -1; - } while (new_div); - - - // Inicializa - for (iVar = 0; iVar < 4; iVar ++) new_tetra[0][iVar] = true; - for (iVar = 4; iVar < 10; iVar ++) new_tetra[0][iVar] = false; - - nElem = 1; - for (iDiv = 0; iDiv < nDiv; iDiv++) { - for (iVar = 0; iVar < 3; iVar++) { - short target_elem = -1; - - for (iElem = 0; iElem < nElem; iElem++) { - set_0 = false; set_1 = false; - if (new_tetra[iElem][edge_div[iDiv][1]]) set_0 = true; - if (new_tetra[iElem][edge_div[iDiv][2]]) set_1 = true; - if (set_0 && set_1) target_elem = iElem; - } - - if (target_elem != -1) { - for (iNode = 0; iNode < 10; iNode++) - new_tetra[nElem][iNode] = new_tetra[target_elem][iNode]; - new_tetra[target_elem][edge_div[iDiv][0]] = true; - new_tetra[target_elem][edge_div[iDiv][2]] = false; - new_tetra[nElem][edge_div[iDiv][0]] = true; - new_tetra[nElem][edge_div[iDiv][1]] = false; - nElem++; - } - } - } - - *nPart = nElem; - - for (iTetra = 0; iTetra < nElem; iTetra++) { - Division[iTetra][0] = 4; - iVar = 1; - for (iNode = 0; iNode < 10; iNode++) - if (new_tetra[iTetra][iNode] == true) { - if (iNode == 0) Division[iTetra][iVar] = nodes[0]; - if (iNode == 1) Division[iTetra][iVar] = nodes[1]; - if (iNode == 2) Division[iTetra][iVar] = nodes[2]; - if (iNode == 3) Division[iTetra][iVar] = nodes[3]; - if (iNode == 4) Division[iTetra][iVar] = nodes[4]; - if (iNode == 5) Division[iTetra][iVar] = nodes[5]; - if (iNode == 6) Division[iTetra][iVar] = nodes[6]; - if (iNode == 7) Division[iTetra][iVar] = nodes[7]; - if (iNode == 8) Division[iTetra][iVar] = nodes[8]; - if (iNode == 9) Division[iTetra][iVar] = nodes[9]; - iVar++; - } - -// cout <<"Boolean "<< new_tetra[iTetra][0] <<" "<< new_tetra[iTetra][1] <<" "<< new_tetra[iTetra][2] <<" "<< new_tetra[iTetra][3] <<" "<< new_tetra[iTetra][4] -// <<" "<< new_tetra[iTetra][5] <<" "<< new_tetra[iTetra][6] <<" "<< new_tetra[iTetra][7] <<" "<< new_tetra[iTetra][8] <<" "<< new_tetra[iTetra][9] << endl; - -// cout <<"Nodes "<< nodes[0] <<" "<< nodes[1] <<" "<< nodes[2] <<" "<< nodes[3] <<" "<< nodes[4] -// <<" "<< nodes[5] <<" "<< nodes[6] <<" "<< nodes[7] <<" "<< nodes[8] <<" "<< nodes[9] << endl; - -// cout <<"Tets "<< Division[iTetra][0] <<" "<< Division[iTetra][1] <<" "<< Division[iTetra][2] <<" "<< Division[iTetra][3] <<" "<< Division[iTetra][4] -// <<" "<< Division[iTetra][5] <<" "<< Division[iTetra][6] <<" "<< Division[iTetra][7] <<" "<< Division[iTetra][8] <<" "<< Division[iTetra][9] << endl; - -// cin.get(); - } - - } - -} - -void CGridAdaptation::HexaDivision(long code , long *nodes, long **Division, long *nPart) { - - if (code == 1) { - - // number of nodes at each new element - Division[0][0] = 9; Division[1][0] = 9; Division[2][0] = 9; Division[3][0] = 9; - Division[4][0] = 9; Division[5][0] = 9; Division[6][0] = 9; Division[7][0] = 9; - *nPart = 8; - - // nodes that compose each element - Division[0][1] = nodes[20]; Division[0][2] = nodes[8]; Division[0][3] = nodes[1]; Division[0][4] = nodes[9]; - Division[0][5] = nodes[26]; Division[0][6] = nodes[25]; Division[0][7] = nodes[17]; Division[0][8] = nodes[22]; - - Division[1][1] = nodes[20]; Division[1][2] = nodes[9]; Division[1][3] = nodes[2]; Division[1][4] = nodes[10]; - Division[1][5] = nodes[26]; Division[1][6] = nodes[22]; Division[1][7] = nodes[18]; Division[1][8] = nodes[23]; - - Division[2][1] = nodes[20]; Division[2][2] = nodes[10]; Division[2][3] = nodes[3]; Division[2][4] = nodes[11]; - Division[2][5] = nodes[26]; Division[2][6] = nodes[23]; Division[2][7] = nodes[19]; Division[2][8] = nodes[24]; - - Division[3][1] = nodes[20]; Division[3][2] = nodes[11]; Division[3][3] = nodes[0]; Division[3][4] = nodes[8]; - Division[3][5] = nodes[26]; Division[3][6] = nodes[24]; Division[3][7] = nodes[16]; Division[3][8] = nodes[25]; - - Division[4][1] = nodes[26]; Division[4][2] = nodes[25]; Division[4][3] = nodes[17]; Division[4][4] = nodes[22]; - Division[4][5] = nodes[21]; Division[4][6] = nodes[12]; Division[4][7] = nodes[5]; Division[4][8] = nodes[13]; - - Division[5][1] = nodes[26]; Division[5][2] = nodes[22]; Division[5][3] = nodes[18]; Division[5][4] = nodes[23]; - Division[5][5] = nodes[21]; Division[5][6] = nodes[13]; Division[5][7] = nodes[6]; Division[5][8] = nodes[14]; - - Division[6][1] = nodes[26]; Division[6][2] = nodes[23]; Division[6][3] = nodes[19]; Division[6][4] = nodes[24]; - Division[6][5] = nodes[21]; Division[6][6] = nodes[14]; Division[6][7] = nodes[7]; Division[6][8] = nodes[15]; - - Division[7][1] = nodes[26]; Division[7][2] = nodes[24]; Division[7][3] = nodes[16]; Division[7][4] = nodes[25]; - Division[7][5] = nodes[21]; Division[7][6] = nodes[15]; Division[7][7] = nodes[4]; Division[7][8] = nodes[12]; - - } - - if (code == 2) { - // number of nodes at each new element - Division[0][0] = 9; Division[1][0] = 9; Division[2][0] = 9; Division[3][0] = 9; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[8]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; Division[0][4] = nodes[10]; - Division[0][5] = nodes[25]; Division[0][17] = nodes[25]; Division[0][7] = nodes[18]; Division[0][8] = nodes[23]; - - Division[1][1] = nodes[0]; Division[1][2] = nodes[8]; Division[1][3] = nodes[10]; Division[1][4] = nodes[3]; - Division[1][5] = nodes[16]; Division[1][6] = nodes[25]; Division[1][7] = nodes[23]; Division[1][8] = nodes[19]; - - Division[2][1] = nodes[25]; Division[2][2] = nodes[17]; Division[2][3] = nodes[18]; Division[2][4] = nodes[23]; - Division[2][5] = nodes[12]; Division[2][6] = nodes[5]; Division[2][7] = nodes[6]; Division[2][8] = nodes[14]; - - Division[3][1] = nodes[16]; Division[3][2] = nodes[25]; Division[3][3] = nodes[23]; Division[3][4] = nodes[19]; - Division[3][5] = nodes[4]; Division[3][6] = nodes[12]; Division[3][7] = nodes[14]; Division[3][8] = nodes[7]; - - } - - if (code == 3) { - // number of nodes at each new element - Division[0][0] = 9; Division[1][0] = 9; Division[2][0] = 9; Division[3][0] = 9; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[11]; Division[0][2] = nodes[0]; Division[0][3] = nodes[1]; Division[0][4] = nodes[9]; - Division[0][5] = nodes[24]; Division[0][6] = nodes[16]; Division[0][7] = nodes[17]; Division[0][8] = nodes[22]; - - Division[1][1] = nodes[3]; Division[1][2] = nodes[11]; Division[1][9] = nodes[2]; Division[1][4] = nodes[2]; - Division[1][5] = nodes[19]; Division[1][6] = nodes[24]; Division[1][7] = nodes[22]; Division[1][8] = nodes[18]; - - Division[2][1] = nodes[24]; Division[2][2] = nodes[16]; Division[2][3] = nodes[17]; Division[2][4] = nodes[22]; - Division[2][5] = nodes[15]; Division[2][6] = nodes[4]; Division[2][7] = nodes[5]; Division[2][8] = nodes[13]; - - Division[3][1] = nodes[19]; Division[3][2] = nodes[24]; Division[3][3] = nodes[22]; Division[3][4] = nodes[18]; - Division[3][5] = nodes[7]; Division[3][6] = nodes[15]; Division[3][7] = nodes[13]; Division[3][8] = nodes[6]; - - } - - if (code == 4) { - // number of nodes at each new element - Division[0][0] = 9; Division[1][0] = 9; Division[2][0] = 9; Division[3][0] = 9; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[20]; Division[0][2] = nodes[8]; Division[0][3] = nodes[1]; Division[0][4] = nodes[9]; - Division[0][5] = nodes[21]; Division[0][6] = nodes[12]; Division[0][7] = nodes[5]; Division[0][8] = nodes[13]; - - Division[1][1] = nodes[20]; Division[1][2] = nodes[9]; Division[1][3] = nodes[2]; Division[1][4] = nodes[10]; - Division[1][5] = nodes[21]; Division[1][6] = nodes[13]; Division[1][7] = nodes[6]; Division[1][8] = nodes[14]; - - Division[2][1] = nodes[20]; Division[2][2] = nodes[10]; Division[2][3] = nodes[0]; Division[2][4] = nodes[8]; - Division[2][5] = nodes[21]; Division[2][6] = nodes[15]; Division[2][7] = nodes[4]; Division[2][8] = nodes[12]; - - Division[3][1] = nodes[20]; Division[3][2] = nodes[10]; Division[3][3] = nodes[3]; Division[3][4] = nodes[11]; - Division[3][5] = nodes[21]; Division[3][6] = nodes[14]; Division[3][7] = nodes[7]; Division[3][8] = nodes[15]; - - } - - if (code == 5) { - // number of nodes at each new element - Division[0][0] = 9; Division[1][0] = 9; - *nPart = 2; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; Division[0][4] = nodes[3]; - Division[0][5] = nodes[16]; Division[0][6] = nodes[17]; Division[0][7] = nodes[18]; Division[0][8] = nodes[19]; - - Division[1][1] = nodes[16]; Division[1][2] = nodes[17]; Division[1][3] = nodes[18]; Division[1][4] = nodes[19]; - Division[1][5] = nodes[4]; Division[1][6] = nodes[5]; Division[1][7] = nodes[6]; Division[1][8] = nodes[7]; - - } - - if (code == 6) { - // number of nodes at each new element - Division[0][0] = 9; Division[1][0] = 9; - *nPart = 2; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[9]; Division[0][4] = nodes[11]; - Division[0][5] = nodes[4]; Division[0][6] = nodes[5]; Division[0][7] = nodes[13]; Division[0][8] = nodes[15]; - - Division[1][1] = nodes[9]; Division[1][2] = nodes[2]; Division[1][3] = nodes[3]; Division[1][4] = nodes[11]; - Division[1][5] = nodes[13]; Division[1][6] = nodes[6]; Division[1][7] = nodes[7]; Division[1][8] = nodes[15]; - - } - - if (code == 7) { - // number of nodes at each new element - Division[0][0] = 9; Division[1][0] = 9; - *nPart = 2; - - // nodes that compose each element - Division[0][1] = nodes[8]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; Division[0][4] = nodes[10]; - Division[0][5] = nodes[12]; Division[0][5] = nodes[5]; Division[0][7] = nodes[6]; Division[0][8] = nodes[14]; - - Division[1][1] = nodes[0]; Division[1][2] = nodes[8]; Division[1][3] = nodes[10]; Division[1][4] = nodes[3]; - Division[1][5] = nodes[4]; Division[1][6] = nodes[12]; Division[1][7] = nodes[14]; Division[1][8] = nodes[7]; - - } - -} - -void CGridAdaptation::PyramDivision(long code , long *nodes, long **Division, long *nPart) { - - if (code == 1) { - - // number of nodes at each new element - Division[0][0] = 6; - *nPart = 1; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; Division[0][4] = nodes[3]; Division[0][5] = nodes[4]; - - } - - if (code == 2) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; - *nPart = 3; - - // nodes that compose each element - Division[0][1] = nodes[5]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; Division[0][4] = nodes[4]; - - Division[1][1] = nodes[5]; Division[1][2] = nodes[2]; Division[1][3] = nodes[3]; Division[1][4] = nodes[4]; - - Division[2][1] = nodes[5]; Division[2][2] = nodes[3]; Division[2][3] = nodes[0]; Division[2][4] = nodes[4]; - - } - - if (code == 3) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; - *nPart = 3; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[6]; Division[0][4] = nodes[4]; - - Division[1][1] = nodes[0]; Division[1][2] = nodes[6]; Division[1][3] = nodes[3]; Division[1][4] = nodes[4]; - - Division[2][1] = nodes[3]; Division[2][2] = nodes[6]; Division[2][3] = nodes[2]; Division[2][4] = nodes[4]; - - } - - if (code == 4) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; - *nPart = 3; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[7]; Division[0][4] = nodes[4]; - - Division[1][1] = nodes[1]; Division[1][2] = nodes[2]; Division[1][3] = nodes[7]; Division[1][4] = nodes[4]; - - Division[2][1] = nodes[0]; Division[2][2] = nodes[7]; Division[2][3] = nodes[3]; Division[2][4] = nodes[4]; - - } - - if (code == 5) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; - *nPart = 3; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[8]; Division[0][4] = nodes[4]; - - Division[1][1] = nodes[1]; Division[1][2] = nodes[2]; Division[1][3] = nodes[8]; Division[1][4] = nodes[4]; - - Division[2][1] = nodes[8]; Division[2][2] = nodes[2]; Division[2][3] = nodes[3]; Division[2][4] = nodes[4]; - - } - - if (code == 6) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[5]; Division[0][3] = nodes[3]; Division[0][4] = nodes[4]; - - Division[1][1] = nodes[5]; Division[1][2] = nodes[1]; Division[1][3] = nodes[6]; Division[1][4] = nodes[4]; - - Division[2][1] = nodes[5]; Division[2][2] = nodes[6]; Division[2][3] = nodes[3]; Division[2][4] = nodes[4]; - - Division[3][1] = nodes[6]; Division[3][2] = nodes[2]; Division[3][3] = nodes[3]; Division[3][4] = nodes[4]; - - } - - if (code == 7) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[6]; Division[0][4] = nodes[4]; - - Division[1][1] = nodes[0]; Division[1][2] = nodes[6]; Division[1][3] = nodes[7]; Division[1][4] = nodes[4]; - - Division[2][1] = nodes[6]; Division[2][2] = nodes[2]; Division[2][3] = nodes[7]; Division[2][4] = nodes[4]; - - Division[3][1] = nodes[0]; Division[3][2] = nodes[7]; Division[3][3] = nodes[3]; Division[3][4] = nodes[4]; - - } - - if (code == 8) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[8]; Division[0][4] = nodes[4]; - - Division[1][1] = nodes[8]; Division[1][2] = nodes[1]; Division[1][3] = nodes[7]; Division[1][4] = nodes[4]; - - Division[2][1] = nodes[1]; Division[2][2] = nodes[2]; Division[2][3] = nodes[7]; Division[2][4] = nodes[4]; - - Division[3][1] = nodes[8]; Division[3][2] = nodes[7]; Division[3][3] = nodes[3]; Division[3][4] = nodes[4]; - - } - - if (code == 9) { - // number of nodes at each new element - Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[5]; Division[0][3] = nodes[8]; Division[0][4] = nodes[4]; - - Division[1][1] = nodes[5]; Division[1][2] = nodes[1]; Division[1][3] = nodes[2]; Division[1][4] = nodes[4]; - - Division[2][1] = nodes[8]; Division[2][2] = nodes[5]; Division[2][3] = nodes[2]; Division[2][4] = nodes[4]; - - Division[3][1] = nodes[8]; Division[3][2] = nodes[2]; Division[3][3] = nodes[3]; Division[3][4] = nodes[4]; - - } - - if (code == 10) { - // number of nodes at each new element - Division[0][0] = 6; Division[1][0] = 6; - *nPart = 2; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[5]; Division[0][3] = nodes[7]; Division[0][4] = nodes[3]; Division[0][5] = nodes[4]; - - Division[1][1] = nodes[5]; Division[1][2] = nodes[1]; Division[1][3] = nodes[2]; Division[1][4] = nodes[7]; Division[1][5] = nodes[4]; - - } - - if (code == 11) { - // number of nodes at each new element - Division[0][0] = 6; Division[1][0] = 6; - *nPart = 2; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[6]; Division[0][4] = nodes[8]; Division[0][5] = nodes[4]; - - Division[1][1] = nodes[8]; Division[1][2] = nodes[6]; Division[1][3] = nodes[2]; Division[1][4] = nodes[3]; Division[1][5] = nodes[4]; - - } - - if (code == 12) { - // number of nodes at each new element - Division[0][0] = 6; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[5]; Division[0][3] = nodes[7]; Division[0][4] = nodes[3]; Division[0][5] = nodes[4]; - - Division[1][1] = nodes[5]; Division[1][2] = nodes[1]; Division[1][3] = nodes[6]; Division[1][4] = nodes[4]; - - Division[2][1] = nodes[5]; Division[2][2] = nodes[6]; Division[2][3] = nodes[7]; Division[2][4] = nodes[4]; - - Division[3][1] = nodes[6]; Division[3][2] = nodes[2]; Division[3][3] = nodes[7]; Division[3][4] = nodes[4]; - - } - - if (code == 13) { - // number of nodes at each new element - Division[0][0] = 6; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[6]; Division[0][4] = nodes[8]; Division[0][5] = nodes[4]; - - Division[1][1] = nodes[6]; Division[1][2] = nodes[2]; Division[1][3] = nodes[7]; Division[1][4] = nodes[4]; - - Division[2][1] = nodes[8]; Division[2][2] = nodes[6]; Division[2][3] = nodes[7]; Division[2][4] = nodes[4]; - - Division[3][1] = nodes[8]; Division[3][2] = nodes[7]; Division[3][3] = nodes[3]; Division[3][4] = nodes[4]; - - } - - if (code == 14) { - // number of nodes at each new element - Division[0][0] = 6; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[5]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; Division[0][4] = nodes[7]; Division[0][5] = nodes[4]; - - Division[1][1] = nodes[0]; Division[1][2] = nodes[5]; Division[1][3] = nodes[8]; Division[1][4] = nodes[4]; - - Division[2][1] = nodes[8]; Division[2][2] = nodes[5]; Division[2][3] = nodes[7]; Division[2][4] = nodes[4]; - - Division[3][1] = nodes[8]; Division[3][2] = nodes[7]; Division[3][3] = nodes[3]; Division[3][4] = nodes[4]; - - } - - if (code == 15) { - // number of nodes at each new element - Division[0][0] = 6; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[8]; Division[0][2] = nodes[6]; Division[0][3] = nodes[2]; Division[0][4] = nodes[3]; Division[0][5] = nodes[4]; - - Division[1][1] = nodes[0]; Division[1][2] = nodes[5]; Division[1][3] = nodes[8]; Division[1][4] = nodes[4]; - - Division[2][1] = nodes[5]; Division[2][2] = nodes[1]; Division[2][3] = nodes[6]; Division[2][4] = nodes[4]; - - Division[3][1] = nodes[5]; Division[3][2] = nodes[6]; Division[3][3] = nodes[8]; Division[3][4] = nodes[4]; - - } - - if (code == 16) { - // number of nodes at each new element - Division[0][0] = 6; Division[1][0] = 6; Division[2][0] = 6; Division[3][0] = 6; - *nPart = 4; - - // nodes that compose each element - Division[0][1] = nodes[9]; Division[0][2] = nodes[8]; Division[0][3] = nodes[0]; Division[0][4] = nodes[5]; Division[0][5] = nodes[4]; - - Division[1][1] = nodes[9]; Division[1][2] = nodes[5]; Division[1][3] = nodes[1]; Division[1][4] = nodes[6]; Division[1][5] = nodes[4]; - - Division[2][1] = nodes[9]; Division[2][2] = nodes[6]; Division[2][3] = nodes[2]; Division[2][4] = nodes[7]; Division[2][5] = nodes[4]; - - Division[3][1] = nodes[9]; Division[3][2] = nodes[7]; Division[3][3] = nodes[3]; Division[3][4] = nodes[8]; Division[3][5] = nodes[4]; - - } - -} - -void CGridAdaptation::SetHomothetic_Adaptation2D(CGeometry *geometry, CPhysicalGeometry *geo_adapt, - CConfig *config) { - - unsigned long iPoint, iElem, iEdge, ip_0, ip_1, ip_2, ip_3, iVertex; - unsigned short iDim, iMarker, iVar; - long no_0 = 0, no_1 = 0, no_2 = 0, no_3 = 0; - unsigned short nMarker_Max = config->GetnMarker_Max(); - - long *TriangleAdaptCode; - long **TriangleEdgeIndex; bool **TriangleEdgeCode; long **TriangleEdgeNode; - - long *RectAdaptCode; - long **RectEdgeIndex; bool **RectEdgeCode; long **RectEdgeNode; - long **RectElemIndex; bool **RectElemCode; long **RectElemNode; - - bool Restart_Flow = false; - bool Restart_Adjoint = false; - - if ((config->GetKind_Adaptation() == FULL_FLOW) || - (config->GetKind_Adaptation() == GRAD_FLOW) || - (config->GetKind_Adaptation() == FULL_ADJOINT) || - (config->GetKind_Adaptation() == GRAD_ADJOINT) || - (config->GetKind_Adaptation() == GRAD_FLOW_ADJ) || - (config->GetKind_Adaptation() == REMAINING) || - (config->GetKind_Adaptation() == COMPUTABLE)) Restart_Flow = true; - - if ((config->GetKind_Adaptation() == FULL_ADJOINT) || - (config->GetKind_Adaptation() == GRAD_ADJOINT) || - (config->GetKind_Adaptation() == GRAD_FLOW_ADJ) || - (config->GetKind_Adaptation() == REMAINING) || - (config->GetKind_Adaptation() == COMPUTABLE)) Restart_Adjoint = true; - - TriangleAdaptCode = new long[geometry->GetnElem()]; - TriangleEdgeIndex = new long*[geometry->GetnElem()]; - TriangleEdgeCode = new bool*[geometry->GetnElem()]; - TriangleEdgeNode = new long*[geometry->GetnElem()]; - - RectAdaptCode = new long[geometry->GetnElem()]; - RectEdgeIndex = new long*[geometry->GetnElem()]; - RectEdgeCode = new bool*[geometry->GetnElem()]; - RectEdgeNode = new long*[geometry->GetnElem()]; - RectElemIndex = new long*[geometry->GetnElem()]; - RectElemCode = new bool*[geometry->GetnElem()]; - RectElemNode = new long*[geometry->GetnElem()]; - - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - TriangleEdgeIndex[iElem] = new long [3]; - TriangleEdgeCode[iElem] = new bool [3]; - TriangleEdgeNode[iElem] = new long [3]; - - RectEdgeIndex[iElem] = new long [4]; - RectEdgeCode[iElem] = new bool [4]; - RectEdgeNode[iElem] = new long [4]; - RectElemIndex[iElem] = new long [1]; - RectElemCode[iElem] = new bool [1]; - RectElemNode[iElem] = new long [1]; - } - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { - ip_0 = geometry->elem[iElem]->GetNode(0); - ip_1 = geometry->elem[iElem]->GetNode(1); - ip_2 = geometry->elem[iElem]->GetNode(2); - - TriangleEdgeIndex[iElem][0] = geometry->FindEdge(ip_0, ip_1); TriangleEdgeCode[iElem][0] = false; TriangleEdgeNode[iElem][0] = -1; - TriangleEdgeIndex[iElem][1] = geometry->FindEdge(ip_1, ip_2); TriangleEdgeCode[iElem][1] = false; TriangleEdgeNode[iElem][1] = -1; - TriangleEdgeIndex[iElem][2] = geometry->FindEdge(ip_2, ip_0); TriangleEdgeCode[iElem][2] = false; TriangleEdgeNode[iElem][2] = -1; - } - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { - ip_0 = geometry->elem[iElem]->GetNode(0); - ip_1 = geometry->elem[iElem]->GetNode(1); - ip_2 = geometry->elem[iElem]->GetNode(2); - ip_3 = geometry->elem[iElem]->GetNode(3); - - RectEdgeIndex[iElem][0] = geometry->FindEdge(ip_0, ip_1); RectEdgeCode[iElem][0] = false; RectEdgeNode[iElem][0] = -1; - RectEdgeIndex[iElem][1] = geometry->FindEdge(ip_1, ip_2); RectEdgeCode[iElem][1] = false; RectEdgeNode[iElem][1] = -1; - RectEdgeIndex[iElem][2] = geometry->FindEdge(ip_2, ip_3); RectEdgeCode[iElem][2] = false; RectEdgeNode[iElem][2] = -1; - RectEdgeIndex[iElem][3] = geometry->FindEdge(ip_3, ip_0); RectEdgeCode[iElem][3] = false; RectEdgeNode[iElem][3] = -1; - - RectElemIndex[iElem][0] = iElem; RectElemCode[iElem][0] = false; RectElemNode[iElem][0] = -1; - } - - } - - /*--- Initial edges that are going to be divided ---*/ - - bool *DivEdge = new bool[geometry->GetnEdge()]; - bool *DivElem = new bool[geometry->GetnElem()]; - - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) DivEdge[iEdge] = false; - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) - DivElem[iElem] = geometry->elem[iElem]->GetDivide(); - - /*--- Set the edge division in the reactangles and in the edge list. ---*/ - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - if (DivElem[iElem] == true) { - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { - for (int iIndex = 0; iIndex < 3; iIndex++) { - DivEdge[TriangleEdgeIndex[iElem][iIndex]] = true; - TriangleEdgeCode[iElem][iIndex] = true; - } - } - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { - for (int iIndex = 0; iIndex < 4; iIndex++) { - DivEdge[RectEdgeIndex[iElem][iIndex]] = true; - RectEdgeCode[iElem][iIndex] = true; - } - } - } - } - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) - for (unsigned long iBoundElem = 0; iBoundElem < geometry->GetnElem_Bound(iMarker); iBoundElem++) { - - ip_0 = geometry->bound[iMarker][iBoundElem]->GetNode(0); - ip_1 = geometry->bound[iMarker][iBoundElem]->GetNode(1); - - long edge = geometry->FindEdge(ip_0, ip_1); - - if (DivEdge[edge]) { - - unsigned long iv_1 = geometry->node[ip_1]->GetVertex(iMarker); - unsigned long ip_1_Nearfield = geometry->vertex[iMarker][iv_1]->GetDonorPoint(); - unsigned long iv_0 = geometry->node[ip_0]->GetVertex(iMarker); - unsigned long ip_0_Nearfield = geometry->vertex[iMarker][iv_0]->GetDonorPoint(); - - long edge_Nearfield = geometry->FindEdge(ip_0_Nearfield, ip_1_Nearfield); - - DivEdge[edge_Nearfield] = true; - - } - - } - - /*--- We must verify that all the elements have the right edges marked ---*/ - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { - for (int iIndex = 0; iIndex < 3; iIndex++) { - if (DivEdge[TriangleEdgeIndex[iElem][iIndex]] == true) { - TriangleEdgeCode[iElem][iIndex] = true; - } - } - } - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { - for (int iIndex = 0; iIndex < 4; iIndex++) { - if (DivEdge[RectEdgeIndex[iElem][iIndex]] == true) { - RectEdgeCode[iElem][iIndex] = true; - } - } - } - } - - /*--- Only those elements that verify certain rules will be marked for hexa adaptation... - the others will need a new point in the middle and RectExts ---*/ - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { - TriangleAdaptCode[iElem] = CheckTriangleCode(TriangleEdgeCode[iElem]); - } - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { - RectAdaptCode[iElem] = CheckRectCode(RectEdgeCode[iElem]); - - /*--- Set the RectAdaptCode ---*/ - - if (RectAdaptCode[iElem] == 1) { - RectElemCode[iElem][0] = true; - } - } - } - - /*--- Create the new nodes on the edges, on the faces, and in the element. ---*/ - - long *NodeAtEdges = new long[geometry->GetnEdge()]; - long *NodeAtElem = new long[geometry->GetnElem()]; - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) NodeAtEdges[iEdge] = -1; - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) NodeAtElem[iElem] = -1; - - nPoint_new = geometry->GetnPoint(); - - su2double **NewNodeCoord; - NewNodeCoord = new su2double *[4*geometry->GetnPoint()]; - for (iPoint = 0; iPoint < 4*geometry->GetnPoint(); iPoint++) - NewNodeCoord[iPoint] = new su2double[geometry->GetnDim()]; - - if (Restart_Flow) { - ConsVar_Adapt = new su2double *[4*geometry->GetnPoint()]; - for (iPoint = 0; iPoint < 4*geometry->GetnPoint(); iPoint++) - ConsVar_Adapt[iPoint] = new su2double[nVar]; - } - - if (Restart_Adjoint) { - AdjVar_Adapt = new su2double *[4*geometry->GetnPoint()]; - for (iPoint = 0; iPoint < 4*geometry->GetnPoint(); iPoint++) - AdjVar_Adapt[iPoint] = new su2double[nVar]; - } - - /*--- Set the value of the variables ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { - for (iVar = 0; iVar < nVar; iVar ++) { - if (Restart_Flow) ConsVar_Adapt[iPoint][iVar] = ConsVar_Sol[iPoint][iVar]; - if (Restart_Adjoint) AdjVar_Adapt[iPoint][iVar] = AdjVar_Sol[iPoint][iVar]; - } - } - - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { - - ip_0 = geometry->elem[iElem]->GetNode(0); - ip_1 = geometry->elem[iElem]->GetNode(1); - ip_2 = geometry->elem[iElem]->GetNode(2); - - for (int iIndex = 0; iIndex < 3; iIndex++) { - - if (TriangleEdgeCode[iElem][iIndex] == true) { - if (NodeAtEdges[TriangleEdgeIndex[iElem][iIndex]] != -1) - TriangleEdgeNode[iElem][iIndex] = NodeAtEdges[TriangleEdgeIndex[iElem][iIndex]]; - - if (NodeAtEdges[TriangleEdgeIndex[iElem][iIndex]] == -1) { - - NodeAtEdges[TriangleEdgeIndex[iElem][iIndex]] = nPoint_new; - TriangleEdgeNode[iElem][iIndex] = nPoint_new; - - /*--- Compute the coordinates of the new node ---*/ - - if (iIndex == 0) {no_0 = ip_0; no_1 = ip_1;} - if (iIndex == 1) {no_0 = ip_1; no_1 = ip_2;} - if (iIndex == 2) {no_0 = ip_2; no_1 = ip_0;} - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) - NewNodeCoord[nPoint_new][iDim] = 0.5*(geometry->node[no_0]->GetCoord(iDim)+geometry->node[no_1]->GetCoord(iDim)); - - for (iVar = 0; iVar < nVar; iVar ++) { - if (Restart_Flow) ConsVar_Adapt[nPoint_new][iVar] = 0.5 * (ConsVar_Adapt[no_0][iVar]+ConsVar_Adapt[no_1][iVar]); - if (Restart_Adjoint) AdjVar_Adapt[nPoint_new][iVar] = 0.5 * (AdjVar_Adapt[no_0][iVar]+AdjVar_Adapt[no_1][iVar]); - } - - nPoint_new++; - } - } - } - } - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { - - ip_0 = geometry->elem[iElem]->GetNode(0); - ip_1 = geometry->elem[iElem]->GetNode(1); - ip_2 = geometry->elem[iElem]->GetNode(2); - ip_3 = geometry->elem[iElem]->GetNode(3); - - for (int iIndex = 0; iIndex < 4; iIndex++) { - - if (RectEdgeCode[iElem][iIndex] == true) { - if (NodeAtEdges[RectEdgeIndex[iElem][iIndex]] != -1) - RectEdgeNode[iElem][iIndex] = NodeAtEdges[RectEdgeIndex[iElem][iIndex]]; - - if (NodeAtEdges[RectEdgeIndex[iElem][iIndex]] == -1) { - - NodeAtEdges[RectEdgeIndex[iElem][iIndex]] = nPoint_new; - RectEdgeNode[iElem][iIndex] = nPoint_new; - - /*--- Compute the coordinates of the new node ---*/ - - if (iIndex == 0) {no_0 = ip_0; no_1 = ip_1;} - if (iIndex == 1) {no_0 = ip_1; no_1 = ip_2;} - if (iIndex == 2) {no_0 = ip_2; no_1 = ip_3;} - if (iIndex == 3) {no_0 = ip_3; no_1 = ip_0;} - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) - NewNodeCoord[nPoint_new][iDim] = 0.5*(geometry->node[no_0]->GetCoord(iDim)+geometry->node[no_1]->GetCoord(iDim)); - - for (iVar = 0; iVar < nVar; iVar ++) { - if (Restart_Flow) ConsVar_Adapt[nPoint_new][iVar] = 0.5 * (ConsVar_Adapt[no_0][iVar]+ConsVar_Adapt[no_1][iVar]); - if (Restart_Adjoint) AdjVar_Adapt[nPoint_new][iVar] = 0.5 * (AdjVar_Adapt[no_0][iVar]+AdjVar_Adapt[no_1][iVar]); - } - - nPoint_new++; - } - } - } - - for (int iIndex = 0; iIndex < 1; iIndex++) { - - if (RectElemCode[iElem][iIndex] == true) { - - if (NodeAtElem[RectElemIndex[iElem][iIndex]] != -1) - RectElemNode[iElem][iIndex] = NodeAtElem[RectElemIndex[iElem][iIndex]]; - - if (NodeAtElem[RectElemIndex[iElem][iIndex]] == -1) { - NodeAtElem[RectElemIndex[iElem][iIndex]] = nPoint_new; - RectElemNode[iElem][iIndex] = nPoint_new; - - /*--- Compute the coordinates of the new node ---*/ - - if (iIndex == 0) {no_0 = ip_0; no_1 = ip_1; no_2 = ip_2; no_3 = ip_3;} - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) - NewNodeCoord[nPoint_new][iDim] = 0.25*(geometry->node[no_0]->GetCoord(iDim) + - geometry->node[no_1]->GetCoord(iDim) + - geometry->node[no_2]->GetCoord(iDim) + - geometry->node[no_3]->GetCoord(iDim)); - - for (iVar = 0; iVar < nVar; iVar ++) { - if (Restart_Flow) ConsVar_Adapt[nPoint_new][iVar] = 0.25 * (ConsVar_Adapt[no_0][iVar]+ConsVar_Adapt[no_1][iVar]+ConsVar_Adapt[no_2][iVar]+ConsVar_Adapt[no_3][iVar]); - if (Restart_Adjoint) AdjVar_Adapt[nPoint_new][iVar] = 0.25 * (AdjVar_Adapt[no_0][iVar]+AdjVar_Adapt[no_1][iVar]+AdjVar_Adapt[no_2][iVar]+AdjVar_Adapt[no_3][iVar]); - } - - nPoint_new++; - } - } - } - } - - } - - - /*--- if Quadrilateral adapt code equals 0, then a semidivision is applied ---*/ - long nSemiDivided = 0; - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { - if (RectAdaptCode[iElem] == 0) - nSemiDivided++; - } - } - - /*--- If semidivision, then divide add a new point, divide the quadrilateral into triangles, - and find the right combination, it also create the new node (hexa). ---*/ - long nRectExt = nSemiDivided; - - long *RectExtAdaptCode; - long **RectExtNode; - long **RectRectExtIndex; - long *RectExtRectIndex; - - long **RectExtEdgeIndex; - bool **RectExtEdgeCode; - long **RectExtEdgeNode; - - RectExtAdaptCode = new long [nRectExt]; - RectExtNode = new long *[nRectExt]; - RectRectExtIndex = new long *[geometry->GetnElem()]; - RectExtRectIndex = new long [nRectExt]; - RectExtEdgeIndex = new long *[nRectExt]; - RectExtEdgeCode = new bool *[nRectExt]; - RectExtEdgeNode = new long *[nRectExt]; - - for (long iRectExt = 0; iRectExt < nRectExt; iRectExt++) { - RectExtNode[iRectExt] = new long [4]; - RectExtEdgeIndex[iRectExt] = new long [4]; - RectExtEdgeCode[iRectExt] = new bool [4]; - RectExtEdgeNode[iRectExt] = new long [4]; - } - - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { - RectRectExtIndex[iElem] = new long [1]; - } - } - - nRectExt = 0; - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { - if (RectAdaptCode[iElem] == 0) { - - /*--- Write the edge combination on the base. ---*/ - - ip_0 = geometry->elem[iElem]->GetNode(0); - ip_1 = geometry->elem[iElem]->GetNode(1); - ip_2 = geometry->elem[iElem]->GetNode(2); - ip_3 = geometry->elem[iElem]->GetNode(3); - - /*--- Create the 1st RectExtid. ---*/ - - RectRectExtIndex[iElem][0] = nRectExt; RectExtRectIndex[nRectExt] = iElem; - - RectExtNode[nRectExt][0] = ip_0; RectExtNode[nRectExt][1] = ip_1; - RectExtNode[nRectExt][2] = ip_2; RectExtNode[nRectExt][3] = ip_3; - - RectExtEdgeIndex[nRectExt][0] = RectEdgeIndex[iElem][0]; RectExtEdgeIndex[nRectExt][1] = RectEdgeIndex[iElem][1]; - RectExtEdgeIndex[nRectExt][2] = RectEdgeIndex[iElem][2]; RectExtEdgeIndex[nRectExt][3] = RectEdgeIndex[iElem][3]; - - RectExtEdgeNode[nRectExt][0] = RectEdgeNode[iElem][0]; RectExtEdgeNode[nRectExt][1] = RectEdgeNode[iElem][1]; - RectExtEdgeNode[nRectExt][2] = RectEdgeNode[iElem][2]; RectExtEdgeNode[nRectExt][3] = RectEdgeNode[iElem][3]; - - - for (int iIndex = 0; iIndex < 4; iIndex++) - if (DivEdge[RectExtEdgeIndex[nRectExt][iIndex]] == true) RectExtEdgeCode[nRectExt][iIndex] = true; - nRectExt++; - - } - } - } - - /*--- Check the kind of RectExt partitioning that should be applied ---*/ - - for (int iRectExt = 0; iRectExt < nRectExt; iRectExt ++) { - RectExtAdaptCode[iRectExt] = CheckRectExtCode(RectExtEdgeCode[iRectExt]); - if (RectExtAdaptCode[iRectExt] == 0) cout << "There is a problem with one RectExt" << endl; - } - - /*--- Create new structure ---*/ - - nElem_new = geometry->GetnElem(); - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { - if (TriangleAdaptCode[iElem] == 1) nElem_new = nElem_new + 3; - if (TriangleAdaptCode[iElem] == 2) nElem_new = nElem_new + 1; - if (TriangleAdaptCode[iElem] == 3) nElem_new = nElem_new + 1; - if (TriangleAdaptCode[iElem] == 4) nElem_new = nElem_new + 1; - if (TriangleAdaptCode[iElem] == 5) nElem_new = nElem_new + 1; - if (TriangleAdaptCode[iElem] == 6) nElem_new = nElem_new + 1; - if (TriangleAdaptCode[iElem] == 7) nElem_new = nElem_new + 1; - } - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { - if (RectAdaptCode[iElem] == 1) nElem_new = nElem_new + 3; - if (RectAdaptCode[iElem] == 2) nElem_new = nElem_new + 1; - if (RectAdaptCode[iElem] == 3) nElem_new = nElem_new + 1; - if (RectAdaptCode[iElem] == 0) { - long iRectExt = RectRectExtIndex[iElem][0]; - if (RectExtAdaptCode[iRectExt] == 2) nElem_new = nElem_new + 2; - if (RectExtAdaptCode[iRectExt] == 3) nElem_new = nElem_new + 2; - if (RectExtAdaptCode[iRectExt] == 4) nElem_new = nElem_new + 2; - if (RectExtAdaptCode[iRectExt] == 5) nElem_new = nElem_new + 2; - if (RectExtAdaptCode[iRectExt] == 6) nElem_new = nElem_new + 3; - if (RectExtAdaptCode[iRectExt] == 7) nElem_new = nElem_new + 3; - if (RectExtAdaptCode[iRectExt] == 8) nElem_new = nElem_new + 3; - if (RectExtAdaptCode[iRectExt] == 9) nElem_new = nElem_new + 3; - if (RectExtAdaptCode[iRectExt] == 12) nElem_new = nElem_new + 3; - if (RectExtAdaptCode[iRectExt] == 13) nElem_new = nElem_new + 3; - if (RectExtAdaptCode[iRectExt] == 14) nElem_new = nElem_new + 3; - if (RectExtAdaptCode[iRectExt] == 15) nElem_new = nElem_new + 3; - } - } - } - - /*--- New points ---*/ - - geo_adapt->node = new CPoint*[nPoint_new]; - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) - geo_adapt->node[iPoint] = new CPoint(geometry->node[iPoint]->GetCoord(0), geometry->node[iPoint]->GetCoord(1), iPoint, config); - - for (iPoint = geometry->GetnPoint(); iPoint < nPoint_new; iPoint++) - geo_adapt->node[iPoint] = new CPoint(NewNodeCoord[iPoint][0], NewNodeCoord[iPoint][1], iPoint, config); - - /*--- New elements ---*/ - - geo_adapt->elem = new CPrimalGrid*[nElem_new]; - - unsigned long iElemNew = 0; - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { - if (TriangleAdaptCode[iElem] == -1) { - geo_adapt->elem[iElemNew] = new CTriangle(geometry->elem[iElem]->GetNode(0), - geometry->elem[iElem]->GetNode(1), - geometry->elem[iElem]->GetNode(2), 2); - iElemNew++; - } - } - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { - if (RectAdaptCode[iElem] == -1) { - geo_adapt->elem[iElemNew] = new CQuadrilateral(geometry->elem[iElem]->GetNode(0), - geometry->elem[iElem]->GetNode(1), - geometry->elem[iElem]->GetNode(2), - geometry->elem[iElem]->GetNode(3), 2); - iElemNew++; - } - } - } - - long nodes[27]; long **Division; long nPart; - - Division = new long*[100]; - for (long iVar = 0; iVar < 100; iVar++) - Division[iVar] = new long[100]; - - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { - - /*--- Triangle elements... ---*/ - - if (TriangleAdaptCode[iElem] > 0) { - - /*--- First the corners ---*/ - - nodes[0] = geometry->elem[iElem]->GetNode(0); - nodes[1] = geometry->elem[iElem]->GetNode(1); - nodes[2] = geometry->elem[iElem]->GetNode(2); - - /*--- Next the points that correspond to the broken edges. ---*/ - - nodes[3] = TriangleEdgeNode[iElem][0]; - nodes[4] = TriangleEdgeNode[iElem][1]; - nodes[5] = TriangleEdgeNode[iElem][2]; - - TriangleDivision(TriangleAdaptCode[iElem], nodes, NULL, Division, &nPart); - for (long iPart = 0; iPart < nPart; iPart++) { - - /*--- Triangle case ---*/ - - if (Division[iPart][0] == 4) { - geo_adapt->elem[iElemNew] = new CTriangle(Division[iPart][1], - Division[iPart][2], - Division[iPart][3], 2); - iElemNew++; - } - - /*--- Quadrilateral case ---*/ - - if (Division[iPart][0] == 5) { - geo_adapt->elem[iElemNew] = new CQuadrilateral(Division[iPart][1], - Division[iPart][2], - Division[iPart][3], - Division[iPart][4], 2); - iElemNew++; - } - } - } - } - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { - - /*--- Rect elements... ---*/ - - if (RectAdaptCode[iElem] > 0) { - - /*--- First the corners ---*/ - - nodes[0] = geometry->elem[iElem]->GetNode(0); nodes[1] = geometry->elem[iElem]->GetNode(1); - nodes[2] = geometry->elem[iElem]->GetNode(2); nodes[3] = geometry->elem[iElem]->GetNode(3); - - /*--- Next the points that correspond to the broken edges. ---*/ - - nodes[4] = RectEdgeNode[iElem][0]; nodes[5] = RectEdgeNode[iElem][1]; - nodes[6] = RectEdgeNode[iElem][2]; nodes[7] = RectEdgeNode[iElem][3]; - - /*--- Next the points that correspond to the element. ---*/ - - nodes[8] = RectElemNode[iElem][0]; - - RectDivision(RectAdaptCode[iElem], nodes, Division, &nPart); - for (long iPart = 0; iPart < nPart; iPart++) { - geo_adapt->elem[iElemNew] = new CQuadrilateral(Division[iPart][1], - Division[iPart][2], - Division[iPart][3], - Division[iPart][4], 2); - iElemNew++; - } - } - - /*--- RectExt elements... ---*/ - - if (RectAdaptCode[iElem] == 0) { - long iRectExt = RectRectExtIndex[iElem][0]; - - /*--- First the corners ---*/ - - nodes[0] = RectExtNode[iRectExt][0]; - nodes[1] = RectExtNode[iRectExt][1]; - nodes[2] = RectExtNode[iRectExt][2]; - nodes[3] = RectExtNode[iRectExt][3]; - - /*--- Next the points that correspond to the broken edges. ---*/ - - nodes[4] = RectExtEdgeNode[iRectExt][0]; - nodes[5] = RectExtEdgeNode[iRectExt][1]; - nodes[6] = RectExtEdgeNode[iRectExt][2]; - nodes[7] = RectExtEdgeNode[iRectExt][3]; - - RectExtDivision(RectExtAdaptCode[iRectExt], nodes, Division, &nPart); - for (long iPart = 0; iPart < nPart; iPart++) { - - /*--- Triangle case ---*/ - - if (Division[iPart][0] == 4) { - geo_adapt->elem[iElemNew] = new CTriangle(Division[iPart][1], - Division[iPart][2], - Division[iPart][3], 2); - iElemNew++; - } - - /*--- Quadrilateral case ---*/ - - if (Division[iPart][0] == 5) { - geo_adapt->elem[iElemNew] = new CQuadrilateral(Division[iPart][1], - Division[iPart][2], - Division[iPart][3], - Division[iPart][4], 2); - iElemNew++; - } - } - } - } - } - - geo_adapt->SetnElem(nElem_new); - geo_adapt->SetnPoint(nPoint_new); - geo_adapt->SetnPointDomain(nPoint_new); - geo_adapt->SetnDim(nDim); - - /*--- Create boundary structure ---*/ - - geo_adapt->SetnMarker(geometry->GetnMarker()); - geo_adapt->nElem_Bound = new unsigned long [geometry->GetnMarker()]; - geo_adapt->Tag_to_Marker = new string [nMarker_Max]; - geo_adapt->bound = new CPrimalGrid**[geometry->GetnMarker()]; - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - long nNewBCcv = 0; - for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { - ip_0 = geometry->bound[iMarker][iVertex]->GetNode(0); - ip_1 = geometry->bound[iMarker][iVertex]->GetNode(1); - if (DivEdge[geometry->FindEdge(ip_0, ip_1)]) nNewBCcv = nNewBCcv + 2; - else nNewBCcv = nNewBCcv + 1; - } - geo_adapt->bound[iMarker] = new CPrimalGrid* [nNewBCcv]; - geo_adapt->SetnElem_Bound(iMarker, nNewBCcv); - geo_adapt->SetMarker_Tag(iMarker, geometry->GetMarker_Tag(iMarker)); - } - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - long nNewBCcv = 0; - for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { - - ip_0 = geometry->bound[iMarker][iVertex]->GetNode(0); geo_adapt->node[ip_0]->SetBoundary(geometry->GetnMarker()); - ip_1 = geometry->bound[iMarker][iVertex]->GetNode(1); geo_adapt->node[ip_1]->SetBoundary(geometry->GetnMarker()); - long ip_01 = NodeAtEdges[geometry->FindEdge(ip_0, ip_1)]; - - if (ip_01 != -1) { - - -// if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || -// (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) || -// (config->GetMarker_All_KindBC(iMarker) == EULER_WALL)) { -// -// /*--- Recompute the coordinates using the NACA 4Digits analytical definition ---*/ -// -// su2double Ya = 0.0 / 100.0; /*--- Maximum camber as a fraction of the chord -// (100 m is the first of the four digits) ---*/ -// su2double Xa = 0.0 / 10.0; /*--- Location of maximum camber as a fraction of -// the chord (10 p is the second digit in the NACA xxxx description) ---*/ -// su2double t = 12.0 / 100.0; /*--- Maximum thickness as a fraction of the -// chord (so 100 t gives the last two digits in -// the NACA 4-digit denomination) ---*/ -// -// su2double *Coord = geo_adapt->node[ip_01]->GetCoord(); -// su2double *Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); -// -// su2double Ycurv = 0.0; -// if (Coord[0] < Xa) Ycurv = (2.0*Xa*Coord[0]-pow(Coord[0],2.0))*(Ya/pow(Xa,2.0)); -// else Ycurv = ((1.0-2.0*Xa)+2.0*Xa*Coord[0]-pow(Coord[0],2.0))*(Ya/pow((1.0-Xa), 2.0)); -// -// su2double Yesp = 0.0; -// Yesp = t*(1.4845*sqrt(Coord[0])-0.6300*Coord[0]-1.7580*pow(Coord[0],2.0)+ -// 1.4215*pow(Coord[0],3.0)-0.518*pow(Coord[0],4.0)); -// -// if (Normal[1] > 0) Coord[1] = (Ycurv + Yesp); -// if (Normal[1] < 0) Coord[1] = (Ycurv - Yesp); -// -// } - - geo_adapt->node[ip_01]->SetBoundary(geometry->GetnMarker()); - geo_adapt->bound[iMarker][nNewBCcv] = new CLine(ip_0, ip_01, 2); - nNewBCcv++; - geo_adapt->bound[iMarker][nNewBCcv] = new CLine(ip_01, ip_1, 2); - nNewBCcv++; - } - else { - geo_adapt->bound[iMarker][nNewBCcv] = new CLine(ip_0, ip_1, 2); - nNewBCcv++; - } - } - } - - delete [] DivEdge; - delete [] DivElem; - delete [] NodeAtEdges; - delete [] NodeAtElem; - -} - -void CGridAdaptation::SetHomothetic_Adaptation3D(CGeometry *geometry, CPhysicalGeometry *geo_adapt, - CConfig *config) { - - unsigned long iPoint, iElem, iEdge, ip_0, ip_1, ip_2, ip_3, ip_4, ip_5, ip_6, ip_7, iVertex; - unsigned short iDim, iMarker, iVar; - long no_0 = 0, no_1 = 0, no_2 = 0, no_3 = 0, no_4 = 0, no_5 = 0, no_6 = 0, no_7 = 0; - unsigned short counter; - unsigned short nMarker_Max = config->GetnMarker_Max(); - - long *TetraAdaptCode; - long **TetraEdgeIndex; bool **TetraEdgeCode; long **TetraEdgeNode; - - long *HexaAdaptCode; - long **HexaEdgeIndex; bool **HexaEdgeCode; long **HexaEdgeNode; - long **HexaFaceIndex; bool **HexaFaceCode; long **HexaFaceNode; - long **HexaElemIndex; bool **HexaElemCode; long **HexaElemNode; - - bool Restart_Flow = false; - bool Restart_Adjoint = false; - - if ((config->GetKind_Adaptation() == FULL_FLOW) || - (config->GetKind_Adaptation() == GRAD_FLOW) || - (config->GetKind_Adaptation() == FULL_ADJOINT) || - (config->GetKind_Adaptation() == GRAD_ADJOINT) || - (config->GetKind_Adaptation() == GRAD_FLOW_ADJ) || - (config->GetKind_Adaptation() == REMAINING) || - (config->GetKind_Adaptation() == COMPUTABLE)) Restart_Flow = true; - - if ((config->GetKind_Adaptation() == FULL_ADJOINT) || - (config->GetKind_Adaptation() == GRAD_ADJOINT) || - (config->GetKind_Adaptation() == GRAD_FLOW_ADJ) || - (config->GetKind_Adaptation() == REMAINING) || - (config->GetKind_Adaptation() == COMPUTABLE)) Restart_Adjoint = true; - - TetraAdaptCode = new long[geometry->GetnElem()]; - TetraEdgeIndex = new long*[geometry->GetnElem()]; - TetraEdgeCode = new bool*[geometry->GetnElem()]; - TetraEdgeNode = new long*[geometry->GetnElem()]; - - HexaAdaptCode = new long[geometry->GetnElem()]; - HexaEdgeIndex = new long*[geometry->GetnElem()]; - HexaEdgeCode = new bool*[geometry->GetnElem()]; - HexaEdgeNode = new long*[geometry->GetnElem()]; - HexaFaceIndex = new long*[geometry->GetnElem()]; - HexaFaceCode = new bool*[geometry->GetnElem()]; - HexaFaceNode = new long*[geometry->GetnElem()]; - HexaElemIndex = new long*[geometry->GetnElem()]; - HexaElemCode = new bool*[geometry->GetnElem()]; - HexaElemNode = new long*[geometry->GetnElem()]; - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - TetraEdgeIndex[iElem] = new long [6]; - TetraEdgeCode[iElem] = new bool [6]; - TetraEdgeNode[iElem] = new long [6]; - - HexaEdgeIndex[iElem] = new long [12]; - HexaEdgeCode[iElem] = new bool [12]; - HexaEdgeNode[iElem] = new long [12]; - HexaFaceIndex[iElem] = new long [6]; - HexaFaceCode[iElem] = new bool [6]; - HexaFaceNode[iElem] = new long [6]; - HexaElemIndex[iElem] = new long [1]; - HexaElemCode[iElem] = new bool [1]; - HexaElemNode[iElem] = new long [1]; - } - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { - ip_0 = geometry->elem[iElem]->GetNode(0); - ip_1 = geometry->elem[iElem]->GetNode(1); - ip_2 = geometry->elem[iElem]->GetNode(2); - ip_3 = geometry->elem[iElem]->GetNode(3); - - TetraEdgeIndex[iElem][0] = geometry->FindEdge(ip_0, ip_1); TetraEdgeCode[iElem][0] = false; TetraEdgeNode[iElem][0] = -1; - TetraEdgeIndex[iElem][1] = geometry->FindEdge(ip_0, ip_2); TetraEdgeCode[iElem][1] = false; TetraEdgeNode[iElem][1] = -1; - TetraEdgeIndex[iElem][2] = geometry->FindEdge(ip_0, ip_3); TetraEdgeCode[iElem][2] = false; TetraEdgeNode[iElem][2] = -1; - TetraEdgeIndex[iElem][3] = geometry->FindEdge(ip_1, ip_2); TetraEdgeCode[iElem][3] = false; TetraEdgeNode[iElem][3] = -1; - TetraEdgeIndex[iElem][4] = geometry->FindEdge(ip_1, ip_3); TetraEdgeCode[iElem][4] = false; TetraEdgeNode[iElem][4] = -1; - TetraEdgeIndex[iElem][5] = geometry->FindEdge(ip_2, ip_3); TetraEdgeCode[iElem][5] = false; TetraEdgeNode[iElem][5] = -1; - - } - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { - ip_0 = geometry->elem[iElem]->GetNode(0); - ip_1 = geometry->elem[iElem]->GetNode(1); - ip_2 = geometry->elem[iElem]->GetNode(2); - ip_3 = geometry->elem[iElem]->GetNode(3); - ip_4 = geometry->elem[iElem]->GetNode(4); - ip_5 = geometry->elem[iElem]->GetNode(5); - ip_6 = geometry->elem[iElem]->GetNode(6); - ip_7 = geometry->elem[iElem]->GetNode(7); - - HexaEdgeIndex[iElem][0] = geometry->FindEdge(ip_0, ip_1); HexaEdgeCode[iElem][0] = false; HexaEdgeNode[iElem][0] = -1; - HexaEdgeIndex[iElem][1] = geometry->FindEdge(ip_1, ip_2); HexaEdgeCode[iElem][1] = false; HexaEdgeNode[iElem][1] = -1; - HexaEdgeIndex[iElem][2] = geometry->FindEdge(ip_2, ip_3); HexaEdgeCode[iElem][2] = false; HexaEdgeNode[iElem][2] = -1; - HexaEdgeIndex[iElem][3] = geometry->FindEdge(ip_3, ip_0); HexaEdgeCode[iElem][3] = false; HexaEdgeNode[iElem][3] = -1; - HexaEdgeIndex[iElem][4] = geometry->FindEdge(ip_4, ip_5); HexaEdgeCode[iElem][4] = false; HexaEdgeNode[iElem][4] = -1; - HexaEdgeIndex[iElem][5] = geometry->FindEdge(ip_5, ip_6); HexaEdgeCode[iElem][5] = false; HexaEdgeNode[iElem][5] = -1; - HexaEdgeIndex[iElem][6] = geometry->FindEdge(ip_6, ip_7); HexaEdgeCode[iElem][6] = false; HexaEdgeNode[iElem][6] = -1; - HexaEdgeIndex[iElem][7] = geometry->FindEdge(ip_7, ip_4); HexaEdgeCode[iElem][7] = false; HexaEdgeNode[iElem][7] = -1; - HexaEdgeIndex[iElem][8] = geometry->FindEdge(ip_0, ip_4); HexaEdgeCode[iElem][8] = false; HexaEdgeNode[iElem][8] = -1; - HexaEdgeIndex[iElem][9] = geometry->FindEdge(ip_1, ip_5); HexaEdgeCode[iElem][9] = false; HexaEdgeNode[iElem][9] = -1; - HexaEdgeIndex[iElem][10] = geometry->FindEdge(ip_2, ip_6); HexaEdgeCode[iElem][10] = false; HexaEdgeNode[iElem][10] = -1; - HexaEdgeIndex[iElem][11] = geometry->FindEdge(ip_3, ip_7); HexaEdgeCode[iElem][11] = false; HexaEdgeNode[iElem][11] = -1; - -// HexaFaceIndex[iElem][0] = geometry->FindFace(iElem, ip_0, ip_1, ip_2, ip_3); HexaFaceCode[iElem][0] = false; HexaFaceNode[iElem][0] = -1; -// HexaFaceIndex[iElem][1] = geometry->FindFace(iElem, ip_4, ip_5, ip_6, ip_7); HexaFaceCode[iElem][1] = false; HexaFaceNode[iElem][1] = -1; -// HexaFaceIndex[iElem][2] = geometry->FindFace(iElem, ip_1, ip_2, ip_6, ip_5); HexaFaceCode[iElem][2] = false; HexaFaceNode[iElem][2] = -1; -// HexaFaceIndex[iElem][3] = geometry->FindFace(iElem, ip_3, ip_2, ip_6, ip_7); HexaFaceCode[iElem][3] = false; HexaFaceNode[iElem][3] = -1; -// HexaFaceIndex[iElem][4] = geometry->FindFace(iElem, ip_0, ip_3, ip_7, ip_4); HexaFaceCode[iElem][4] = false; HexaFaceNode[iElem][4] = -1; -// HexaFaceIndex[iElem][5] = geometry->FindFace(iElem, ip_0, ip_1, ip_5, ip_4); HexaFaceCode[iElem][5] = false; HexaFaceNode[iElem][5] = -1; - - HexaElemIndex[iElem][0] = iElem; HexaElemCode[iElem][0] = false; HexaElemNode[iElem][0] = -1; - - } - - } - - /*--- Remove pyramids and prisms in the adaptation process ---*/ - unsigned short iFace, iNode, ElemIndex; - long jElem; - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - if ((geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) || - (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) || - (geometry->elem[iElem]->GetVTK_Type() == PRISM)) { - geometry->elem[iElem]->SetDivide(false); - for (iFace = 0; iFace < geometry->elem[iElem]->GetnFaces(); iFace++) - for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodesFace(iFace); iNode++) { - iPoint = geometry->elem[iElem]->GetNode(geometry->elem[iElem]->GetFaces(iFace, iNode)); - for (ElemIndex = 0; ElemIndex < geometry->node[iPoint]->GetnElem(); ElemIndex++) { - jElem = geometry->node[iPoint]->GetElem(ElemIndex); - if (jElem != -1) geometry->elem[jElem]->SetDivide(false); - } - } - } - } - - /*--- Do not addapt the boundaries ---*/ - if (!config->GetAdaptBoundary()) { - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { - for (iNode = 0; iNode < geometry->bound[iMarker][iVertex]->GetnNodes(); iNode++) { - iPoint = geometry->bound[iMarker][iVertex]->GetNode(iNode); - for (ElemIndex = 0; ElemIndex < geometry->node[iPoint]->GetnElem(); ElemIndex++) { - jElem = geometry->node[iPoint]->GetElem(ElemIndex); - if (jElem != -1) geometry->elem[jElem]->SetDivide(false); - } - } - } - } - } - - /*--- Initial edges that are going to be divided ---*/ - bool *DivEdge = new bool[geometry->GetnEdge()]; - bool *DivElem = new bool[geometry->GetnElem()]; - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) DivEdge[iEdge] = false; - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) - DivElem[iElem] = geometry->elem[iElem]->GetDivide(); - - /*--- Set the edge division in the reactangles and in the edge list ---*/ - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - if (DivElem[iElem] == true) { - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { - for (long iIndex = 0; iIndex < 6; iIndex++) { - DivEdge[TetraEdgeIndex[iElem][iIndex]] = true; - TetraEdgeCode[iElem][iIndex] = true; - } - } - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { - for (long iIndex = 0; iIndex < 12; iIndex++) { - DivEdge[HexaEdgeIndex[iElem][iIndex]] = true; - HexaEdgeCode[iElem][iIndex] = true; - } - } - } - } - - /*--- Only with tets, check if an element have more than 4 divided edges, the element should be completelly divided ---*/ - bool new_elem; - do { new_elem = false; - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { - - ip_0 = geometry->elem[iElem]->GetNode(0); - ip_1 = geometry->elem[iElem]->GetNode(1); - ip_2 = geometry->elem[iElem]->GetNode(2); - ip_3 = geometry->elem[iElem]->GetNode(3); - - counter = 0; - if (DivEdge[TetraEdgeIndex[iElem][0]]) counter++; - if (DivEdge[TetraEdgeIndex[iElem][1]]) counter++; - if (DivEdge[TetraEdgeIndex[iElem][2]]) counter++; - if (DivEdge[TetraEdgeIndex[iElem][3]]) counter++; - if (DivEdge[TetraEdgeIndex[iElem][4]]) counter++; - if (DivEdge[TetraEdgeIndex[iElem][5]]) counter++; - - if ((counter > 3) && (!DivElem[iElem])) { - DivEdge[geometry->FindEdge(ip_0, ip_1)] = true; - DivEdge[geometry->FindEdge(ip_0, ip_2)] = true; - DivEdge[geometry->FindEdge(ip_0, ip_3)] = true; - DivEdge[geometry->FindEdge(ip_1, ip_2)] = true; - DivEdge[geometry->FindEdge(ip_1, ip_3)] = true; - DivEdge[geometry->FindEdge(ip_2, ip_3)] = true; - DivElem[iElem] = true; - new_elem = true; - } - } - } - } while (new_elem); - - /*--- We must verify that all the elements have the right edges marked, - with tets 4 and 5 edges are not allowed ---*/ - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { - for (long iIndex = 0; iIndex < 6; iIndex++) { - if (DivEdge[TetraEdgeIndex[iElem][iIndex]] == true) { - TetraEdgeCode[iElem][iIndex] = true; - } - } - } - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { - for (long iIndex = 0; iIndex < 12; iIndex++) { - if (DivEdge[HexaEdgeIndex[iElem][iIndex]] == true) { - HexaEdgeCode[iElem][iIndex] = true; - } - } - } - } - - // Only those elements that verify certain rules will be marked for hexa adaptation... - // the others will need a new point in the middle and Pyrams - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { - TetraAdaptCode[iElem] = CheckTetraCode(TetraEdgeCode[iElem]); -// if (TetraAdaptCode[iElem] != -1) cout << TetraAdaptCode[iElem] <<" "<< iElem << endl; - } - - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { - - HexaAdaptCode[iElem] = CheckHexaCode(HexaEdgeCode[iElem]); -// if (HexaAdaptCode[iElem] != -1) cout << HexaAdaptCode[iElem] <<" "<< iElem << endl; - - // Set the HexaFaceCode, and HexaElemCode - if (HexaAdaptCode[iElem] == 1) { - HexaFaceCode[iElem][0] = true; HexaFaceCode[iElem][1] = true; HexaFaceCode[iElem][2] = true; - HexaFaceCode[iElem][3] = true; HexaFaceCode[iElem][4] = true; HexaFaceCode[iElem][5] = true; - HexaElemCode[iElem][0] = true; - } - if (HexaAdaptCode[iElem] == 2) { - HexaFaceCode[iElem][3] = true; HexaFaceCode[iElem][5] = true; - } - if (HexaAdaptCode[iElem] == 3) { - HexaFaceCode[iElem][2] = true; HexaFaceCode[iElem][4] = true; - } - if (HexaAdaptCode[iElem] == 4) { - HexaFaceCode[iElem][0] = true; HexaFaceCode[iElem][1] = true; - } - } - } - - // Create the new nodes on the edges, on the faces, and in the element. - long *NodeAtEdges = new long[geometry->GetnEdge()]; -// long *NodeAtElem = new long[geometry->GetnFace()]; - long *NodeAtElem = new long[geometry->GetnElem()]; - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) NodeAtEdges[iEdge] = -1; -// for (iFace = 0; iFace < geometry->GetnFace(); iFace++) NodeAtFaces[iEdge] = -1; - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) NodeAtElem[iElem] = -1; - - nPoint_new = geometry->GetnPoint(); - - su2double **NewNodeCoord; - NewNodeCoord = new su2double *[10*geometry->GetnPoint()]; - for (iPoint = 0; iPoint < 10*geometry->GetnPoint(); iPoint++) - NewNodeCoord[iPoint] = new su2double[geometry->GetnDim()]; - - if (Restart_Flow) { - ConsVar_Adapt = new su2double *[10*geometry->GetnPoint()]; - for (iPoint = 0; iPoint < 10*geometry->GetnPoint(); iPoint++) - ConsVar_Adapt[iPoint] = new su2double[nVar]; - } - - if (Restart_Adjoint) { - AdjVar_Adapt = new su2double *[10*geometry->GetnPoint()]; - for (iPoint = 0; iPoint < 10*geometry->GetnPoint(); iPoint++) - AdjVar_Adapt[iPoint] = new su2double[nVar]; - } - - // Set the value of the variables - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { - for (iVar = 0; iVar < nVar; iVar ++) { - if (Restart_Flow) ConsVar_Adapt[iPoint][iVar] = ConsVar_Sol[iPoint][iVar]; - if (Restart_Adjoint) AdjVar_Adapt[iPoint][iVar] = AdjVar_Sol[iPoint][iVar]; - } - } - - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { - - ip_0 = geometry->elem[iElem]->GetNode(0); - ip_1 = geometry->elem[iElem]->GetNode(1); - ip_2 = geometry->elem[iElem]->GetNode(2); - ip_3 = geometry->elem[iElem]->GetNode(3); - - for (long iIndex = 0; iIndex < 6; iIndex++) { - - if (TetraEdgeCode[iElem][iIndex] == true) { - if (NodeAtEdges[TetraEdgeIndex[iElem][iIndex]] != -1) - TetraEdgeNode[iElem][iIndex] = NodeAtEdges[TetraEdgeIndex[iElem][iIndex]]; - - if (NodeAtEdges[TetraEdgeIndex[iElem][iIndex]] == -1) { - - NodeAtEdges[TetraEdgeIndex[iElem][iIndex]] = nPoint_new; - TetraEdgeNode[iElem][iIndex] = nPoint_new; - - // Compute the coordinates of the new node - if (iIndex == 0) {no_0 = ip_0; no_1 = ip_1;} - if (iIndex == 1) {no_0 = ip_0; no_1 = ip_2;} - if (iIndex == 2) {no_0 = ip_0; no_1 = ip_3;} - if (iIndex == 3) {no_0 = ip_1; no_1 = ip_2;} - if (iIndex == 4) {no_0 = ip_1; no_1 = ip_3;} - if (iIndex == 5) {no_0 = ip_2; no_1 = ip_3;} - - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) - NewNodeCoord[nPoint_new][iDim] = 0.5*(geometry->node[no_0]->GetCoord(iDim)+geometry->node[no_1]->GetCoord(iDim)); - - for (iVar = 0; iVar < nVar; iVar ++) { - if (Restart_Flow) ConsVar_Adapt[nPoint_new][iVar] = 0.5 * (ConsVar_Adapt[no_0][iVar]+ConsVar_Adapt[no_1][iVar]); - if (Restart_Adjoint) AdjVar_Adapt[nPoint_new][iVar] = 0.5 * (AdjVar_Adapt[no_0][iVar]+AdjVar_Adapt[no_1][iVar]); - } - - nPoint_new++; - } - } - } - } - - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { - - ip_0 = geometry->elem[iElem]->GetNode(0); - ip_1 = geometry->elem[iElem]->GetNode(1); - ip_2 = geometry->elem[iElem]->GetNode(2); - ip_3 = geometry->elem[iElem]->GetNode(3); - ip_4 = geometry->elem[iElem]->GetNode(4); - ip_5 = geometry->elem[iElem]->GetNode(5); - ip_6 = geometry->elem[iElem]->GetNode(6); - ip_7 = geometry->elem[iElem]->GetNode(7); - - for (long iIndex = 0; iIndex < 12; iIndex++) { - - if (HexaEdgeCode[iElem][iIndex] == true) { - if (NodeAtEdges[HexaEdgeIndex[iElem][iIndex]] != -1) - HexaEdgeNode[iElem][iIndex] = NodeAtEdges[HexaEdgeIndex[iElem][iIndex]]; - - if (NodeAtEdges[HexaEdgeIndex[iElem][iIndex]] == -1) { - - NodeAtEdges[HexaEdgeIndex[iElem][iIndex]] = nPoint_new; - HexaEdgeNode[iElem][iIndex] = nPoint_new; - - // Compute the coordinates of the new node - if (iIndex == 0) {no_0 = ip_0; no_1 = ip_1;} - if (iIndex == 1) {no_0 = ip_1; no_1 = ip_2;} - if (iIndex == 2) {no_0 = ip_2; no_1 = ip_3;} - if (iIndex == 3) {no_0 = ip_3; no_1 = ip_0;} - if (iIndex == 4) {no_0 = ip_4; no_1 = ip_5;} - if (iIndex == 5) {no_0 = ip_5; no_1 = ip_6;} - if (iIndex == 6) {no_0 = ip_6; no_1 = ip_7;} - if (iIndex == 7) {no_0 = ip_7; no_1 = ip_4;} - if (iIndex == 8) {no_0 = ip_0; no_1 = ip_4;} - if (iIndex == 9) {no_0 = ip_1; no_1 = ip_5;} - if (iIndex == 10) {no_0 = ip_2; no_1 = ip_6;} - if (iIndex == 11) {no_0 = ip_3; no_1 = ip_7;} - - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) - NewNodeCoord[nPoint_new][iDim] = 0.5*(geometry->node[no_0]->GetCoord(iDim)+geometry->node[no_1]->GetCoord(iDim)); - - for (iVar = 0; iVar < nVar; iVar ++) { - if (Restart_Flow) ConsVar_Adapt[nPoint_new][iVar] = 0.5 * (ConsVar_Adapt[no_0][iVar]+ConsVar_Adapt[no_1][iVar]); - if (Restart_Adjoint) AdjVar_Adapt[nPoint_new][iVar] = 0.5 * (AdjVar_Adapt[no_0][iVar]+AdjVar_Adapt[no_1][iVar]); - } - - nPoint_new++; - } - } - } - -/* for (long iIndex = 0; iIndex < 6; iIndex++) { - if (HexaFaceCode[iElem][iIndex] == true) { - - if (NodeAtFaces[HexaFaceIndex[iElem][iIndex]] != -1) - HexaFaceNode[iElem][iIndex] = NodeAtFaces[HexaFaceIndex[iElem][iIndex]]; - - if (NodeAtFaces[HexaFaceIndex[iElem][iIndex]] == -1) { - NodeAtFaces[HexaFaceIndex[iElem][iIndex]] = nPoint_new; - HexaFaceNode[iElem][iIndex] = nPoint_new; - // Compute the coordinates of the new node - if (iIndex == 0) {no_0 = ip_0; no_1 = ip_1; no_2 = ip_2; no_3 = ip_3;} - if (iIndex == 1) {no_0 = ip_4; no_1 = ip_5; no_2 = ip_6; no_3 = ip_7;} - if (iIndex == 2) {no_0 = ip_1; no_1 = ip_2; no_2 = ip_6; no_3 = ip_5;} - if (iIndex == 3) {no_0 = ip_3; no_1 = ip_2; no_2 = ip_6; no_3 = ip_7;} - if (iIndex == 4) {no_0 = ip_0; no_1 = ip_3; no_2 = ip_7; no_3 = ip_4;} - if (iIndex == 5) {no_0 = ip_0; no_1 = ip_1; no_2 = ip_5; no_3 = ip_4;} - - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) - NewNodeCoord[nPoint_new][iDim] = 0.25*(x_no[no_0][iDim]+x_no[no_1][iDim]+x_no[no_2][iDim]+x_no[no_3][iDim]); - - for (iVar = 0; iVar < nVar; iVar ++) { - if (Restart_Flow) ConsVar_Adapt[nPoint_new][iVar] = 0.25 * (ConsVar_Adapt[no_0][iVar]+ConsVar_Adapt[no_1][iVar]+ConsVar_Adapt[no_2][iVar]+ConsVar_Adapt[no_3][iVar]); - if (Restart_Adjoint) AdjVar_Adapt[nPoint_new][iVar] = 0.25 * (AdjVar_Adapt[no_0][iVar]+AdjVar_Adapt[no_1][iVar]+AdjVar_Adapt[no_2][iVar]+AdjVar_Adapt[no_3][iVar]); - if (Restart_Linear) LinVar_Adapt[nPoint_new][iVar] = 0.25 * (LinVar_Adapt[no_0][iVar]+LinVar_Adapt[no_1][iVar]+LinVar_Adapt[no_2][iVar]+LinVar_Adapt[no_3][iVar]); - } - - nPoint_new++; - - } - } - - } */ - - for (long iIndex = 0; iIndex < 1; iIndex++) { - - if (HexaElemCode[iElem][iIndex] == true) { - - if (NodeAtElem[HexaElemIndex[iElem][iIndex]] != -1) - HexaElemNode[iElem][iIndex] = NodeAtElem[HexaElemIndex[iElem][iIndex]]; - - if (NodeAtElem[HexaElemIndex[iElem][iIndex]] == -1) { - NodeAtElem[HexaElemIndex[iElem][iIndex]] = nPoint_new; - HexaElemNode[iElem][iIndex] = nPoint_new; - - // Compute the coordinates of the new node - if (iIndex == 0) {no_0 = ip_0; no_1 = ip_1; no_2 = ip_2; no_3 = ip_3; no_4 = ip_4; no_5 = ip_5; no_6 = ip_6; no_7 = ip_7;} - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) - NewNodeCoord[nPoint_new][iDim] = 0.125*(geometry->node[no_0]->GetCoord(iDim) + - geometry->node[no_1]->GetCoord(iDim) + - geometry->node[no_2]->GetCoord(iDim) + - geometry->node[no_3]->GetCoord(iDim) + - geometry->node[no_4]->GetCoord(iDim) + - geometry->node[no_5]->GetCoord(iDim) + - geometry->node[no_6]->GetCoord(iDim) + - geometry->node[no_7]->GetCoord(iDim)); - - for (iVar = 0; iVar < nVar; iVar ++) { - if (Restart_Flow) ConsVar_Adapt[nPoint_new][iVar] = 0.125 * (ConsVar_Adapt[no_0][iVar]+ConsVar_Adapt[no_1][iVar]+ConsVar_Adapt[no_2][iVar]+ConsVar_Adapt[no_3][iVar]+ - ConsVar_Adapt[no_4][iVar]+ConsVar_Adapt[no_5][iVar]+ConsVar_Adapt[no_6][iVar]+ConsVar_Adapt[no_7][iVar]); - if (Restart_Adjoint) AdjVar_Adapt[nPoint_new][iVar] = 0.125 * (AdjVar_Adapt[no_0][iVar]+AdjVar_Adapt[no_1][iVar]+AdjVar_Adapt[no_2][iVar]+AdjVar_Adapt[no_3][iVar]+ - AdjVar_Adapt[no_4][iVar]+AdjVar_Adapt[no_5][iVar]+AdjVar_Adapt[no_6][iVar]+AdjVar_Adapt[no_7][iVar]); - } - - nPoint_new++; - } - } - } - } - - } - - - // if Hexa adapt code equals 0, then a semidivision is applied - long nSemiDivided = 0; - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { - if (HexaAdaptCode[iElem] == 0) - nSemiDivided++; - } - } - - // If semidivision, then divide add a new point (hexa), divide the hexahedron into Tetras, - // and find the right combination, it also create the new node (hexa). - long nPyram = nSemiDivided*6; - - long *PyramAdaptCode; - long **PyramNode; - long **HexaPyramIndex; - long *PyramHexaIndex; - - long **PyramEdgeIndex; - bool **PyramEdgeCode; - long **PyramEdgeNode; - - long **PyramFaceNode; - - long **PyramElemNode; - - PyramAdaptCode = new long [nPyram]; - PyramNode = new long *[nPyram]; - HexaPyramIndex = new long *[geometry->GetnElem()]; - PyramHexaIndex = new long [nPyram]; - PyramEdgeIndex = new long *[nPyram]; - PyramEdgeCode = new bool *[nPyram]; - PyramEdgeNode = new long *[nPyram]; - PyramFaceNode = new long *[nPyram]; - PyramElemNode = new long *[nPyram]; - - for (long iPyram = 0; iPyram < nPyram; iPyram++) { - PyramNode[iPyram] = new long [4]; - PyramEdgeIndex[iPyram] = new long [4]; - PyramEdgeCode[iPyram] = new bool [4]; - PyramEdgeNode[iPyram] = new long [4]; - PyramFaceNode[iPyram] = new long [1]; - PyramElemNode[iPyram] = new long [1]; - } - - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { - HexaPyramIndex[iElem] = new long [6]; - } - } - - nPyram = 0; - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { - if (HexaAdaptCode[iElem] == 0) { - - // Write the edge combination on the base. - ip_0 = geometry->elem[iElem]->GetNode(0); - ip_1 = geometry->elem[iElem]->GetNode(1); - ip_2 = geometry->elem[iElem]->GetNode(2); - ip_3 = geometry->elem[iElem]->GetNode(3); - ip_4 = geometry->elem[iElem]->GetNode(4); - ip_5 = geometry->elem[iElem]->GetNode(5); - ip_6 = geometry->elem[iElem]->GetNode(6); - ip_7 = geometry->elem[iElem]->GetNode(7); - - // Create the 1st pyramid. - HexaPyramIndex[iElem][0] = nPyram; PyramHexaIndex[nPyram] = iElem; PyramElemNode[nPyram][0] = nPoint_new; - - PyramNode[nPyram][0] = ip_0; PyramNode[nPyram][1] = ip_1; - PyramNode[nPyram][2] = ip_2; PyramNode[nPyram][3] = ip_3; - - PyramEdgeIndex[nPyram][0] = HexaEdgeIndex[iElem][0]; PyramEdgeIndex[nPyram][1] = HexaEdgeIndex[iElem][1]; - PyramEdgeIndex[nPyram][2] = HexaEdgeIndex[iElem][2]; PyramEdgeIndex[nPyram][3] = HexaEdgeIndex[iElem][3]; - - PyramEdgeNode[nPyram][0] = HexaEdgeNode[iElem][0]; PyramEdgeNode[nPyram][1] = HexaEdgeNode[iElem][1]; - PyramEdgeNode[nPyram][2] = HexaEdgeNode[iElem][2]; PyramEdgeNode[nPyram][3] = HexaEdgeNode[iElem][3]; - - - for (long iIndex = 0; iIndex < 4; iIndex++) - if (DivEdge[PyramEdgeIndex[nPyram][iIndex]] == true) PyramEdgeCode[nPyram][iIndex] = true; - nPyram++; - - // Create the 2nd pyramid. - HexaPyramIndex[iElem][1] = nPyram; PyramHexaIndex[nPyram] = iElem; PyramElemNode[nPyram][0] = nPoint_new; - - PyramNode[nPyram][0] = ip_4; PyramNode[nPyram][1] = ip_7; - PyramNode[nPyram][2] = ip_6; PyramNode[nPyram][3] = ip_5; - - PyramEdgeIndex[nPyram][0] = HexaEdgeIndex[iElem][7]; PyramEdgeIndex[nPyram][1] = HexaEdgeIndex[iElem][6]; - PyramEdgeIndex[nPyram][2] = HexaEdgeIndex[iElem][5]; PyramEdgeIndex[nPyram][3] = HexaEdgeIndex[iElem][4]; - - PyramEdgeNode[nPyram][0] = HexaEdgeNode[iElem][7]; PyramEdgeNode[nPyram][1] = HexaEdgeNode[iElem][6]; - PyramEdgeNode[nPyram][2] = HexaEdgeNode[iElem][5]; PyramEdgeNode[nPyram][3] = HexaEdgeNode[iElem][4]; - - for (long iIndex = 0; iIndex < 4; iIndex++) - if (DivEdge[PyramEdgeIndex[nPyram][iIndex]] == true) PyramEdgeCode[nPyram][iIndex] = true; - nPyram++; - - // Create the 3th pyramid. - HexaPyramIndex[iElem][2] = nPyram; PyramHexaIndex[nPyram] = iElem; PyramElemNode[nPyram][0] = nPoint_new; - - PyramNode[nPyram][0] = ip_0; PyramNode[nPyram][1] = ip_4; - PyramNode[nPyram][2] = ip_5; PyramNode[nPyram][3] = ip_1; - - PyramEdgeIndex[nPyram][0] = HexaEdgeIndex[iElem][8]; PyramEdgeIndex[nPyram][1] = HexaEdgeIndex[iElem][4]; - PyramEdgeIndex[nPyram][2] = HexaEdgeIndex[iElem][9]; PyramEdgeIndex[nPyram][3] = HexaEdgeIndex[iElem][0]; - - PyramEdgeNode[nPyram][0] = HexaEdgeNode[iElem][8]; PyramEdgeNode[nPyram][1] = HexaEdgeNode[iElem][4]; - PyramEdgeNode[nPyram][2] = HexaEdgeNode[iElem][9]; PyramEdgeNode[nPyram][3] = HexaEdgeNode[iElem][0]; - - for (long iIndex = 0; iIndex < 4; iIndex++) - if (DivEdge[PyramEdgeIndex[nPyram][iIndex]] == true) PyramEdgeCode[nPyram][iIndex] = true; - nPyram++; - - // Create the 4th pyramid. - HexaPyramIndex[iElem][3] = nPyram; PyramHexaIndex[nPyram] = iElem; PyramElemNode[nPyram][0] = nPoint_new; - - PyramNode[nPyram][0] = ip_3; PyramNode[nPyram][1] = ip_2; - PyramNode[nPyram][2] = ip_6; PyramNode[nPyram][3] = ip_7; - - PyramEdgeIndex[nPyram][0] = HexaEdgeIndex[iElem][2]; PyramEdgeIndex[nPyram][1] = HexaEdgeIndex[iElem][10]; - PyramEdgeIndex[nPyram][2] = HexaEdgeIndex[iElem][6]; PyramEdgeIndex[nPyram][3] = HexaEdgeIndex[iElem][11]; - - PyramEdgeNode[nPyram][0] = HexaEdgeNode[iElem][2]; PyramEdgeNode[nPyram][1] = HexaEdgeNode[iElem][10]; - PyramEdgeNode[nPyram][2] = HexaEdgeNode[iElem][6]; PyramEdgeNode[nPyram][3] = HexaEdgeNode[iElem][11]; - - for (long iIndex = 0; iIndex < 4; iIndex++) - if (DivEdge[PyramEdgeIndex[nPyram][iIndex]] == true) PyramEdgeCode[nPyram][iIndex] = true; - nPyram++; - - // Create the 5th pyramid. - HexaPyramIndex[iElem][4] = nPyram; PyramHexaIndex[nPyram] = iElem; PyramElemNode[nPyram][0] = nPoint_new; - - PyramNode[nPyram][0] = ip_1; PyramNode[nPyram][1] = ip_5; - PyramNode[nPyram][2] = ip_6; PyramNode[nPyram][3] = ip_2; - - PyramEdgeIndex[nPyram][0] = HexaEdgeIndex[iElem][9]; PyramEdgeIndex[nPyram][1] = HexaEdgeIndex[iElem][5]; - PyramEdgeIndex[nPyram][2] = HexaEdgeIndex[iElem][10]; PyramEdgeIndex[nPyram][3] = HexaEdgeIndex[iElem][1]; - - PyramEdgeNode[nPyram][0] = HexaEdgeNode[iElem][9]; PyramEdgeNode[nPyram][1] = HexaEdgeNode[iElem][5]; - PyramEdgeNode[nPyram][2] = HexaEdgeNode[iElem][10]; PyramEdgeNode[nPyram][3] = HexaEdgeNode[iElem][1]; - - for (long iIndex = 0; iIndex < 4; iIndex++) - if (DivEdge[PyramEdgeIndex[nPyram][iIndex]] == true) PyramEdgeCode[nPyram][iIndex] = true; - nPyram++; - - // Create the 6th pyramid. - HexaPyramIndex[iElem][5] = nPyram; PyramHexaIndex[nPyram] = iElem; PyramElemNode[nPyram][0] = nPoint_new; - - PyramNode[nPyram][0] = ip_0; PyramNode[nPyram][1] = ip_3; - PyramNode[nPyram][2] = ip_7; PyramNode[nPyram][3] = ip_4; - - PyramEdgeIndex[nPyram][0] = HexaEdgeIndex[iElem][3]; PyramEdgeIndex[nPyram][1] = HexaEdgeIndex[iElem][11]; - PyramEdgeIndex[nPyram][2] = HexaEdgeIndex[iElem][7]; PyramEdgeIndex[nPyram][3] = HexaEdgeIndex[iElem][8]; - - PyramEdgeNode[nPyram][0] = HexaEdgeNode[iElem][3]; PyramEdgeNode[nPyram][1] = HexaEdgeNode[iElem][11]; - PyramEdgeNode[nPyram][2] = HexaEdgeNode[iElem][7]; PyramEdgeNode[nPyram][3] = HexaEdgeNode[iElem][8]; - - for (long iIndex = 0; iIndex < 4; iIndex++) - if (DivEdge[PyramEdgeIndex[nPyram][iIndex]] == true) PyramEdgeCode[nPyram][iIndex] = true; - nPyram++; - - nPoint_new++; - - - } - } - } - - // Check the kind of Pyram partitioning that should be applied - for (long iPyram = 0; iPyram < nPyram; iPyram ++) { - PyramAdaptCode[iPyram] = CheckPyramCode(PyramEdgeCode[iPyram]); - if (PyramAdaptCode[iPyram] == 0) cout << "There is a problem with one Pyram" << endl; - } - - // Create new structure - nElem_new = geometry->GetnElem(); - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { - if (TetraAdaptCode[iElem] == 1) nElem_new = nElem_new + 7; - if (TetraAdaptCode[iElem] == 2) nElem_new = nElem_new + 3; - if (TetraAdaptCode[iElem] == 3) nElem_new = nElem_new + 3; - if (TetraAdaptCode[iElem] == 4) nElem_new = nElem_new + 3; - if (TetraAdaptCode[iElem] == 5) nElem_new = nElem_new + 3; - if (TetraAdaptCode[iElem] == 6) nElem_new = nElem_new + 7; - } - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { - if (HexaAdaptCode[iElem] == 1) nElem_new = nElem_new + 7; - if (HexaAdaptCode[iElem] == 2) nElem_new = nElem_new + 3; - if (HexaAdaptCode[iElem] == 3) nElem_new = nElem_new + 3; - if (HexaAdaptCode[iElem] == 4) nElem_new = nElem_new + 3; - if (HexaAdaptCode[iElem] == 5) nElem_new = nElem_new + 1; - if (HexaAdaptCode[iElem] == 6) nElem_new = nElem_new + 1; - if (HexaAdaptCode[iElem] == 7) nElem_new = nElem_new + 1; - if (HexaAdaptCode[iElem] == 0) { - long iPyram; - for (long iIndex = 0; iIndex < 6; iIndex++) { - iPyram = HexaPyramIndex[iElem][0]; - if (PyramAdaptCode[iPyram] == 1) nElem_new = nElem_new + 0; - if (PyramAdaptCode[iPyram] == 2) nElem_new = nElem_new + 2; - if (PyramAdaptCode[iPyram] == 3) nElem_new = nElem_new + 2; - if (PyramAdaptCode[iPyram] == 4) nElem_new = nElem_new + 2; - if (PyramAdaptCode[iPyram] == 5) nElem_new = nElem_new + 2; - if (PyramAdaptCode[iPyram] == 6) nElem_new = nElem_new + 3; - if (PyramAdaptCode[iPyram] == 7) nElem_new = nElem_new + 3; - if (PyramAdaptCode[iPyram] == 8) nElem_new = nElem_new + 3; - if (PyramAdaptCode[iPyram] == 9) nElem_new = nElem_new + 3; - if (PyramAdaptCode[iPyram] == 10) nElem_new = nElem_new + 1; - if (PyramAdaptCode[iPyram] == 11) nElem_new = nElem_new + 1; - if (PyramAdaptCode[iPyram] == 12) nElem_new = nElem_new + 3; - if (PyramAdaptCode[iPyram] == 13) nElem_new = nElem_new + 3; - if (PyramAdaptCode[iPyram] == 14) nElem_new = nElem_new + 3; - if (PyramAdaptCode[iPyram] == 15) nElem_new = nElem_new + 3; - if (PyramAdaptCode[iPyram] == 16) nElem_new = nElem_new + 3; - } - } - } - } - - // New points - geo_adapt->node = new CPoint*[nPoint_new]; - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) - geo_adapt->node[iPoint] = new CPoint(geometry->node[iPoint]->GetCoord(0), geometry->node[iPoint]->GetCoord(1), geometry->node[iPoint]->GetCoord(2), iPoint, config); - - for (iPoint = geometry->GetnPoint(); iPoint < nPoint_new; iPoint++) - geo_adapt->node[iPoint] = new CPoint(NewNodeCoord[iPoint][0], NewNodeCoord[iPoint][1], NewNodeCoord[iPoint][2], iPoint, config); - - // New elements - geo_adapt->elem = new CPrimalGrid*[nElem_new]; - - unsigned long iElemNew = 0; - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { - if (TetraAdaptCode[iElem] == -1) { - geo_adapt->elem[iElemNew] = new CTetrahedron(geometry->elem[iElem]->GetNode(0), - geometry->elem[iElem]->GetNode(1), - geometry->elem[iElem]->GetNode(2), - geometry->elem[iElem]->GetNode(3)); - iElemNew++; - } - } - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { - if (HexaAdaptCode[iElem] == -1) { - geo_adapt->elem[iElemNew] = new CHexahedron(geometry->elem[iElem]->GetNode(0), - geometry->elem[iElem]->GetNode(1), - geometry->elem[iElem]->GetNode(2), - geometry->elem[iElem]->GetNode(3), - geometry->elem[iElem]->GetNode(4), - geometry->elem[iElem]->GetNode(5), - geometry->elem[iElem]->GetNode(6), - geometry->elem[iElem]->GetNode(7)); - iElemNew++; - } - } - if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) { - geo_adapt->elem[iElemNew] = new CPyramid(geometry->elem[iElem]->GetNode(0), - geometry->elem[iElem]->GetNode(1), - geometry->elem[iElem]->GetNode(2), - geometry->elem[iElem]->GetNode(3), - geometry->elem[iElem]->GetNode(4)); - iElemNew++; - } - if (geometry->elem[iElem]->GetVTK_Type() == PRISM) { - geo_adapt->elem[iElemNew] = new CPrism(geometry->elem[iElem]->GetNode(0), - geometry->elem[iElem]->GetNode(1), - geometry->elem[iElem]->GetNode(2), - geometry->elem[iElem]->GetNode(3), - geometry->elem[iElem]->GetNode(4), - geometry->elem[iElem]->GetNode(5)); - iElemNew++; - } - } - - long nodes[27]; long **Division; long nPart; - - Division = new long*[100]; - for (long iVar = 0; iVar < 100; iVar++) - Division[iVar] = new long[100]; - - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { - - // Tetra elements... - if (TetraAdaptCode[iElem] > 0) { - - // First the corners - nodes[0] = geometry->elem[iElem]->GetNode(0); - nodes[1] = geometry->elem[iElem]->GetNode(1); - nodes[2] = geometry->elem[iElem]->GetNode(2); - nodes[3] = geometry->elem[iElem]->GetNode(3); - - // Next the points that correspond to the broken edges. - nodes[4] = TetraEdgeNode[iElem][0]; - nodes[5] = TetraEdgeNode[iElem][1]; - nodes[6] = TetraEdgeNode[iElem][2]; - nodes[7] = TetraEdgeNode[iElem][3]; - nodes[8] = TetraEdgeNode[iElem][4]; - nodes[9] = TetraEdgeNode[iElem][5]; - - ip_0 = geometry->elem[iElem]->GetNode(0); - ip_1 = geometry->elem[iElem]->GetNode(1); - ip_2 = geometry->elem[iElem]->GetNode(2); - ip_3 = geometry->elem[iElem]->GetNode(3); - - long edges[6] = {-1, -1, -1, -1, -1 , -1}; - if (DivEdge[geometry->FindEdge(ip_0, ip_1)]) {edges[0] = geometry->FindEdge(ip_0, ip_1);} - if (DivEdge[geometry->FindEdge(ip_0, ip_2)]) {edges[1] = geometry->FindEdge(ip_0, ip_2);} - if (DivEdge[geometry->FindEdge(ip_0, ip_3)]) {edges[2] = geometry->FindEdge(ip_0, ip_3);} - if (DivEdge[geometry->FindEdge(ip_1, ip_2)]) {edges[3] = geometry->FindEdge(ip_1, ip_2);} - if (DivEdge[geometry->FindEdge(ip_1, ip_3)]) {edges[4] = geometry->FindEdge(ip_1, ip_3);} - if (DivEdge[geometry->FindEdge(ip_2, ip_3)]) {edges[5] = geometry->FindEdge(ip_2, ip_3);} - - - TetraDivision(TetraAdaptCode[iElem], nodes, edges, Division, &nPart); - - for (long iPart = 0; iPart < nPart; iPart++) { - - // Tetra case - geo_adapt->elem[iElemNew] = new CTetrahedron(Division[iPart][1], - Division[iPart][2], - Division[iPart][3], - Division[iPart][4]); - iElemNew++; - } - } - } - - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { - // Hexa elements... - if (HexaAdaptCode[iElem] > 0) { - - // First the corners - nodes[0] = geometry->elem[iElem]->GetNode(0); nodes[1] = geometry->elem[iElem]->GetNode(1); - nodes[2] = geometry->elem[iElem]->GetNode(2); nodes[3] = geometry->elem[iElem]->GetNode(3); - nodes[4] = geometry->elem[iElem]->GetNode(4); nodes[5] = geometry->elem[iElem]->GetNode(5); - nodes[6] = geometry->elem[iElem]->GetNode(6); nodes[7] = geometry->elem[iElem]->GetNode(7); - - // Next the points that correspond to the broken edges. - nodes[8] = HexaEdgeNode[iElem][0]; nodes[9] = HexaEdgeNode[iElem][1]; - nodes[10] = HexaEdgeNode[iElem][2]; nodes[11] = HexaEdgeNode[iElem][3]; - nodes[12] = HexaEdgeNode[iElem][4]; nodes[13] = HexaEdgeNode[iElem][5]; - nodes[14] = HexaEdgeNode[iElem][6]; nodes[15] = HexaEdgeNode[iElem][7]; - nodes[16] = HexaEdgeNode[iElem][8]; nodes[17] = HexaEdgeNode[iElem][9]; - nodes[18] = HexaEdgeNode[iElem][10]; nodes[19] = HexaEdgeNode[iElem][11]; - - // Next the points that correspond to the faces. - nodes[20] = HexaFaceNode[iElem][0]; - nodes[21] = HexaFaceNode[iElem][1]; - nodes[22] = HexaFaceNode[iElem][2]; - nodes[23] = HexaFaceNode[iElem][3]; - nodes[24] = HexaFaceNode[iElem][4]; - nodes[25] = HexaFaceNode[iElem][5]; - - // Next the points that correspond to the element. - nodes[8] = HexaElemNode[iElem][0]; - - HexaDivision(HexaAdaptCode[iElem], nodes, Division, &nPart); - for (long iPart = 0; iPart < nPart; iPart++) { - geo_adapt->elem[iElemNew] = new CHexahedron(Division[iPart][1], - Division[iPart][2], - Division[iPart][3], - Division[iPart][4], - Division[iPart][5], - Division[iPart][6], - Division[iPart][7], - Division[iPart][8]); - iElemNew++; - } - } - - // Pyram elements... - if (HexaAdaptCode[iElem] == 0) { - long iPyram = HexaPyramIndex[iElem][0]; - - // First the corners - nodes[0] = PyramNode[iPyram][0]; - nodes[1] = PyramNode[iPyram][1]; - nodes[2] = PyramNode[iPyram][2]; - nodes[3] = PyramNode[iPyram][3]; - nodes[4] = PyramElemNode[iPyram][0]; - - // Next the points that correspond to the broken edges. - nodes[5] = PyramEdgeNode[iPyram][0]; - nodes[6] = PyramEdgeNode[iPyram][1]; - nodes[7] = PyramEdgeNode[iPyram][2]; - nodes[8] = PyramEdgeNode[iPyram][3]; - - // Next the points that correspond to the base face. - nodes[9] = PyramFaceNode[iPyram][0]; - - PyramDivision(PyramAdaptCode[iPyram], nodes, Division, &nPart); - for (long iPart = 0; iPart < nPart; iPart++) { - - // Tetra case - if (Division[iPart][0] == 5) { - geo_adapt->elem[iElemNew] = new CTetrahedron(Division[iPart][1], - Division[iPart][2], - Division[iPart][3], - Division[iPart][4]); - iElemNew++; - } - - // Pyram case - if (Division[iPart][0] == 6) { - geo_adapt->elem[iElemNew] = new CPyramid(Division[iPart][1], - Division[iPart][2], - Division[iPart][3], - Division[iPart][4], - Division[iPart][5]); - iElemNew++; - } - } - } - } - } - - geo_adapt->SetnElem(iElemNew); - geo_adapt->SetnPoint(nPoint_new); - geo_adapt->SetnPointDomain(nPoint_new); - geo_adapt->SetnDim(nDim); - - // Create boundary structure - geo_adapt->SetnMarker(geometry->GetnMarker()); - geo_adapt->nElem_Bound = new unsigned long [geometry->GetnMarker()]; - geo_adapt->Tag_to_Marker = new string [nMarker_Max]; - geo_adapt->bound = new CPrimalGrid**[geometry->GetnMarker()]; - - // Conservative estimation of the number of boundary elements. - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - long nNewBCcv = 0; - for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { - nNewBCcv = nNewBCcv + 4; - } - geo_adapt->bound[iMarker] = new CPrimalGrid* [nNewBCcv]; - geo_adapt->SetMarker_Tag(iMarker, geometry->GetMarker_Tag(iMarker)); - } - - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - long nNewBCcv = 0; - for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { - - bool TriangleEdgeCode[3] = { false, false, false }; - long TriangleAdaptCode, nodes[6]; - long nNodesBound = geometry->bound[iMarker][iVertex]->GetnNodes(); - - ip_0 = geometry->bound[iMarker][iVertex]->GetNode(0); geo_adapt->node[ip_0]->SetBoundary(geometry->GetnMarker()); - ip_1 = geometry->bound[iMarker][iVertex]->GetNode(1); geo_adapt->node[ip_1]->SetBoundary(geometry->GetnMarker()); - ip_2 = geometry->bound[iMarker][iVertex]->GetNode(2); geo_adapt->node[ip_2]->SetBoundary(geometry->GetnMarker()); - if (nNodesBound == 4) { - ip_3 = geometry->bound[iMarker][iVertex]->GetNode(3); geo_adapt->node[ip_3]->SetBoundary(geometry->GetnMarker()); - geo_adapt->bound[iMarker][nNewBCcv] = new CQuadrilateral(ip_0, ip_1, ip_2, ip_3, 3); - nNewBCcv++; - } - else { - // First the corners - nodes[0] = geometry->bound[iMarker][iVertex]->GetNode(0); - nodes[1] = geometry->bound[iMarker][iVertex]->GetNode(1); - nodes[2] = geometry->bound[iMarker][iVertex]->GetNode(2); - if (nNodesBound == 4) nodes[3] = geometry->bound[iMarker][iVertex]->GetNode(3); - - // Next the points that correspond to the broken edges. - nodes[3] = NodeAtEdges[geometry->FindEdge(ip_0, ip_1)]; if (nodes[3] != -1) geo_adapt->node[nodes[3]]->SetBoundary(geometry->GetnMarker()); - nodes[4] = NodeAtEdges[geometry->FindEdge(ip_1, ip_2)]; if (nodes[4] != -1) geo_adapt->node[nodes[4]]->SetBoundary(geometry->GetnMarker()); - nodes[5] = NodeAtEdges[geometry->FindEdge(ip_0, ip_2)]; if (nodes[5] != -1) geo_adapt->node[nodes[5]]->SetBoundary(geometry->GetnMarker()); - - long edges[3] = {-1, -1, -1}; - if (DivEdge[geometry->FindEdge(ip_0, ip_1)]) { edges[0] = geometry->FindEdge(ip_0, ip_1); TriangleEdgeCode[0] = true;} - if (DivEdge[geometry->FindEdge(ip_1, ip_2)]) { edges[1] = geometry->FindEdge(ip_1, ip_2); TriangleEdgeCode[1] = true;} - if (DivEdge[geometry->FindEdge(ip_2, ip_0)]) { edges[2] = geometry->FindEdge(ip_2, ip_0); TriangleEdgeCode[2] = true;} - - TriangleAdaptCode = CheckTriangleCode(TriangleEdgeCode); - TriangleDivision(TriangleAdaptCode, nodes, edges, Division, &nPart); - - for (long iPart = 0; iPart < nPart; iPart++) { - geo_adapt->bound[iMarker][nNewBCcv] = new CTriangle(Division[iPart][1], Division[iPart][2], Division[iPart][3], 3); - nNewBCcv++; - } - } - } - geo_adapt->SetnElem_Bound(iMarker, nNewBCcv); - } - - delete [] DivEdge; - delete [] DivElem; - delete [] NodeAtEdges; - delete [] NodeAtElem; -} - -void CGridAdaptation::SetIndicator_Flow(CGeometry *geometry, CConfig *config, unsigned short strength) { - unsigned long Point = 0, Point_0 = 0, Point_1 = 0, iEdge, iVertex, iPoint, iElem, max_elem_new; - unsigned short iDim, iMarker; - su2double Dual_Area, norm, Solution_Vertex, Solution_0, Solution_1, Solution_Average, - DualArea, Partial_Res, Grad_Val, *Normal; - su2double scale_area = config->GetDualVol_Power(); - - /*--- Initialization ---*/ - nElem_new = 0; - max_elem_new = SU2_TYPE::Int(0.01*config->GetNew_Elem_Adapt()*su2double(geometry->GetnElem())); - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - geometry->elem[iElem]->SetDivide(false); - } - - /*--- Compute the gradient of the first variable ---*/ - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - for (iDim = 0; iDim < nDim; iDim++) - Gradient[iPoint][iDim] = 0.0; - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - Point_0 = geometry->edge[iEdge]->GetNode(0); Solution_0 = ConsVar_Sol[Point_0][0]; - Point_1 = geometry->edge[iEdge]->GetNode(1); Solution_1 = ConsVar_Sol[Point_1][0]; - Normal = geometry->edge[iEdge]->GetNormal(); - Solution_Average = 0.5 * ( Solution_0 + Solution_1); - for (iDim = 0; iDim < nDim; iDim++) { - Partial_Res = Solution_Average*Normal[iDim]; - Gradient[Point_0][iDim] = Gradient[Point_0][iDim] + Partial_Res; - Gradient[Point_1][iDim] = Gradient[Point_1][iDim] - Partial_Res; - } - } - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - Point = geometry->vertex[iMarker][iVertex]->GetNode(); - Solution_Vertex = ConsVar_Sol[Point][0]; - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - for (iDim = 0; iDim < nDim; iDim++) { - Partial_Res = Solution_Vertex*Normal[iDim]; - Gradient[Point][iDim] = Gradient[Point][iDim] - Partial_Res; - } - } - - for (iPoint = 0; iPointGetnPoint(); iPoint++) - for (iDim = 0; iDim < nDim; iDim++) { - DualArea = geometry->node[iPoint]->GetVolume(); - Grad_Val = Gradient[iPoint][iDim]/DualArea; - Gradient[iPoint][iDim] = Grad_Val; - } - - /*--- Compute the the adaptation index at each point ---*/ - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { - Dual_Area = geometry->node[iPoint]->GetVolume(); - norm = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - norm += Gradient[iPoint][iDim]*Gradient[iPoint][iDim]; - norm = sqrt(norm); - Index[iPoint] = pow(Dual_Area, scale_area)*norm; - } - - SetSensorElem(geometry, config, max_elem_new); -} - - -void CGridAdaptation::SetIndicator_Adj(CGeometry *geometry, CConfig *config, unsigned short strength) { - su2double Dual_Area; - unsigned long Point = 0, Point_0 = 0, Point_1 = 0, iEdge, iVertex, iPoint, iElem, max_elem_new; - unsigned short iDim, iMarker; - su2double norm, Solution_Vertex, Solution_0, Solution_1, Solution_Average, - DualArea, Partial_Res, Grad_Val, *Normal; - su2double scale_area = config->GetDualVol_Power(); - - // Initialization - nElem_new = 0; - max_elem_new = SU2_TYPE::Int(0.01*config->GetNew_Elem_Adapt()*su2double(geometry->GetnElem())); - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - geometry->elem[iElem]->SetDivide(false); - } - - - // Compute the gradient of the density. - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - for (iDim = 0; iDim < nDim; iDim++) - Gradient[iPoint][iDim] = 0.0; - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - Point_0 = geometry->edge[iEdge]->GetNode(0); Solution_0 = AdjVar_Sol[Point_0][0]; - Point_1 = geometry->edge[iEdge]->GetNode(1); Solution_1 = AdjVar_Sol[Point_1][0]; - Normal = geometry->edge[iEdge]->GetNormal(); - Solution_Average = 0.5 * ( Solution_0 + Solution_1); - for (iDim = 0; iDim < nDim; iDim++) { - Partial_Res = Solution_Average*Normal[iDim]; - Gradient[Point_0][iDim] = Gradient[Point_0][iDim] + Partial_Res; - Gradient[Point_1][iDim] = Gradient[Point_1][iDim] - Partial_Res; - } - } - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - Point = geometry->vertex[iMarker][iVertex]->GetNode(); - Solution_Vertex = AdjVar_Sol[Point][0]; - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - for (iDim = 0; iDim < nDim; iDim++) { - Partial_Res = Solution_Vertex*Normal[iDim]; - Gradient[Point][iDim] = Gradient[Point][iDim] - Partial_Res; - } - } - - for (iPoint = 0; iPointGetnPoint(); iPoint++) - for (iDim = 0; iDim < nDim; iDim++) { - DualArea = geometry->node[iPoint]->GetVolume(); - Grad_Val = Gradient[iPoint][iDim]/DualArea; - Gradient[iPoint][iDim] = Grad_Val; - } - - - // Compute the the adaptation index at each point. - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { - Dual_Area = geometry->node[iPoint]->GetVolume(); - norm = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - norm += Gradient[iPoint][iDim]*Gradient[iPoint][iDim]; - norm = sqrt(norm); - Index[iPoint] = pow(Dual_Area, scale_area)*norm; - } - - SetSensorElem(geometry, config, max_elem_new); - -} - -void CGridAdaptation::SetIndicator_FlowAdj(CGeometry *geometry, CConfig *config) { - su2double Dual_Area; - unsigned long Point = 0, Point_0 = 0, Point_1 = 0, iEdge, iVertex, iPoint, iElem, max_elem_new_flow, max_elem_new_adj; - unsigned short iDim, iMarker; - su2double norm, DualArea, Partial_Res, *Normal; - su2double scale_area = config->GetDualVol_Power(); - - // Initialization - max_elem_new_flow = SU2_TYPE::Int(0.5*0.01*config->GetNew_Elem_Adapt()*su2double(geometry->GetnElem())); - max_elem_new_adj = SU2_TYPE::Int(0.5*0.01*config->GetNew_Elem_Adapt()*su2double(geometry->GetnElem())); - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - geometry->elem[iElem]->SetDivide(false); - } - - // Compute the gradient of the first variable. - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - for (iDim = 0; iDim < nDim; iDim++) { - Gradient_Flow[iPoint][iDim] = 0.0; - Gradient_Adj[iPoint][iDim] = 0.0; - } - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - Point_0 = geometry->edge[iEdge]->GetNode(0); - Point_1 = geometry->edge[iEdge]->GetNode(1); - Normal = geometry->edge[iEdge]->GetNormal(); - for (iDim = 0; iDim < nDim; iDim++) { - Partial_Res = 0.5 * ( ConsVar_Sol[Point_0][0] + ConsVar_Sol[Point_1][0] ) * Normal[iDim]; - Gradient_Flow[Point_0][iDim] = Gradient_Flow[Point_0][iDim] + Partial_Res; - Gradient_Flow[Point_1][iDim] = Gradient_Flow[Point_1][iDim] - Partial_Res; - - Partial_Res = 0.5 * ( AdjVar_Sol[Point_0][0] + AdjVar_Sol[Point_1][0] ) * Normal[iDim]; - Gradient_Adj[Point_0][iDim] = Gradient_Adj[Point_0][iDim] + Partial_Res; - Gradient_Adj[Point_1][iDim] = Gradient_Adj[Point_1][iDim] - Partial_Res; - } - } - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - Point = geometry->vertex[iMarker][iVertex]->GetNode(); - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - for (iDim = 0; iDim < nDim; iDim++) { - Gradient_Flow[Point][iDim] = Gradient_Flow[Point][iDim] - ConsVar_Sol[Point][0] * Normal[iDim]; - Gradient_Adj[Point][iDim] = Gradient_Adj[Point][iDim] - AdjVar_Sol[Point][0] * Normal[iDim]; - } - } - - for (iPoint = 0; iPointGetnPoint(); iPoint++) - for (iDim = 0; iDim < nDim; iDim++) { - DualArea = geometry->node[iPoint]->GetVolume(); - Gradient_Flow[iPoint][iDim] = Gradient_Flow[iPoint][iDim]/DualArea; - Gradient_Adj[iPoint][iDim] = Gradient_Adj[iPoint][iDim]/DualArea; - } - - // Compute the the adaptation index at each point. - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { - Dual_Area=geometry->node[iPoint]->GetVolume(); - norm = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - norm += Gradient_Flow[iPoint][iDim]*Gradient_Flow[iPoint][iDim]; - norm = sqrt(norm); - Index[iPoint] = pow(Dual_Area, scale_area)*norm; - } - - - SetSensorElem(geometry, config, max_elem_new_flow); - - // Compute the the adaptation index at each point. - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { - Dual_Area=geometry->node[iPoint]->GetVolume(); - norm = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - norm += Gradient_Adj[iPoint][iDim]*Gradient_Adj[iPoint][iDim]; - norm = sqrt(norm); - Index[iPoint] = pow(Dual_Area, scale_area)*norm; - } - - SetSensorElem(geometry, config, max_elem_new_adj); - -} - -void CGridAdaptation::SetIndicator_Robust(CGeometry *geometry, CConfig *config) { - unsigned long iPoint, iElem, max_elem_new_flow, max_elem_new_adj; - unsigned short iVar; - su2double Dual_Area; - su2double scale_area = config->GetDualVol_Power(); - - // Inicializa la malla para la adaptacion - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - geometry->elem[iElem]->SetDivide (false); - } - - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { - Dual_Area = geometry->node[iPoint]->GetVolume(); - Index[iPoint] = 0.0; - for (iVar = 0; iVar < nVar; iVar++) - Index[iPoint] += ConsVar_Res[iPoint][iVar]*ConsVar_Res[iPoint][iVar]; - - Index[iPoint] = pow(Dual_Area, scale_area)*sqrt(Index[iPoint]); - } - - max_elem_new_flow = SU2_TYPE::Int(0.5*0.01*config->GetNew_Elem_Adapt()*su2double(geometry->GetnElem())); - SetSensorElem(geometry, config, max_elem_new_flow); - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { - Dual_Area = geometry->node[iPoint]->GetVolume(); - Index[iPoint] = 0.0; - for (iVar = 0; iVar < nVar; iVar++) - Index[iPoint] += AdjVar_Res[iPoint][iVar]*AdjVar_Res[iPoint][iVar]; - - Index[iPoint] = pow(Dual_Area, scale_area)*sqrt(Index[iPoint]); - } - - max_elem_new_adj = SU2_TYPE::Int(0.5*0.01*config->GetNew_Elem_Adapt()*su2double(geometry->GetnElem())); - SetSensorElem(geometry, config, max_elem_new_adj); - -} - -void CGridAdaptation::SetIndicator_Computable(CGeometry *geometry, CConfig *config) { - unsigned long iPoint, iElem, max_elem_new; - unsigned short iVar; - su2double Dual_Area; - su2double scale_area = config->GetDualVol_Power(); - - max_elem_new = SU2_TYPE::Int(0.01*config->GetNew_Elem_Adapt()*su2double(geometry->GetnElem())); - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - geometry->elem[iElem]->SetDivide (false); - } - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { - Dual_Area = geometry->node[iPoint]->GetVolume(); - Index[iPoint] = 0.0; - for (iVar = 0; iVar < nVar; iVar++) - Index[iPoint] += ConsVar_Res[iPoint][iVar]*AdjVar_Sol[iPoint][iVar]*ConsVar_Res[iPoint][iVar]*AdjVar_Sol[iPoint][iVar]; - - Index[iPoint] = pow(Dual_Area, scale_area)*sqrt(Index[iPoint]); - } - - SetSensorElem(geometry, config, max_elem_new); - -} - -void CGridAdaptation::SetIndicator_Computable_Robust(CGeometry *geometry, CConfig *config) { - unsigned long iPoint, iElem, max_elem_new; - unsigned short iVar; - su2double Dual_Area ; - su2double scale_area = config->GetDualVol_Power(); - - /*--- Initializate the numerical grid for the adaptation ---*/ - max_elem_new = SU2_TYPE::Int(0.01*config->GetNew_Elem_Adapt()*su2double(geometry->GetnElem())); - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - geometry->elem[iElem]->SetDivide (false); - } - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { - Dual_Area = geometry->node[iPoint]->GetVolume(); - Index[iPoint] = 0.0; - for (iVar = 0; iVar < nVar; iVar++) - Index[iPoint] += LinVar_Res[iPoint][iVar]*AdjVar_Sol[iPoint][iVar]*LinVar_Res[iPoint][iVar]*AdjVar_Sol[iPoint][iVar]; - - Index[iPoint] = pow(Dual_Area, scale_area)*sqrt(Index[iPoint]); - } - - SetSensorElem(geometry, config, max_elem_new); - -} - -void CGridAdaptation::SetRestart_FlowSolution(CConfig *config, CPhysicalGeometry *geo_adapt, string mesh_flowfilename) { - - unsigned long iPoint; - unsigned short iVar, iDim; - - char *cstr = new char [mesh_flowfilename.size()+1]; - strcpy (cstr, mesh_flowfilename.c_str()); - - ofstream restart_flowfile; - restart_flowfile.open(cstr, ios::out); - restart_flowfile.precision(15); - - restart_flowfile << "Restart file generated with SU2_MSH" << endl; - - for (iPoint = 0; iPoint < nPoint_new; iPoint++) { - restart_flowfile << iPoint <<"\t"; - - for (iDim = 0; iDim < nDim; iDim++) - restart_flowfile << scientific << geo_adapt->node[iPoint]->GetCoord(iDim) <<"\t"; - for (iVar = 0; iVar < nVar; iVar++) - restart_flowfile << scientific << ConsVar_Adapt[iPoint][iVar] <<"\t"; - - restart_flowfile << endl; - } - restart_flowfile.close(); - -} - -void CGridAdaptation::SetRestart_AdjSolution(CConfig *config, CPhysicalGeometry *geo_adapt, string mesh_adjfilename) { - - char cstr[MAX_STRING_SIZE], buffer[50]; - unsigned short iDim, iVar; - unsigned long iPoint; - string copy; - - copy.assign(mesh_adjfilename); - unsigned short lastindex = copy.find_last_of("."); - copy = copy.substr(0, lastindex); - strcpy (cstr, copy.c_str()); - if (config->GetKind_ObjFunc() == DRAG_COEFFICIENT) SPRINTF (buffer, "_cd.dat"); - if (config->GetKind_ObjFunc() == LIFT_COEFFICIENT) SPRINTF (buffer, "_cl.dat"); - if (config->GetKind_ObjFunc() == SIDEFORCE_COEFFICIENT) SPRINTF (buffer, "_csf.dat"); - if (config->GetKind_ObjFunc() == INVERSE_DESIGN_PRESSURE) SPRINTF (buffer, "_invpress.dat"); - if (config->GetKind_ObjFunc() == INVERSE_DESIGN_HEATFLUX) SPRINTF (buffer, "_invheat.dat"); - if (config->GetKind_ObjFunc() == MOMENT_X_COEFFICIENT) SPRINTF (buffer, "_cmx.dat"); - if (config->GetKind_ObjFunc() == MOMENT_Y_COEFFICIENT) SPRINTF (buffer, "_cmy.dat"); - if (config->GetKind_ObjFunc() == MOMENT_Z_COEFFICIENT) SPRINTF (buffer, "_cmz.dat"); - if (config->GetKind_ObjFunc() == EFFICIENCY) SPRINTF (buffer, "_eff.dat"); - if (config->GetKind_ObjFunc() == FORCE_X_COEFFICIENT) SPRINTF (buffer, "_cfx.dat"); - if (config->GetKind_ObjFunc() == FORCE_Y_COEFFICIENT) SPRINTF (buffer, "_cfy.dat"); - if (config->GetKind_ObjFunc() == FORCE_Z_COEFFICIENT) SPRINTF (buffer, "_cfz.dat"); - if (config->GetKind_ObjFunc() == TOTAL_HEATFLUX) SPRINTF (buffer, "_totheat.dat"); - if (config->GetKind_ObjFunc() == MAXIMUM_HEATFLUX) SPRINTF (buffer, "_maxheat.dat"); - if (config->GetKind_ObjFunc() == AVG_TOTAL_PRESSURE) SPRINTF (buffer, "_pt.dat"); - if (config->GetKind_ObjFunc() == AVG_OUTLET_PRESSURE) SPRINTF (buffer, "_pe.dat"); - if (config->GetKind_ObjFunc() == MASS_FLOW_RATE) SPRINTF (buffer, "_mfr.dat"); - if (config->GetKind_ObjFunc() == OUTLET_CHAIN_RULE) SPRINTF (buffer, "_chn.dat"); - - strcat(cstr, buffer); - - ofstream restart_adjfile; - restart_adjfile.open(cstr, ios::out); - restart_adjfile.precision(15); - - restart_adjfile << "Restart file generated with SU2_MSH" << endl; - - for (iPoint = 0; iPoint < nPoint_new; iPoint++) { - restart_adjfile << iPoint <<"\t"; - - for (iDim = 0; iDim < nDim; iDim++) - restart_adjfile << scientific << geo_adapt->node[iPoint]->GetCoord(iDim) <<"\t"; - for (iVar = 0; iVar < nVar; iVar++) - restart_adjfile << scientific << AdjVar_Adapt[iPoint][iVar]<<"\t"; - restart_adjfile << endl; - - } - restart_adjfile.close(); -} - -void CGridAdaptation::SetRestart_LinSolution(CConfig *config, CPhysicalGeometry *geo_adapt, string mesh_linfilename) { - - unsigned long iPoint; - unsigned short iVar, iDim; - - char *cstr_ = new char [mesh_linfilename.size()+1]; - strcpy (cstr_, mesh_linfilename.c_str()); - - ofstream restart_linfile; - restart_linfile.open(cstr_, ios::out); - restart_linfile.precision(15); - - restart_linfile << "Restart file generated with SU2_MSH" << endl; - - for (iPoint = 0; iPoint < nPoint_new; iPoint++) { - restart_linfile << iPoint <<"\t"; - - for (iDim = 0; iDim < nDim; iDim++) - restart_linfile << scientific << geo_adapt->node[iPoint]->GetCoord(iDim) <<"\t"; - for (iVar = 0; iVar < nVar; iVar++) - restart_linfile << scientific << LinVar_Adapt[iPoint][iVar]<<"\t"; - restart_linfile << endl; - - } - restart_linfile.close(); -} - -void CGridAdaptation::SetSensorElem(CGeometry *geometry, CConfig *config, unsigned long max_elem) { - su2double Max_Sensor, threshold; - su2double *Sensor = new su2double[geometry->GetnElem()]; - unsigned long ip_0, ip_1, ip_2, ip_3, iElem, nElem_real; - - /*--- Compute the the adaptation index at each element ---*/ - Max_Sensor = 0.0; - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - ip_0 = geometry->elem[iElem]->GetNode(0); - ip_1 = geometry->elem[iElem]->GetNode(1); - ip_2 = geometry->elem[iElem]->GetNode(2); - Sensor[iElem] = (Index[ip_0]+Index[ip_1]+Index[ip_2])/3.0; - if ((geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) || - (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON)) { - ip_3 = geometry->elem[iElem]->GetNode(2); - Sensor[iElem] = (Index[ip_0]+Index[ip_1]+Index[ip_2]+Index[ip_3])/4.0; - } - Max_Sensor = max(Max_Sensor, Sensor[iElem]); - } - - /*--- Adimensionalization of the adaptation sensor ---*/ - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { - Sensor[iElem] = Sensor[iElem]/Max_Sensor; - } - - /*--- Selection of the elements to be adapted ---*/ - threshold = 0.999; - nElem_real = 0; - while (nElem_real <= max_elem) { - for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) - if ( Sensor[iElem] >= threshold && !geometry->elem[iElem]->GetDivide() ) { - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) nElem_real = nElem_real + 3; - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) nElem_real = nElem_real + 3; - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) nElem_real = nElem_real + 7; - geometry->elem[iElem]->SetDivide(true); - if (nElem_real >= max_elem) break; - } - threshold = threshold - 0.001; - } - - cout << "Number of elements to adapt: " << nElem_real << endl; - delete [] Sensor; -} +/*! + * \file grid_adaptation_structure.cpp + * \brief Main subroutines for grid adaptation + * \author F. Palacios + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#include "../include/grid_adaptation_structure.hpp" +#include + +CGridAdaptation::CGridAdaptation(CGeometry *geometry, CConfig *config) { + + unsigned long iPoint; + + nDim = geometry->GetnDim(); + + switch (config->GetKind_Solver()) { + + case POISSON_EQUATION: + nVar = 1; + break; + + default: + nVar = geometry->GetnDim()+2; + break; + } + + ConsVar_Sol = new su2double* [geometry->GetnPoint()]; + AdjVar_Sol = new su2double* [geometry->GetnPoint()]; + LinVar_Sol = new su2double* [geometry->GetnPoint()]; + ConsVar_Res = new su2double* [geometry->GetnPoint()]; + AdjVar_Res = new su2double* [geometry->GetnPoint()]; + LinVar_Res = new su2double* [geometry->GetnPoint()]; + Gradient = new su2double* [geometry->GetnPoint()]; + Gradient_Flow = new su2double* [geometry->GetnPoint()]; + Gradient_Adj = new su2double* [geometry->GetnPoint()]; + + Index = new su2double [geometry->GetnPoint()]; + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { + ConsVar_Sol[iPoint] = new su2double [nVar]; + AdjVar_Sol[iPoint] = new su2double [nVar]; + LinVar_Sol[iPoint] = new su2double [nVar]; + ConsVar_Res[iPoint] = new su2double [nVar]; + LinVar_Res[iPoint] = new su2double [nVar]; + AdjVar_Res[iPoint] = new su2double [nVar]; + Gradient[iPoint] = new su2double [nDim]; + Gradient_Flow[iPoint] = new su2double [nDim]; + Gradient_Adj[iPoint] = new su2double [nDim]; + } + +} + +CGridAdaptation::~CGridAdaptation(void) { + + unsigned short iVar, iDim; + + for (iVar = 0; iVar < nVar; iVar++) { + delete [] ConsVar_Adapt[iVar]; + delete [] ConsVar_Sol[iVar]; + delete [] ConsVar_Res[iVar]; + delete [] AdjVar_Adapt[iVar]; + delete [] AdjVar_Sol[iVar]; + delete [] AdjVar_Res[iVar]; + delete [] LinVar_Adapt[iVar]; + delete [] LinVar_Sol[iVar]; + delete [] LinVar_Res[iVar]; + } + + for (iDim = 0; iDim < nDim; iDim++) { + delete [] Gradient[iDim]; + delete [] Gradient_Flow[iDim]; + delete [] Gradient_Adj[iDim]; + } + delete [] ConsVar_Adapt; + delete [] ConsVar_Sol; + delete [] ConsVar_Res; + delete [] AdjVar_Adapt; + delete [] AdjVar_Sol; + delete [] AdjVar_Res; + delete [] LinVar_Adapt; + delete [] LinVar_Sol; + delete [] LinVar_Res; + delete [] Gradient; + delete [] Gradient_Flow; + delete [] Gradient_Adj; + delete [] Index; +} + +void CGridAdaptation::GetFlowSolution(CGeometry *geometry, CConfig *config) { + unsigned long iPoint, index; + unsigned short iVar; + su2double dummy; + + string text_line; + + string mesh_filename = config->GetSolution_FlowFileName(); + ifstream restart_file; + + char *cstr = new char [mesh_filename.size()+1]; + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + strcpy (cstr, mesh_filename.c_str()); + restart_file.open(cstr, ios::in); + if (restart_file.fail()) { + if (rank == MASTER_NODE) + cout << "There is no flow restart file!!" << endl; + exit(EXIT_FAILURE); } + + /*--- Read the header of the file ---*/ + getline(restart_file, text_line); + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + getline(restart_file, text_line); + istringstream point_line(text_line); + + point_line >> index; + + if (nDim == 2) point_line >> dummy >> dummy; + else point_line >> dummy >> dummy >> dummy; + + for (iVar = 0; iVar < nVar; iVar ++) + point_line >> ConsVar_Sol[iPoint][iVar]; + } + restart_file.close(); +} + +void CGridAdaptation::GetFlowResidual(CGeometry *geometry, CConfig *config) { + unsigned long iPoint, index; + unsigned short iVar; + +// su2double dummy[5]; + su2double dummy; + string text_line; + + string mesh_filename = config->GetSolution_FlowFileName(); + ifstream restart_file; + + char *cstr = new char [mesh_filename.size()+1]; + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + strcpy (cstr, mesh_filename.c_str()); + restart_file.open(cstr, ios::in); + if (restart_file.fail()) { + if (rank == MASTER_NODE) + cout << "There is no flow restart file!!" << endl; + exit(EXIT_FAILURE); } + + /*--- Read the header of the file ---*/ + getline(restart_file, text_line); + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + getline(restart_file, text_line); + istringstream point_line(text_line); + + point_line >> index; + + if (nDim == 2) point_line >> dummy >> dummy; + else point_line >> dummy >> dummy >> dummy; + + for (iVar = 0; iVar < nVar; iVar++) + point_line >> dummy; + for (iVar = 0; iVar < nVar; iVar++) + point_line >> ConsVar_Res[iPoint][iVar]; + } + restart_file.close(); +} + +void CGridAdaptation::GetAdjSolution(CGeometry *geometry, CConfig *config) { + unsigned long iPoint, index; + unsigned short iVar; + su2double dummy; + string text_line; + + string copy, mesh_filename; + ifstream restart_file; + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Get the adjoint solution file name ---*/ + mesh_filename = config->GetSolution_AdjFileName(); + mesh_filename = config->GetObjFunc_Extension(mesh_filename); + + restart_file.open(mesh_filename.c_str(), ios::in); + if (restart_file.fail()) { + if (rank == MASTER_NODE) + cout << "There is no adjoint restart file!!" << endl; + exit(EXIT_FAILURE); } + + /*--- Read the header of the file ---*/ + getline(restart_file, text_line); + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + getline(restart_file, text_line); + istringstream point_line(text_line); + + point_line >> index; + + if (nDim == 2) point_line >> dummy >> dummy; + else point_line >> dummy >> dummy >> dummy; + + for (iVar = 0; iVar < nVar; iVar ++) + point_line >> AdjVar_Sol[iPoint][iVar]; + } + + restart_file.close(); +} + +void CGridAdaptation::GetAdjResidual(CGeometry *geometry, CConfig *config) { + unsigned long iPoint, index; + string text_line; + su2double dummy; + + string mesh_filename, copy; + ifstream restart_file; + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + char buffer[50], cstr[MAX_STRING_SIZE]; + mesh_filename = config->GetSolution_AdjFileName(); + copy.assign(mesh_filename); + unsigned short lastindex = copy.find_last_of("."); + copy = copy.substr(0, lastindex); + strcpy (cstr, copy.c_str()); + if (config->GetKind_ObjFunc() == DRAG_COEFFICIENT) SPRINTF (buffer, "_cd.dat"); + if (config->GetKind_ObjFunc() == LIFT_COEFFICIENT) SPRINTF (buffer, "_cl.dat"); + if (config->GetKind_ObjFunc() == SIDEFORCE_COEFFICIENT) SPRINTF (buffer, "_csf.dat"); + if (config->GetKind_ObjFunc() == INVERSE_DESIGN_PRESSURE) SPRINTF (buffer, "_invpress.dat"); + if (config->GetKind_ObjFunc() == INVERSE_DESIGN_HEATFLUX) SPRINTF (buffer, "_invheat.dat"); + if (config->GetKind_ObjFunc() == MOMENT_X_COEFFICIENT) SPRINTF (buffer, "_cmx.dat"); + if (config->GetKind_ObjFunc() == MOMENT_Y_COEFFICIENT) SPRINTF (buffer, "_cmy.dat"); + if (config->GetKind_ObjFunc() == MOMENT_Z_COEFFICIENT) SPRINTF (buffer, "_cmz.dat"); + if (config->GetKind_ObjFunc() == EFFICIENCY) SPRINTF (buffer, "_eff.dat"); + if (config->GetKind_ObjFunc() == FORCE_X_COEFFICIENT) SPRINTF (buffer, "_cfx.dat"); + if (config->GetKind_ObjFunc() == FORCE_Y_COEFFICIENT) SPRINTF (buffer, "_cfy.dat"); + if (config->GetKind_ObjFunc() == FORCE_Z_COEFFICIENT) SPRINTF (buffer, "_cfz.dat"); + if (config->GetKind_ObjFunc() == TOTAL_HEATFLUX) SPRINTF (buffer, "_totheat.dat"); + if (config->GetKind_ObjFunc() == MAXIMUM_HEATFLUX) SPRINTF (buffer, "_maxheat.dat"); + if (config->GetKind_ObjFunc() == AVG_TOTAL_PRESSURE) SPRINTF (buffer, "_pt.dat"); + if (config->GetKind_ObjFunc() == AVG_OUTLET_PRESSURE) SPRINTF (buffer, "_pe.dat"); + if (config->GetKind_ObjFunc() == MASS_FLOW_RATE) SPRINTF (buffer, "_mfr.dat"); + if (config->GetKind_ObjFunc() == OUTLET_CHAIN_RULE) SPRINTF (buffer, "_chn.dat"); + + strcat(cstr, buffer); + + restart_file.open(cstr, ios::in); + + if (restart_file.fail()) { + if (rank == MASTER_NODE) + cout << "There is no flow restart file!!" << endl; + exit(EXIT_FAILURE); } + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + getline(restart_file, text_line); + istringstream point_line(text_line); + + point_line >> index; + + if (nDim == 2) point_line >> dummy >> dummy; + else point_line >> dummy >> dummy >> dummy; + + if (nVar == 1) point_line >> dummy >> AdjVar_Res[iPoint][0]; + if (nVar == 4) point_line >> dummy >> dummy >> dummy >> dummy >> + AdjVar_Res[iPoint][0] >> AdjVar_Res[iPoint][1] >> AdjVar_Res[iPoint][2] >> + AdjVar_Res[iPoint][3]; + if (nVar == 5) point_line >> dummy >> dummy >> dummy >> dummy >> dummy >> + AdjVar_Res[iPoint][0] >> AdjVar_Res[iPoint][1] >> AdjVar_Res[iPoint][2] >> + AdjVar_Res[iPoint][3] >> AdjVar_Res[iPoint][4]; + } + restart_file.close(); +} + +void CGridAdaptation::SetComplete_Refinement(CGeometry *geometry, unsigned short strength) { + unsigned long iElem; + + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + geometry->elem[iElem]->SetDivide (true); + } +} + +void CGridAdaptation::SetNo_Refinement(CGeometry *geometry, unsigned short strength) { + unsigned long iElem; + + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + geometry->elem[iElem]->SetDivide (false); + } +} + +void CGridAdaptation::SetWake_Refinement(CGeometry *geometry, unsigned short strength) { + unsigned long iElem, iPoint; + unsigned short iNode; + su2double Coordx, Coordy, dist, wake = 0.5; + + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { + iPoint = geometry->elem[iElem]->GetNode(iNode); + Coordx = geometry->node[iPoint]->GetCoord(0); + Coordy = geometry->node[iPoint]->GetCoord(1); + dist = sqrt(Coordx*Coordx+Coordy*Coordy); + if (dist < wake) { + geometry->elem[iElem]->SetDivide (true); + } + if ((Coordx > 0) && ((Coordy > -wake) && (Coordy < wake))) { + geometry->elem[iElem]->SetDivide (true); + } + } +} + +void CGridAdaptation::SetSupShock_Refinement(CGeometry *geometry, CConfig *config) { + unsigned long iElem, iPoint; + unsigned short iNode; + su2double Coordx, Coordy; + su2double mu_1 = asin(1/config->GetMach()-0.1); + su2double mu_2 = asin(1/(config->GetMach()-0.7)); + + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) { + iPoint = geometry->elem[iElem]->GetNode(iNode); + Coordx = geometry->node[iPoint]->GetCoord(0); + Coordy = geometry->node[iPoint]->GetCoord(1); + if (Coordy < 0.0) + if ((Coordx > fabs(Coordy/tan(mu_2))-0.25) && (Coordx < fabs(Coordy/tan(mu_1))+1.25)) { + geometry->elem[iElem]->SetDivide (true); + } + } +} + +long CGridAdaptation::CheckRectCode(bool *AdaptCode) { + + int Code = -1; + + // Default + + if ((AdaptCode[0] == true) || (AdaptCode[1] == true) || (AdaptCode[2] == true) || (AdaptCode[3] == true)) { Code = 0; } + + // Combination 1:4 + + if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == true)) {Code = 1; return Code;} + + // Combination 1:2 + + if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == false)) {Code = 2; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == true)) {Code = 3; return Code;} + + return Code; + +} + +long CGridAdaptation::CheckRectExtCode(bool *AdaptCode) { + + int Code = -1; + + if ((AdaptCode[0] == true) || (AdaptCode[1] == true) || (AdaptCode[2] == true) || (AdaptCode[3] == true)) {Code = 0;} + + // Combination 1R -> 3T + + if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == false)) {Code = 2; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == false)) {Code = 3; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == false)) {Code = 4; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == true)) {Code = 5; return Code;} + + // Combination 1R -> 4T + + if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == false)) {Code = 6; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == false)) {Code = 7; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == true)) {Code = 8; return Code;} + + if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == true)) {Code = 9; return Code;} + + // Combination 1R -> 1R+3T + + if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == false)) {Code = 12; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == true)) {Code = 13; return Code;} + + if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == true)) {Code = 14; return Code;} + + if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == true)) {Code = 15; return Code;} + + return Code; + +} + +long CGridAdaptation::CheckTriangleCode(bool *AdaptCode) { + + int Code = -1; + + if ((AdaptCode[0] == true) || (AdaptCode[1] == true) || (AdaptCode[2] == true)) {Code = 0;} + + // Combination 1T -> 3T + + if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == true)) {Code = 1; return Code;} + + // Combination 1T -> 2T + + if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == false)) {Code = 2; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == false)) {Code = 3; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == true)) {Code = 4; return Code;} + + // Combination 1T -> 1R+1T (2D) or 3T (3D) + + if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == false)) {Code = 5; return Code;} + + if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == true)) {Code = 6; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == true)) {Code = 7; return Code;} + + return Code; + +} + +long CGridAdaptation::CheckTetraCode(bool *AdaptCode) { + + int Code = -1; + unsigned short nDivEdges, iVar; + + // Default + + if ((AdaptCode[0] == true) || (AdaptCode[1] == true) || (AdaptCode[2] == true) || (AdaptCode[3] == true) || (AdaptCode[4] == true) || + (AdaptCode[5] == true) ) { Code = 0; } + + // Combination 1:8 + + if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == true) && (AdaptCode[4] == true) && + (AdaptCode[5] == true) ) {Code = 1; return Code;} + + // Combination 1:4 + + if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == false) && (AdaptCode[4] == true) && + (AdaptCode[5] == false) ) {Code = 2; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == true) && (AdaptCode[4] == true) && + (AdaptCode[5] == true) ) {Code = 3; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == false) && (AdaptCode[4] == false) && + (AdaptCode[5] == true) ) {Code = 4; return Code;} + + if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == true) && (AdaptCode[4] == false) && + (AdaptCode[5] == false) ) {Code = 5; return Code;} + + // Combinations with 1, 2, and 3 (no regular) divided edges. + + nDivEdges = 0; + for (iVar = 0; iVar < 6; iVar ++) + if (AdaptCode[iVar] == true) nDivEdges++; + + if ((nDivEdges == 1) || (nDivEdges == 2) || (nDivEdges == 3)) {Code = 6; return Code;} + + return Code; + +} + +long CGridAdaptation::CheckHexaCode(bool *AdaptCode) { + + int Code = -1; + + // Default + + if ((AdaptCode[0] == true) || (AdaptCode[1] == true) || (AdaptCode[2] == true) || (AdaptCode[3] == true) || (AdaptCode[4] == true) || + (AdaptCode[5] == true) || (AdaptCode[6] == true) || (AdaptCode[7] == true) || (AdaptCode[8] == true) || (AdaptCode[9] == true) || + (AdaptCode[10] == true) || (AdaptCode[11] == true)) { Code = 0; } + + // Combination 1:8 + + if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == true) && (AdaptCode[4] == true) && + (AdaptCode[5] == true) && (AdaptCode[6] == true) && (AdaptCode[7] == true) && (AdaptCode[8] == true) && (AdaptCode[9] == true) && + (AdaptCode[10] == true) && (AdaptCode[11] == true)) {Code = 1; return Code;} + + // Combination 1:4 + + if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == false) && (AdaptCode[4] == true) && + (AdaptCode[5] == false) && (AdaptCode[6] == true) && (AdaptCode[7] == false) && (AdaptCode[8] == true) && (AdaptCode[9] == true) && + (AdaptCode[10] == true) && (AdaptCode[11] == true)) {Code = 2; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == true) && (AdaptCode[4] == false) && + (AdaptCode[5] == true) && (AdaptCode[6] == false) && (AdaptCode[7] == true) && (AdaptCode[8] == true) && (AdaptCode[9] == true) && + (AdaptCode[10] == true) && (AdaptCode[11] == true)) {Code = 3; return Code;} + + if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == true) && (AdaptCode[4] == true) && + (AdaptCode[5] == true) && (AdaptCode[6] == true) && (AdaptCode[7] == true) && (AdaptCode[8] == false) && (AdaptCode[9] == false) && + (AdaptCode[10] == false) && (AdaptCode[11] == false)) {Code = 4; return Code;} + + // Combination 1:2 + + if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == false) && (AdaptCode[4] == false) && + (AdaptCode[5] == false) && (AdaptCode[6] == false) && (AdaptCode[7] == false) && (AdaptCode[8] == true) && (AdaptCode[9] == true) && + (AdaptCode[10] == true) && (AdaptCode[11] == true)) {Code = 5; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == true) && (AdaptCode[4] == false) && + (AdaptCode[5] == true) && (AdaptCode[6] == false) && (AdaptCode[7] == true) && (AdaptCode[8] == false) && (AdaptCode[9] == false) && + (AdaptCode[10] == false) && (AdaptCode[11] == false)) {Code = 6; return Code;} + + if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == false) && (AdaptCode[4] == true) && + (AdaptCode[5] == false) && (AdaptCode[6] == true) && (AdaptCode[7] == false) && (AdaptCode[8] == false) && (AdaptCode[9] == false) && + (AdaptCode[10] == false) && (AdaptCode[11] == false)) {Code = 7; return Code; } + + return Code; + +} + +long CGridAdaptation::CheckPyramCode(bool *AdaptCode) { + + int Code = -1; + + if ((AdaptCode[0] == true) || (AdaptCode[1] == true) || (AdaptCode[2] == true) || (AdaptCode[3] == true)) {Code = 0;} + + // Combination 1P -> 1P + + if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == false)) {Code = 1; return Code;} + + // Combination 1P -> 3T + + if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == false)) {Code = 2; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == false)) {Code = 3; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == false)) {Code = 4; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == true)) {Code = 5; return Code;} + + // Combination 1P -> 4T + + if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == false)) {Code = 6; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == false)) {Code = 7; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == true)) {Code = 8; return Code;} + + if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == false) && (AdaptCode[3] == true)) {Code = 9; return Code;} + + // Combination 1P -> 2P + + if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == false)) {Code = 10; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == true)) {Code = 11; return Code;} + + // Combination 1P -> 1P+3T + + if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == false)) {Code = 12; return Code;} + + if ((AdaptCode[0] == false) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == true)) {Code = 13; return Code;} + + if ((AdaptCode[0] == true) && (AdaptCode[1] == false) && (AdaptCode[2] == true) && (AdaptCode[3] == true)) {Code = 14; return Code;} + + if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == false) && (AdaptCode[3] == true)) {Code = 15; return Code;} + + + // Combination 1P -> 4P + + if ((AdaptCode[0] == true) && (AdaptCode[1] == true) && (AdaptCode[2] == true) && (AdaptCode[3] == true)) {Code = 16; return Code;} + + return Code; + +} + +void CGridAdaptation::RectDivision(long code , long *nodes, long **Division, long *nPart) { + + if (code == 1) { + + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[8]; Division[0][2] = nodes[7]; Division[0][3] = nodes[0]; Division[0][4] = nodes[4]; + + Division[1][1] = nodes[8]; Division[1][2] = nodes[4]; Division[1][3] = nodes[1]; Division[1][4] = nodes[5]; + + Division[2][1] = nodes[8]; Division[2][2] = nodes[5]; Division[2][3] = nodes[2]; Division[2][4] = nodes[6]; + + Division[3][1] = nodes[8]; Division[3][2] = nodes[6]; Division[3][3] = nodes[3]; Division[3][4] = nodes[7]; + + } + + if (code == 2) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 5; + *nPart = 2; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[4]; Division[0][3] = nodes[6]; Division[0][4] = nodes[3]; + + Division[1][1] = nodes[4]; Division[1][2] = nodes[1]; Division[1][3] = nodes[2]; Division[1][4] = nodes[6]; + + } + + if (code == 3) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 5; + *nPart = 2; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[5]; Division[0][4] = nodes[7]; + + Division[1][1] = nodes[5]; Division[1][2] = nodes[2]; Division[1][3] = nodes[3]; Division[1][4] = nodes[7]; + + } + +} + +void CGridAdaptation::RectExtDivision(long code , long *nodes, long **Division, long *nPart) { + + if (code == 2) { + // number of nodes at each new element + Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; + *nPart = 3; + + // nodes that compose each element + Division[0][1] = nodes[4]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; + + Division[1][1] = nodes[4]; Division[1][2] = nodes[2]; Division[1][3] = nodes[3]; + + Division[2][1] = nodes[4]; Division[2][2] = nodes[3]; Division[2][3] = nodes[0]; + + } + + if (code == 3) { + // number of nodes at each new element + Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; + *nPart = 3; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[5]; + + Division[1][1] = nodes[0]; Division[1][2] = nodes[5]; Division[1][3] = nodes[3]; + + Division[2][1] = nodes[3]; Division[2][2] = nodes[5]; Division[2][3] = nodes[2]; + + } + + if (code == 4) { + // number of nodes at each new element + Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; + *nPart = 3; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[6]; + + Division[1][1] = nodes[1]; Division[1][2] = nodes[2]; Division[1][3] = nodes[6]; + + Division[2][1] = nodes[0]; Division[2][2] = nodes[6]; Division[2][3] = nodes[3]; + + } + + if (code == 5) { + // number of nodes at each new element + Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; + *nPart = 3; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[7]; + + Division[1][1] = nodes[1]; Division[1][2] = nodes[2]; Division[1][3] = nodes[7]; + + Division[2][1] = nodes[7]; Division[2][2] = nodes[2]; Division[2][3] = nodes[3]; + + } + + if (code == 6) { + // number of nodes at each new element + Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[4]; Division[0][3] = nodes[3]; + + Division[1][1] = nodes[4]; Division[1][2] = nodes[1]; Division[1][3] = nodes[5]; + + Division[2][1] = nodes[4]; Division[2][2] = nodes[5]; Division[2][3] = nodes[3]; + + Division[3][1] = nodes[5]; Division[3][2] = nodes[2]; Division[3][3] = nodes[3]; + + } + + if (code == 7) { + // number of nodes at each new element + Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[5]; + + Division[1][1] = nodes[0]; Division[1][2] = nodes[5]; Division[1][3] = nodes[6]; + + Division[2][1] = nodes[5]; Division[2][2] = nodes[2]; Division[2][3] = nodes[6]; + + Division[3][1] = nodes[0]; Division[3][2] = nodes[6]; Division[3][3] = nodes[3]; + + } + + if (code == 8) { + // number of nodes at each new element + Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[7]; + + Division[1][1] = nodes[7]; Division[1][2] = nodes[1]; Division[1][3] = nodes[6]; + + Division[2][1] = nodes[1]; Division[2][2] = nodes[2]; Division[2][3] = nodes[6]; + + Division[3][1] = nodes[7]; Division[3][2] = nodes[6]; Division[3][3] = nodes[3]; + + } + + if (code == 9) { + // number of nodes at each new element + Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[4]; Division[0][3] = nodes[7]; + + Division[1][1] = nodes[4]; Division[1][2] = nodes[1]; Division[1][3] = nodes[2]; + + Division[2][1] = nodes[7]; Division[2][2] = nodes[4]; Division[2][3] = nodes[2]; + + Division[3][1] = nodes[7]; Division[3][2] = nodes[2]; Division[3][3] = nodes[3]; + + } + + if (code == 12) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[4]; Division[0][3] = nodes[6]; Division[0][4] = nodes[3]; + + Division[1][1] = nodes[4]; Division[1][2] = nodes[1]; Division[1][3] = nodes[5]; + + Division[2][1] = nodes[4]; Division[2][2] = nodes[5]; Division[2][3] = nodes[6]; + + Division[3][1] = nodes[5]; Division[3][2] = nodes[2]; Division[3][3] = nodes[6]; + + } + + if (code == 13) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[5]; Division[0][4] = nodes[7]; + + Division[1][1] = nodes[5]; Division[1][2] = nodes[2]; Division[1][3] = nodes[6]; + + Division[2][1] = nodes[7]; Division[2][2] = nodes[5]; Division[2][3] = nodes[6]; + + Division[3][1] = nodes[7]; Division[3][2] = nodes[6]; Division[3][3] = nodes[3]; + + } + + if (code == 14) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[4]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; Division[0][4] = nodes[6]; + + Division[1][1] = nodes[0]; Division[1][2] = nodes[4]; Division[1][3] = nodes[7]; + + Division[2][1] = nodes[7]; Division[2][2] = nodes[4]; Division[2][3] = nodes[6]; + + Division[3][1] = nodes[7]; Division[3][2] = nodes[6]; Division[3][3] = nodes[3]; + + } + + if (code == 15) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[7]; Division[0][2] = nodes[5]; Division[0][3] = nodes[2]; Division[0][4] = nodes[3]; + + Division[1][1] = nodes[0]; Division[1][2] = nodes[4]; Division[1][3] = nodes[7]; + + Division[2][1] = nodes[4]; Division[2][2] = nodes[1]; Division[2][3] = nodes[5]; + + Division[3][1] = nodes[4]; Division[3][2] = nodes[5]; Division[3][3] = nodes[7]; + + } + +} + +void CGridAdaptation::TriangleDivision(long code , long *nodes, long *edges, long **Division, long *nPart) { + + if (code == 1) { + // number of nodes at each new element + Division[0][0] = 4; Division[1][0] = 4; Division[2][0] = 4; Division[3][0] = 4; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[3]; Division[0][3] = nodes[5]; + + Division[1][1] = nodes[3]; Division[1][2] = nodes[1]; Division[1][3] = nodes[4]; + + Division[2][1] = nodes[5]; Division[2][2] = nodes[4]; Division[2][3] = nodes[2]; + + Division[3][1] = nodes[3]; Division[3][2] = nodes[4]; Division[3][3] = nodes[5]; + return; + } + + if (code == 2) { + // number of nodes at each new element + Division[0][0] = 4; Division[1][0] = 4; + *nPart = 2; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[3]; Division[0][3] = nodes[2]; + + Division[1][1] = nodes[3]; Division[1][2] = nodes[1]; Division[1][3] = nodes[2]; + return; + + } + + if (code == 3) { + // number of nodes at each new element + Division[0][0] = 4; Division[1][0] = 4; + *nPart = 2; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[4]; + + Division[1][1] = nodes[0]; Division[1][2] = nodes[4]; Division[1][3] = nodes[2]; + return; + + } + + if (code == 4) { + // number of nodes at each new element + Division[0][0] = 4; Division[1][0] = 4; + *nPart = 2; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[5]; + + Division[1][1] = nodes[5]; Division[1][2] = nodes[1]; Division[1][3] = nodes[2]; + return; + + } + + if (edges == NULL) { + + if (code == 5) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 4; + *nPart = 2; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[3]; Division[0][3] = nodes[4]; Division[0][4] = nodes[2]; + + Division[1][1] = nodes[3]; Division[1][2] = nodes[1]; Division[1][3] = nodes[4]; + return; + + } + + if (code == 6) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 4; + *nPart = 2; + + // nodes that compose each element + Division[0][1] = nodes[3]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; Division[0][4] = nodes[5]; + + Division[1][1] = nodes[0]; Division[1][2] = nodes[3]; Division[1][3] = nodes[5]; + return; + + } + + if (code == 7) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 4; + *nPart = 2; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[4]; Division[0][4] = nodes[5]; + + Division[1][1] = nodes[5]; Division[1][2] = nodes[4]; Division[1][3] = nodes[2]; + return; + + } + + } + else { + + unsigned short iDiv, nDiv, edge_div[6][3], max_iVar, iVar, nElem, iElem, iNode, iTriangle; + bool set_0, set_1, new_div, new_triangle[8][10]; + long max_edge; + + nDiv = 0; + do { new_div = false; + + // Compute the greatest edge index + max_edge = 0; max_iVar = 0; + for (iVar = 0; iVar < 3; iVar ++) { + max_edge = max(max_edge, edges[iVar]); + if ( max_edge == edges[iVar] ) max_iVar = iVar; + } + + // If the edge is divided compose the vector with the information of the division + if (edges[max_iVar] >= 0) { + if (max_iVar == 0) { edge_div[nDiv][0] = 3; edge_div[nDiv][1] = 0; edge_div[nDiv][2] = 1; } + if (max_iVar == 1) { edge_div[nDiv][0] = 4; edge_div[nDiv][1] = 0; edge_div[nDiv][2] = 2; } + if (max_iVar == 2) { edge_div[nDiv][0] = 5; edge_div[nDiv][1] = 1; edge_div[nDiv][2] = 2; } + nDiv++; new_div = true; + } + // In order to do not repeat the egde, restart the code + edges[max_iVar] = -1; + } while (new_div); + + + // Inicializa + for (iVar = 0; iVar < 3; iVar ++) new_triangle[0][iVar] = true; + for (iVar = 3; iVar < 6; iVar ++) new_triangle[0][iVar] = false; + + nElem = 1; + for (iDiv = 0; iDiv < nDiv; iDiv++) { + short target_elem = -1; + + for (iElem = 0; iElem < nElem; iElem++) { + set_0 = false; set_1 = false; + if (new_triangle[iElem][edge_div[iDiv][1]]) set_0 = true; + if (new_triangle[iElem][edge_div[iDiv][2]]) set_1 = true; + if (set_0 && set_1) target_elem = iElem; + } + + if (target_elem != -1) { + for (iNode = 0; iNode < 6; iNode++) + new_triangle[nElem][iNode] = new_triangle[target_elem][iNode]; + new_triangle[target_elem][edge_div[iDiv][0]] = true; + new_triangle[target_elem][edge_div[iDiv][2]] = false; + new_triangle[nElem][edge_div[iDiv][0]] = true; + new_triangle[nElem][edge_div[iDiv][1]] = false; + nElem++; + } + } + + *nPart = nElem; + + for (iTriangle = 0; iTriangle < nElem; iTriangle++) { + Division[iTriangle][0] = 3; + iVar = 1; + for (iNode = 0; iNode < 6; iNode++) + if (new_triangle[iTriangle][iNode] == true) { + if (iNode == 0) Division[iTriangle][iVar] = nodes[0]; + if (iNode == 1) Division[iTriangle][iVar] = nodes[1]; + if (iNode == 2) Division[iTriangle][iVar] = nodes[2]; + if (iNode == 3) Division[iTriangle][iVar] = nodes[3]; + if (iNode == 4) Division[iTriangle][iVar] = nodes[4]; + if (iNode == 5) Division[iTriangle][iVar] = nodes[5]; + iVar++; + } + + } + + } +} + +void CGridAdaptation::TetraDivision(long code , long *nodes, long *edges, long **Division, long *nPart) { + + + if (code == 1) { + + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; + Division[4][0] = 5; Division[5][0] = 5; Division[6][0] = 5; Division[7][0] = 5; + *nPart = 8; + + // nodes that compose each element + Division[0][1] = nodes[6]; Division[0][2] = nodes[5]; Division[0][3] = nodes[4]; Division[0][4] = nodes[0]; + Division[1][1] = nodes[8]; Division[1][2] = nodes[4]; Division[1][3] = nodes[7]; Division[1][4] = nodes[1]; + Division[2][1] = nodes[6]; Division[2][2] = nodes[8]; Division[2][3] = nodes[9]; Division[2][4] = nodes[3]; + Division[3][1] = nodes[9]; Division[3][2] = nodes[7]; Division[3][3] = nodes[5]; Division[3][4] = nodes[2]; + Division[4][1] = nodes[6]; Division[4][2] = nodes[8]; Division[4][3] = nodes[7]; Division[4][4] = nodes[9]; + Division[5][1] = nodes[6]; Division[5][2] = nodes[7]; Division[5][3] = nodes[5]; Division[5][4] = nodes[9]; + Division[6][1] = nodes[7]; Division[6][2] = nodes[8]; Division[6][3] = nodes[6]; Division[6][4] = nodes[4]; + Division[7][1] = nodes[5]; Division[7][2] = nodes[7]; Division[7][3] = nodes[6]; Division[7][4] = nodes[4]; + + } + + if (code == 2) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[4]; Division[0][3] = nodes[6]; Division[0][4] = nodes[2]; + Division[1][1] = nodes[6]; Division[1][2] = nodes[4]; Division[1][3] = nodes[8]; Division[1][4] = nodes[2]; + Division[2][1] = nodes[6]; Division[2][2] = nodes[8]; Division[2][3] = nodes[3]; Division[2][4] = nodes[2]; + Division[3][1] = nodes[4]; Division[3][2] = nodes[1]; Division[3][3] = nodes[8]; Division[3][4] = nodes[2]; + + } + + if (code == 3) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[2]; Division[0][2] = nodes[7]; Division[0][3] = nodes[9]; Division[0][4] = nodes[0]; + Division[1][1] = nodes[7]; Division[1][2] = nodes[8]; Division[1][3] = nodes[9]; Division[1][4] = nodes[0]; + Division[2][1] = nodes[7]; Division[2][2] = nodes[1]; Division[2][3] = nodes[8]; Division[2][4] = nodes[0]; + Division[3][1] = nodes[9]; Division[3][2] = nodes[8]; Division[3][3] = nodes[3]; Division[3][4] = nodes[0]; + + } + + if (code == 4) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[2]; Division[0][2] = nodes[5]; Division[0][3] = nodes[9]; Division[0][4] = nodes[1]; + Division[1][1] = nodes[9]; Division[1][2] = nodes[5]; Division[1][3] = nodes[6]; Division[1][4] = nodes[1]; + Division[2][1] = nodes[5]; Division[2][2] = nodes[0]; Division[2][3] = nodes[6]; Division[2][4] = nodes[1]; + Division[3][1] = nodes[9]; Division[3][2] = nodes[6]; Division[3][3] = nodes[3]; Division[3][4] = nodes[1]; + + } + + if (code == 5) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[4]; Division[0][3] = nodes[5]; Division[0][4] = nodes[3]; + Division[1][1] = nodes[5]; Division[1][2] = nodes[4]; Division[1][3] = nodes[7]; Division[1][4] = nodes[3]; + Division[2][1] = nodes[2]; Division[2][2] = nodes[5]; Division[2][3] = nodes[7]; Division[2][4] = nodes[3]; + Division[3][1] = nodes[7]; Division[3][2] = nodes[4]; Division[3][3] = nodes[1]; Division[3][4] = nodes[3]; + + } + + if (code == 6) { + + unsigned short iDiv, nDiv, edge_div[6][3], max_iVar, iVar, nElem, iElem, iNode, iTetra; + bool set_0, set_1, new_div, new_tetra[8][10]; + long max_edge; + + nDiv = 0; + do { new_div = false; + + // Compute the greatest node at the divided edge + max_edge = 0; max_iVar = 0; + for (iVar = 0; iVar < 6; iVar ++) { + max_edge = max(max_edge, edges[iVar]); + if ( max_edge == edges[iVar] ) max_iVar = iVar; + } + + // If the edge is divided compose the vector with the information of the division + if (edges[max_iVar] >= 0) { + if (max_iVar == 0) { edge_div[nDiv][0] = 4; edge_div[nDiv][1] = 0; edge_div[nDiv][2] = 1; } + if (max_iVar == 1) { edge_div[nDiv][0] = 5; edge_div[nDiv][1] = 0; edge_div[nDiv][2] = 2; } + if (max_iVar == 2) { edge_div[nDiv][0] = 6; edge_div[nDiv][1] = 0; edge_div[nDiv][2] = 3; } + if (max_iVar == 3) { edge_div[nDiv][0] = 7; edge_div[nDiv][1] = 1; edge_div[nDiv][2] = 2; } + if (max_iVar == 4) { edge_div[nDiv][0] = 8; edge_div[nDiv][1] = 1; edge_div[nDiv][2] = 3; } + if (max_iVar == 5) { edge_div[nDiv][0] = 9; edge_div[nDiv][1] = 2; edge_div[nDiv][2] = 3; } + nDiv++; new_div = true; + } + // In order to do not repeat the egde, restart the code + edges[max_iVar] = -1; + } while (new_div); + + + // Inicializa + for (iVar = 0; iVar < 4; iVar ++) new_tetra[0][iVar] = true; + for (iVar = 4; iVar < 10; iVar ++) new_tetra[0][iVar] = false; + + nElem = 1; + for (iDiv = 0; iDiv < nDiv; iDiv++) { + for (iVar = 0; iVar < 3; iVar++) { + short target_elem = -1; + + for (iElem = 0; iElem < nElem; iElem++) { + set_0 = false; set_1 = false; + if (new_tetra[iElem][edge_div[iDiv][1]]) set_0 = true; + if (new_tetra[iElem][edge_div[iDiv][2]]) set_1 = true; + if (set_0 && set_1) target_elem = iElem; + } + + if (target_elem != -1) { + for (iNode = 0; iNode < 10; iNode++) + new_tetra[nElem][iNode] = new_tetra[target_elem][iNode]; + new_tetra[target_elem][edge_div[iDiv][0]] = true; + new_tetra[target_elem][edge_div[iDiv][2]] = false; + new_tetra[nElem][edge_div[iDiv][0]] = true; + new_tetra[nElem][edge_div[iDiv][1]] = false; + nElem++; + } + } + } + + *nPart = nElem; + + for (iTetra = 0; iTetra < nElem; iTetra++) { + Division[iTetra][0] = 4; + iVar = 1; + for (iNode = 0; iNode < 10; iNode++) + if (new_tetra[iTetra][iNode] == true) { + if (iNode == 0) Division[iTetra][iVar] = nodes[0]; + if (iNode == 1) Division[iTetra][iVar] = nodes[1]; + if (iNode == 2) Division[iTetra][iVar] = nodes[2]; + if (iNode == 3) Division[iTetra][iVar] = nodes[3]; + if (iNode == 4) Division[iTetra][iVar] = nodes[4]; + if (iNode == 5) Division[iTetra][iVar] = nodes[5]; + if (iNode == 6) Division[iTetra][iVar] = nodes[6]; + if (iNode == 7) Division[iTetra][iVar] = nodes[7]; + if (iNode == 8) Division[iTetra][iVar] = nodes[8]; + if (iNode == 9) Division[iTetra][iVar] = nodes[9]; + iVar++; + } + +// cout <<"Boolean "<< new_tetra[iTetra][0] <<" "<< new_tetra[iTetra][1] <<" "<< new_tetra[iTetra][2] <<" "<< new_tetra[iTetra][3] <<" "<< new_tetra[iTetra][4] +// <<" "<< new_tetra[iTetra][5] <<" "<< new_tetra[iTetra][6] <<" "<< new_tetra[iTetra][7] <<" "<< new_tetra[iTetra][8] <<" "<< new_tetra[iTetra][9] << endl; + +// cout <<"Nodes "<< nodes[0] <<" "<< nodes[1] <<" "<< nodes[2] <<" "<< nodes[3] <<" "<< nodes[4] +// <<" "<< nodes[5] <<" "<< nodes[6] <<" "<< nodes[7] <<" "<< nodes[8] <<" "<< nodes[9] << endl; + +// cout <<"Tets "<< Division[iTetra][0] <<" "<< Division[iTetra][1] <<" "<< Division[iTetra][2] <<" "<< Division[iTetra][3] <<" "<< Division[iTetra][4] +// <<" "<< Division[iTetra][5] <<" "<< Division[iTetra][6] <<" "<< Division[iTetra][7] <<" "<< Division[iTetra][8] <<" "<< Division[iTetra][9] << endl; + +// cin.get(); + } + + } + +} + +void CGridAdaptation::HexaDivision(long code , long *nodes, long **Division, long *nPart) { + + if (code == 1) { + + // number of nodes at each new element + Division[0][0] = 9; Division[1][0] = 9; Division[2][0] = 9; Division[3][0] = 9; + Division[4][0] = 9; Division[5][0] = 9; Division[6][0] = 9; Division[7][0] = 9; + *nPart = 8; + + // nodes that compose each element + Division[0][1] = nodes[20]; Division[0][2] = nodes[8]; Division[0][3] = nodes[1]; Division[0][4] = nodes[9]; + Division[0][5] = nodes[26]; Division[0][6] = nodes[25]; Division[0][7] = nodes[17]; Division[0][8] = nodes[22]; + + Division[1][1] = nodes[20]; Division[1][2] = nodes[9]; Division[1][3] = nodes[2]; Division[1][4] = nodes[10]; + Division[1][5] = nodes[26]; Division[1][6] = nodes[22]; Division[1][7] = nodes[18]; Division[1][8] = nodes[23]; + + Division[2][1] = nodes[20]; Division[2][2] = nodes[10]; Division[2][3] = nodes[3]; Division[2][4] = nodes[11]; + Division[2][5] = nodes[26]; Division[2][6] = nodes[23]; Division[2][7] = nodes[19]; Division[2][8] = nodes[24]; + + Division[3][1] = nodes[20]; Division[3][2] = nodes[11]; Division[3][3] = nodes[0]; Division[3][4] = nodes[8]; + Division[3][5] = nodes[26]; Division[3][6] = nodes[24]; Division[3][7] = nodes[16]; Division[3][8] = nodes[25]; + + Division[4][1] = nodes[26]; Division[4][2] = nodes[25]; Division[4][3] = nodes[17]; Division[4][4] = nodes[22]; + Division[4][5] = nodes[21]; Division[4][6] = nodes[12]; Division[4][7] = nodes[5]; Division[4][8] = nodes[13]; + + Division[5][1] = nodes[26]; Division[5][2] = nodes[22]; Division[5][3] = nodes[18]; Division[5][4] = nodes[23]; + Division[5][5] = nodes[21]; Division[5][6] = nodes[13]; Division[5][7] = nodes[6]; Division[5][8] = nodes[14]; + + Division[6][1] = nodes[26]; Division[6][2] = nodes[23]; Division[6][3] = nodes[19]; Division[6][4] = nodes[24]; + Division[6][5] = nodes[21]; Division[6][6] = nodes[14]; Division[6][7] = nodes[7]; Division[6][8] = nodes[15]; + + Division[7][1] = nodes[26]; Division[7][2] = nodes[24]; Division[7][3] = nodes[16]; Division[7][4] = nodes[25]; + Division[7][5] = nodes[21]; Division[7][6] = nodes[15]; Division[7][7] = nodes[4]; Division[7][8] = nodes[12]; + + } + + if (code == 2) { + // number of nodes at each new element + Division[0][0] = 9; Division[1][0] = 9; Division[2][0] = 9; Division[3][0] = 9; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[8]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; Division[0][4] = nodes[10]; + Division[0][5] = nodes[25]; Division[0][17] = nodes[25]; Division[0][7] = nodes[18]; Division[0][8] = nodes[23]; + + Division[1][1] = nodes[0]; Division[1][2] = nodes[8]; Division[1][3] = nodes[10]; Division[1][4] = nodes[3]; + Division[1][5] = nodes[16]; Division[1][6] = nodes[25]; Division[1][7] = nodes[23]; Division[1][8] = nodes[19]; + + Division[2][1] = nodes[25]; Division[2][2] = nodes[17]; Division[2][3] = nodes[18]; Division[2][4] = nodes[23]; + Division[2][5] = nodes[12]; Division[2][6] = nodes[5]; Division[2][7] = nodes[6]; Division[2][8] = nodes[14]; + + Division[3][1] = nodes[16]; Division[3][2] = nodes[25]; Division[3][3] = nodes[23]; Division[3][4] = nodes[19]; + Division[3][5] = nodes[4]; Division[3][6] = nodes[12]; Division[3][7] = nodes[14]; Division[3][8] = nodes[7]; + + } + + if (code == 3) { + // number of nodes at each new element + Division[0][0] = 9; Division[1][0] = 9; Division[2][0] = 9; Division[3][0] = 9; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[11]; Division[0][2] = nodes[0]; Division[0][3] = nodes[1]; Division[0][4] = nodes[9]; + Division[0][5] = nodes[24]; Division[0][6] = nodes[16]; Division[0][7] = nodes[17]; Division[0][8] = nodes[22]; + + Division[1][1] = nodes[3]; Division[1][2] = nodes[11]; Division[1][9] = nodes[2]; Division[1][4] = nodes[2]; + Division[1][5] = nodes[19]; Division[1][6] = nodes[24]; Division[1][7] = nodes[22]; Division[1][8] = nodes[18]; + + Division[2][1] = nodes[24]; Division[2][2] = nodes[16]; Division[2][3] = nodes[17]; Division[2][4] = nodes[22]; + Division[2][5] = nodes[15]; Division[2][6] = nodes[4]; Division[2][7] = nodes[5]; Division[2][8] = nodes[13]; + + Division[3][1] = nodes[19]; Division[3][2] = nodes[24]; Division[3][3] = nodes[22]; Division[3][4] = nodes[18]; + Division[3][5] = nodes[7]; Division[3][6] = nodes[15]; Division[3][7] = nodes[13]; Division[3][8] = nodes[6]; + + } + + if (code == 4) { + // number of nodes at each new element + Division[0][0] = 9; Division[1][0] = 9; Division[2][0] = 9; Division[3][0] = 9; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[20]; Division[0][2] = nodes[8]; Division[0][3] = nodes[1]; Division[0][4] = nodes[9]; + Division[0][5] = nodes[21]; Division[0][6] = nodes[12]; Division[0][7] = nodes[5]; Division[0][8] = nodes[13]; + + Division[1][1] = nodes[20]; Division[1][2] = nodes[9]; Division[1][3] = nodes[2]; Division[1][4] = nodes[10]; + Division[1][5] = nodes[21]; Division[1][6] = nodes[13]; Division[1][7] = nodes[6]; Division[1][8] = nodes[14]; + + Division[2][1] = nodes[20]; Division[2][2] = nodes[10]; Division[2][3] = nodes[0]; Division[2][4] = nodes[8]; + Division[2][5] = nodes[21]; Division[2][6] = nodes[15]; Division[2][7] = nodes[4]; Division[2][8] = nodes[12]; + + Division[3][1] = nodes[20]; Division[3][2] = nodes[10]; Division[3][3] = nodes[3]; Division[3][4] = nodes[11]; + Division[3][5] = nodes[21]; Division[3][6] = nodes[14]; Division[3][7] = nodes[7]; Division[3][8] = nodes[15]; + + } + + if (code == 5) { + // number of nodes at each new element + Division[0][0] = 9; Division[1][0] = 9; + *nPart = 2; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; Division[0][4] = nodes[3]; + Division[0][5] = nodes[16]; Division[0][6] = nodes[17]; Division[0][7] = nodes[18]; Division[0][8] = nodes[19]; + + Division[1][1] = nodes[16]; Division[1][2] = nodes[17]; Division[1][3] = nodes[18]; Division[1][4] = nodes[19]; + Division[1][5] = nodes[4]; Division[1][6] = nodes[5]; Division[1][7] = nodes[6]; Division[1][8] = nodes[7]; + + } + + if (code == 6) { + // number of nodes at each new element + Division[0][0] = 9; Division[1][0] = 9; + *nPart = 2; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[9]; Division[0][4] = nodes[11]; + Division[0][5] = nodes[4]; Division[0][6] = nodes[5]; Division[0][7] = nodes[13]; Division[0][8] = nodes[15]; + + Division[1][1] = nodes[9]; Division[1][2] = nodes[2]; Division[1][3] = nodes[3]; Division[1][4] = nodes[11]; + Division[1][5] = nodes[13]; Division[1][6] = nodes[6]; Division[1][7] = nodes[7]; Division[1][8] = nodes[15]; + + } + + if (code == 7) { + // number of nodes at each new element + Division[0][0] = 9; Division[1][0] = 9; + *nPart = 2; + + // nodes that compose each element + Division[0][1] = nodes[8]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; Division[0][4] = nodes[10]; + Division[0][5] = nodes[12]; Division[0][5] = nodes[5]; Division[0][7] = nodes[6]; Division[0][8] = nodes[14]; + + Division[1][1] = nodes[0]; Division[1][2] = nodes[8]; Division[1][3] = nodes[10]; Division[1][4] = nodes[3]; + Division[1][5] = nodes[4]; Division[1][6] = nodes[12]; Division[1][7] = nodes[14]; Division[1][8] = nodes[7]; + + } + +} + +void CGridAdaptation::PyramDivision(long code , long *nodes, long **Division, long *nPart) { + + if (code == 1) { + + // number of nodes at each new element + Division[0][0] = 6; + *nPart = 1; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; Division[0][4] = nodes[3]; Division[0][5] = nodes[4]; + + } + + if (code == 2) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; + *nPart = 3; + + // nodes that compose each element + Division[0][1] = nodes[5]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; Division[0][4] = nodes[4]; + + Division[1][1] = nodes[5]; Division[1][2] = nodes[2]; Division[1][3] = nodes[3]; Division[1][4] = nodes[4]; + + Division[2][1] = nodes[5]; Division[2][2] = nodes[3]; Division[2][3] = nodes[0]; Division[2][4] = nodes[4]; + + } + + if (code == 3) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; + *nPart = 3; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[6]; Division[0][4] = nodes[4]; + + Division[1][1] = nodes[0]; Division[1][2] = nodes[6]; Division[1][3] = nodes[3]; Division[1][4] = nodes[4]; + + Division[2][1] = nodes[3]; Division[2][2] = nodes[6]; Division[2][3] = nodes[2]; Division[2][4] = nodes[4]; + + } + + if (code == 4) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; + *nPart = 3; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[7]; Division[0][4] = nodes[4]; + + Division[1][1] = nodes[1]; Division[1][2] = nodes[2]; Division[1][3] = nodes[7]; Division[1][4] = nodes[4]; + + Division[2][1] = nodes[0]; Division[2][2] = nodes[7]; Division[2][3] = nodes[3]; Division[2][4] = nodes[4]; + + } + + if (code == 5) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; + *nPart = 3; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[8]; Division[0][4] = nodes[4]; + + Division[1][1] = nodes[1]; Division[1][2] = nodes[2]; Division[1][3] = nodes[8]; Division[1][4] = nodes[4]; + + Division[2][1] = nodes[8]; Division[2][2] = nodes[2]; Division[2][3] = nodes[3]; Division[2][4] = nodes[4]; + + } + + if (code == 6) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[5]; Division[0][3] = nodes[3]; Division[0][4] = nodes[4]; + + Division[1][1] = nodes[5]; Division[1][2] = nodes[1]; Division[1][3] = nodes[6]; Division[1][4] = nodes[4]; + + Division[2][1] = nodes[5]; Division[2][2] = nodes[6]; Division[2][3] = nodes[3]; Division[2][4] = nodes[4]; + + Division[3][1] = nodes[6]; Division[3][2] = nodes[2]; Division[3][3] = nodes[3]; Division[3][4] = nodes[4]; + + } + + if (code == 7) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[6]; Division[0][4] = nodes[4]; + + Division[1][1] = nodes[0]; Division[1][2] = nodes[6]; Division[1][3] = nodes[7]; Division[1][4] = nodes[4]; + + Division[2][1] = nodes[6]; Division[2][2] = nodes[2]; Division[2][3] = nodes[7]; Division[2][4] = nodes[4]; + + Division[3][1] = nodes[0]; Division[3][2] = nodes[7]; Division[3][3] = nodes[3]; Division[3][4] = nodes[4]; + + } + + if (code == 8) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[8]; Division[0][4] = nodes[4]; + + Division[1][1] = nodes[8]; Division[1][2] = nodes[1]; Division[1][3] = nodes[7]; Division[1][4] = nodes[4]; + + Division[2][1] = nodes[1]; Division[2][2] = nodes[2]; Division[2][3] = nodes[7]; Division[2][4] = nodes[4]; + + Division[3][1] = nodes[8]; Division[3][2] = nodes[7]; Division[3][3] = nodes[3]; Division[3][4] = nodes[4]; + + } + + if (code == 9) { + // number of nodes at each new element + Division[0][0] = 5; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[5]; Division[0][3] = nodes[8]; Division[0][4] = nodes[4]; + + Division[1][1] = nodes[5]; Division[1][2] = nodes[1]; Division[1][3] = nodes[2]; Division[1][4] = nodes[4]; + + Division[2][1] = nodes[8]; Division[2][2] = nodes[5]; Division[2][3] = nodes[2]; Division[2][4] = nodes[4]; + + Division[3][1] = nodes[8]; Division[3][2] = nodes[2]; Division[3][3] = nodes[3]; Division[3][4] = nodes[4]; + + } + + if (code == 10) { + // number of nodes at each new element + Division[0][0] = 6; Division[1][0] = 6; + *nPart = 2; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[5]; Division[0][3] = nodes[7]; Division[0][4] = nodes[3]; Division[0][5] = nodes[4]; + + Division[1][1] = nodes[5]; Division[1][2] = nodes[1]; Division[1][3] = nodes[2]; Division[1][4] = nodes[7]; Division[1][5] = nodes[4]; + + } + + if (code == 11) { + // number of nodes at each new element + Division[0][0] = 6; Division[1][0] = 6; + *nPart = 2; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[6]; Division[0][4] = nodes[8]; Division[0][5] = nodes[4]; + + Division[1][1] = nodes[8]; Division[1][2] = nodes[6]; Division[1][3] = nodes[2]; Division[1][4] = nodes[3]; Division[1][5] = nodes[4]; + + } + + if (code == 12) { + // number of nodes at each new element + Division[0][0] = 6; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[5]; Division[0][3] = nodes[7]; Division[0][4] = nodes[3]; Division[0][5] = nodes[4]; + + Division[1][1] = nodes[5]; Division[1][2] = nodes[1]; Division[1][3] = nodes[6]; Division[1][4] = nodes[4]; + + Division[2][1] = nodes[5]; Division[2][2] = nodes[6]; Division[2][3] = nodes[7]; Division[2][4] = nodes[4]; + + Division[3][1] = nodes[6]; Division[3][2] = nodes[2]; Division[3][3] = nodes[7]; Division[3][4] = nodes[4]; + + } + + if (code == 13) { + // number of nodes at each new element + Division[0][0] = 6; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[0]; Division[0][2] = nodes[1]; Division[0][3] = nodes[6]; Division[0][4] = nodes[8]; Division[0][5] = nodes[4]; + + Division[1][1] = nodes[6]; Division[1][2] = nodes[2]; Division[1][3] = nodes[7]; Division[1][4] = nodes[4]; + + Division[2][1] = nodes[8]; Division[2][2] = nodes[6]; Division[2][3] = nodes[7]; Division[2][4] = nodes[4]; + + Division[3][1] = nodes[8]; Division[3][2] = nodes[7]; Division[3][3] = nodes[3]; Division[3][4] = nodes[4]; + + } + + if (code == 14) { + // number of nodes at each new element + Division[0][0] = 6; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[5]; Division[0][2] = nodes[1]; Division[0][3] = nodes[2]; Division[0][4] = nodes[7]; Division[0][5] = nodes[4]; + + Division[1][1] = nodes[0]; Division[1][2] = nodes[5]; Division[1][3] = nodes[8]; Division[1][4] = nodes[4]; + + Division[2][1] = nodes[8]; Division[2][2] = nodes[5]; Division[2][3] = nodes[7]; Division[2][4] = nodes[4]; + + Division[3][1] = nodes[8]; Division[3][2] = nodes[7]; Division[3][3] = nodes[3]; Division[3][4] = nodes[4]; + + } + + if (code == 15) { + // number of nodes at each new element + Division[0][0] = 6; Division[1][0] = 5; Division[2][0] = 5; Division[3][0] = 5; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[8]; Division[0][2] = nodes[6]; Division[0][3] = nodes[2]; Division[0][4] = nodes[3]; Division[0][5] = nodes[4]; + + Division[1][1] = nodes[0]; Division[1][2] = nodes[5]; Division[1][3] = nodes[8]; Division[1][4] = nodes[4]; + + Division[2][1] = nodes[5]; Division[2][2] = nodes[1]; Division[2][3] = nodes[6]; Division[2][4] = nodes[4]; + + Division[3][1] = nodes[5]; Division[3][2] = nodes[6]; Division[3][3] = nodes[8]; Division[3][4] = nodes[4]; + + } + + if (code == 16) { + // number of nodes at each new element + Division[0][0] = 6; Division[1][0] = 6; Division[2][0] = 6; Division[3][0] = 6; + *nPart = 4; + + // nodes that compose each element + Division[0][1] = nodes[9]; Division[0][2] = nodes[8]; Division[0][3] = nodes[0]; Division[0][4] = nodes[5]; Division[0][5] = nodes[4]; + + Division[1][1] = nodes[9]; Division[1][2] = nodes[5]; Division[1][3] = nodes[1]; Division[1][4] = nodes[6]; Division[1][5] = nodes[4]; + + Division[2][1] = nodes[9]; Division[2][2] = nodes[6]; Division[2][3] = nodes[2]; Division[2][4] = nodes[7]; Division[2][5] = nodes[4]; + + Division[3][1] = nodes[9]; Division[3][2] = nodes[7]; Division[3][3] = nodes[3]; Division[3][4] = nodes[8]; Division[3][5] = nodes[4]; + + } + +} + +void CGridAdaptation::SetHomothetic_Adaptation2D(CGeometry *geometry, CPhysicalGeometry *geo_adapt, + CConfig *config) { + + unsigned long iPoint, iElem, iEdge, ip_0, ip_1, ip_2, ip_3, iVertex; + unsigned short iDim, iMarker, iVar; + long no_0 = 0, no_1 = 0, no_2 = 0, no_3 = 0; + unsigned short nMarker_Max = config->GetnMarker_Max(); + + long *TriangleAdaptCode; + long **TriangleEdgeIndex; bool **TriangleEdgeCode; long **TriangleEdgeNode; + + long *RectAdaptCode; + long **RectEdgeIndex; bool **RectEdgeCode; long **RectEdgeNode; + long **RectElemIndex; bool **RectElemCode; long **RectElemNode; + + bool Restart_Flow = false; + bool Restart_Adjoint = false; + + if ((config->GetKind_Adaptation() == FULL_FLOW) || + (config->GetKind_Adaptation() == GRAD_FLOW) || + (config->GetKind_Adaptation() == FULL_ADJOINT) || + (config->GetKind_Adaptation() == GRAD_ADJOINT) || + (config->GetKind_Adaptation() == GRAD_FLOW_ADJ) || + (config->GetKind_Adaptation() == REMAINING) || + (config->GetKind_Adaptation() == COMPUTABLE)) Restart_Flow = true; + + if ((config->GetKind_Adaptation() == FULL_ADJOINT) || + (config->GetKind_Adaptation() == GRAD_ADJOINT) || + (config->GetKind_Adaptation() == GRAD_FLOW_ADJ) || + (config->GetKind_Adaptation() == REMAINING) || + (config->GetKind_Adaptation() == COMPUTABLE)) Restart_Adjoint = true; + + TriangleAdaptCode = new long[geometry->GetnElem()]; + TriangleEdgeIndex = new long*[geometry->GetnElem()]; + TriangleEdgeCode = new bool*[geometry->GetnElem()]; + TriangleEdgeNode = new long*[geometry->GetnElem()]; + + RectAdaptCode = new long[geometry->GetnElem()]; + RectEdgeIndex = new long*[geometry->GetnElem()]; + RectEdgeCode = new bool*[geometry->GetnElem()]; + RectEdgeNode = new long*[geometry->GetnElem()]; + RectElemIndex = new long*[geometry->GetnElem()]; + RectElemCode = new bool*[geometry->GetnElem()]; + RectElemNode = new long*[geometry->GetnElem()]; + + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + TriangleEdgeIndex[iElem] = new long [3]; + TriangleEdgeCode[iElem] = new bool [3]; + TriangleEdgeNode[iElem] = new long [3]; + + RectEdgeIndex[iElem] = new long [4]; + RectEdgeCode[iElem] = new bool [4]; + RectEdgeNode[iElem] = new long [4]; + RectElemIndex[iElem] = new long [1]; + RectElemCode[iElem] = new bool [1]; + RectElemNode[iElem] = new long [1]; + } + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { + ip_0 = geometry->elem[iElem]->GetNode(0); + ip_1 = geometry->elem[iElem]->GetNode(1); + ip_2 = geometry->elem[iElem]->GetNode(2); + + TriangleEdgeIndex[iElem][0] = geometry->FindEdge(ip_0, ip_1); TriangleEdgeCode[iElem][0] = false; TriangleEdgeNode[iElem][0] = -1; + TriangleEdgeIndex[iElem][1] = geometry->FindEdge(ip_1, ip_2); TriangleEdgeCode[iElem][1] = false; TriangleEdgeNode[iElem][1] = -1; + TriangleEdgeIndex[iElem][2] = geometry->FindEdge(ip_2, ip_0); TriangleEdgeCode[iElem][2] = false; TriangleEdgeNode[iElem][2] = -1; + } + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { + ip_0 = geometry->elem[iElem]->GetNode(0); + ip_1 = geometry->elem[iElem]->GetNode(1); + ip_2 = geometry->elem[iElem]->GetNode(2); + ip_3 = geometry->elem[iElem]->GetNode(3); + + RectEdgeIndex[iElem][0] = geometry->FindEdge(ip_0, ip_1); RectEdgeCode[iElem][0] = false; RectEdgeNode[iElem][0] = -1; + RectEdgeIndex[iElem][1] = geometry->FindEdge(ip_1, ip_2); RectEdgeCode[iElem][1] = false; RectEdgeNode[iElem][1] = -1; + RectEdgeIndex[iElem][2] = geometry->FindEdge(ip_2, ip_3); RectEdgeCode[iElem][2] = false; RectEdgeNode[iElem][2] = -1; + RectEdgeIndex[iElem][3] = geometry->FindEdge(ip_3, ip_0); RectEdgeCode[iElem][3] = false; RectEdgeNode[iElem][3] = -1; + + RectElemIndex[iElem][0] = iElem; RectElemCode[iElem][0] = false; RectElemNode[iElem][0] = -1; + } + + } + + /*--- Initial edges that are going to be divided ---*/ + + bool *DivEdge = new bool[geometry->GetnEdge()]; + bool *DivElem = new bool[geometry->GetnElem()]; + + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) DivEdge[iEdge] = false; + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) + DivElem[iElem] = geometry->elem[iElem]->GetDivide(); + + /*--- Set the edge division in the reactangles and in the edge list. ---*/ + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + if (DivElem[iElem] == true) { + if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { + for (int iIndex = 0; iIndex < 3; iIndex++) { + DivEdge[TriangleEdgeIndex[iElem][iIndex]] = true; + TriangleEdgeCode[iElem][iIndex] = true; + } + } + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { + for (int iIndex = 0; iIndex < 4; iIndex++) { + DivEdge[RectEdgeIndex[iElem][iIndex]] = true; + RectEdgeCode[iElem][iIndex] = true; + } + } + } + } + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) + for (unsigned long iBoundElem = 0; iBoundElem < geometry->GetnElem_Bound(iMarker); iBoundElem++) { + + ip_0 = geometry->bound[iMarker][iBoundElem]->GetNode(0); + ip_1 = geometry->bound[iMarker][iBoundElem]->GetNode(1); + + long edge = geometry->FindEdge(ip_0, ip_1); + + if (DivEdge[edge]) { + + unsigned long iv_1 = geometry->node[ip_1]->GetVertex(iMarker); + unsigned long ip_1_Nearfield = geometry->vertex[iMarker][iv_1]->GetDonorPoint(); + unsigned long iv_0 = geometry->node[ip_0]->GetVertex(iMarker); + unsigned long ip_0_Nearfield = geometry->vertex[iMarker][iv_0]->GetDonorPoint(); + + long edge_Nearfield = geometry->FindEdge(ip_0_Nearfield, ip_1_Nearfield); + + DivEdge[edge_Nearfield] = true; + + } + + } + + /*--- We must verify that all the elements have the right edges marked ---*/ + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { + for (int iIndex = 0; iIndex < 3; iIndex++) { + if (DivEdge[TriangleEdgeIndex[iElem][iIndex]] == true) { + TriangleEdgeCode[iElem][iIndex] = true; + } + } + } + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { + for (int iIndex = 0; iIndex < 4; iIndex++) { + if (DivEdge[RectEdgeIndex[iElem][iIndex]] == true) { + RectEdgeCode[iElem][iIndex] = true; + } + } + } + } + + /*--- Only those elements that verify certain rules will be marked for hexa adaptation... + the others will need a new point in the middle and RectExts ---*/ + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { + TriangleAdaptCode[iElem] = CheckTriangleCode(TriangleEdgeCode[iElem]); + } + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { + RectAdaptCode[iElem] = CheckRectCode(RectEdgeCode[iElem]); + + /*--- Set the RectAdaptCode ---*/ + + if (RectAdaptCode[iElem] == 1) { + RectElemCode[iElem][0] = true; + } + } + } + + /*--- Create the new nodes on the edges, on the faces, and in the element. ---*/ + + long *NodeAtEdges = new long[geometry->GetnEdge()]; + long *NodeAtElem = new long[geometry->GetnElem()]; + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) NodeAtEdges[iEdge] = -1; + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) NodeAtElem[iElem] = -1; + + nPoint_new = geometry->GetnPoint(); + + su2double **NewNodeCoord; + NewNodeCoord = new su2double *[4*geometry->GetnPoint()]; + for (iPoint = 0; iPoint < 4*geometry->GetnPoint(); iPoint++) + NewNodeCoord[iPoint] = new su2double[geometry->GetnDim()]; + + if (Restart_Flow) { + ConsVar_Adapt = new su2double *[4*geometry->GetnPoint()]; + for (iPoint = 0; iPoint < 4*geometry->GetnPoint(); iPoint++) + ConsVar_Adapt[iPoint] = new su2double[nVar]; + } + + if (Restart_Adjoint) { + AdjVar_Adapt = new su2double *[4*geometry->GetnPoint()]; + for (iPoint = 0; iPoint < 4*geometry->GetnPoint(); iPoint++) + AdjVar_Adapt[iPoint] = new su2double[nVar]; + } + + /*--- Set the value of the variables ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { + for (iVar = 0; iVar < nVar; iVar ++) { + if (Restart_Flow) ConsVar_Adapt[iPoint][iVar] = ConsVar_Sol[iPoint][iVar]; + if (Restart_Adjoint) AdjVar_Adapt[iPoint][iVar] = AdjVar_Sol[iPoint][iVar]; + } + } + + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { + + ip_0 = geometry->elem[iElem]->GetNode(0); + ip_1 = geometry->elem[iElem]->GetNode(1); + ip_2 = geometry->elem[iElem]->GetNode(2); + + for (int iIndex = 0; iIndex < 3; iIndex++) { + + if (TriangleEdgeCode[iElem][iIndex] == true) { + if (NodeAtEdges[TriangleEdgeIndex[iElem][iIndex]] != -1) + TriangleEdgeNode[iElem][iIndex] = NodeAtEdges[TriangleEdgeIndex[iElem][iIndex]]; + + if (NodeAtEdges[TriangleEdgeIndex[iElem][iIndex]] == -1) { + + NodeAtEdges[TriangleEdgeIndex[iElem][iIndex]] = nPoint_new; + TriangleEdgeNode[iElem][iIndex] = nPoint_new; + + /*--- Compute the coordinates of the new node ---*/ + + if (iIndex == 0) {no_0 = ip_0; no_1 = ip_1;} + if (iIndex == 1) {no_0 = ip_1; no_1 = ip_2;} + if (iIndex == 2) {no_0 = ip_2; no_1 = ip_0;} + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) + NewNodeCoord[nPoint_new][iDim] = 0.5*(geometry->node[no_0]->GetCoord(iDim)+geometry->node[no_1]->GetCoord(iDim)); + + for (iVar = 0; iVar < nVar; iVar ++) { + if (Restart_Flow) ConsVar_Adapt[nPoint_new][iVar] = 0.5 * (ConsVar_Adapt[no_0][iVar]+ConsVar_Adapt[no_1][iVar]); + if (Restart_Adjoint) AdjVar_Adapt[nPoint_new][iVar] = 0.5 * (AdjVar_Adapt[no_0][iVar]+AdjVar_Adapt[no_1][iVar]); + } + + nPoint_new++; + } + } + } + } + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { + + ip_0 = geometry->elem[iElem]->GetNode(0); + ip_1 = geometry->elem[iElem]->GetNode(1); + ip_2 = geometry->elem[iElem]->GetNode(2); + ip_3 = geometry->elem[iElem]->GetNode(3); + + for (int iIndex = 0; iIndex < 4; iIndex++) { + + if (RectEdgeCode[iElem][iIndex] == true) { + if (NodeAtEdges[RectEdgeIndex[iElem][iIndex]] != -1) + RectEdgeNode[iElem][iIndex] = NodeAtEdges[RectEdgeIndex[iElem][iIndex]]; + + if (NodeAtEdges[RectEdgeIndex[iElem][iIndex]] == -1) { + + NodeAtEdges[RectEdgeIndex[iElem][iIndex]] = nPoint_new; + RectEdgeNode[iElem][iIndex] = nPoint_new; + + /*--- Compute the coordinates of the new node ---*/ + + if (iIndex == 0) {no_0 = ip_0; no_1 = ip_1;} + if (iIndex == 1) {no_0 = ip_1; no_1 = ip_2;} + if (iIndex == 2) {no_0 = ip_2; no_1 = ip_3;} + if (iIndex == 3) {no_0 = ip_3; no_1 = ip_0;} + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) + NewNodeCoord[nPoint_new][iDim] = 0.5*(geometry->node[no_0]->GetCoord(iDim)+geometry->node[no_1]->GetCoord(iDim)); + + for (iVar = 0; iVar < nVar; iVar ++) { + if (Restart_Flow) ConsVar_Adapt[nPoint_new][iVar] = 0.5 * (ConsVar_Adapt[no_0][iVar]+ConsVar_Adapt[no_1][iVar]); + if (Restart_Adjoint) AdjVar_Adapt[nPoint_new][iVar] = 0.5 * (AdjVar_Adapt[no_0][iVar]+AdjVar_Adapt[no_1][iVar]); + } + + nPoint_new++; + } + } + } + + for (int iIndex = 0; iIndex < 1; iIndex++) { + + if (RectElemCode[iElem][iIndex] == true) { + + if (NodeAtElem[RectElemIndex[iElem][iIndex]] != -1) + RectElemNode[iElem][iIndex] = NodeAtElem[RectElemIndex[iElem][iIndex]]; + + if (NodeAtElem[RectElemIndex[iElem][iIndex]] == -1) { + NodeAtElem[RectElemIndex[iElem][iIndex]] = nPoint_new; + RectElemNode[iElem][iIndex] = nPoint_new; + + /*--- Compute the coordinates of the new node ---*/ + + if (iIndex == 0) {no_0 = ip_0; no_1 = ip_1; no_2 = ip_2; no_3 = ip_3;} + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) + NewNodeCoord[nPoint_new][iDim] = 0.25*(geometry->node[no_0]->GetCoord(iDim) + + geometry->node[no_1]->GetCoord(iDim) + + geometry->node[no_2]->GetCoord(iDim) + + geometry->node[no_3]->GetCoord(iDim)); + + for (iVar = 0; iVar < nVar; iVar ++) { + if (Restart_Flow) ConsVar_Adapt[nPoint_new][iVar] = 0.25 * (ConsVar_Adapt[no_0][iVar]+ConsVar_Adapt[no_1][iVar]+ConsVar_Adapt[no_2][iVar]+ConsVar_Adapt[no_3][iVar]); + if (Restart_Adjoint) AdjVar_Adapt[nPoint_new][iVar] = 0.25 * (AdjVar_Adapt[no_0][iVar]+AdjVar_Adapt[no_1][iVar]+AdjVar_Adapt[no_2][iVar]+AdjVar_Adapt[no_3][iVar]); + } + + nPoint_new++; + } + } + } + } + + } + + + /*--- if Quadrilateral adapt code equals 0, then a semidivision is applied ---*/ + long nSemiDivided = 0; + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { + if (RectAdaptCode[iElem] == 0) + nSemiDivided++; + } + } + + /*--- If semidivision, then divide add a new point, divide the quadrilateral into triangles, + and find the right combination, it also create the new node (hexa). ---*/ + long nRectExt = nSemiDivided; + + long *RectExtAdaptCode; + long **RectExtNode; + long **RectRectExtIndex; + long *RectExtRectIndex; + + long **RectExtEdgeIndex; + bool **RectExtEdgeCode; + long **RectExtEdgeNode; + + RectExtAdaptCode = new long [nRectExt]; + RectExtNode = new long *[nRectExt]; + RectRectExtIndex = new long *[geometry->GetnElem()]; + RectExtRectIndex = new long [nRectExt]; + RectExtEdgeIndex = new long *[nRectExt]; + RectExtEdgeCode = new bool *[nRectExt]; + RectExtEdgeNode = new long *[nRectExt]; + + for (long iRectExt = 0; iRectExt < nRectExt; iRectExt++) { + RectExtNode[iRectExt] = new long [4]; + RectExtEdgeIndex[iRectExt] = new long [4]; + RectExtEdgeCode[iRectExt] = new bool [4]; + RectExtEdgeNode[iRectExt] = new long [4]; + } + + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { + RectRectExtIndex[iElem] = new long [1]; + } + } + + nRectExt = 0; + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { + if (RectAdaptCode[iElem] == 0) { + + /*--- Write the edge combination on the base. ---*/ + + ip_0 = geometry->elem[iElem]->GetNode(0); + ip_1 = geometry->elem[iElem]->GetNode(1); + ip_2 = geometry->elem[iElem]->GetNode(2); + ip_3 = geometry->elem[iElem]->GetNode(3); + + /*--- Create the 1st RectExtid. ---*/ + + RectRectExtIndex[iElem][0] = nRectExt; RectExtRectIndex[nRectExt] = iElem; + + RectExtNode[nRectExt][0] = ip_0; RectExtNode[nRectExt][1] = ip_1; + RectExtNode[nRectExt][2] = ip_2; RectExtNode[nRectExt][3] = ip_3; + + RectExtEdgeIndex[nRectExt][0] = RectEdgeIndex[iElem][0]; RectExtEdgeIndex[nRectExt][1] = RectEdgeIndex[iElem][1]; + RectExtEdgeIndex[nRectExt][2] = RectEdgeIndex[iElem][2]; RectExtEdgeIndex[nRectExt][3] = RectEdgeIndex[iElem][3]; + + RectExtEdgeNode[nRectExt][0] = RectEdgeNode[iElem][0]; RectExtEdgeNode[nRectExt][1] = RectEdgeNode[iElem][1]; + RectExtEdgeNode[nRectExt][2] = RectEdgeNode[iElem][2]; RectExtEdgeNode[nRectExt][3] = RectEdgeNode[iElem][3]; + + + for (int iIndex = 0; iIndex < 4; iIndex++) + if (DivEdge[RectExtEdgeIndex[nRectExt][iIndex]] == true) RectExtEdgeCode[nRectExt][iIndex] = true; + nRectExt++; + + } + } + } + + /*--- Check the kind of RectExt partitioning that should be applied ---*/ + + for (int iRectExt = 0; iRectExt < nRectExt; iRectExt ++) { + RectExtAdaptCode[iRectExt] = CheckRectExtCode(RectExtEdgeCode[iRectExt]); + if (RectExtAdaptCode[iRectExt] == 0) cout << "There is a problem with one RectExt" << endl; + } + + /*--- Create new structure ---*/ + + nElem_new = geometry->GetnElem(); + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { + if (TriangleAdaptCode[iElem] == 1) nElem_new = nElem_new + 3; + if (TriangleAdaptCode[iElem] == 2) nElem_new = nElem_new + 1; + if (TriangleAdaptCode[iElem] == 3) nElem_new = nElem_new + 1; + if (TriangleAdaptCode[iElem] == 4) nElem_new = nElem_new + 1; + if (TriangleAdaptCode[iElem] == 5) nElem_new = nElem_new + 1; + if (TriangleAdaptCode[iElem] == 6) nElem_new = nElem_new + 1; + if (TriangleAdaptCode[iElem] == 7) nElem_new = nElem_new + 1; + } + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { + if (RectAdaptCode[iElem] == 1) nElem_new = nElem_new + 3; + if (RectAdaptCode[iElem] == 2) nElem_new = nElem_new + 1; + if (RectAdaptCode[iElem] == 3) nElem_new = nElem_new + 1; + if (RectAdaptCode[iElem] == 0) { + long iRectExt = RectRectExtIndex[iElem][0]; + if (RectExtAdaptCode[iRectExt] == 2) nElem_new = nElem_new + 2; + if (RectExtAdaptCode[iRectExt] == 3) nElem_new = nElem_new + 2; + if (RectExtAdaptCode[iRectExt] == 4) nElem_new = nElem_new + 2; + if (RectExtAdaptCode[iRectExt] == 5) nElem_new = nElem_new + 2; + if (RectExtAdaptCode[iRectExt] == 6) nElem_new = nElem_new + 3; + if (RectExtAdaptCode[iRectExt] == 7) nElem_new = nElem_new + 3; + if (RectExtAdaptCode[iRectExt] == 8) nElem_new = nElem_new + 3; + if (RectExtAdaptCode[iRectExt] == 9) nElem_new = nElem_new + 3; + if (RectExtAdaptCode[iRectExt] == 12) nElem_new = nElem_new + 3; + if (RectExtAdaptCode[iRectExt] == 13) nElem_new = nElem_new + 3; + if (RectExtAdaptCode[iRectExt] == 14) nElem_new = nElem_new + 3; + if (RectExtAdaptCode[iRectExt] == 15) nElem_new = nElem_new + 3; + } + } + } + + /*--- New points ---*/ + + geo_adapt->node = new CPoint*[nPoint_new]; + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) + geo_adapt->node[iPoint] = new CPoint(geometry->node[iPoint]->GetCoord(0), geometry->node[iPoint]->GetCoord(1), iPoint, config); + + for (iPoint = geometry->GetnPoint(); iPoint < nPoint_new; iPoint++) + geo_adapt->node[iPoint] = new CPoint(NewNodeCoord[iPoint][0], NewNodeCoord[iPoint][1], iPoint, config); + + /*--- New elements ---*/ + + geo_adapt->elem = new CPrimalGrid*[nElem_new]; + + unsigned long iElemNew = 0; + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { + if (TriangleAdaptCode[iElem] == -1) { + geo_adapt->elem[iElemNew] = new CTriangle(geometry->elem[iElem]->GetNode(0), + geometry->elem[iElem]->GetNode(1), + geometry->elem[iElem]->GetNode(2), 2); + iElemNew++; + } + } + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { + if (RectAdaptCode[iElem] == -1) { + geo_adapt->elem[iElemNew] = new CQuadrilateral(geometry->elem[iElem]->GetNode(0), + geometry->elem[iElem]->GetNode(1), + geometry->elem[iElem]->GetNode(2), + geometry->elem[iElem]->GetNode(3), 2); + iElemNew++; + } + } + } + + long nodes[27]; long **Division; long nPart; + + Division = new long*[100]; + for (long iVar = 0; iVar < 100; iVar++) + Division[iVar] = new long[100]; + + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { + + /*--- Triangle elements... ---*/ + + if (TriangleAdaptCode[iElem] > 0) { + + /*--- First the corners ---*/ + + nodes[0] = geometry->elem[iElem]->GetNode(0); + nodes[1] = geometry->elem[iElem]->GetNode(1); + nodes[2] = geometry->elem[iElem]->GetNode(2); + + /*--- Next the points that correspond to the broken edges. ---*/ + + nodes[3] = TriangleEdgeNode[iElem][0]; + nodes[4] = TriangleEdgeNode[iElem][1]; + nodes[5] = TriangleEdgeNode[iElem][2]; + + TriangleDivision(TriangleAdaptCode[iElem], nodes, NULL, Division, &nPart); + for (long iPart = 0; iPart < nPart; iPart++) { + + /*--- Triangle case ---*/ + + if (Division[iPart][0] == 4) { + geo_adapt->elem[iElemNew] = new CTriangle(Division[iPart][1], + Division[iPart][2], + Division[iPart][3], 2); + iElemNew++; + } + + /*--- Quadrilateral case ---*/ + + if (Division[iPart][0] == 5) { + geo_adapt->elem[iElemNew] = new CQuadrilateral(Division[iPart][1], + Division[iPart][2], + Division[iPart][3], + Division[iPart][4], 2); + iElemNew++; + } + } + } + } + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { + + /*--- Rect elements... ---*/ + + if (RectAdaptCode[iElem] > 0) { + + /*--- First the corners ---*/ + + nodes[0] = geometry->elem[iElem]->GetNode(0); nodes[1] = geometry->elem[iElem]->GetNode(1); + nodes[2] = geometry->elem[iElem]->GetNode(2); nodes[3] = geometry->elem[iElem]->GetNode(3); + + /*--- Next the points that correspond to the broken edges. ---*/ + + nodes[4] = RectEdgeNode[iElem][0]; nodes[5] = RectEdgeNode[iElem][1]; + nodes[6] = RectEdgeNode[iElem][2]; nodes[7] = RectEdgeNode[iElem][3]; + + /*--- Next the points that correspond to the element. ---*/ + + nodes[8] = RectElemNode[iElem][0]; + + RectDivision(RectAdaptCode[iElem], nodes, Division, &nPart); + for (long iPart = 0; iPart < nPart; iPart++) { + geo_adapt->elem[iElemNew] = new CQuadrilateral(Division[iPart][1], + Division[iPart][2], + Division[iPart][3], + Division[iPart][4], 2); + iElemNew++; + } + } + + /*--- RectExt elements... ---*/ + + if (RectAdaptCode[iElem] == 0) { + long iRectExt = RectRectExtIndex[iElem][0]; + + /*--- First the corners ---*/ + + nodes[0] = RectExtNode[iRectExt][0]; + nodes[1] = RectExtNode[iRectExt][1]; + nodes[2] = RectExtNode[iRectExt][2]; + nodes[3] = RectExtNode[iRectExt][3]; + + /*--- Next the points that correspond to the broken edges. ---*/ + + nodes[4] = RectExtEdgeNode[iRectExt][0]; + nodes[5] = RectExtEdgeNode[iRectExt][1]; + nodes[6] = RectExtEdgeNode[iRectExt][2]; + nodes[7] = RectExtEdgeNode[iRectExt][3]; + + RectExtDivision(RectExtAdaptCode[iRectExt], nodes, Division, &nPart); + for (long iPart = 0; iPart < nPart; iPart++) { + + /*--- Triangle case ---*/ + + if (Division[iPart][0] == 4) { + geo_adapt->elem[iElemNew] = new CTriangle(Division[iPart][1], + Division[iPart][2], + Division[iPart][3], 2); + iElemNew++; + } + + /*--- Quadrilateral case ---*/ + + if (Division[iPart][0] == 5) { + geo_adapt->elem[iElemNew] = new CQuadrilateral(Division[iPart][1], + Division[iPart][2], + Division[iPart][3], + Division[iPart][4], 2); + iElemNew++; + } + } + } + } + } + + geo_adapt->SetnElem(nElem_new); + geo_adapt->SetnPoint(nPoint_new); + geo_adapt->SetnPointDomain(nPoint_new); + geo_adapt->SetnDim(nDim); + + /*--- Create boundary structure ---*/ + + geo_adapt->SetnMarker(geometry->GetnMarker()); + geo_adapt->nElem_Bound = new unsigned long [geometry->GetnMarker()]; + geo_adapt->Tag_to_Marker = new string [nMarker_Max]; + geo_adapt->bound = new CPrimalGrid**[geometry->GetnMarker()]; + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + long nNewBCcv = 0; + for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { + ip_0 = geometry->bound[iMarker][iVertex]->GetNode(0); + ip_1 = geometry->bound[iMarker][iVertex]->GetNode(1); + if (DivEdge[geometry->FindEdge(ip_0, ip_1)]) nNewBCcv = nNewBCcv + 2; + else nNewBCcv = nNewBCcv + 1; + } + geo_adapt->bound[iMarker] = new CPrimalGrid* [nNewBCcv]; + geo_adapt->SetnElem_Bound(iMarker, nNewBCcv); + geo_adapt->SetMarker_Tag(iMarker, geometry->GetMarker_Tag(iMarker)); + } + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + long nNewBCcv = 0; + for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { + + ip_0 = geometry->bound[iMarker][iVertex]->GetNode(0); geo_adapt->node[ip_0]->SetBoundary(geometry->GetnMarker()); + ip_1 = geometry->bound[iMarker][iVertex]->GetNode(1); geo_adapt->node[ip_1]->SetBoundary(geometry->GetnMarker()); + long ip_01 = NodeAtEdges[geometry->FindEdge(ip_0, ip_1)]; + + if (ip_01 != -1) { + + +// if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || +// (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) || +// (config->GetMarker_All_KindBC(iMarker) == EULER_WALL)) { +// +// /*--- Recompute the coordinates using the NACA 4Digits analytical definition ---*/ +// +// su2double Ya = 0.0 / 100.0; /*--- Maximum camber as a fraction of the chord +// (100 m is the first of the four digits) ---*/ +// su2double Xa = 0.0 / 10.0; /*--- Location of maximum camber as a fraction of +// the chord (10 p is the second digit in the NACA xxxx description) ---*/ +// su2double t = 12.0 / 100.0; /*--- Maximum thickness as a fraction of the +// chord (so 100 t gives the last two digits in +// the NACA 4-digit denomination) ---*/ +// +// su2double *Coord = geo_adapt->node[ip_01]->GetCoord(); +// su2double *Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); +// +// su2double Ycurv = 0.0; +// if (Coord[0] < Xa) Ycurv = (2.0*Xa*Coord[0]-pow(Coord[0],2.0))*(Ya/pow(Xa,2.0)); +// else Ycurv = ((1.0-2.0*Xa)+2.0*Xa*Coord[0]-pow(Coord[0],2.0))*(Ya/pow((1.0-Xa), 2.0)); +// +// su2double Yesp = 0.0; +// Yesp = t*(1.4845*sqrt(Coord[0])-0.6300*Coord[0]-1.7580*pow(Coord[0],2.0)+ +// 1.4215*pow(Coord[0],3.0)-0.518*pow(Coord[0],4.0)); +// +// if (Normal[1] > 0) Coord[1] = (Ycurv + Yesp); +// if (Normal[1] < 0) Coord[1] = (Ycurv - Yesp); +// +// } + + geo_adapt->node[ip_01]->SetBoundary(geometry->GetnMarker()); + geo_adapt->bound[iMarker][nNewBCcv] = new CLine(ip_0, ip_01, 2); + nNewBCcv++; + geo_adapt->bound[iMarker][nNewBCcv] = new CLine(ip_01, ip_1, 2); + nNewBCcv++; + } + else { + geo_adapt->bound[iMarker][nNewBCcv] = new CLine(ip_0, ip_1, 2); + nNewBCcv++; + } + } + } + + delete [] DivEdge; + delete [] DivElem; + delete [] NodeAtEdges; + delete [] NodeAtElem; + +} + +void CGridAdaptation::SetHomothetic_Adaptation3D(CGeometry *geometry, CPhysicalGeometry *geo_adapt, + CConfig *config) { + + unsigned long iPoint, iElem, iEdge, ip_0, ip_1, ip_2, ip_3, ip_4, ip_5, ip_6, ip_7, iVertex; + unsigned short iDim, iMarker, iVar; + long no_0 = 0, no_1 = 0, no_2 = 0, no_3 = 0, no_4 = 0, no_5 = 0, no_6 = 0, no_7 = 0; + unsigned short counter; + unsigned short nMarker_Max = config->GetnMarker_Max(); + + long *TetraAdaptCode; + long **TetraEdgeIndex; bool **TetraEdgeCode; long **TetraEdgeNode; + + long *HexaAdaptCode; + long **HexaEdgeIndex; bool **HexaEdgeCode; long **HexaEdgeNode; + long **HexaFaceIndex; bool **HexaFaceCode; long **HexaFaceNode; + long **HexaElemIndex; bool **HexaElemCode; long **HexaElemNode; + + bool Restart_Flow = false; + bool Restart_Adjoint = false; + + if ((config->GetKind_Adaptation() == FULL_FLOW) || + (config->GetKind_Adaptation() == GRAD_FLOW) || + (config->GetKind_Adaptation() == FULL_ADJOINT) || + (config->GetKind_Adaptation() == GRAD_ADJOINT) || + (config->GetKind_Adaptation() == GRAD_FLOW_ADJ) || + (config->GetKind_Adaptation() == REMAINING) || + (config->GetKind_Adaptation() == COMPUTABLE)) Restart_Flow = true; + + if ((config->GetKind_Adaptation() == FULL_ADJOINT) || + (config->GetKind_Adaptation() == GRAD_ADJOINT) || + (config->GetKind_Adaptation() == GRAD_FLOW_ADJ) || + (config->GetKind_Adaptation() == REMAINING) || + (config->GetKind_Adaptation() == COMPUTABLE)) Restart_Adjoint = true; + + TetraAdaptCode = new long[geometry->GetnElem()]; + TetraEdgeIndex = new long*[geometry->GetnElem()]; + TetraEdgeCode = new bool*[geometry->GetnElem()]; + TetraEdgeNode = new long*[geometry->GetnElem()]; + + HexaAdaptCode = new long[geometry->GetnElem()]; + HexaEdgeIndex = new long*[geometry->GetnElem()]; + HexaEdgeCode = new bool*[geometry->GetnElem()]; + HexaEdgeNode = new long*[geometry->GetnElem()]; + HexaFaceIndex = new long*[geometry->GetnElem()]; + HexaFaceCode = new bool*[geometry->GetnElem()]; + HexaFaceNode = new long*[geometry->GetnElem()]; + HexaElemIndex = new long*[geometry->GetnElem()]; + HexaElemCode = new bool*[geometry->GetnElem()]; + HexaElemNode = new long*[geometry->GetnElem()]; + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + TetraEdgeIndex[iElem] = new long [6]; + TetraEdgeCode[iElem] = new bool [6]; + TetraEdgeNode[iElem] = new long [6]; + + HexaEdgeIndex[iElem] = new long [12]; + HexaEdgeCode[iElem] = new bool [12]; + HexaEdgeNode[iElem] = new long [12]; + HexaFaceIndex[iElem] = new long [6]; + HexaFaceCode[iElem] = new bool [6]; + HexaFaceNode[iElem] = new long [6]; + HexaElemIndex[iElem] = new long [1]; + HexaElemCode[iElem] = new bool [1]; + HexaElemNode[iElem] = new long [1]; + } + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { + ip_0 = geometry->elem[iElem]->GetNode(0); + ip_1 = geometry->elem[iElem]->GetNode(1); + ip_2 = geometry->elem[iElem]->GetNode(2); + ip_3 = geometry->elem[iElem]->GetNode(3); + + TetraEdgeIndex[iElem][0] = geometry->FindEdge(ip_0, ip_1); TetraEdgeCode[iElem][0] = false; TetraEdgeNode[iElem][0] = -1; + TetraEdgeIndex[iElem][1] = geometry->FindEdge(ip_0, ip_2); TetraEdgeCode[iElem][1] = false; TetraEdgeNode[iElem][1] = -1; + TetraEdgeIndex[iElem][2] = geometry->FindEdge(ip_0, ip_3); TetraEdgeCode[iElem][2] = false; TetraEdgeNode[iElem][2] = -1; + TetraEdgeIndex[iElem][3] = geometry->FindEdge(ip_1, ip_2); TetraEdgeCode[iElem][3] = false; TetraEdgeNode[iElem][3] = -1; + TetraEdgeIndex[iElem][4] = geometry->FindEdge(ip_1, ip_3); TetraEdgeCode[iElem][4] = false; TetraEdgeNode[iElem][4] = -1; + TetraEdgeIndex[iElem][5] = geometry->FindEdge(ip_2, ip_3); TetraEdgeCode[iElem][5] = false; TetraEdgeNode[iElem][5] = -1; + + } + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { + ip_0 = geometry->elem[iElem]->GetNode(0); + ip_1 = geometry->elem[iElem]->GetNode(1); + ip_2 = geometry->elem[iElem]->GetNode(2); + ip_3 = geometry->elem[iElem]->GetNode(3); + ip_4 = geometry->elem[iElem]->GetNode(4); + ip_5 = geometry->elem[iElem]->GetNode(5); + ip_6 = geometry->elem[iElem]->GetNode(6); + ip_7 = geometry->elem[iElem]->GetNode(7); + + HexaEdgeIndex[iElem][0] = geometry->FindEdge(ip_0, ip_1); HexaEdgeCode[iElem][0] = false; HexaEdgeNode[iElem][0] = -1; + HexaEdgeIndex[iElem][1] = geometry->FindEdge(ip_1, ip_2); HexaEdgeCode[iElem][1] = false; HexaEdgeNode[iElem][1] = -1; + HexaEdgeIndex[iElem][2] = geometry->FindEdge(ip_2, ip_3); HexaEdgeCode[iElem][2] = false; HexaEdgeNode[iElem][2] = -1; + HexaEdgeIndex[iElem][3] = geometry->FindEdge(ip_3, ip_0); HexaEdgeCode[iElem][3] = false; HexaEdgeNode[iElem][3] = -1; + HexaEdgeIndex[iElem][4] = geometry->FindEdge(ip_4, ip_5); HexaEdgeCode[iElem][4] = false; HexaEdgeNode[iElem][4] = -1; + HexaEdgeIndex[iElem][5] = geometry->FindEdge(ip_5, ip_6); HexaEdgeCode[iElem][5] = false; HexaEdgeNode[iElem][5] = -1; + HexaEdgeIndex[iElem][6] = geometry->FindEdge(ip_6, ip_7); HexaEdgeCode[iElem][6] = false; HexaEdgeNode[iElem][6] = -1; + HexaEdgeIndex[iElem][7] = geometry->FindEdge(ip_7, ip_4); HexaEdgeCode[iElem][7] = false; HexaEdgeNode[iElem][7] = -1; + HexaEdgeIndex[iElem][8] = geometry->FindEdge(ip_0, ip_4); HexaEdgeCode[iElem][8] = false; HexaEdgeNode[iElem][8] = -1; + HexaEdgeIndex[iElem][9] = geometry->FindEdge(ip_1, ip_5); HexaEdgeCode[iElem][9] = false; HexaEdgeNode[iElem][9] = -1; + HexaEdgeIndex[iElem][10] = geometry->FindEdge(ip_2, ip_6); HexaEdgeCode[iElem][10] = false; HexaEdgeNode[iElem][10] = -1; + HexaEdgeIndex[iElem][11] = geometry->FindEdge(ip_3, ip_7); HexaEdgeCode[iElem][11] = false; HexaEdgeNode[iElem][11] = -1; + +// HexaFaceIndex[iElem][0] = geometry->FindFace(iElem, ip_0, ip_1, ip_2, ip_3); HexaFaceCode[iElem][0] = false; HexaFaceNode[iElem][0] = -1; +// HexaFaceIndex[iElem][1] = geometry->FindFace(iElem, ip_4, ip_5, ip_6, ip_7); HexaFaceCode[iElem][1] = false; HexaFaceNode[iElem][1] = -1; +// HexaFaceIndex[iElem][2] = geometry->FindFace(iElem, ip_1, ip_2, ip_6, ip_5); HexaFaceCode[iElem][2] = false; HexaFaceNode[iElem][2] = -1; +// HexaFaceIndex[iElem][3] = geometry->FindFace(iElem, ip_3, ip_2, ip_6, ip_7); HexaFaceCode[iElem][3] = false; HexaFaceNode[iElem][3] = -1; +// HexaFaceIndex[iElem][4] = geometry->FindFace(iElem, ip_0, ip_3, ip_7, ip_4); HexaFaceCode[iElem][4] = false; HexaFaceNode[iElem][4] = -1; +// HexaFaceIndex[iElem][5] = geometry->FindFace(iElem, ip_0, ip_1, ip_5, ip_4); HexaFaceCode[iElem][5] = false; HexaFaceNode[iElem][5] = -1; + + HexaElemIndex[iElem][0] = iElem; HexaElemCode[iElem][0] = false; HexaElemNode[iElem][0] = -1; + + } + + } + + /*--- Remove pyramids and prisms in the adaptation process ---*/ + unsigned short iFace, iNode, ElemIndex; + long jElem; + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + if ((geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) || + (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) || + (geometry->elem[iElem]->GetVTK_Type() == PRISM)) { + geometry->elem[iElem]->SetDivide(false); + for (iFace = 0; iFace < geometry->elem[iElem]->GetnFaces(); iFace++) + for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodesFace(iFace); iNode++) { + iPoint = geometry->elem[iElem]->GetNode(geometry->elem[iElem]->GetFaces(iFace, iNode)); + for (ElemIndex = 0; ElemIndex < geometry->node[iPoint]->GetnElem(); ElemIndex++) { + jElem = geometry->node[iPoint]->GetElem(ElemIndex); + if (jElem != -1) geometry->elem[jElem]->SetDivide(false); + } + } + } + } + + /*--- Do not addapt the boundaries ---*/ + if (!config->GetAdaptBoundary()) { + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { + for (iNode = 0; iNode < geometry->bound[iMarker][iVertex]->GetnNodes(); iNode++) { + iPoint = geometry->bound[iMarker][iVertex]->GetNode(iNode); + for (ElemIndex = 0; ElemIndex < geometry->node[iPoint]->GetnElem(); ElemIndex++) { + jElem = geometry->node[iPoint]->GetElem(ElemIndex); + if (jElem != -1) geometry->elem[jElem]->SetDivide(false); + } + } + } + } + } + + /*--- Initial edges that are going to be divided ---*/ + bool *DivEdge = new bool[geometry->GetnEdge()]; + bool *DivElem = new bool[geometry->GetnElem()]; + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) DivEdge[iEdge] = false; + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) + DivElem[iElem] = geometry->elem[iElem]->GetDivide(); + + /*--- Set the edge division in the reactangles and in the edge list ---*/ + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + if (DivElem[iElem] == true) { + if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { + for (long iIndex = 0; iIndex < 6; iIndex++) { + DivEdge[TetraEdgeIndex[iElem][iIndex]] = true; + TetraEdgeCode[iElem][iIndex] = true; + } + } + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { + for (long iIndex = 0; iIndex < 12; iIndex++) { + DivEdge[HexaEdgeIndex[iElem][iIndex]] = true; + HexaEdgeCode[iElem][iIndex] = true; + } + } + } + } + + /*--- Only with tets, check if an element have more than 4 divided edges, the element should be completelly divided ---*/ + bool new_elem; + do { new_elem = false; + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { + + ip_0 = geometry->elem[iElem]->GetNode(0); + ip_1 = geometry->elem[iElem]->GetNode(1); + ip_2 = geometry->elem[iElem]->GetNode(2); + ip_3 = geometry->elem[iElem]->GetNode(3); + + counter = 0; + if (DivEdge[TetraEdgeIndex[iElem][0]]) counter++; + if (DivEdge[TetraEdgeIndex[iElem][1]]) counter++; + if (DivEdge[TetraEdgeIndex[iElem][2]]) counter++; + if (DivEdge[TetraEdgeIndex[iElem][3]]) counter++; + if (DivEdge[TetraEdgeIndex[iElem][4]]) counter++; + if (DivEdge[TetraEdgeIndex[iElem][5]]) counter++; + + if ((counter > 3) && (!DivElem[iElem])) { + DivEdge[geometry->FindEdge(ip_0, ip_1)] = true; + DivEdge[geometry->FindEdge(ip_0, ip_2)] = true; + DivEdge[geometry->FindEdge(ip_0, ip_3)] = true; + DivEdge[geometry->FindEdge(ip_1, ip_2)] = true; + DivEdge[geometry->FindEdge(ip_1, ip_3)] = true; + DivEdge[geometry->FindEdge(ip_2, ip_3)] = true; + DivElem[iElem] = true; + new_elem = true; + } + } + } + } while (new_elem); + + /*--- We must verify that all the elements have the right edges marked, + with tets 4 and 5 edges are not allowed ---*/ + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { + for (long iIndex = 0; iIndex < 6; iIndex++) { + if (DivEdge[TetraEdgeIndex[iElem][iIndex]] == true) { + TetraEdgeCode[iElem][iIndex] = true; + } + } + } + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { + for (long iIndex = 0; iIndex < 12; iIndex++) { + if (DivEdge[HexaEdgeIndex[iElem][iIndex]] == true) { + HexaEdgeCode[iElem][iIndex] = true; + } + } + } + } + + // Only those elements that verify certain rules will be marked for hexa adaptation... + // the others will need a new point in the middle and Pyrams + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { + TetraAdaptCode[iElem] = CheckTetraCode(TetraEdgeCode[iElem]); +// if (TetraAdaptCode[iElem] != -1) cout << TetraAdaptCode[iElem] <<" "<< iElem << endl; + } + + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { + + HexaAdaptCode[iElem] = CheckHexaCode(HexaEdgeCode[iElem]); +// if (HexaAdaptCode[iElem] != -1) cout << HexaAdaptCode[iElem] <<" "<< iElem << endl; + + // Set the HexaFaceCode, and HexaElemCode + if (HexaAdaptCode[iElem] == 1) { + HexaFaceCode[iElem][0] = true; HexaFaceCode[iElem][1] = true; HexaFaceCode[iElem][2] = true; + HexaFaceCode[iElem][3] = true; HexaFaceCode[iElem][4] = true; HexaFaceCode[iElem][5] = true; + HexaElemCode[iElem][0] = true; + } + if (HexaAdaptCode[iElem] == 2) { + HexaFaceCode[iElem][3] = true; HexaFaceCode[iElem][5] = true; + } + if (HexaAdaptCode[iElem] == 3) { + HexaFaceCode[iElem][2] = true; HexaFaceCode[iElem][4] = true; + } + if (HexaAdaptCode[iElem] == 4) { + HexaFaceCode[iElem][0] = true; HexaFaceCode[iElem][1] = true; + } + } + } + + // Create the new nodes on the edges, on the faces, and in the element. + long *NodeAtEdges = new long[geometry->GetnEdge()]; +// long *NodeAtElem = new long[geometry->GetnFace()]; + long *NodeAtElem = new long[geometry->GetnElem()]; + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) NodeAtEdges[iEdge] = -1; +// for (iFace = 0; iFace < geometry->GetnFace(); iFace++) NodeAtFaces[iEdge] = -1; + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) NodeAtElem[iElem] = -1; + + nPoint_new = geometry->GetnPoint(); + + su2double **NewNodeCoord; + NewNodeCoord = new su2double *[10*geometry->GetnPoint()]; + for (iPoint = 0; iPoint < 10*geometry->GetnPoint(); iPoint++) + NewNodeCoord[iPoint] = new su2double[geometry->GetnDim()]; + + if (Restart_Flow) { + ConsVar_Adapt = new su2double *[10*geometry->GetnPoint()]; + for (iPoint = 0; iPoint < 10*geometry->GetnPoint(); iPoint++) + ConsVar_Adapt[iPoint] = new su2double[nVar]; + } + + if (Restart_Adjoint) { + AdjVar_Adapt = new su2double *[10*geometry->GetnPoint()]; + for (iPoint = 0; iPoint < 10*geometry->GetnPoint(); iPoint++) + AdjVar_Adapt[iPoint] = new su2double[nVar]; + } + + // Set the value of the variables + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { + for (iVar = 0; iVar < nVar; iVar ++) { + if (Restart_Flow) ConsVar_Adapt[iPoint][iVar] = ConsVar_Sol[iPoint][iVar]; + if (Restart_Adjoint) AdjVar_Adapt[iPoint][iVar] = AdjVar_Sol[iPoint][iVar]; + } + } + + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + + if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { + + ip_0 = geometry->elem[iElem]->GetNode(0); + ip_1 = geometry->elem[iElem]->GetNode(1); + ip_2 = geometry->elem[iElem]->GetNode(2); + ip_3 = geometry->elem[iElem]->GetNode(3); + + for (long iIndex = 0; iIndex < 6; iIndex++) { + + if (TetraEdgeCode[iElem][iIndex] == true) { + if (NodeAtEdges[TetraEdgeIndex[iElem][iIndex]] != -1) + TetraEdgeNode[iElem][iIndex] = NodeAtEdges[TetraEdgeIndex[iElem][iIndex]]; + + if (NodeAtEdges[TetraEdgeIndex[iElem][iIndex]] == -1) { + + NodeAtEdges[TetraEdgeIndex[iElem][iIndex]] = nPoint_new; + TetraEdgeNode[iElem][iIndex] = nPoint_new; + + // Compute the coordinates of the new node + if (iIndex == 0) {no_0 = ip_0; no_1 = ip_1;} + if (iIndex == 1) {no_0 = ip_0; no_1 = ip_2;} + if (iIndex == 2) {no_0 = ip_0; no_1 = ip_3;} + if (iIndex == 3) {no_0 = ip_1; no_1 = ip_2;} + if (iIndex == 4) {no_0 = ip_1; no_1 = ip_3;} + if (iIndex == 5) {no_0 = ip_2; no_1 = ip_3;} + + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) + NewNodeCoord[nPoint_new][iDim] = 0.5*(geometry->node[no_0]->GetCoord(iDim)+geometry->node[no_1]->GetCoord(iDim)); + + for (iVar = 0; iVar < nVar; iVar ++) { + if (Restart_Flow) ConsVar_Adapt[nPoint_new][iVar] = 0.5 * (ConsVar_Adapt[no_0][iVar]+ConsVar_Adapt[no_1][iVar]); + if (Restart_Adjoint) AdjVar_Adapt[nPoint_new][iVar] = 0.5 * (AdjVar_Adapt[no_0][iVar]+AdjVar_Adapt[no_1][iVar]); + } + + nPoint_new++; + } + } + } + } + + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { + + ip_0 = geometry->elem[iElem]->GetNode(0); + ip_1 = geometry->elem[iElem]->GetNode(1); + ip_2 = geometry->elem[iElem]->GetNode(2); + ip_3 = geometry->elem[iElem]->GetNode(3); + ip_4 = geometry->elem[iElem]->GetNode(4); + ip_5 = geometry->elem[iElem]->GetNode(5); + ip_6 = geometry->elem[iElem]->GetNode(6); + ip_7 = geometry->elem[iElem]->GetNode(7); + + for (long iIndex = 0; iIndex < 12; iIndex++) { + + if (HexaEdgeCode[iElem][iIndex] == true) { + if (NodeAtEdges[HexaEdgeIndex[iElem][iIndex]] != -1) + HexaEdgeNode[iElem][iIndex] = NodeAtEdges[HexaEdgeIndex[iElem][iIndex]]; + + if (NodeAtEdges[HexaEdgeIndex[iElem][iIndex]] == -1) { + + NodeAtEdges[HexaEdgeIndex[iElem][iIndex]] = nPoint_new; + HexaEdgeNode[iElem][iIndex] = nPoint_new; + + // Compute the coordinates of the new node + if (iIndex == 0) {no_0 = ip_0; no_1 = ip_1;} + if (iIndex == 1) {no_0 = ip_1; no_1 = ip_2;} + if (iIndex == 2) {no_0 = ip_2; no_1 = ip_3;} + if (iIndex == 3) {no_0 = ip_3; no_1 = ip_0;} + if (iIndex == 4) {no_0 = ip_4; no_1 = ip_5;} + if (iIndex == 5) {no_0 = ip_5; no_1 = ip_6;} + if (iIndex == 6) {no_0 = ip_6; no_1 = ip_7;} + if (iIndex == 7) {no_0 = ip_7; no_1 = ip_4;} + if (iIndex == 8) {no_0 = ip_0; no_1 = ip_4;} + if (iIndex == 9) {no_0 = ip_1; no_1 = ip_5;} + if (iIndex == 10) {no_0 = ip_2; no_1 = ip_6;} + if (iIndex == 11) {no_0 = ip_3; no_1 = ip_7;} + + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) + NewNodeCoord[nPoint_new][iDim] = 0.5*(geometry->node[no_0]->GetCoord(iDim)+geometry->node[no_1]->GetCoord(iDim)); + + for (iVar = 0; iVar < nVar; iVar ++) { + if (Restart_Flow) ConsVar_Adapt[nPoint_new][iVar] = 0.5 * (ConsVar_Adapt[no_0][iVar]+ConsVar_Adapt[no_1][iVar]); + if (Restart_Adjoint) AdjVar_Adapt[nPoint_new][iVar] = 0.5 * (AdjVar_Adapt[no_0][iVar]+AdjVar_Adapt[no_1][iVar]); + } + + nPoint_new++; + } + } + } + +/* for (long iIndex = 0; iIndex < 6; iIndex++) { + if (HexaFaceCode[iElem][iIndex] == true) { + + if (NodeAtFaces[HexaFaceIndex[iElem][iIndex]] != -1) + HexaFaceNode[iElem][iIndex] = NodeAtFaces[HexaFaceIndex[iElem][iIndex]]; + + if (NodeAtFaces[HexaFaceIndex[iElem][iIndex]] == -1) { + NodeAtFaces[HexaFaceIndex[iElem][iIndex]] = nPoint_new; + HexaFaceNode[iElem][iIndex] = nPoint_new; + // Compute the coordinates of the new node + if (iIndex == 0) {no_0 = ip_0; no_1 = ip_1; no_2 = ip_2; no_3 = ip_3;} + if (iIndex == 1) {no_0 = ip_4; no_1 = ip_5; no_2 = ip_6; no_3 = ip_7;} + if (iIndex == 2) {no_0 = ip_1; no_1 = ip_2; no_2 = ip_6; no_3 = ip_5;} + if (iIndex == 3) {no_0 = ip_3; no_1 = ip_2; no_2 = ip_6; no_3 = ip_7;} + if (iIndex == 4) {no_0 = ip_0; no_1 = ip_3; no_2 = ip_7; no_3 = ip_4;} + if (iIndex == 5) {no_0 = ip_0; no_1 = ip_1; no_2 = ip_5; no_3 = ip_4;} + + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) + NewNodeCoord[nPoint_new][iDim] = 0.25*(x_no[no_0][iDim]+x_no[no_1][iDim]+x_no[no_2][iDim]+x_no[no_3][iDim]); + + for (iVar = 0; iVar < nVar; iVar ++) { + if (Restart_Flow) ConsVar_Adapt[nPoint_new][iVar] = 0.25 * (ConsVar_Adapt[no_0][iVar]+ConsVar_Adapt[no_1][iVar]+ConsVar_Adapt[no_2][iVar]+ConsVar_Adapt[no_3][iVar]); + if (Restart_Adjoint) AdjVar_Adapt[nPoint_new][iVar] = 0.25 * (AdjVar_Adapt[no_0][iVar]+AdjVar_Adapt[no_1][iVar]+AdjVar_Adapt[no_2][iVar]+AdjVar_Adapt[no_3][iVar]); + if (Restart_Linear) LinVar_Adapt[nPoint_new][iVar] = 0.25 * (LinVar_Adapt[no_0][iVar]+LinVar_Adapt[no_1][iVar]+LinVar_Adapt[no_2][iVar]+LinVar_Adapt[no_3][iVar]); + } + + nPoint_new++; + + } + } + + } */ + + for (long iIndex = 0; iIndex < 1; iIndex++) { + + if (HexaElemCode[iElem][iIndex] == true) { + + if (NodeAtElem[HexaElemIndex[iElem][iIndex]] != -1) + HexaElemNode[iElem][iIndex] = NodeAtElem[HexaElemIndex[iElem][iIndex]]; + + if (NodeAtElem[HexaElemIndex[iElem][iIndex]] == -1) { + NodeAtElem[HexaElemIndex[iElem][iIndex]] = nPoint_new; + HexaElemNode[iElem][iIndex] = nPoint_new; + + // Compute the coordinates of the new node + if (iIndex == 0) {no_0 = ip_0; no_1 = ip_1; no_2 = ip_2; no_3 = ip_3; no_4 = ip_4; no_5 = ip_5; no_6 = ip_6; no_7 = ip_7;} + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) + NewNodeCoord[nPoint_new][iDim] = 0.125*(geometry->node[no_0]->GetCoord(iDim) + + geometry->node[no_1]->GetCoord(iDim) + + geometry->node[no_2]->GetCoord(iDim) + + geometry->node[no_3]->GetCoord(iDim) + + geometry->node[no_4]->GetCoord(iDim) + + geometry->node[no_5]->GetCoord(iDim) + + geometry->node[no_6]->GetCoord(iDim) + + geometry->node[no_7]->GetCoord(iDim)); + + for (iVar = 0; iVar < nVar; iVar ++) { + if (Restart_Flow) ConsVar_Adapt[nPoint_new][iVar] = 0.125 * (ConsVar_Adapt[no_0][iVar]+ConsVar_Adapt[no_1][iVar]+ConsVar_Adapt[no_2][iVar]+ConsVar_Adapt[no_3][iVar]+ + ConsVar_Adapt[no_4][iVar]+ConsVar_Adapt[no_5][iVar]+ConsVar_Adapt[no_6][iVar]+ConsVar_Adapt[no_7][iVar]); + if (Restart_Adjoint) AdjVar_Adapt[nPoint_new][iVar] = 0.125 * (AdjVar_Adapt[no_0][iVar]+AdjVar_Adapt[no_1][iVar]+AdjVar_Adapt[no_2][iVar]+AdjVar_Adapt[no_3][iVar]+ + AdjVar_Adapt[no_4][iVar]+AdjVar_Adapt[no_5][iVar]+AdjVar_Adapt[no_6][iVar]+AdjVar_Adapt[no_7][iVar]); + } + + nPoint_new++; + } + } + } + } + + } + + + // if Hexa adapt code equals 0, then a semidivision is applied + long nSemiDivided = 0; + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { + if (HexaAdaptCode[iElem] == 0) + nSemiDivided++; + } + } + + // If semidivision, then divide add a new point (hexa), divide the hexahedron into Tetras, + // and find the right combination, it also create the new node (hexa). + long nPyram = nSemiDivided*6; + + long *PyramAdaptCode; + long **PyramNode; + long **HexaPyramIndex; + long *PyramHexaIndex; + + long **PyramEdgeIndex; + bool **PyramEdgeCode; + long **PyramEdgeNode; + + long **PyramFaceNode; + + long **PyramElemNode; + + PyramAdaptCode = new long [nPyram]; + PyramNode = new long *[nPyram]; + HexaPyramIndex = new long *[geometry->GetnElem()]; + PyramHexaIndex = new long [nPyram]; + PyramEdgeIndex = new long *[nPyram]; + PyramEdgeCode = new bool *[nPyram]; + PyramEdgeNode = new long *[nPyram]; + PyramFaceNode = new long *[nPyram]; + PyramElemNode = new long *[nPyram]; + + for (long iPyram = 0; iPyram < nPyram; iPyram++) { + PyramNode[iPyram] = new long [4]; + PyramEdgeIndex[iPyram] = new long [4]; + PyramEdgeCode[iPyram] = new bool [4]; + PyramEdgeNode[iPyram] = new long [4]; + PyramFaceNode[iPyram] = new long [1]; + PyramElemNode[iPyram] = new long [1]; + } + + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { + HexaPyramIndex[iElem] = new long [6]; + } + } + + nPyram = 0; + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { + if (HexaAdaptCode[iElem] == 0) { + + // Write the edge combination on the base. + ip_0 = geometry->elem[iElem]->GetNode(0); + ip_1 = geometry->elem[iElem]->GetNode(1); + ip_2 = geometry->elem[iElem]->GetNode(2); + ip_3 = geometry->elem[iElem]->GetNode(3); + ip_4 = geometry->elem[iElem]->GetNode(4); + ip_5 = geometry->elem[iElem]->GetNode(5); + ip_6 = geometry->elem[iElem]->GetNode(6); + ip_7 = geometry->elem[iElem]->GetNode(7); + + // Create the 1st pyramid. + HexaPyramIndex[iElem][0] = nPyram; PyramHexaIndex[nPyram] = iElem; PyramElemNode[nPyram][0] = nPoint_new; + + PyramNode[nPyram][0] = ip_0; PyramNode[nPyram][1] = ip_1; + PyramNode[nPyram][2] = ip_2; PyramNode[nPyram][3] = ip_3; + + PyramEdgeIndex[nPyram][0] = HexaEdgeIndex[iElem][0]; PyramEdgeIndex[nPyram][1] = HexaEdgeIndex[iElem][1]; + PyramEdgeIndex[nPyram][2] = HexaEdgeIndex[iElem][2]; PyramEdgeIndex[nPyram][3] = HexaEdgeIndex[iElem][3]; + + PyramEdgeNode[nPyram][0] = HexaEdgeNode[iElem][0]; PyramEdgeNode[nPyram][1] = HexaEdgeNode[iElem][1]; + PyramEdgeNode[nPyram][2] = HexaEdgeNode[iElem][2]; PyramEdgeNode[nPyram][3] = HexaEdgeNode[iElem][3]; + + + for (long iIndex = 0; iIndex < 4; iIndex++) + if (DivEdge[PyramEdgeIndex[nPyram][iIndex]] == true) PyramEdgeCode[nPyram][iIndex] = true; + nPyram++; + + // Create the 2nd pyramid. + HexaPyramIndex[iElem][1] = nPyram; PyramHexaIndex[nPyram] = iElem; PyramElemNode[nPyram][0] = nPoint_new; + + PyramNode[nPyram][0] = ip_4; PyramNode[nPyram][1] = ip_7; + PyramNode[nPyram][2] = ip_6; PyramNode[nPyram][3] = ip_5; + + PyramEdgeIndex[nPyram][0] = HexaEdgeIndex[iElem][7]; PyramEdgeIndex[nPyram][1] = HexaEdgeIndex[iElem][6]; + PyramEdgeIndex[nPyram][2] = HexaEdgeIndex[iElem][5]; PyramEdgeIndex[nPyram][3] = HexaEdgeIndex[iElem][4]; + + PyramEdgeNode[nPyram][0] = HexaEdgeNode[iElem][7]; PyramEdgeNode[nPyram][1] = HexaEdgeNode[iElem][6]; + PyramEdgeNode[nPyram][2] = HexaEdgeNode[iElem][5]; PyramEdgeNode[nPyram][3] = HexaEdgeNode[iElem][4]; + + for (long iIndex = 0; iIndex < 4; iIndex++) + if (DivEdge[PyramEdgeIndex[nPyram][iIndex]] == true) PyramEdgeCode[nPyram][iIndex] = true; + nPyram++; + + // Create the 3th pyramid. + HexaPyramIndex[iElem][2] = nPyram; PyramHexaIndex[nPyram] = iElem; PyramElemNode[nPyram][0] = nPoint_new; + + PyramNode[nPyram][0] = ip_0; PyramNode[nPyram][1] = ip_4; + PyramNode[nPyram][2] = ip_5; PyramNode[nPyram][3] = ip_1; + + PyramEdgeIndex[nPyram][0] = HexaEdgeIndex[iElem][8]; PyramEdgeIndex[nPyram][1] = HexaEdgeIndex[iElem][4]; + PyramEdgeIndex[nPyram][2] = HexaEdgeIndex[iElem][9]; PyramEdgeIndex[nPyram][3] = HexaEdgeIndex[iElem][0]; + + PyramEdgeNode[nPyram][0] = HexaEdgeNode[iElem][8]; PyramEdgeNode[nPyram][1] = HexaEdgeNode[iElem][4]; + PyramEdgeNode[nPyram][2] = HexaEdgeNode[iElem][9]; PyramEdgeNode[nPyram][3] = HexaEdgeNode[iElem][0]; + + for (long iIndex = 0; iIndex < 4; iIndex++) + if (DivEdge[PyramEdgeIndex[nPyram][iIndex]] == true) PyramEdgeCode[nPyram][iIndex] = true; + nPyram++; + + // Create the 4th pyramid. + HexaPyramIndex[iElem][3] = nPyram; PyramHexaIndex[nPyram] = iElem; PyramElemNode[nPyram][0] = nPoint_new; + + PyramNode[nPyram][0] = ip_3; PyramNode[nPyram][1] = ip_2; + PyramNode[nPyram][2] = ip_6; PyramNode[nPyram][3] = ip_7; + + PyramEdgeIndex[nPyram][0] = HexaEdgeIndex[iElem][2]; PyramEdgeIndex[nPyram][1] = HexaEdgeIndex[iElem][10]; + PyramEdgeIndex[nPyram][2] = HexaEdgeIndex[iElem][6]; PyramEdgeIndex[nPyram][3] = HexaEdgeIndex[iElem][11]; + + PyramEdgeNode[nPyram][0] = HexaEdgeNode[iElem][2]; PyramEdgeNode[nPyram][1] = HexaEdgeNode[iElem][10]; + PyramEdgeNode[nPyram][2] = HexaEdgeNode[iElem][6]; PyramEdgeNode[nPyram][3] = HexaEdgeNode[iElem][11]; + + for (long iIndex = 0; iIndex < 4; iIndex++) + if (DivEdge[PyramEdgeIndex[nPyram][iIndex]] == true) PyramEdgeCode[nPyram][iIndex] = true; + nPyram++; + + // Create the 5th pyramid. + HexaPyramIndex[iElem][4] = nPyram; PyramHexaIndex[nPyram] = iElem; PyramElemNode[nPyram][0] = nPoint_new; + + PyramNode[nPyram][0] = ip_1; PyramNode[nPyram][1] = ip_5; + PyramNode[nPyram][2] = ip_6; PyramNode[nPyram][3] = ip_2; + + PyramEdgeIndex[nPyram][0] = HexaEdgeIndex[iElem][9]; PyramEdgeIndex[nPyram][1] = HexaEdgeIndex[iElem][5]; + PyramEdgeIndex[nPyram][2] = HexaEdgeIndex[iElem][10]; PyramEdgeIndex[nPyram][3] = HexaEdgeIndex[iElem][1]; + + PyramEdgeNode[nPyram][0] = HexaEdgeNode[iElem][9]; PyramEdgeNode[nPyram][1] = HexaEdgeNode[iElem][5]; + PyramEdgeNode[nPyram][2] = HexaEdgeNode[iElem][10]; PyramEdgeNode[nPyram][3] = HexaEdgeNode[iElem][1]; + + for (long iIndex = 0; iIndex < 4; iIndex++) + if (DivEdge[PyramEdgeIndex[nPyram][iIndex]] == true) PyramEdgeCode[nPyram][iIndex] = true; + nPyram++; + + // Create the 6th pyramid. + HexaPyramIndex[iElem][5] = nPyram; PyramHexaIndex[nPyram] = iElem; PyramElemNode[nPyram][0] = nPoint_new; + + PyramNode[nPyram][0] = ip_0; PyramNode[nPyram][1] = ip_3; + PyramNode[nPyram][2] = ip_7; PyramNode[nPyram][3] = ip_4; + + PyramEdgeIndex[nPyram][0] = HexaEdgeIndex[iElem][3]; PyramEdgeIndex[nPyram][1] = HexaEdgeIndex[iElem][11]; + PyramEdgeIndex[nPyram][2] = HexaEdgeIndex[iElem][7]; PyramEdgeIndex[nPyram][3] = HexaEdgeIndex[iElem][8]; + + PyramEdgeNode[nPyram][0] = HexaEdgeNode[iElem][3]; PyramEdgeNode[nPyram][1] = HexaEdgeNode[iElem][11]; + PyramEdgeNode[nPyram][2] = HexaEdgeNode[iElem][7]; PyramEdgeNode[nPyram][3] = HexaEdgeNode[iElem][8]; + + for (long iIndex = 0; iIndex < 4; iIndex++) + if (DivEdge[PyramEdgeIndex[nPyram][iIndex]] == true) PyramEdgeCode[nPyram][iIndex] = true; + nPyram++; + + nPoint_new++; + + + } + } + } + + // Check the kind of Pyram partitioning that should be applied + for (long iPyram = 0; iPyram < nPyram; iPyram ++) { + PyramAdaptCode[iPyram] = CheckPyramCode(PyramEdgeCode[iPyram]); + if (PyramAdaptCode[iPyram] == 0) cout << "There is a problem with one Pyram" << endl; + } + + // Create new structure + nElem_new = geometry->GetnElem(); + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { + if (TetraAdaptCode[iElem] == 1) nElem_new = nElem_new + 7; + if (TetraAdaptCode[iElem] == 2) nElem_new = nElem_new + 3; + if (TetraAdaptCode[iElem] == 3) nElem_new = nElem_new + 3; + if (TetraAdaptCode[iElem] == 4) nElem_new = nElem_new + 3; + if (TetraAdaptCode[iElem] == 5) nElem_new = nElem_new + 3; + if (TetraAdaptCode[iElem] == 6) nElem_new = nElem_new + 7; + } + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { + if (HexaAdaptCode[iElem] == 1) nElem_new = nElem_new + 7; + if (HexaAdaptCode[iElem] == 2) nElem_new = nElem_new + 3; + if (HexaAdaptCode[iElem] == 3) nElem_new = nElem_new + 3; + if (HexaAdaptCode[iElem] == 4) nElem_new = nElem_new + 3; + if (HexaAdaptCode[iElem] == 5) nElem_new = nElem_new + 1; + if (HexaAdaptCode[iElem] == 6) nElem_new = nElem_new + 1; + if (HexaAdaptCode[iElem] == 7) nElem_new = nElem_new + 1; + if (HexaAdaptCode[iElem] == 0) { + long iPyram; + for (long iIndex = 0; iIndex < 6; iIndex++) { + iPyram = HexaPyramIndex[iElem][0]; + if (PyramAdaptCode[iPyram] == 1) nElem_new = nElem_new + 0; + if (PyramAdaptCode[iPyram] == 2) nElem_new = nElem_new + 2; + if (PyramAdaptCode[iPyram] == 3) nElem_new = nElem_new + 2; + if (PyramAdaptCode[iPyram] == 4) nElem_new = nElem_new + 2; + if (PyramAdaptCode[iPyram] == 5) nElem_new = nElem_new + 2; + if (PyramAdaptCode[iPyram] == 6) nElem_new = nElem_new + 3; + if (PyramAdaptCode[iPyram] == 7) nElem_new = nElem_new + 3; + if (PyramAdaptCode[iPyram] == 8) nElem_new = nElem_new + 3; + if (PyramAdaptCode[iPyram] == 9) nElem_new = nElem_new + 3; + if (PyramAdaptCode[iPyram] == 10) nElem_new = nElem_new + 1; + if (PyramAdaptCode[iPyram] == 11) nElem_new = nElem_new + 1; + if (PyramAdaptCode[iPyram] == 12) nElem_new = nElem_new + 3; + if (PyramAdaptCode[iPyram] == 13) nElem_new = nElem_new + 3; + if (PyramAdaptCode[iPyram] == 14) nElem_new = nElem_new + 3; + if (PyramAdaptCode[iPyram] == 15) nElem_new = nElem_new + 3; + if (PyramAdaptCode[iPyram] == 16) nElem_new = nElem_new + 3; + } + } + } + } + + // New points + geo_adapt->node = new CPoint*[nPoint_new]; + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) + geo_adapt->node[iPoint] = new CPoint(geometry->node[iPoint]->GetCoord(0), geometry->node[iPoint]->GetCoord(1), geometry->node[iPoint]->GetCoord(2), iPoint, config); + + for (iPoint = geometry->GetnPoint(); iPoint < nPoint_new; iPoint++) + geo_adapt->node[iPoint] = new CPoint(NewNodeCoord[iPoint][0], NewNodeCoord[iPoint][1], NewNodeCoord[iPoint][2], iPoint, config); + + // New elements + geo_adapt->elem = new CPrimalGrid*[nElem_new]; + + unsigned long iElemNew = 0; + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { + if (TetraAdaptCode[iElem] == -1) { + geo_adapt->elem[iElemNew] = new CTetrahedron(geometry->elem[iElem]->GetNode(0), + geometry->elem[iElem]->GetNode(1), + geometry->elem[iElem]->GetNode(2), + geometry->elem[iElem]->GetNode(3)); + iElemNew++; + } + } + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { + if (HexaAdaptCode[iElem] == -1) { + geo_adapt->elem[iElemNew] = new CHexahedron(geometry->elem[iElem]->GetNode(0), + geometry->elem[iElem]->GetNode(1), + geometry->elem[iElem]->GetNode(2), + geometry->elem[iElem]->GetNode(3), + geometry->elem[iElem]->GetNode(4), + geometry->elem[iElem]->GetNode(5), + geometry->elem[iElem]->GetNode(6), + geometry->elem[iElem]->GetNode(7)); + iElemNew++; + } + } + if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) { + geo_adapt->elem[iElemNew] = new CPyramid(geometry->elem[iElem]->GetNode(0), + geometry->elem[iElem]->GetNode(1), + geometry->elem[iElem]->GetNode(2), + geometry->elem[iElem]->GetNode(3), + geometry->elem[iElem]->GetNode(4)); + iElemNew++; + } + if (geometry->elem[iElem]->GetVTK_Type() == PRISM) { + geo_adapt->elem[iElemNew] = new CPrism(geometry->elem[iElem]->GetNode(0), + geometry->elem[iElem]->GetNode(1), + geometry->elem[iElem]->GetNode(2), + geometry->elem[iElem]->GetNode(3), + geometry->elem[iElem]->GetNode(4), + geometry->elem[iElem]->GetNode(5)); + iElemNew++; + } + } + + long nodes[27]; long **Division; long nPart; + + Division = new long*[100]; + for (long iVar = 0; iVar < 100; iVar++) + Division[iVar] = new long[100]; + + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { + + // Tetra elements... + if (TetraAdaptCode[iElem] > 0) { + + // First the corners + nodes[0] = geometry->elem[iElem]->GetNode(0); + nodes[1] = geometry->elem[iElem]->GetNode(1); + nodes[2] = geometry->elem[iElem]->GetNode(2); + nodes[3] = geometry->elem[iElem]->GetNode(3); + + // Next the points that correspond to the broken edges. + nodes[4] = TetraEdgeNode[iElem][0]; + nodes[5] = TetraEdgeNode[iElem][1]; + nodes[6] = TetraEdgeNode[iElem][2]; + nodes[7] = TetraEdgeNode[iElem][3]; + nodes[8] = TetraEdgeNode[iElem][4]; + nodes[9] = TetraEdgeNode[iElem][5]; + + ip_0 = geometry->elem[iElem]->GetNode(0); + ip_1 = geometry->elem[iElem]->GetNode(1); + ip_2 = geometry->elem[iElem]->GetNode(2); + ip_3 = geometry->elem[iElem]->GetNode(3); + + long edges[6] = {-1, -1, -1, -1, -1 , -1}; + if (DivEdge[geometry->FindEdge(ip_0, ip_1)]) {edges[0] = geometry->FindEdge(ip_0, ip_1);} + if (DivEdge[geometry->FindEdge(ip_0, ip_2)]) {edges[1] = geometry->FindEdge(ip_0, ip_2);} + if (DivEdge[geometry->FindEdge(ip_0, ip_3)]) {edges[2] = geometry->FindEdge(ip_0, ip_3);} + if (DivEdge[geometry->FindEdge(ip_1, ip_2)]) {edges[3] = geometry->FindEdge(ip_1, ip_2);} + if (DivEdge[geometry->FindEdge(ip_1, ip_3)]) {edges[4] = geometry->FindEdge(ip_1, ip_3);} + if (DivEdge[geometry->FindEdge(ip_2, ip_3)]) {edges[5] = geometry->FindEdge(ip_2, ip_3);} + + + TetraDivision(TetraAdaptCode[iElem], nodes, edges, Division, &nPart); + + for (long iPart = 0; iPart < nPart; iPart++) { + + // Tetra case + geo_adapt->elem[iElemNew] = new CTetrahedron(Division[iPart][1], + Division[iPart][2], + Division[iPart][3], + Division[iPart][4]); + iElemNew++; + } + } + } + + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { + // Hexa elements... + if (HexaAdaptCode[iElem] > 0) { + + // First the corners + nodes[0] = geometry->elem[iElem]->GetNode(0); nodes[1] = geometry->elem[iElem]->GetNode(1); + nodes[2] = geometry->elem[iElem]->GetNode(2); nodes[3] = geometry->elem[iElem]->GetNode(3); + nodes[4] = geometry->elem[iElem]->GetNode(4); nodes[5] = geometry->elem[iElem]->GetNode(5); + nodes[6] = geometry->elem[iElem]->GetNode(6); nodes[7] = geometry->elem[iElem]->GetNode(7); + + // Next the points that correspond to the broken edges. + nodes[8] = HexaEdgeNode[iElem][0]; nodes[9] = HexaEdgeNode[iElem][1]; + nodes[10] = HexaEdgeNode[iElem][2]; nodes[11] = HexaEdgeNode[iElem][3]; + nodes[12] = HexaEdgeNode[iElem][4]; nodes[13] = HexaEdgeNode[iElem][5]; + nodes[14] = HexaEdgeNode[iElem][6]; nodes[15] = HexaEdgeNode[iElem][7]; + nodes[16] = HexaEdgeNode[iElem][8]; nodes[17] = HexaEdgeNode[iElem][9]; + nodes[18] = HexaEdgeNode[iElem][10]; nodes[19] = HexaEdgeNode[iElem][11]; + + // Next the points that correspond to the faces. + nodes[20] = HexaFaceNode[iElem][0]; + nodes[21] = HexaFaceNode[iElem][1]; + nodes[22] = HexaFaceNode[iElem][2]; + nodes[23] = HexaFaceNode[iElem][3]; + nodes[24] = HexaFaceNode[iElem][4]; + nodes[25] = HexaFaceNode[iElem][5]; + + // Next the points that correspond to the element. + nodes[8] = HexaElemNode[iElem][0]; + + HexaDivision(HexaAdaptCode[iElem], nodes, Division, &nPart); + for (long iPart = 0; iPart < nPart; iPart++) { + geo_adapt->elem[iElemNew] = new CHexahedron(Division[iPart][1], + Division[iPart][2], + Division[iPart][3], + Division[iPart][4], + Division[iPart][5], + Division[iPart][6], + Division[iPart][7], + Division[iPart][8]); + iElemNew++; + } + } + + // Pyram elements... + if (HexaAdaptCode[iElem] == 0) { + long iPyram = HexaPyramIndex[iElem][0]; + + // First the corners + nodes[0] = PyramNode[iPyram][0]; + nodes[1] = PyramNode[iPyram][1]; + nodes[2] = PyramNode[iPyram][2]; + nodes[3] = PyramNode[iPyram][3]; + nodes[4] = PyramElemNode[iPyram][0]; + + // Next the points that correspond to the broken edges. + nodes[5] = PyramEdgeNode[iPyram][0]; + nodes[6] = PyramEdgeNode[iPyram][1]; + nodes[7] = PyramEdgeNode[iPyram][2]; + nodes[8] = PyramEdgeNode[iPyram][3]; + + // Next the points that correspond to the base face. + nodes[9] = PyramFaceNode[iPyram][0]; + + PyramDivision(PyramAdaptCode[iPyram], nodes, Division, &nPart); + for (long iPart = 0; iPart < nPart; iPart++) { + + // Tetra case + if (Division[iPart][0] == 5) { + geo_adapt->elem[iElemNew] = new CTetrahedron(Division[iPart][1], + Division[iPart][2], + Division[iPart][3], + Division[iPart][4]); + iElemNew++; + } + + // Pyram case + if (Division[iPart][0] == 6) { + geo_adapt->elem[iElemNew] = new CPyramid(Division[iPart][1], + Division[iPart][2], + Division[iPart][3], + Division[iPart][4], + Division[iPart][5]); + iElemNew++; + } + } + } + } + } + + geo_adapt->SetnElem(iElemNew); + geo_adapt->SetnPoint(nPoint_new); + geo_adapt->SetnPointDomain(nPoint_new); + geo_adapt->SetnDim(nDim); + + // Create boundary structure + geo_adapt->SetnMarker(geometry->GetnMarker()); + geo_adapt->nElem_Bound = new unsigned long [geometry->GetnMarker()]; + geo_adapt->Tag_to_Marker = new string [nMarker_Max]; + geo_adapt->bound = new CPrimalGrid**[geometry->GetnMarker()]; + + // Conservative estimation of the number of boundary elements. + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + long nNewBCcv = 0; + for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { + nNewBCcv = nNewBCcv + 4; + } + geo_adapt->bound[iMarker] = new CPrimalGrid* [nNewBCcv]; + geo_adapt->SetMarker_Tag(iMarker, geometry->GetMarker_Tag(iMarker)); + } + + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + long nNewBCcv = 0; + for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) { + + bool TriangleEdgeCode[3] = { false, false, false }; + long TriangleAdaptCode, nodes[6]; + long nNodesBound = geometry->bound[iMarker][iVertex]->GetnNodes(); + + ip_0 = geometry->bound[iMarker][iVertex]->GetNode(0); geo_adapt->node[ip_0]->SetBoundary(geometry->GetnMarker()); + ip_1 = geometry->bound[iMarker][iVertex]->GetNode(1); geo_adapt->node[ip_1]->SetBoundary(geometry->GetnMarker()); + ip_2 = geometry->bound[iMarker][iVertex]->GetNode(2); geo_adapt->node[ip_2]->SetBoundary(geometry->GetnMarker()); + if (nNodesBound == 4) { + ip_3 = geometry->bound[iMarker][iVertex]->GetNode(3); geo_adapt->node[ip_3]->SetBoundary(geometry->GetnMarker()); + geo_adapt->bound[iMarker][nNewBCcv] = new CQuadrilateral(ip_0, ip_1, ip_2, ip_3, 3); + nNewBCcv++; + } + else { + // First the corners + nodes[0] = geometry->bound[iMarker][iVertex]->GetNode(0); + nodes[1] = geometry->bound[iMarker][iVertex]->GetNode(1); + nodes[2] = geometry->bound[iMarker][iVertex]->GetNode(2); + if (nNodesBound == 4) nodes[3] = geometry->bound[iMarker][iVertex]->GetNode(3); + + // Next the points that correspond to the broken edges. + nodes[3] = NodeAtEdges[geometry->FindEdge(ip_0, ip_1)]; if (nodes[3] != -1) geo_adapt->node[nodes[3]]->SetBoundary(geometry->GetnMarker()); + nodes[4] = NodeAtEdges[geometry->FindEdge(ip_1, ip_2)]; if (nodes[4] != -1) geo_adapt->node[nodes[4]]->SetBoundary(geometry->GetnMarker()); + nodes[5] = NodeAtEdges[geometry->FindEdge(ip_0, ip_2)]; if (nodes[5] != -1) geo_adapt->node[nodes[5]]->SetBoundary(geometry->GetnMarker()); + + long edges[3] = {-1, -1, -1}; + if (DivEdge[geometry->FindEdge(ip_0, ip_1)]) { edges[0] = geometry->FindEdge(ip_0, ip_1); TriangleEdgeCode[0] = true;} + if (DivEdge[geometry->FindEdge(ip_1, ip_2)]) { edges[1] = geometry->FindEdge(ip_1, ip_2); TriangleEdgeCode[1] = true;} + if (DivEdge[geometry->FindEdge(ip_2, ip_0)]) { edges[2] = geometry->FindEdge(ip_2, ip_0); TriangleEdgeCode[2] = true;} + + TriangleAdaptCode = CheckTriangleCode(TriangleEdgeCode); + TriangleDivision(TriangleAdaptCode, nodes, edges, Division, &nPart); + + for (long iPart = 0; iPart < nPart; iPart++) { + geo_adapt->bound[iMarker][nNewBCcv] = new CTriangle(Division[iPart][1], Division[iPart][2], Division[iPart][3], 3); + nNewBCcv++; + } + } + } + geo_adapt->SetnElem_Bound(iMarker, nNewBCcv); + } + + delete [] DivEdge; + delete [] DivElem; + delete [] NodeAtEdges; + delete [] NodeAtElem; +} + +void CGridAdaptation::SetIndicator_Flow(CGeometry *geometry, CConfig *config, unsigned short strength) { + unsigned long Point = 0, Point_0 = 0, Point_1 = 0, iEdge, iVertex, iPoint, iElem, max_elem_new; + unsigned short iDim, iMarker; + su2double Dual_Area, norm, Solution_Vertex, Solution_0, Solution_1, Solution_Average, + DualArea, Partial_Res, Grad_Val, *Normal; + su2double scale_area = config->GetDualVol_Power(); + + /*--- Initialization ---*/ + nElem_new = 0; + max_elem_new = SU2_TYPE::Int(0.01*config->GetNew_Elem_Adapt()*su2double(geometry->GetnElem())); + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + geometry->elem[iElem]->SetDivide(false); + } + + /*--- Compute the gradient of the first variable ---*/ + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + for (iDim = 0; iDim < nDim; iDim++) + Gradient[iPoint][iDim] = 0.0; + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + Point_0 = geometry->edge[iEdge]->GetNode(0); Solution_0 = ConsVar_Sol[Point_0][0]; + Point_1 = geometry->edge[iEdge]->GetNode(1); Solution_1 = ConsVar_Sol[Point_1][0]; + Normal = geometry->edge[iEdge]->GetNormal(); + Solution_Average = 0.5 * ( Solution_0 + Solution_1); + for (iDim = 0; iDim < nDim; iDim++) { + Partial_Res = Solution_Average*Normal[iDim]; + Gradient[Point_0][iDim] = Gradient[Point_0][iDim] + Partial_Res; + Gradient[Point_1][iDim] = Gradient[Point_1][iDim] - Partial_Res; + } + } + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + Point = geometry->vertex[iMarker][iVertex]->GetNode(); + Solution_Vertex = ConsVar_Sol[Point][0]; + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + for (iDim = 0; iDim < nDim; iDim++) { + Partial_Res = Solution_Vertex*Normal[iDim]; + Gradient[Point][iDim] = Gradient[Point][iDim] - Partial_Res; + } + } + + for (iPoint = 0; iPointGetnPoint(); iPoint++) + for (iDim = 0; iDim < nDim; iDim++) { + DualArea = geometry->node[iPoint]->GetVolume(); + Grad_Val = Gradient[iPoint][iDim]/DualArea; + Gradient[iPoint][iDim] = Grad_Val; + } + + /*--- Compute the the adaptation index at each point ---*/ + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { + Dual_Area = geometry->node[iPoint]->GetVolume(); + norm = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + norm += Gradient[iPoint][iDim]*Gradient[iPoint][iDim]; + norm = sqrt(norm); + Index[iPoint] = pow(Dual_Area, scale_area)*norm; + } + + SetSensorElem(geometry, config, max_elem_new); +} + + +void CGridAdaptation::SetIndicator_Adj(CGeometry *geometry, CConfig *config, unsigned short strength) { + su2double Dual_Area; + unsigned long Point = 0, Point_0 = 0, Point_1 = 0, iEdge, iVertex, iPoint, iElem, max_elem_new; + unsigned short iDim, iMarker; + su2double norm, Solution_Vertex, Solution_0, Solution_1, Solution_Average, + DualArea, Partial_Res, Grad_Val, *Normal; + su2double scale_area = config->GetDualVol_Power(); + + // Initialization + nElem_new = 0; + max_elem_new = SU2_TYPE::Int(0.01*config->GetNew_Elem_Adapt()*su2double(geometry->GetnElem())); + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + geometry->elem[iElem]->SetDivide(false); + } + + + // Compute the gradient of the density. + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + for (iDim = 0; iDim < nDim; iDim++) + Gradient[iPoint][iDim] = 0.0; + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + Point_0 = geometry->edge[iEdge]->GetNode(0); Solution_0 = AdjVar_Sol[Point_0][0]; + Point_1 = geometry->edge[iEdge]->GetNode(1); Solution_1 = AdjVar_Sol[Point_1][0]; + Normal = geometry->edge[iEdge]->GetNormal(); + Solution_Average = 0.5 * ( Solution_0 + Solution_1); + for (iDim = 0; iDim < nDim; iDim++) { + Partial_Res = Solution_Average*Normal[iDim]; + Gradient[Point_0][iDim] = Gradient[Point_0][iDim] + Partial_Res; + Gradient[Point_1][iDim] = Gradient[Point_1][iDim] - Partial_Res; + } + } + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + Point = geometry->vertex[iMarker][iVertex]->GetNode(); + Solution_Vertex = AdjVar_Sol[Point][0]; + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + for (iDim = 0; iDim < nDim; iDim++) { + Partial_Res = Solution_Vertex*Normal[iDim]; + Gradient[Point][iDim] = Gradient[Point][iDim] - Partial_Res; + } + } + + for (iPoint = 0; iPointGetnPoint(); iPoint++) + for (iDim = 0; iDim < nDim; iDim++) { + DualArea = geometry->node[iPoint]->GetVolume(); + Grad_Val = Gradient[iPoint][iDim]/DualArea; + Gradient[iPoint][iDim] = Grad_Val; + } + + + // Compute the the adaptation index at each point. + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { + Dual_Area = geometry->node[iPoint]->GetVolume(); + norm = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + norm += Gradient[iPoint][iDim]*Gradient[iPoint][iDim]; + norm = sqrt(norm); + Index[iPoint] = pow(Dual_Area, scale_area)*norm; + } + + SetSensorElem(geometry, config, max_elem_new); + +} + +void CGridAdaptation::SetIndicator_FlowAdj(CGeometry *geometry, CConfig *config) { + su2double Dual_Area; + unsigned long Point = 0, Point_0 = 0, Point_1 = 0, iEdge, iVertex, iPoint, iElem, max_elem_new_flow, max_elem_new_adj; + unsigned short iDim, iMarker; + su2double norm, DualArea, Partial_Res, *Normal; + su2double scale_area = config->GetDualVol_Power(); + + // Initialization + max_elem_new_flow = SU2_TYPE::Int(0.5*0.01*config->GetNew_Elem_Adapt()*su2double(geometry->GetnElem())); + max_elem_new_adj = SU2_TYPE::Int(0.5*0.01*config->GetNew_Elem_Adapt()*su2double(geometry->GetnElem())); + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + geometry->elem[iElem]->SetDivide(false); + } + + // Compute the gradient of the first variable. + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + for (iDim = 0; iDim < nDim; iDim++) { + Gradient_Flow[iPoint][iDim] = 0.0; + Gradient_Adj[iPoint][iDim] = 0.0; + } + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + Point_0 = geometry->edge[iEdge]->GetNode(0); + Point_1 = geometry->edge[iEdge]->GetNode(1); + Normal = geometry->edge[iEdge]->GetNormal(); + for (iDim = 0; iDim < nDim; iDim++) { + Partial_Res = 0.5 * ( ConsVar_Sol[Point_0][0] + ConsVar_Sol[Point_1][0] ) * Normal[iDim]; + Gradient_Flow[Point_0][iDim] = Gradient_Flow[Point_0][iDim] + Partial_Res; + Gradient_Flow[Point_1][iDim] = Gradient_Flow[Point_1][iDim] - Partial_Res; + + Partial_Res = 0.5 * ( AdjVar_Sol[Point_0][0] + AdjVar_Sol[Point_1][0] ) * Normal[iDim]; + Gradient_Adj[Point_0][iDim] = Gradient_Adj[Point_0][iDim] + Partial_Res; + Gradient_Adj[Point_1][iDim] = Gradient_Adj[Point_1][iDim] - Partial_Res; + } + } + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + Point = geometry->vertex[iMarker][iVertex]->GetNode(); + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + for (iDim = 0; iDim < nDim; iDim++) { + Gradient_Flow[Point][iDim] = Gradient_Flow[Point][iDim] - ConsVar_Sol[Point][0] * Normal[iDim]; + Gradient_Adj[Point][iDim] = Gradient_Adj[Point][iDim] - AdjVar_Sol[Point][0] * Normal[iDim]; + } + } + + for (iPoint = 0; iPointGetnPoint(); iPoint++) + for (iDim = 0; iDim < nDim; iDim++) { + DualArea = geometry->node[iPoint]->GetVolume(); + Gradient_Flow[iPoint][iDim] = Gradient_Flow[iPoint][iDim]/DualArea; + Gradient_Adj[iPoint][iDim] = Gradient_Adj[iPoint][iDim]/DualArea; + } + + // Compute the the adaptation index at each point. + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { + Dual_Area=geometry->node[iPoint]->GetVolume(); + norm = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + norm += Gradient_Flow[iPoint][iDim]*Gradient_Flow[iPoint][iDim]; + norm = sqrt(norm); + Index[iPoint] = pow(Dual_Area, scale_area)*norm; + } + + + SetSensorElem(geometry, config, max_elem_new_flow); + + // Compute the the adaptation index at each point. + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { + Dual_Area=geometry->node[iPoint]->GetVolume(); + norm = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + norm += Gradient_Adj[iPoint][iDim]*Gradient_Adj[iPoint][iDim]; + norm = sqrt(norm); + Index[iPoint] = pow(Dual_Area, scale_area)*norm; + } + + SetSensorElem(geometry, config, max_elem_new_adj); + +} + +void CGridAdaptation::SetIndicator_Robust(CGeometry *geometry, CConfig *config) { + unsigned long iPoint, iElem, max_elem_new_flow, max_elem_new_adj; + unsigned short iVar; + su2double Dual_Area; + su2double scale_area = config->GetDualVol_Power(); + + // Inicializa la malla para la adaptacion + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + geometry->elem[iElem]->SetDivide (false); + } + + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { + Dual_Area = geometry->node[iPoint]->GetVolume(); + Index[iPoint] = 0.0; + for (iVar = 0; iVar < nVar; iVar++) + Index[iPoint] += ConsVar_Res[iPoint][iVar]*ConsVar_Res[iPoint][iVar]; + + Index[iPoint] = pow(Dual_Area, scale_area)*sqrt(Index[iPoint]); + } + + max_elem_new_flow = SU2_TYPE::Int(0.5*0.01*config->GetNew_Elem_Adapt()*su2double(geometry->GetnElem())); + SetSensorElem(geometry, config, max_elem_new_flow); + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { + Dual_Area = geometry->node[iPoint]->GetVolume(); + Index[iPoint] = 0.0; + for (iVar = 0; iVar < nVar; iVar++) + Index[iPoint] += AdjVar_Res[iPoint][iVar]*AdjVar_Res[iPoint][iVar]; + + Index[iPoint] = pow(Dual_Area, scale_area)*sqrt(Index[iPoint]); + } + + max_elem_new_adj = SU2_TYPE::Int(0.5*0.01*config->GetNew_Elem_Adapt()*su2double(geometry->GetnElem())); + SetSensorElem(geometry, config, max_elem_new_adj); + +} + +void CGridAdaptation::SetIndicator_Computable(CGeometry *geometry, CConfig *config) { + unsigned long iPoint, iElem, max_elem_new; + unsigned short iVar; + su2double Dual_Area; + su2double scale_area = config->GetDualVol_Power(); + + max_elem_new = SU2_TYPE::Int(0.01*config->GetNew_Elem_Adapt()*su2double(geometry->GetnElem())); + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + geometry->elem[iElem]->SetDivide (false); + } + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { + Dual_Area = geometry->node[iPoint]->GetVolume(); + Index[iPoint] = 0.0; + for (iVar = 0; iVar < nVar; iVar++) + Index[iPoint] += ConsVar_Res[iPoint][iVar]*AdjVar_Sol[iPoint][iVar]*ConsVar_Res[iPoint][iVar]*AdjVar_Sol[iPoint][iVar]; + + Index[iPoint] = pow(Dual_Area, scale_area)*sqrt(Index[iPoint]); + } + + SetSensorElem(geometry, config, max_elem_new); + +} + +void CGridAdaptation::SetIndicator_Computable_Robust(CGeometry *geometry, CConfig *config) { + unsigned long iPoint, iElem, max_elem_new; + unsigned short iVar; + su2double Dual_Area ; + su2double scale_area = config->GetDualVol_Power(); + + /*--- Initializate the numerical grid for the adaptation ---*/ + max_elem_new = SU2_TYPE::Int(0.01*config->GetNew_Elem_Adapt()*su2double(geometry->GetnElem())); + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + geometry->elem[iElem]->SetDivide (false); + } + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { + Dual_Area = geometry->node[iPoint]->GetVolume(); + Index[iPoint] = 0.0; + for (iVar = 0; iVar < nVar; iVar++) + Index[iPoint] += LinVar_Res[iPoint][iVar]*AdjVar_Sol[iPoint][iVar]*LinVar_Res[iPoint][iVar]*AdjVar_Sol[iPoint][iVar]; + + Index[iPoint] = pow(Dual_Area, scale_area)*sqrt(Index[iPoint]); + } + + SetSensorElem(geometry, config, max_elem_new); + +} + +void CGridAdaptation::SetRestart_FlowSolution(CConfig *config, CPhysicalGeometry *geo_adapt, string mesh_flowfilename) { + + unsigned long iPoint; + unsigned short iVar, iDim; + + char *cstr = new char [mesh_flowfilename.size()+1]; + strcpy (cstr, mesh_flowfilename.c_str()); + + ofstream restart_flowfile; + restart_flowfile.open(cstr, ios::out); + restart_flowfile.precision(15); + + restart_flowfile << "Restart file generated with SU2_MSH" << endl; + + for (iPoint = 0; iPoint < nPoint_new; iPoint++) { + restart_flowfile << iPoint <<"\t"; + + for (iDim = 0; iDim < nDim; iDim++) + restart_flowfile << scientific << geo_adapt->node[iPoint]->GetCoord(iDim) <<"\t"; + for (iVar = 0; iVar < nVar; iVar++) + restart_flowfile << scientific << ConsVar_Adapt[iPoint][iVar] <<"\t"; + + restart_flowfile << endl; + } + restart_flowfile.close(); + +} + +void CGridAdaptation::SetRestart_AdjSolution(CConfig *config, CPhysicalGeometry *geo_adapt, string mesh_adjfilename) { + + char cstr[MAX_STRING_SIZE], buffer[50]; + unsigned short iDim, iVar; + unsigned long iPoint; + string copy; + + copy.assign(mesh_adjfilename); + unsigned short lastindex = copy.find_last_of("."); + copy = copy.substr(0, lastindex); + strcpy (cstr, copy.c_str()); + if (config->GetKind_ObjFunc() == DRAG_COEFFICIENT) SPRINTF (buffer, "_cd.dat"); + if (config->GetKind_ObjFunc() == LIFT_COEFFICIENT) SPRINTF (buffer, "_cl.dat"); + if (config->GetKind_ObjFunc() == SIDEFORCE_COEFFICIENT) SPRINTF (buffer, "_csf.dat"); + if (config->GetKind_ObjFunc() == INVERSE_DESIGN_PRESSURE) SPRINTF (buffer, "_invpress.dat"); + if (config->GetKind_ObjFunc() == INVERSE_DESIGN_HEATFLUX) SPRINTF (buffer, "_invheat.dat"); + if (config->GetKind_ObjFunc() == MOMENT_X_COEFFICIENT) SPRINTF (buffer, "_cmx.dat"); + if (config->GetKind_ObjFunc() == MOMENT_Y_COEFFICIENT) SPRINTF (buffer, "_cmy.dat"); + if (config->GetKind_ObjFunc() == MOMENT_Z_COEFFICIENT) SPRINTF (buffer, "_cmz.dat"); + if (config->GetKind_ObjFunc() == EFFICIENCY) SPRINTF (buffer, "_eff.dat"); + if (config->GetKind_ObjFunc() == FORCE_X_COEFFICIENT) SPRINTF (buffer, "_cfx.dat"); + if (config->GetKind_ObjFunc() == FORCE_Y_COEFFICIENT) SPRINTF (buffer, "_cfy.dat"); + if (config->GetKind_ObjFunc() == FORCE_Z_COEFFICIENT) SPRINTF (buffer, "_cfz.dat"); + if (config->GetKind_ObjFunc() == TOTAL_HEATFLUX) SPRINTF (buffer, "_totheat.dat"); + if (config->GetKind_ObjFunc() == MAXIMUM_HEATFLUX) SPRINTF (buffer, "_maxheat.dat"); + if (config->GetKind_ObjFunc() == AVG_TOTAL_PRESSURE) SPRINTF (buffer, "_pt.dat"); + if (config->GetKind_ObjFunc() == AVG_OUTLET_PRESSURE) SPRINTF (buffer, "_pe.dat"); + if (config->GetKind_ObjFunc() == MASS_FLOW_RATE) SPRINTF (buffer, "_mfr.dat"); + if (config->GetKind_ObjFunc() == OUTLET_CHAIN_RULE) SPRINTF (buffer, "_chn.dat"); + + strcat(cstr, buffer); + + ofstream restart_adjfile; + restart_adjfile.open(cstr, ios::out); + restart_adjfile.precision(15); + + restart_adjfile << "Restart file generated with SU2_MSH" << endl; + + for (iPoint = 0; iPoint < nPoint_new; iPoint++) { + restart_adjfile << iPoint <<"\t"; + + for (iDim = 0; iDim < nDim; iDim++) + restart_adjfile << scientific << geo_adapt->node[iPoint]->GetCoord(iDim) <<"\t"; + for (iVar = 0; iVar < nVar; iVar++) + restart_adjfile << scientific << AdjVar_Adapt[iPoint][iVar]<<"\t"; + restart_adjfile << endl; + + } + restart_adjfile.close(); +} + +void CGridAdaptation::SetRestart_LinSolution(CConfig *config, CPhysicalGeometry *geo_adapt, string mesh_linfilename) { + + unsigned long iPoint; + unsigned short iVar, iDim; + + char *cstr_ = new char [mesh_linfilename.size()+1]; + strcpy (cstr_, mesh_linfilename.c_str()); + + ofstream restart_linfile; + restart_linfile.open(cstr_, ios::out); + restart_linfile.precision(15); + + restart_linfile << "Restart file generated with SU2_MSH" << endl; + + for (iPoint = 0; iPoint < nPoint_new; iPoint++) { + restart_linfile << iPoint <<"\t"; + + for (iDim = 0; iDim < nDim; iDim++) + restart_linfile << scientific << geo_adapt->node[iPoint]->GetCoord(iDim) <<"\t"; + for (iVar = 0; iVar < nVar; iVar++) + restart_linfile << scientific << LinVar_Adapt[iPoint][iVar]<<"\t"; + restart_linfile << endl; + + } + restart_linfile.close(); +} + +void CGridAdaptation::SetSensorElem(CGeometry *geometry, CConfig *config, unsigned long max_elem) { + su2double Max_Sensor, threshold; + su2double *Sensor = new su2double[geometry->GetnElem()]; + unsigned long ip_0, ip_1, ip_2, ip_3, iElem, nElem_real; + + /*--- Compute the the adaptation index at each element ---*/ + Max_Sensor = 0.0; + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + ip_0 = geometry->elem[iElem]->GetNode(0); + ip_1 = geometry->elem[iElem]->GetNode(1); + ip_2 = geometry->elem[iElem]->GetNode(2); + Sensor[iElem] = (Index[ip_0]+Index[ip_1]+Index[ip_2])/3.0; + if ((geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) || + (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON)) { + ip_3 = geometry->elem[iElem]->GetNode(2); + Sensor[iElem] = (Index[ip_0]+Index[ip_1]+Index[ip_2]+Index[ip_3])/4.0; + } + Max_Sensor = max(Max_Sensor, Sensor[iElem]); + } + + /*--- Adimensionalization of the adaptation sensor ---*/ + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) { + Sensor[iElem] = Sensor[iElem]/Max_Sensor; + } + + /*--- Selection of the elements to be adapted ---*/ + threshold = 0.999; + nElem_real = 0; + while (nElem_real <= max_elem) { + for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) + if ( Sensor[iElem] >= threshold && !geometry->elem[iElem]->GetDivide() ) { + if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) nElem_real = nElem_real + 3; + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) nElem_real = nElem_real + 3; + if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) nElem_real = nElem_real + 7; + geometry->elem[iElem]->SetDivide(true); + if (nElem_real >= max_elem) break; + } + threshold = threshold - 0.001; + } + + cout << "Number of elements to adapt: " << nElem_real << endl; + delete [] Sensor; +} diff --git a/Common/src/grid_movement_structure.cpp b/Common/src/grid_movement_structure.cpp index ae87f20dcf3..9acc8991a99 100644 --- a/Common/src/grid_movement_structure.cpp +++ b/Common/src/grid_movement_structure.cpp @@ -1,7559 +1,7559 @@ -/*! - * \file grid_movement_structure.cpp - * \brief Subroutines for doing the grid movement using different strategies - * \author F. Palacios, T. Economon, S. Padron - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#include "../include/grid_movement_structure.hpp" -#include - -using namespace std; - -CGridMovement::CGridMovement(void) { } - -CGridMovement::~CGridMovement(void) { } - -CVolumetricMovement::CVolumetricMovement(CGeometry *geometry, CConfig *config) : CGridMovement() { - - /*--- Initialize the number of spatial dimensions, length of the state - vector (same as spatial dimensions for grid deformation), and grid nodes. ---*/ - - nDim = geometry->GetnDim(); - nVar = geometry->GetnDim(); - nPoint = geometry->GetnPoint(); - nPointDomain = geometry->GetnPointDomain(); - - /*--- Initialize matrix, solution, and r.h.s. structures for the linear solver. ---*/ - - config->SetKind_Linear_Solver_Prec(LU_SGS); - LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); - StiffMatrix.Initialize(nPoint, nPointDomain, nVar, nVar, false, geometry, config); - -} - -CVolumetricMovement::~CVolumetricMovement(void) { - - -} - - -void CVolumetricMovement::UpdateGridCoord(CGeometry *geometry, CConfig *config) { - - unsigned short iDim; - unsigned long iPoint, total_index; - su2double new_coord; - - /*--- Update the grid coordinates using the solution of the linear system - after grid deformation (LinSysSol contains the x, y, z displacements). ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint*nDim + iDim; - new_coord = geometry->node[iPoint]->GetCoord(iDim)+LinSysSol[total_index]; - if (fabs(new_coord) < EPS*EPS) new_coord = 0.0; - geometry->node[iPoint]->SetCoord(iDim, new_coord); - } - -} - -void CVolumetricMovement::UpdateDualGrid(CGeometry *geometry, CConfig *config) { - - /*--- After moving all nodes, update the dual mesh. Recompute the edges and - dual mesh control volumes in the domain and on the boundaries. ---*/ - - geometry->SetCoord_CG(); - geometry->SetControlVolume(config, UPDATE); - geometry->SetBoundControlVolume(config, UPDATE); - -} - -void CVolumetricMovement::UpdateMultiGrid(CGeometry **geometry, CConfig *config) { - - unsigned short iMGfine, iMGlevel, nMGlevel = config->GetnMGLevels(); - - /*--- Update the multigrid structure after moving the finest grid, - including computing the grid velocities on the coarser levels. ---*/ - - for (iMGlevel = 1; iMGlevel <= nMGlevel; iMGlevel++) { - iMGfine = iMGlevel-1; - geometry[iMGlevel]->SetControlVolume(config, geometry[iMGfine], UPDATE); - geometry[iMGlevel]->SetBoundControlVolume(config, geometry[iMGfine],UPDATE); - geometry[iMGlevel]->SetCoord(geometry[iMGfine]); - if (config->GetGrid_Movement()) - geometry[iMGlevel]->SetRestricted_GridVelocity(geometry[iMGfine], config); - } - -} - -void CVolumetricMovement::SetVolume_Deformation(CGeometry *geometry, CConfig *config, bool UpdateGeo, bool Derivative) { - - unsigned long IterLinSol = 0, Smoothing_Iter, iNonlinear_Iter, MaxIter = 0, RestartIter = 50, Tot_Iter = 0, Nonlinear_Iter = 0; - unsigned long iPoint, iDim; - su2double MinVolume, NumError, Tol_Factor, Residual = 0.0, Residual_Init = 0.0; - bool Screen_Output; - bool fsi=config->GetFSI_Simulation(); - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Retrieve number or iterations, tol, output, etc. from config ---*/ - - Smoothing_Iter = config->GetGridDef_Linear_Iter(); - Screen_Output = config->GetDeform_Output(); - Tol_Factor = config->GetDeform_Tol_Factor(); - Nonlinear_Iter = config->GetGridDef_Nonlinear_Iter(); - - /*--- Disable the screen output if we're running SU2_CFD ---*/ - - if (config->GetKind_SU2() == SU2_CFD && !Derivative) Screen_Output = false; - - /*--- Set the number of nonlinear iterations to 1 if Derivative computation is enabled ---*/ - - if (Derivative) Nonlinear_Iter = 1; - - /*--- Loop over the total number of grid deformation iterations. The surface - deformation can be divided into increments to help with stability. In - particular, the linear elasticity equations hold only for small deformations. ---*/ - - for (iNonlinear_Iter = 0; iNonlinear_Iter < Nonlinear_Iter; iNonlinear_Iter++) { - - /*--- Initialize vector and sparse matrix ---*/ - - LinSysSol.SetValZero(); - LinSysRes.SetValZero(); - StiffMatrix.SetValZero(); - - /*--- Compute the stiffness matrix entries for all nodes/elements in the - mesh. FEA uses a finite element method discretization of the linear - elasticity equations (transfers element stiffnesses to point-to-point). ---*/ - - MinVolume = SetFEAMethodContributions_Elem(geometry, config); - - /*--- Compute the tolerance of the linear solver using MinLength ---*/ - - NumError = MinVolume * Tol_Factor; - - /*--- Set the boundary displacements (as prescribed by the design variable - perturbations controlling the surface shape) as a Dirichlet BC. ---*/ - - SetBoundaryDisplacements(geometry, config); - - /*--- Set the boundary derivatives (overrides the actual displacements) ---*/ - - if (Derivative){ - SetBoundaryDerivatives(geometry, config); - } - - /*--- Fix the location of any points in the domain, if requested. ---*/ - - if (config->GetHold_GridFixed()) - SetDomainDisplacements(geometry, config); - - CMatrixVectorProduct* mat_vec = NULL; - CPreconditioner* precond = NULL; - - /*--- Communicate any prescribed boundary displacements via MPI, - so that all nodes have the same solution and r.h.s. entries - across all partitions. ---*/ - - StiffMatrix.SendReceive_Solution(LinSysSol, geometry, config); - StiffMatrix.SendReceive_Solution(LinSysRes, geometry, config); - - /*--- Definition of the preconditioner matrix vector multiplication, and linear solver ---*/ - - /*--- If we want no derivatives or the direct derivatives, - * we solve the system using the normal matrix vector product and preconditioner. - * For the mesh sensitivities using the discrete adjoint method we solve the system using the transposed matrix, - * hence we need the corresponding matrix vector product and the preconditioner. ---*/ - if (!Derivative || ((config->GetKind_SU2() == SU2_CFD) && Derivative)){ - mat_vec = new CSysMatrixVectorProduct(StiffMatrix, geometry, config); - precond = new CLU_SGSPreconditioner(StiffMatrix, geometry, config); - - } else if (Derivative && (config->GetKind_SU2() == SU2_DOT)) { - /*--- Build the ILU preconditioner for the transposed system ---*/ - - StiffMatrix.BuildILUPreconditioner(true); - mat_vec = new CSysMatrixVectorProductTransposed(StiffMatrix, geometry, config); - precond = new CILUPreconditioner(StiffMatrix, geometry, config); - } - - CSysSolve *system = new CSysSolve(); - - switch (config->GetDeform_Linear_Solver()) { - - /*--- Solve the linear system (GMRES with restart) ---*/ - - case RESTARTED_FGMRES: - - Tot_Iter = 0; MaxIter = RestartIter; - - system->FGMRES_LinSolver(LinSysRes, LinSysSol, *mat_vec, *precond, NumError, 1, &Residual_Init, false); - - if ((rank == MASTER_NODE) && Screen_Output) { - cout << "\n# FGMRES (with restart) residual history" << endl; - cout << "# Residual tolerance target = " << NumError << endl; - cout << "# Initial residual norm = " << Residual_Init << endl; - } - - if (rank == MASTER_NODE) { cout << " " << Tot_Iter << " " << Residual_Init/Residual_Init << endl; } - - while (Tot_Iter < Smoothing_Iter) { - - if (IterLinSol + RestartIter > Smoothing_Iter) - MaxIter = Smoothing_Iter - IterLinSol; - - IterLinSol = system->FGMRES_LinSolver(LinSysRes, LinSysSol, *mat_vec, *precond, NumError, MaxIter, &Residual, false); - Tot_Iter += IterLinSol; - - if ((rank == MASTER_NODE) && Screen_Output) { cout << " " << Tot_Iter << " " << Residual/Residual_Init << endl; } - - if (Residual < Residual_Init*NumError) { break; } - - } - - if ((rank == MASTER_NODE) && Screen_Output) { - cout << "# FGMRES (with restart) final (true) residual:" << endl; - cout << "# Iteration = " << Tot_Iter << ": |res|/|res0| = " << Residual/Residual_Init << ".\n" << endl; - } - - break; - - /*--- Solve the linear system (GMRES) ---*/ - - case FGMRES: - - Tot_Iter = system->FGMRES_LinSolver(LinSysRes, LinSysSol, *mat_vec, *precond, NumError, Smoothing_Iter, &Residual, Screen_Output); - - break; - - /*--- Solve the linear system (BCGSTAB) ---*/ - - case BCGSTAB: - - Tot_Iter = system->BCGSTAB_LinSolver(LinSysRes, LinSysSol, *mat_vec, *precond, NumError, Smoothing_Iter, &Residual, Screen_Output); - - break; - - } - - /*--- Deallocate memory needed by the Krylov linear solver ---*/ - - delete system; - delete mat_vec; - delete precond; - - /*--- Update the grid coordinates and cell volumes using the solution - of the linear system (usol contains the x, y, z displacements). ---*/ - - if (!Derivative){ - UpdateGridCoord(geometry, config); - }else{ - UpdateGridCoord_Derivatives(geometry, config); - } - - if (UpdateGeo) - UpdateDualGrid(geometry, config); - - /*--- Check for failed deformation (negative volumes). ---*/ - - MinVolume = Check_Grid(geometry); - - if (rank == MASTER_NODE) { - cout << "Non-linear iter.: " << iNonlinear_Iter+1 << "/" << Nonlinear_Iter - << ". Linear iter.: " << Tot_Iter << ". "; - if (nDim == 2) cout << "Min. area: " << MinVolume << ". Error: " << Residual << "." << endl; - else cout << "Min. volume: " << MinVolume << ". Error: " << Residual << "." << endl; - } - - } - - if (fsi){ - /*--- Grid velocity (there is a function that does this -> Modify) ---*/ - - /*--- Local variables ---*/ - - su2double *Coord_nP1 = NULL, *Coord_n = NULL, *Coord_nM1 = NULL; - su2double TimeStep, GridVel = 0.0; - - /*--- Compute the velocity of each node in the volume mesh ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - - /*--- Coordinates of the current point at n+1, n, & n-1 time levels ---*/ - - Coord_nM1 = geometry->node[iPoint]->GetCoord_n1(); - Coord_n = geometry->node[iPoint]->GetCoord_n(); - Coord_nP1 = geometry->node[iPoint]->GetCoord(); - - /*--- Unsteady time step ---*/ - - TimeStep = config->GetDelta_UnstTimeND(); - - /*--- Compute mesh velocity with 1st or 2nd-order approximation ---*/ - - for(iDim = 0; iDim < nDim; iDim++) { - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - GridVel = ( Coord_nP1[iDim] - Coord_n[iDim] ) / TimeStep; - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - GridVel = ( 3.0*Coord_nP1[iDim] - 4.0*Coord_n[iDim] - + 1.0*Coord_nM1[iDim] ) / (2.0*TimeStep); - - /*--- Store grid velocity for this point ---*/ - - geometry->node[iPoint]->SetGridVel(iDim, GridVel); - } - } - - } - - -} - -su2double CVolumetricMovement::Check_Grid(CGeometry *geometry) { - - unsigned long iElem, ElemCounter = 0, PointCorners[8]; - su2double Area = 0.0, Volume = 0.0, MaxArea = -1E22, MaxVolume = -1E22, MinArea = 1E22, MinVolume = 1E22, CoordCorners[8][3]; - unsigned short nNodes = 0, iNodes, iDim; - bool RightVol = true; - - int rank = MASTER_NODE; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Load up each triangle and tetrahedron to check for negative volumes. ---*/ - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) nNodes = 3; - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) nNodes = 4; - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) nNodes = 4; - if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) nNodes = 5; - if (geometry->elem[iElem]->GetVTK_Type() == PRISM) nNodes = 6; - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) nNodes = 8; - - for (iNodes = 0; iNodes < nNodes; iNodes++) { - PointCorners[iNodes] = geometry->elem[iElem]->GetNode(iNodes); - for (iDim = 0; iDim < nDim; iDim++) { - CoordCorners[iNodes][iDim] = geometry->node[PointCorners[iNodes]]->GetCoord(iDim); - } - } - - /*--- Triangles ---*/ - - if (nDim == 2) { - - if (nNodes == 3) Area = GetTriangle_Area(CoordCorners); - if (nNodes == 4) Area = GetQuadrilateral_Area(CoordCorners); - - if (Area >= -EPS) RightVol = true; - else RightVol = false;; - - MaxArea = max(MaxArea, Area); - MinArea = min(MinArea, Area); - - } - - /*--- Tetrahedra ---*/ - - if (nDim == 3) { - - if (nNodes == 4) Volume = GetTetra_Volume(CoordCorners); - if (nNodes == 5) Volume = GetPyram_Volume(CoordCorners); - if (nNodes == 6) Volume = GetPrism_Volume(CoordCorners); - if (nNodes == 8) Volume = GetHexa_Volume(CoordCorners); - - if (Volume >= -EPS) RightVol = true; - else RightVol = false;; - - MaxVolume = max(MaxVolume, Volume); - MinVolume = min(MinVolume, Volume); - - } - - if (!RightVol) ElemCounter++; - - } - -#ifdef HAVE_MPI - unsigned long ElemCounter_Local = ElemCounter; ElemCounter = 0; - su2double MaxVolume_Local = MaxVolume; MaxVolume = 0.0; - su2double MinVolume_Local = MinVolume; MinVolume = 0.0; - SU2_MPI::Allreduce(&ElemCounter_Local, &ElemCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MaxVolume_Local, &MaxVolume, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MinVolume_Local, &MinVolume, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); -#endif - - if ((ElemCounter != 0) && (rank == MASTER_NODE)) - cout <<"There are " << ElemCounter << " elements with negative volume.\n" << endl; - - if (nDim == 2) return MinArea; - else return MinVolume; - -} - -void CVolumetricMovement::ComputeDeforming_Wall_Distance(CGeometry *geometry, CConfig *config) { - - su2double *coord, dist2, dist; - unsigned short iDim, iMarker; - unsigned long iPoint, iVertex, nVertex_SolidWall; - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - if (rank == MASTER_NODE) - cout << "Computing distances to the nearest deforming surface." << endl; - - /*--- Get the SU2 module. SU2_CFD will use this routine for dynamically - deforming meshes (MARKER_MOVING), while SU2_DEF will use it for deforming - meshes after imposing design variable surface deformations (DV_MARKER). ---*/ - - unsigned short Kind_SU2 = config->GetKind_SU2(); - -#ifndef HAVE_MPI - - /*--- Compute the total number of nodes on deforming boundaries ---*/ - - nVertex_SolidWall = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_CFD)) || - ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DEF))) - nVertex_SolidWall += geometry->GetnVertex(iMarker); - - /*--- Allocate an array to hold boundary node coordinates ---*/ - - su2double **Coord_bound; - Coord_bound = new su2double* [nVertex_SolidWall]; - for (iVertex = 0; iVertex < nVertex_SolidWall; iVertex++) - Coord_bound[iVertex] = new su2double [nDim]; - - /*--- Retrieve and store the coordinates of the deforming boundary nodes ---*/ - - nVertex_SolidWall = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_CFD)) || - ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DEF))) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - for (iDim = 0; iDim < nDim; iDim++) - Coord_bound[nVertex_SolidWall][iDim] = geometry->node[iPoint]->GetCoord(iDim); - nVertex_SolidWall++; - } - } - - /*--- Loop over all interior mesh nodes and compute the distances to each - of the deforming boundary nodes. Store the minimum distance to the wall for - each interior mesh node. Store the global minimum distance. ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - coord = geometry->node[iPoint]->GetCoord(); - dist = 1E20; - for (iVertex = 0; iVertex < nVertex_SolidWall; iVertex++) { - dist2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - dist2 += (coord[iDim]-Coord_bound[iVertex][iDim]) - *(coord[iDim]-Coord_bound[iVertex][iDim]); - if (dist2 < dist) dist = dist2; - } - geometry->node[iPoint]->SetWall_Distance(sqrt(dist)); - } - - /*--- Deallocate the vector of boundary coordinates. ---*/ - - for (iVertex = 0; iVertex < nVertex_SolidWall; iVertex++) - delete[] Coord_bound[iVertex]; - delete[] Coord_bound; - - -#else - - /*--- Variables and buffers needed for MPI ---*/ - - int iProcessor, nProcessor; - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); - - unsigned long nLocalVertex_NS = 0, nGlobalVertex_NS = 0, MaxLocalVertex_NS = 0; - unsigned long *Buffer_Send_nVertex = new unsigned long [1]; - unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor]; - - /*--- Count the total number of nodes on deforming boundaries within the - local partition. ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_CFD)) || - ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DEF))) - nLocalVertex_NS += geometry->GetnVertex(iMarker); - - /*--- Communicate to all processors the total number of deforming boundary - nodes, the maximum number of deforming boundary nodes on any single - partition, and the number of deforming nodes on each partition. ---*/ - - Buffer_Send_nVertex[0] = nLocalVertex_NS; - SU2_MPI::Allreduce(&nLocalVertex_NS, &nGlobalVertex_NS, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalVertex_NS, &MaxLocalVertex_NS, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - - /*--- Create and initialize to zero some buffers to hold the coordinates - of the boundary nodes that are communicated from each partition (all-to-all). ---*/ - - su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_NS*nDim]; - su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_NS*nDim]; - unsigned long nBuffer = MaxLocalVertex_NS*nDim; - - for (iVertex = 0; iVertex < MaxLocalVertex_NS; iVertex++) - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; - - /*--- Retrieve and store the coordinates of the deforming boundary nodes on - the local partition and broadcast them to all partitions. ---*/ - - nVertex_SolidWall = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_CFD)) || - ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DEF))) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[nVertex_SolidWall*nDim+iDim] = geometry->node[iPoint]->GetCoord(iDim); - nVertex_SolidWall++; - } - - SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer, MPI_DOUBLE, MPI_COMM_WORLD); - - /*--- Loop over all interior mesh nodes on the local partition and compute - the distances to each of the deforming boundary nodes in the entire mesh. - Store the minimum distance to the wall for each interior mesh node. ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - coord = geometry->node[iPoint]->GetCoord(); - dist = 1E20; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) - for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { - dist2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - dist2 += (coord[iDim]-Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_NS+iVertex)*nDim+iDim])* - (coord[iDim]-Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_NS+iVertex)*nDim+iDim]); - if (dist2 < dist) dist = dist2; - } - geometry->node[iPoint]->SetWall_Distance(sqrt(dist)); - } - - /*--- Deallocate the buffers needed for the MPI communication. ---*/ - - delete[] Buffer_Send_Coord; - delete[] Buffer_Receive_Coord; - delete[] Buffer_Send_nVertex; - delete[] Buffer_Receive_nVertex; - -#endif - -} - -su2double CVolumetricMovement::SetFEAMethodContributions_Elem(CGeometry *geometry, CConfig *config) { - - unsigned short iVar, iDim, nNodes = 0, iNodes, StiffMatrix_nElem = 0; - unsigned long Point_0, Point_1, iElem, iEdge, ElemCounter = 0, PointCorners[8]; - su2double *Coord_0, *Coord_1, Length, MinLength = 1E10, **StiffMatrix_Elem = NULL, Scale, CoordCorners[8][3]; - su2double *Edge_Vector = new su2double [nDim]; - - /*--- Allocate maximum size (quadrilateral and hexahedron) ---*/ - - if (nDim == 2) StiffMatrix_nElem = 8; - else StiffMatrix_nElem = 24; - - StiffMatrix_Elem = new su2double* [StiffMatrix_nElem]; - for (iVar = 0; iVar < StiffMatrix_nElem; iVar++) - StiffMatrix_Elem[iVar] = new su2double [StiffMatrix_nElem]; - - /*--- Check the minimum edge length in the entire mesh. ---*/ - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Points in edge and coordinates ---*/ - - Point_0 = geometry->edge[iEdge]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); - Point_1 = geometry->edge[iEdge]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); - - /*--- Compute Edge_Vector ---*/ - - Length = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Edge_Vector[iDim] = Coord_1[iDim] - Coord_0[iDim]; - Length += Edge_Vector[iDim]*Edge_Vector[iDim]; - } - Length = sqrt(Length); - MinLength = min(Length, MinLength); - - } - - /*--- Compute min volume in the entire mesh. ---*/ - - Scale = Check_Grid(geometry); - - /*--- Compute the distance to the nearest deforming surface if needed - as part of the stiffness calculation. In this case, we can scale based - on the minimum edge length. ---*/ - - if (config->GetDeform_Stiffness_Type() == WALL_DISTANCE) { - ComputeDeforming_Wall_Distance(geometry, config); - Scale = MinLength; - } - - /*--- Compute contributions from each element by forming the stiffness matrix (FEA) ---*/ - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) nNodes = 3; - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) nNodes = 4; - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) nNodes = 4; - if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) nNodes = 5; - if (geometry->elem[iElem]->GetVTK_Type() == PRISM) nNodes = 6; - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) nNodes = 8; - - for (iNodes = 0; iNodes < nNodes; iNodes++) { - PointCorners[iNodes] = geometry->elem[iElem]->GetNode(iNodes); - for (iDim = 0; iDim < nDim; iDim++) { - CoordCorners[iNodes][iDim] = geometry->node[PointCorners[iNodes]]->GetCoord(iDim); - } - } - - if (nDim == 2) SetFEA_StiffMatrix2D(geometry, config, StiffMatrix_Elem, PointCorners, CoordCorners, nNodes, Scale); - if (nDim == 3) SetFEA_StiffMatrix3D(geometry, config, StiffMatrix_Elem, PointCorners, CoordCorners, nNodes, Scale); - - AddFEA_StiffMatrix(geometry, StiffMatrix_Elem, PointCorners, nNodes); - - } - -#ifdef HAVE_MPI - unsigned long ElemCounter_Local = ElemCounter; ElemCounter = 0; - SU2_MPI::Allreduce(&ElemCounter_Local, &ElemCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#endif - - /*--- Deallocate memory and exit ---*/ - - for (iVar = 0; iVar < StiffMatrix_nElem; iVar++) - delete [] StiffMatrix_Elem[iVar]; - delete [] StiffMatrix_Elem; - - delete [] Edge_Vector; - - /*--- If there are no degenerate cells, use the minimum volume instead ---*/ - if (ElemCounter == 0) MinLength = Scale; - -#ifdef HAVE_MPI - su2double MinLength_Local = MinLength; MinLength = 0.0; - SU2_MPI::Allreduce(&MinLength_Local, &MinLength, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); -#endif - - return MinLength; -} - -su2double CVolumetricMovement::ShapeFunc_Triangle(su2double Xi, su2double Eta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { - - int i, j, k; - su2double c0, c1, xsj; - su2double xs[3][3], ad[3][3]; - - /*--- Shape functions ---*/ - - DShapeFunction[0][3] = Xi; - DShapeFunction[1][3] = Eta; - DShapeFunction[2][3] = 1-Xi-Eta; - - /*--- dN/d xi, dN/d eta ---*/ - - DShapeFunction[0][0] = 1.0; DShapeFunction[0][1] = 0.0; - DShapeFunction[1][0] = 0.0; DShapeFunction[1][1] = 1.0; - DShapeFunction[2][0] = -1.0; DShapeFunction[2][1] = -1.0; - - /*--- Jacobian transformation ---*/ - - for (i = 0; i < 2; i++) { - for (j = 0; j < 2; j++) { - xs[i][j] = 0.0; - for (k = 0; k < 3; k++) { - xs[i][j] = xs[i][j]+CoordCorners[k][j]*DShapeFunction[k][i]; - } - } - } - - /*--- Adjoint to Jacobian ---*/ - - ad[0][0] = xs[1][1]; - ad[0][1] = -xs[0][1]; - ad[1][0] = -xs[1][0]; - ad[1][1] = xs[0][0]; - - /*--- Determinant of Jacobian ---*/ - - xsj = ad[0][0]*ad[1][1]-ad[0][1]*ad[1][0]; - - /*--- Jacobian inverse ---*/ - - for (i = 0; i < 2; i++) { - for (j = 0; j < 2; j++) { - xs[i][j] = ad[i][j]/xsj; - } - } - - /*--- Derivatives with repect to global coordinates ---*/ - - for (k = 0; k < 3; k++) { - c0 = xs[0][0]*DShapeFunction[k][0]+xs[0][1]*DShapeFunction[k][1]; // dN/dx - c1 = xs[1][0]*DShapeFunction[k][0]+xs[1][1]*DShapeFunction[k][1]; // dN/dy - DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi - DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta - } - - return xsj; - -} - -su2double CVolumetricMovement::ShapeFunc_Quadrilateral(su2double Xi, su2double Eta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { - - int i, j, k; - su2double c0, c1, xsj; - su2double xs[3][3], ad[3][3]; - - /*--- Shape functions ---*/ - - DShapeFunction[0][3] = 0.25*(1.0-Xi)*(1.0-Eta); - DShapeFunction[1][3] = 0.25*(1.0+Xi)*(1.0-Eta); - DShapeFunction[2][3] = 0.25*(1.0+Xi)*(1.0+Eta); - DShapeFunction[3][3] = 0.25*(1.0-Xi)*(1.0+Eta); - - /*--- dN/d xi, dN/d eta ---*/ - - DShapeFunction[0][0] = -0.25*(1.0-Eta); DShapeFunction[0][1] = -0.25*(1.0-Xi); - DShapeFunction[1][0] = 0.25*(1.0-Eta); DShapeFunction[1][1] = -0.25*(1.0+Xi); - DShapeFunction[2][0] = 0.25*(1.0+Eta); DShapeFunction[2][1] = 0.25*(1.0+Xi); - DShapeFunction[3][0] = -0.25*(1.0+Eta); DShapeFunction[3][1] = 0.25*(1.0-Xi); - - /*--- Jacobian transformation ---*/ - - for (i = 0; i < 2; i++) { - for (j = 0; j < 2; j++) { - xs[i][j] = 0.0; - for (k = 0; k < 4; k++) { - xs[i][j] = xs[i][j]+CoordCorners[k][j]*DShapeFunction[k][i]; - } - } - } - - /*--- Adjoint to Jacobian ---*/ - - ad[0][0] = xs[1][1]; - ad[0][1] = -xs[0][1]; - ad[1][0] = -xs[1][0]; - ad[1][1] = xs[0][0]; - - /*--- Determinant of Jacobian ---*/ - - xsj = ad[0][0]*ad[1][1]-ad[0][1]*ad[1][0]; - - /*--- Jacobian inverse ---*/ - - for (i = 0; i < 2; i++) { - for (j = 0; j < 2; j++) { - xs[i][j] = ad[i][j]/xsj; - } - } - - /*--- Derivatives with repect to global coordinates ---*/ - - for (k = 0; k < 4; k++) { - c0 = xs[0][0]*DShapeFunction[k][0]+xs[0][1]*DShapeFunction[k][1]; // dN/dx - c1 = xs[1][0]*DShapeFunction[k][0]+xs[1][1]*DShapeFunction[k][1]; // dN/dy - DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi - DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta - } - - return xsj; - -} - -su2double CVolumetricMovement::ShapeFunc_Tetra(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { - - int i, j, k; - su2double c0, c1, c2, xsj; - su2double xs[3][3], ad[3][3]; - - /*--- Shape functions ---*/ - - DShapeFunction[0][3] = Xi; - DShapeFunction[1][3] = Zeta; - DShapeFunction[2][3] = 1.0 - Xi - Eta - Zeta; - DShapeFunction[3][3] = Eta; - - /*--- dN/d xi, dN/d eta, dN/d zeta ---*/ - - DShapeFunction[0][0] = 1.0; DShapeFunction[0][1] = 0.0; DShapeFunction[0][2] = 0.0; - DShapeFunction[1][0] = 0.0; DShapeFunction[1][1] = 0.0; DShapeFunction[1][2] = 1.0; - DShapeFunction[2][0] = -1.0; DShapeFunction[2][1] = -1.0; DShapeFunction[2][2] = -1.0; - DShapeFunction[3][0] = 0.0; DShapeFunction[3][1] = 1.0; DShapeFunction[3][2] = 0.0; - - /*--- Jacobian transformation ---*/ - - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - xs[i][j] = 0.0; - for (k = 0; k < 4; k++) { - xs[i][j] = xs[i][j]+CoordCorners[k][j]*DShapeFunction[k][i]; - } - } - } - - /*--- Adjoint to Jacobian ---*/ - - ad[0][0] = xs[1][1]*xs[2][2]-xs[1][2]*xs[2][1]; - ad[0][1] = xs[0][2]*xs[2][1]-xs[0][1]*xs[2][2]; - ad[0][2] = xs[0][1]*xs[1][2]-xs[0][2]*xs[1][1]; - ad[1][0] = xs[1][2]*xs[2][0]-xs[1][0]*xs[2][2]; - ad[1][1] = xs[0][0]*xs[2][2]-xs[0][2]*xs[2][0]; - ad[1][2] = xs[0][2]*xs[1][0]-xs[0][0]*xs[1][2]; - ad[2][0] = xs[1][0]*xs[2][1]-xs[1][1]*xs[2][0]; - ad[2][1] = xs[0][1]*xs[2][0]-xs[0][0]*xs[2][1]; - ad[2][2] = xs[0][0]*xs[1][1]-xs[0][1]*xs[1][0]; - - /*--- Determinant of Jacobian ---*/ - - xsj = xs[0][0]*ad[0][0]+xs[0][1]*ad[1][0]+xs[0][2]*ad[2][0]; - - /*--- Jacobian inverse ---*/ - - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - xs[i][j] = ad[i][j]/xsj; - } - } - - /*--- Derivatives with repect to global coordinates ---*/ - - for (k = 0; k < 4; k++) { - c0 = xs[0][0]*DShapeFunction[k][0]+xs[0][1]*DShapeFunction[k][1]+xs[0][2]*DShapeFunction[k][2]; // dN/dx - c1 = xs[1][0]*DShapeFunction[k][0]+xs[1][1]*DShapeFunction[k][1]+xs[1][2]*DShapeFunction[k][2]; // dN/dy - c2 = xs[2][0]*DShapeFunction[k][0]+xs[2][1]*DShapeFunction[k][1]+xs[2][2]*DShapeFunction[k][2]; // dN/dz - DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi - DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta - DShapeFunction[k][2] = c2; // store dN/dz instead of dN/d zeta - } - - return xsj; - -} - -su2double CVolumetricMovement::ShapeFunc_Pyram(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { - - int i, j, k; - su2double c0, c1, c2, xsj; - su2double xs[3][3], ad[3][3]; - - /*--- Shape functions ---*/ - - DShapeFunction[0][3] = 0.125*(1.0-Xi)*(1.0-Eta)*(1.0-Zeta); - DShapeFunction[1][3] = 0.125*(1.0+Xi)*(1.0-Eta)*(1.0-Zeta); - DShapeFunction[2][3] = 0.125*(1.0+Xi)*(1.0+Eta)*(1.0-Zeta); - DShapeFunction[3][3] = 0.125*(1.0-Xi)*(1.0+Eta)*(1.0-Zeta); - DShapeFunction[4][3] = 0.5*(1.0+Zeta); - - /*--- dN/d xi ---*/ - - DShapeFunction[0][0] = -0.125*(1.0-Eta)*(1.0-Zeta); - DShapeFunction[1][0] = 0.125*(1.0-Eta)*(1.0-Zeta); - DShapeFunction[2][0] = 0.125*(1.0+Eta)*(1.0-Zeta); - DShapeFunction[3][0] = -0.125*(1.0+Eta)*(1.0-Zeta); - DShapeFunction[4][0] = 0.0; - - /*--- dN/d eta ---*/ - - DShapeFunction[0][1] = -0.125*(1.0-Xi)*(1.0-Zeta); - DShapeFunction[1][1] = -0.125*(1.0+Xi)*(1.0-Zeta); - DShapeFunction[2][1] = 0.125*(1.0+Xi)*(1.0-Zeta); - DShapeFunction[3][1] = 0.125*(1.0-Xi)*(1.0-Zeta); - DShapeFunction[4][1] = 0.0; - - /*--- dN/d zeta ---*/ - - DShapeFunction[0][2] = -0.125*(1.0-Xi)*(1.0-Eta); - DShapeFunction[1][2] = -0.125*(1.0+Xi)*(1.0-Eta); - DShapeFunction[2][2] = -0.125*(1.0+Xi)*(1.0+Eta); - DShapeFunction[3][2] = -0.125*(1.0-Xi)*(1.0+Eta); - DShapeFunction[4][2] = 0.5; - - /*--- Jacobian transformation ---*/ - - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - xs[i][j] = 0.0; - for (k = 0; k < 5; k++) { - xs[i][j] = xs[i][j]+CoordCorners[k][j]*DShapeFunction[k][i]; - } - } - } - - /*--- Adjoint to Jacobian ---*/ - - ad[0][0] = xs[1][1]*xs[2][2]-xs[1][2]*xs[2][1]; - ad[0][1] = xs[0][2]*xs[2][1]-xs[0][1]*xs[2][2]; - ad[0][2] = xs[0][1]*xs[1][2]-xs[0][2]*xs[1][1]; - ad[1][0] = xs[1][2]*xs[2][0]-xs[1][0]*xs[2][2]; - ad[1][1] = xs[0][0]*xs[2][2]-xs[0][2]*xs[2][0]; - ad[1][2] = xs[0][2]*xs[1][0]-xs[0][0]*xs[1][2]; - ad[2][0] = xs[1][0]*xs[2][1]-xs[1][1]*xs[2][0]; - ad[2][1] = xs[0][1]*xs[2][0]-xs[0][0]*xs[2][1]; - ad[2][2] = xs[0][0]*xs[1][1]-xs[0][1]*xs[1][0]; - - /*--- Determinant of Jacobian ---*/ - - xsj = xs[0][0]*ad[0][0]+xs[0][1]*ad[1][0]+xs[0][2]*ad[2][0]; - - /*--- Jacobian inverse ---*/ - - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - xs[i][j] = ad[i][j]/xsj; - } - } - - /*--- Derivatives with repect to global coordinates ---*/ - - for (k = 0; k < 5; k++) { - c0 = xs[0][0]*DShapeFunction[k][0]+xs[0][1]*DShapeFunction[k][1]+xs[0][2]*DShapeFunction[k][2]; // dN/dx - c1 = xs[1][0]*DShapeFunction[k][0]+xs[1][1]*DShapeFunction[k][1]+xs[1][2]*DShapeFunction[k][2]; // dN/dy - c2 = xs[2][0]*DShapeFunction[k][0]+xs[2][1]*DShapeFunction[k][1]+xs[2][2]*DShapeFunction[k][2]; // dN/dz - DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi - DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta - DShapeFunction[k][2] = c2; // store dN/dz instead of dN/d zeta - } - - return xsj; - -} - -su2double CVolumetricMovement::ShapeFunc_Prism(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { - - int i, j, k; - su2double c0, c1, c2, xsj; - su2double xs[3][3], ad[3][3]; - - /*--- Shape functions ---*/ - - DShapeFunction[0][3] = 0.5*Eta*(1.0-Xi); - DShapeFunction[1][3] = 0.5*Zeta*(1.0-Xi); - DShapeFunction[2][3] = 0.5*(1.0-Eta-Zeta)*(1.0-Xi); - DShapeFunction[3][3] = 0.5*Eta*(Xi+1.0); - DShapeFunction[4][3] = 0.5*Zeta*(Xi+1.0); - DShapeFunction[5][3] = 0.5*(1.0-Eta-Zeta)*(Xi+1.0); - - /*--- dN/d Xi, dN/d Eta, dN/d Zeta ---*/ - - DShapeFunction[0][0] = -0.5*Eta; DShapeFunction[0][1] = 0.5*(1.0-Xi); DShapeFunction[0][2] = 0.0; - DShapeFunction[1][0] = -0.5*Zeta; DShapeFunction[1][1] = 0.0; DShapeFunction[1][2] = 0.5*(1.0-Xi); - DShapeFunction[2][0] = -0.5*(1.0-Eta-Zeta); DShapeFunction[2][1] = -0.5*(1.0-Xi); DShapeFunction[2][2] = -0.5*(1.0-Xi); - DShapeFunction[3][0] = 0.5*Eta; DShapeFunction[3][1] = 0.5*(Xi+1.0); DShapeFunction[3][2] = 0.0; - DShapeFunction[4][0] = 0.5*Zeta; DShapeFunction[4][1] = 0.0; DShapeFunction[4][2] = 0.5*(Xi+1.0); - DShapeFunction[5][0] = 0.5*(1.0-Eta-Zeta); DShapeFunction[5][1] = -0.5*(Xi+1.0); DShapeFunction[5][2] = -0.5*(Xi+1.0); - - /*--- Jacobian transformation ---*/ - - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - xs[i][j] = 0.0; - for (k = 0; k < 6; k++) { - xs[i][j] = xs[i][j]+CoordCorners[k][j]*DShapeFunction[k][i]; - } - } - } - - /*--- Adjoint to Jacobian ---*/ - - ad[0][0] = xs[1][1]*xs[2][2]-xs[1][2]*xs[2][1]; - ad[0][1] = xs[0][2]*xs[2][1]-xs[0][1]*xs[2][2]; - ad[0][2] = xs[0][1]*xs[1][2]-xs[0][2]*xs[1][1]; - ad[1][0] = xs[1][2]*xs[2][0]-xs[1][0]*xs[2][2]; - ad[1][1] = xs[0][0]*xs[2][2]-xs[0][2]*xs[2][0]; - ad[1][2] = xs[0][2]*xs[1][0]-xs[0][0]*xs[1][2]; - ad[2][0] = xs[1][0]*xs[2][1]-xs[1][1]*xs[2][0]; - ad[2][1] = xs[0][1]*xs[2][0]-xs[0][0]*xs[2][1]; - ad[2][2] = xs[0][0]*xs[1][1]-xs[0][1]*xs[1][0]; - - /*--- Determinant of Jacobian ---*/ - - xsj = xs[0][0]*ad[0][0]+xs[0][1]*ad[1][0]+xs[0][2]*ad[2][0]; - - /*--- Jacobian inverse ---*/ - - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - xs[i][j] = ad[i][j]/xsj; - } - } - - /*--- Derivatives with repect to global coordinates ---*/ - - for (k = 0; k < 6; k++) { - c0 = xs[0][0]*DShapeFunction[k][0]+xs[0][1]*DShapeFunction[k][1]+xs[0][2]*DShapeFunction[k][2]; // dN/dx - c1 = xs[1][0]*DShapeFunction[k][0]+xs[1][1]*DShapeFunction[k][1]+xs[1][2]*DShapeFunction[k][2]; // dN/dy - c2 = xs[2][0]*DShapeFunction[k][0]+xs[2][1]*DShapeFunction[k][1]+xs[2][2]*DShapeFunction[k][2]; // dN/dz - DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi - DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta - DShapeFunction[k][2] = c2; // store dN/dz instead of dN/d zeta - } - - return xsj; - -} - -su2double CVolumetricMovement::ShapeFunc_Hexa(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { - - int i, j, k; - su2double c0, c1, c2, xsj; - su2double xs[3][3], ad[3][3]; - - - /*--- Shape functions ---*/ - - DShapeFunction[0][3] = 0.125*(1.0-Xi)*(1.0-Eta)*(1.0-Zeta); - DShapeFunction[1][3] = 0.125*(1.0+Xi)*(1.0-Eta)*(1.0-Zeta); - DShapeFunction[2][3] = 0.125*(1.0+Xi)*(1.0+Eta)*(1.0-Zeta); - DShapeFunction[3][3] = 0.125*(1.0-Xi)*(1.0+Eta)*(1.0-Zeta); - DShapeFunction[4][3] = 0.125*(1.0-Xi)*(1.0-Eta)*(1.0+Zeta); - DShapeFunction[5][3] = 0.125*(1.0+Xi)*(1.0-Eta)*(1.0+Zeta); - DShapeFunction[6][3] = 0.125*(1.0+Xi)*(1.0+Eta)*(1.0+Zeta); - DShapeFunction[7][3] = 0.125*(1.0-Xi)*(1.0+Eta)*(1.0+Zeta); - - /*--- dN/d xi ---*/ - - DShapeFunction[0][0] = -0.125*(1.0-Eta)*(1.0-Zeta); - DShapeFunction[1][0] = 0.125*(1.0-Eta)*(1.0-Zeta); - DShapeFunction[2][0] = 0.125*(1.0+Eta)*(1.0-Zeta); - DShapeFunction[3][0] = -0.125*(1.0+Eta)*(1.0-Zeta); - DShapeFunction[4][0] = -0.125*(1.0-Eta)*(1.0+Zeta); - DShapeFunction[5][0] = 0.125*(1.0-Eta)*(1.0+Zeta); - DShapeFunction[6][0] = 0.125*(1.0+Eta)*(1.0+Zeta); - DShapeFunction[7][0] = -0.125*(1.0+Eta)*(1.0+Zeta); - - /*--- dN/d eta ---*/ - - DShapeFunction[0][1] = -0.125*(1.0-Xi)*(1.0-Zeta); - DShapeFunction[1][1] = -0.125*(1.0+Xi)*(1.0-Zeta); - DShapeFunction[2][1] = 0.125*(1.0+Xi)*(1.0-Zeta); - DShapeFunction[3][1] = 0.125*(1.0-Xi)*(1.0-Zeta); - DShapeFunction[4][1] = -0.125*(1.0-Xi)*(1.0+Zeta); - DShapeFunction[5][1] = -0.125*(1.0+Xi)*(1.0+Zeta); - DShapeFunction[6][1] = 0.125*(1.0+Xi)*(1.0+Zeta); - DShapeFunction[7][1] = 0.125*(1.0-Xi)*(1.0+Zeta); - - /*--- dN/d zeta ---*/ - - DShapeFunction[0][2] = -0.125*(1.0-Xi)*(1.0-Eta); - DShapeFunction[1][2] = -0.125*(1.0+Xi)*(1.0-Eta); - DShapeFunction[2][2] = -0.125*(1.0+Xi)*(1.0+Eta); - DShapeFunction[3][2] = -0.125*(1.0-Xi)*(1.0+Eta); - DShapeFunction[4][2] = 0.125*(1.0-Xi)*(1.0-Eta); - DShapeFunction[5][2] = 0.125*(1.0+Xi)*(1.0-Eta); - DShapeFunction[6][2] = 0.125*(1.0+Xi)*(1.0+Eta); - DShapeFunction[7][2] = 0.125*(1.0-Xi)*(1.0+Eta); - - /*--- Jacobian transformation ---*/ - - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - xs[i][j] = 0.0; - for (k = 0; k < 8; k++) { - xs[i][j] = xs[i][j]+CoordCorners[k][j]*DShapeFunction[k][i]; - } - } - } - - /*--- Adjoint to Jacobian ---*/ - - ad[0][0] = xs[1][1]*xs[2][2]-xs[1][2]*xs[2][1]; - ad[0][1] = xs[0][2]*xs[2][1]-xs[0][1]*xs[2][2]; - ad[0][2] = xs[0][1]*xs[1][2]-xs[0][2]*xs[1][1]; - ad[1][0] = xs[1][2]*xs[2][0]-xs[1][0]*xs[2][2]; - ad[1][1] = xs[0][0]*xs[2][2]-xs[0][2]*xs[2][0]; - ad[1][2] = xs[0][2]*xs[1][0]-xs[0][0]*xs[1][2]; - ad[2][0] = xs[1][0]*xs[2][1]-xs[1][1]*xs[2][0]; - ad[2][1] = xs[0][1]*xs[2][0]-xs[0][0]*xs[2][1]; - ad[2][2] = xs[0][0]*xs[1][1]-xs[0][1]*xs[1][0]; - - /*--- Determinant of Jacobian ---*/ - - xsj = xs[0][0]*ad[0][0]+xs[0][1]*ad[1][0]+xs[0][2]*ad[2][0]; - - /*--- Jacobian inverse ---*/ - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - xs[i][j] = ad[i][j]/xsj; - } - } - - /*--- Derivatives with repect to global coordinates ---*/ - - for (k = 0; k < 8; k++) { - c0 = xs[0][0]*DShapeFunction[k][0]+xs[0][1]*DShapeFunction[k][1]+xs[0][2]*DShapeFunction[k][2]; // dN/dx - c1 = xs[1][0]*DShapeFunction[k][0]+xs[1][1]*DShapeFunction[k][1]+xs[1][2]*DShapeFunction[k][2]; // dN/dy - c2 = xs[2][0]*DShapeFunction[k][0]+xs[2][1]*DShapeFunction[k][1]+xs[2][2]*DShapeFunction[k][2]; // dN/dz - DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi - DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta - DShapeFunction[k][2] = c2; // store dN/dz instead of dN/d zeta - } - - return xsj; - -} - -su2double CVolumetricMovement::GetTriangle_Area(su2double CoordCorners[8][3]) { - - unsigned short iDim; - su2double a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}; - su2double *Coord_0, *Coord_1, *Coord_2, Area; - - Coord_0 = CoordCorners[0]; - Coord_1 = CoordCorners[1]; - Coord_2 = CoordCorners[2]; - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = Coord_0[iDim]-Coord_2[iDim]; - b[iDim] = Coord_1[iDim]-Coord_2[iDim]; - } - - Area = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); - - return Area; - -} - -su2double CVolumetricMovement::GetQuadrilateral_Area(su2double CoordCorners[8][3]) { - - unsigned short iDim; - su2double a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}; - su2double *Coord_0, *Coord_1, *Coord_2, Area; - - Coord_0 = CoordCorners[0]; - Coord_1 = CoordCorners[1]; - Coord_2 = CoordCorners[2]; - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = Coord_0[iDim]-Coord_2[iDim]; - b[iDim] = Coord_1[iDim]-Coord_2[iDim]; - } - - Area = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); - - Coord_0 = CoordCorners[0]; - Coord_1 = CoordCorners[2]; - Coord_2 = CoordCorners[3]; - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = Coord_0[iDim]-Coord_2[iDim]; - b[iDim] = Coord_1[iDim]-Coord_2[iDim]; - } - - Area += 0.5*fabs(a[0]*b[1]-a[1]*b[0]); - - return Area; - -} - -su2double CVolumetricMovement::GetTetra_Volume(su2double CoordCorners[8][3]) { - - unsigned short iDim; - su2double *Coord_0, *Coord_1, *Coord_2, *Coord_3; - su2double r1[3] = {0.0,0.0,0.0}, r2[3] = {0.0,0.0,0.0}, r3[3] = {0.0,0.0,0.0}, CrossProduct[3] = {0.0,0.0,0.0}, Volume; - - Coord_0 = CoordCorners[0]; - Coord_1 = CoordCorners[1]; - Coord_2 = CoordCorners[2]; - Coord_3 = CoordCorners[3]; - - for (iDim = 0; iDim < nDim; iDim++) { - r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; - r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; - r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; - } - - CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; - CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; - CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; - - Volume = (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; - - return Volume; - -} - -su2double CVolumetricMovement::GetPyram_Volume(su2double CoordCorners[8][3]) { - - unsigned short iDim; - su2double *Coord_0, *Coord_1, *Coord_2, *Coord_3; - su2double r1[3] = {0.0,0.0,0.0}, r2[3] = {0.0,0.0,0.0}, r3[3] = {0.0,0.0,0.0}, CrossProduct[3] = {0.0,0.0,0.0}, Volume; - - Coord_0 = CoordCorners[0]; - Coord_1 = CoordCorners[1]; - Coord_2 = CoordCorners[2]; - Coord_3 = CoordCorners[4]; - - for (iDim = 0; iDim < nDim; iDim++) { - r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; - r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; - r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; - } - - CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; - CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; - CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; - - Volume = (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; - - Coord_0 = CoordCorners[0]; - Coord_1 = CoordCorners[2]; - Coord_2 = CoordCorners[3]; - Coord_3 = CoordCorners[4]; - - for (iDim = 0; iDim < nDim; iDim++) { - r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; - r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; - r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; - } - - CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; - CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; - CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; - - Volume += (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; - - return Volume; - -} - -su2double CVolumetricMovement::GetPrism_Volume(su2double CoordCorners[8][3]) { - - unsigned short iDim; - su2double *Coord_0, *Coord_1, *Coord_2, *Coord_3; - su2double r1[3] = {0.0,0.0,0.0}, r2[3] = {0.0,0.0,0.0}, r3[3] = {0.0,0.0,0.0}, CrossProduct[3] = {0.0,0.0,0.0}, Volume; - - Coord_0 = CoordCorners[0]; - Coord_1 = CoordCorners[2]; - Coord_2 = CoordCorners[1]; - Coord_3 = CoordCorners[5]; - - for (iDim = 0; iDim < nDim; iDim++) { - r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; - r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; - r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; - } - - CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; - CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; - CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; - - Volume = (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; - - Coord_0 = CoordCorners[0]; - Coord_1 = CoordCorners[5]; - Coord_2 = CoordCorners[1]; - Coord_3 = CoordCorners[4]; - - for (iDim = 0; iDim < nDim; iDim++) { - r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; - r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; - r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; - } - - CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; - CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; - CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; - - Volume += (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; - - Coord_0 = CoordCorners[0]; - Coord_1 = CoordCorners[5]; - Coord_2 = CoordCorners[4]; - Coord_3 = CoordCorners[3]; - - for (iDim = 0; iDim < nDim; iDim++) { - r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; - r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; - r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; - } - - CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; - CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; - CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; - - Volume += (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; - - return Volume; - -} - -su2double CVolumetricMovement::GetHexa_Volume(su2double CoordCorners[8][3]) { - - unsigned short iDim; - su2double *Coord_0, *Coord_1, *Coord_2, *Coord_3; - su2double r1[3] = {0.0,0.0,0.0}, r2[3] = {0.0,0.0,0.0}, r3[3] = {0.0,0.0,0.0}, CrossProduct[3] = {0.0,0.0,0.0}, Volume; - - Coord_0 = CoordCorners[0]; - Coord_1 = CoordCorners[1]; - Coord_2 = CoordCorners[2]; - Coord_3 = CoordCorners[5]; - - for (iDim = 0; iDim < nDim; iDim++) { - r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; - r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; - r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; - } - - CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; - CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; - CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; - - Volume = (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; - - Coord_0 = CoordCorners[0]; - Coord_1 = CoordCorners[2]; - Coord_2 = CoordCorners[7]; - Coord_3 = CoordCorners[5]; - - for (iDim = 0; iDim < nDim; iDim++) { - r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; - r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; - r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; - } - - CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; - CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; - CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; - - Volume += (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; - - Coord_0 = CoordCorners[0]; - Coord_1 = CoordCorners[2]; - Coord_2 = CoordCorners[3]; - Coord_3 = CoordCorners[7]; - - for (iDim = 0; iDim < nDim; iDim++) { - r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; - r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; - r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; - } - - CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; - CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; - CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; - - Volume += (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; - - Coord_0 = CoordCorners[0]; - Coord_1 = CoordCorners[5]; - Coord_2 = CoordCorners[7]; - Coord_3 = CoordCorners[4]; - - for (iDim = 0; iDim < nDim; iDim++) { - r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; - r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; - r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; - } - - CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; - CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; - CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; - - Volume += (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; - - Coord_0 = CoordCorners[2]; - Coord_1 = CoordCorners[7]; - Coord_2 = CoordCorners[5]; - Coord_3 = CoordCorners[6]; - - for (iDim = 0; iDim < nDim; iDim++) { - r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; - r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; - r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; - } - - CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; - CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; - CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; - - Volume += (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; - - return Volume; - -} - -void CVolumetricMovement::SetFEA_StiffMatrix2D(CGeometry *geometry, CConfig *config, su2double **StiffMatrix_Elem, unsigned long PointCorners[8], su2double CoordCorners[8][3], unsigned short nNodes, su2double scale) { - - su2double B_Matrix[3][8], D_Matrix[3][3], Aux_Matrix[8][3]; - su2double Xi = 0.0, Eta = 0.0, Det = 0.0, E, Lambda = 0.0, Nu, Mu = 0.0, Avg_Wall_Dist; - unsigned short iNode, jNode, iVar, jVar, kVar, iGauss, nGauss = 0; - su2double DShapeFunction[8][4] = {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, - {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}}; - su2double Location[4][3], Weight[4]; - unsigned short nVar = geometry->GetnDim(); - - for (iVar = 0; iVar < nNodes*nVar; iVar++) { - for (jVar = 0; jVar < nNodes*nVar; jVar++) { - StiffMatrix_Elem[iVar][jVar] = 0.0; - } - } - - /*--- Each element uses their own stiffness which is inversely - proportional to the area/volume of the cell. Using Mu = E & Lambda = -E - is a modification to help allow rigid rotation of elements (see - "Robust Mesh Deformation using the Linear Elasticity Equations" by - R. P. Dwight. ---*/ - - /*--- Integration formulae from "Shape functions and points of - integration of the Résumé" by Josselin DELMAS (2013) ---*/ - - /*--- Triangle. Nodes of numerical integration at 1 point (order 1). ---*/ - - if (nNodes == 3) { - nGauss = 1; - Location[0][0] = 0.333333333333333; Location[0][1] = 0.333333333333333; Weight[0] = 0.5; - } - - /*--- Quadrilateral. Nodes of numerical integration at 4 points (order 2). ---*/ - - if (nNodes == 4) { - nGauss = 4; - Location[0][0] = -0.577350269189626; Location[0][1] = -0.577350269189626; Weight[0] = 1.0; - Location[1][0] = 0.577350269189626; Location[1][1] = -0.577350269189626; Weight[1] = 1.0; - Location[2][0] = 0.577350269189626; Location[2][1] = 0.577350269189626; Weight[2] = 1.0; - Location[3][0] = -0.577350269189626; Location[3][1] = 0.577350269189626; Weight[3] = 1.0; - } - - for (iGauss = 0; iGauss < nGauss; iGauss++) { - - Xi = Location[iGauss][0]; Eta = Location[iGauss][1]; - - if (nNodes == 3) Det = ShapeFunc_Triangle(Xi, Eta, CoordCorners, DShapeFunction); - if (nNodes == 4) Det = ShapeFunc_Quadrilateral(Xi, Eta, CoordCorners, DShapeFunction); - - /*--- Compute the B Matrix ---*/ - - for (iVar = 0; iVar < 3; iVar++) - for (jVar = 0; jVar < nNodes*nVar; jVar++) - B_Matrix[iVar][jVar] = 0.0; - - for (iNode = 0; iNode < nNodes; iNode++) { - B_Matrix[0][0+iNode*nVar] = DShapeFunction[iNode][0]; - B_Matrix[1][1+iNode*nVar] = DShapeFunction[iNode][1]; - - B_Matrix[2][0+iNode*nVar] = DShapeFunction[iNode][1]; - B_Matrix[2][1+iNode*nVar] = DShapeFunction[iNode][0]; - } - - /*--- Impose a type of stiffness for each element ---*/ - - switch (config->GetDeform_Stiffness_Type()) { - - case INVERSE_VOLUME: - E = scale / (Weight[iGauss] * Det) ; - Mu = E; - Lambda = -E; - break; - - case WALL_DISTANCE: - Avg_Wall_Dist = 0.0; - for (jNode = 0; jNode < nNodes; jNode++) { - Avg_Wall_Dist += geometry->node[PointCorners[jNode]]->GetWall_Distance()/((su2double)nNodes); - } - E = scale / (Weight[iGauss] * Avg_Wall_Dist); - Mu = E; - Lambda = -E; - break; - - case CONSTANT_STIFFNESS: - E=config->GetDeform_ElasticityMod(); - Nu=config->GetDeform_PoissonRatio(); - //E = 2E11; Nu = 0.30; - Mu = E / (2.0*(1.0 + Nu)); - Lambda = Nu*E/((1.0+Nu)*(1.0-2.0*Nu)); - break; - } - - /*--- Compute the D Matrix (for plane strain and 3-D)---*/ - - D_Matrix[0][0] = Lambda + 2.0*Mu; D_Matrix[0][1] = Lambda; D_Matrix[0][2] = 0.0; - D_Matrix[1][0] = Lambda; D_Matrix[1][1] = Lambda + 2.0*Mu; D_Matrix[1][2] = 0.0; - D_Matrix[2][0] = 0.0; D_Matrix[2][1] = 0.0; D_Matrix[2][2] = Mu; - - - /*--- Compute the BT.D Matrix ---*/ - - for (iVar = 0; iVar < nNodes*nVar; iVar++) { - for (jVar = 0; jVar < 3; jVar++) { - Aux_Matrix[iVar][jVar] = 0.0; - for (kVar = 0; kVar < 3; kVar++) - Aux_Matrix[iVar][jVar] += B_Matrix[kVar][iVar]*D_Matrix[kVar][jVar]; - } - } - - /*--- Compute the BT.D.B Matrix (stiffness matrix), and add to the original - matrix using Gauss integration ---*/ - - for (iVar = 0; iVar < nNodes*nVar; iVar++) { - for (jVar = 0; jVar < nNodes*nVar; jVar++) { - for (kVar = 0; kVar < 3; kVar++) { - StiffMatrix_Elem[iVar][jVar] += Weight[iGauss] * Aux_Matrix[iVar][kVar]*B_Matrix[kVar][jVar] * Det; - } - } - } - - } - -} - -void CVolumetricMovement::SetFEA_StiffMatrix3D(CGeometry *geometry, CConfig *config, su2double **StiffMatrix_Elem, unsigned long PointCorners[8], su2double CoordCorners[8][3], unsigned short nNodes, su2double scale) { - - su2double B_Matrix[6][24], D_Matrix[6][6] = {{0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}, Aux_Matrix[24][6]; - su2double Xi = 0.0, Eta = 0.0, Zeta = 0.0, Det = 0.0, Mu = 0.0, E = 0.0, Lambda = 0.0, Nu = 0.0, Avg_Wall_Dist; - unsigned short iNode, jNode, iVar, jVar, kVar, iGauss, nGauss = 0; - su2double DShapeFunction[8][4] = {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, - {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}}; - su2double Location[8][3], Weight[8]; - unsigned short nVar = geometry->GetnDim(); - - for (iVar = 0; iVar < nNodes*nVar; iVar++) { - for (jVar = 0; jVar < nNodes*nVar; jVar++) { - StiffMatrix_Elem[iVar][jVar] = 0.0; - } - } - - /*--- Each element uses their own stiffness which is inversely - proportional to the area/volume of the cell. Using Mu = E & Lambda = -E - is a modification to help allow rigid rotation of elements (see - "Robust Mesh Deformation using the Linear Elasticity Equations" by - R. P. Dwight. ---*/ - - /*--- Integration formulae from "Shape functions and points of - integration of the Résumé" by Josselin Delmas (2013) ---*/ - - /*--- Tetrahedrons. Nodes of numerical integration at 1 point (order 1). ---*/ - - if (nNodes == 4) { - nGauss = 1; - Location[0][0] = 0.25; Location[0][1] = 0.25; Location[0][2] = 0.25; Weight[0] = 0.166666666666666; - } - - /*--- Pyramids. Nodes numerical integration at 5 points. ---*/ - - if (nNodes == 5) { - nGauss = 5; - Location[0][0] = 0.5; Location[0][1] = 0.0; Location[0][2] = 0.1531754163448146; Weight[0] = 0.133333333333333; - Location[1][0] = 0.0; Location[1][1] = 0.5; Location[1][2] = 0.1531754163448146; Weight[1] = 0.133333333333333; - Location[2][0] = -0.5; Location[2][1] = 0.0; Location[2][2] = 0.1531754163448146; Weight[2] = 0.133333333333333; - Location[3][0] = 0.0; Location[3][1] = -0.5; Location[3][2] = 0.1531754163448146; Weight[3] = 0.133333333333333; - Location[4][0] = 0.0; Location[4][1] = 0.0; Location[4][2] = 0.6372983346207416; Weight[4] = 0.133333333333333; - } - - /*--- Prism. Nodes of numerical integration at 6 points (order 3 in Xi, order 2 in Eta and Mu ). ---*/ - - if (nNodes == 6) { - nGauss = 6; - Location[0][0] = 0.5; Location[0][1] = 0.5; Location[0][2] = -0.577350269189626; Weight[0] = 0.166666666666666; - Location[1][0] = -0.577350269189626; Location[1][1] = 0.0; Location[1][2] = 0.5; Weight[1] = 0.166666666666666; - Location[2][0] = 0.5; Location[2][1] = -0.577350269189626; Location[2][2] = 0.0; Weight[2] = 0.166666666666666; - Location[3][0] = 0.5; Location[3][1] = 0.5; Location[3][2] = 0.577350269189626; Weight[3] = 0.166666666666666; - Location[4][0] = 0.577350269189626; Location[4][1] = 0.0; Location[4][2] = 0.5; Weight[4] = 0.166666666666666; - Location[5][0] = 0.5; Location[5][1] = 0.577350269189626; Location[5][2] = 0.0; Weight[5] = 0.166666666666666; - } - - /*--- Hexahedrons. Nodes of numerical integration at 6 points (order 3). ---*/ - - if (nNodes == 8) { - nGauss = 8; - Location[0][0] = -0.577350269189626; Location[0][1] = -0.577350269189626; Location[0][2] = -0.577350269189626; Weight[0] = 1.0; - Location[1][0] = -0.577350269189626; Location[1][1] = -0.577350269189626; Location[1][2] = 0.577350269189626; Weight[1] = 1.0; - Location[2][0] = -0.577350269189626; Location[2][1] = 0.577350269189626; Location[2][2] = -0.577350269189626; Weight[2] = 1.0; - Location[3][0] = -0.577350269189626; Location[3][1] = 0.577350269189626; Location[3][2] = 0.577350269189626; Weight[3] = 1.0; - Location[4][0] = 0.577350269189626; Location[4][1] = -0.577350269189626; Location[4][2] = -0.577350269189626; Weight[4] = 1.0; - Location[5][0] = 0.577350269189626; Location[5][1] = -0.577350269189626; Location[5][2] = 0.577350269189626; Weight[5] = 1.0; - Location[6][0] = 0.577350269189626; Location[6][1] = 0.577350269189626; Location[6][2] = -0.577350269189626; Weight[6] = 1.0; - Location[7][0] = 0.577350269189626; Location[7][1] = 0.577350269189626; Location[7][2] = 0.577350269189626; Weight[7] = 1.0; - } - - for (iGauss = 0; iGauss < nGauss; iGauss++) { - - Xi = Location[iGauss][0]; Eta = Location[iGauss][1]; Zeta = Location[iGauss][2]; - - if (nNodes == 4) Det = ShapeFunc_Tetra(Xi, Eta, Zeta, CoordCorners, DShapeFunction); - if (nNodes == 5) Det = ShapeFunc_Pyram(Xi, Eta, Zeta, CoordCorners, DShapeFunction); - if (nNodes == 6) Det = ShapeFunc_Prism(Xi, Eta, Zeta, CoordCorners, DShapeFunction); - if (nNodes == 8) Det = ShapeFunc_Hexa(Xi, Eta, Zeta, CoordCorners, DShapeFunction); - - /*--- Compute the B Matrix ---*/ - - for (iVar = 0; iVar < 6; iVar++) - for (jVar = 0; jVar < nNodes*nVar; jVar++) - B_Matrix[iVar][jVar] = 0.0; - - for (iNode = 0; iNode < nNodes; iNode++) { - B_Matrix[0][0+iNode*nVar] = DShapeFunction[iNode][0]; - B_Matrix[1][1+iNode*nVar] = DShapeFunction[iNode][1]; - B_Matrix[2][2+iNode*nVar] = DShapeFunction[iNode][2]; - - B_Matrix[3][0+iNode*nVar] = DShapeFunction[iNode][1]; - B_Matrix[3][1+iNode*nVar] = DShapeFunction[iNode][0]; - - B_Matrix[4][1+iNode*nVar] = DShapeFunction[iNode][2]; - B_Matrix[4][2+iNode*nVar] = DShapeFunction[iNode][1]; - - B_Matrix[5][0+iNode*nVar] = DShapeFunction[iNode][2]; - B_Matrix[5][2+iNode*nVar] = DShapeFunction[iNode][0]; - } - - /*--- Impose a type of stiffness for each element ---*/ - - switch (config->GetDeform_Stiffness_Type()) { - - case INVERSE_VOLUME: - E = scale / (Weight[iGauss] * Det) ; - Mu = E; - Lambda = -E; - break; - - case WALL_DISTANCE: - Avg_Wall_Dist = 0.0; - for (jNode = 0; jNode < nNodes; jNode++) { - Avg_Wall_Dist += geometry->node[PointCorners[jNode]]->GetWall_Distance()/((su2double)nNodes); - } - E = scale / (Weight[iGauss] * Avg_Wall_Dist); - Mu = E; - Lambda = -E; - break; - - case CONSTANT_STIFFNESS: - E=config->GetDeform_ElasticityMod(); - Nu=config->GetDeform_PoissonRatio(); - //E = 2E11; Nu = 0.30; - Mu = E / (2.0*(1.0 + Nu)); - Lambda = Nu*E/((1.0+Nu)*(1.0-2.0*Nu)); - break; - } - - /*--- Compute the D Matrix (for plane strain and 3-D)---*/ - - D_Matrix[0][0] = Lambda + 2.0*Mu; D_Matrix[0][1] = Lambda; D_Matrix[0][2] = Lambda; - D_Matrix[1][0] = Lambda; D_Matrix[1][1] = Lambda + 2.0*Mu; D_Matrix[1][2] = Lambda; - D_Matrix[2][0] = Lambda; D_Matrix[2][1] = Lambda; D_Matrix[2][2] = Lambda + 2.0*Mu; - D_Matrix[3][3] = Mu; - D_Matrix[4][4] = Mu; - D_Matrix[5][5] = Mu; - - - /*--- Compute the BT.D Matrix ---*/ - - for (iVar = 0; iVar < nNodes*nVar; iVar++) { - for (jVar = 0; jVar < 6; jVar++) { - Aux_Matrix[iVar][jVar] = 0.0; - for (kVar = 0; kVar < 6; kVar++) - Aux_Matrix[iVar][jVar] += B_Matrix[kVar][iVar]*D_Matrix[kVar][jVar]; - } - } - - /*--- Compute the BT.D.B Matrix (stiffness matrix), and add to the original - matrix using Gauss integration ---*/ - - for (iVar = 0; iVar < nNodes*nVar; iVar++) { - for (jVar = 0; jVar < nNodes*nVar; jVar++) { - for (kVar = 0; kVar < 6; kVar++) { - StiffMatrix_Elem[iVar][jVar] += Weight[iGauss] * Aux_Matrix[iVar][kVar]*B_Matrix[kVar][jVar] * Det; - } - } - } - - } - -} - -void CVolumetricMovement::AddFEA_StiffMatrix(CGeometry *geometry, su2double **StiffMatrix_Elem, unsigned long PointCorners[8], unsigned short nNodes) { - - unsigned short iVar, jVar, iDim, jDim; - - unsigned short nVar = geometry->GetnDim(); - - su2double **StiffMatrix_Node; - StiffMatrix_Node = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - StiffMatrix_Node[iVar] = new su2double [nVar]; - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - StiffMatrix_Node[iVar][jVar] = 0.0; - - /*--- Transform the stiffness matrix for the hexahedral element into the - contributions for the individual nodes relative to each other. ---*/ - - for (iVar = 0; iVar < nNodes; iVar++) { - for (jVar = 0; jVar < nNodes; jVar++) { - - for (iDim = 0; iDim < nVar; iDim++) { - for (jDim = 0; jDim < nVar; jDim++) { - StiffMatrix_Node[iDim][jDim] = StiffMatrix_Elem[(iVar*nVar)+iDim][(jVar*nVar)+jDim]; - } - } - - StiffMatrix.AddBlock(PointCorners[iVar], PointCorners[jVar], StiffMatrix_Node); - - } - } - - /*--- Deallocate memory and exit ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - delete [] StiffMatrix_Node[iVar]; - delete [] StiffMatrix_Node; - -} - -void CVolumetricMovement::SetBoundaryDisplacements(CGeometry *geometry, CConfig *config) { - - unsigned short iDim, nDim = geometry->GetnDim(), iMarker, axis = 0; - unsigned long iPoint, total_index, iVertex; - su2double *VarCoord, MeanCoord[3] = {0.0,0.0,0.0}, VarIncrement = 1.0; - - /*--- Get the SU2 module. SU2_CFD will use this routine for dynamically - deforming meshes (MARKER_MOVING), while SU2_DEF will use it for deforming - meshes after imposing design variable surface deformations (DV_MARKER). ---*/ - - unsigned short Kind_SU2 = config->GetKind_SU2(); - - /*--- If requested (no by default) impose the surface deflections in - increments and solve the grid deformation equations iteratively with - successive small deformations. ---*/ - - VarIncrement = 1.0/((su2double)config->GetGridDef_Nonlinear_Iter()); - - /*--- As initialization, set to zero displacements of all the surfaces except the symmetry - plane and the receive boundaries. ---*/ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (((config->GetMarker_All_KindBC(iMarker) != SYMMETRY_PLANE) ) - && (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE)) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint*nDim + iDim; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - StiffMatrix.DeleteValsRowi(total_index); - } - } - } - } - - /*--- Set to zero displacements of the normal component for the symmetry plane condition ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_KindBC(iMarker) == SYMMETRY_PLANE) ) { - - for (iDim = 0; iDim < nDim; iDim++) MeanCoord[iDim] = 0.0; - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - VarCoord = geometry->node[iPoint]->GetCoord(); - for (iDim = 0; iDim < nDim; iDim++) - MeanCoord[iDim] += VarCoord[iDim]*VarCoord[iDim]; - } - for (iDim = 0; iDim < nDim; iDim++) MeanCoord[iDim] = sqrt(MeanCoord[iDim]); - if (nDim==3){ - if ((MeanCoord[0] <= MeanCoord[1]) && (MeanCoord[0] <= MeanCoord[2])) axis = 0; - if ((MeanCoord[1] <= MeanCoord[0]) && (MeanCoord[1] <= MeanCoord[2])) axis = 1; - if ((MeanCoord[2] <= MeanCoord[0]) && (MeanCoord[2] <= MeanCoord[1])) axis = 2; - } - else{ - if ((MeanCoord[0] <= MeanCoord[1]) ) axis = 0; - if ((MeanCoord[1] <= MeanCoord[0]) ) axis = 1; - } - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - total_index = iPoint*nDim + axis; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - StiffMatrix.DeleteValsRowi(total_index); - } - } - } - - /*--- Set the known displacements, note that some points of the moving surfaces - could be on on the symmetry plane, we should specify DeleteValsRowi again (just in case) ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_CFD)) || - ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DEF)) || - ((config->GetDirectDiff() == D_DESIGN) && (Kind_SU2 == SU2_CFD) && (config->GetMarker_All_DV(iMarker) == YES)) || - ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DOT))) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint*nDim + iDim; - LinSysRes[total_index] = SU2_TYPE::GetValue(VarCoord[iDim] * VarIncrement); - LinSysSol[total_index] = SU2_TYPE::GetValue(VarCoord[iDim] * VarIncrement); - StiffMatrix.DeleteValsRowi(total_index); - } - } - } - } - - /*--- Don't move the nearfield plane ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint*nDim + iDim; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - StiffMatrix.DeleteValsRowi(total_index); - } - } - } - } - - /*--- Move the FSI interfaces ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_FSIinterface(iMarker) != 0) && (Kind_SU2 == SU2_CFD)) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint*nDim + iDim; - LinSysRes[total_index] = SU2_TYPE::GetValue(VarCoord[iDim] * VarIncrement); - LinSysSol[total_index] = SU2_TYPE::GetValue(VarCoord[iDim] * VarIncrement); - StiffMatrix.DeleteValsRowi(total_index); - } - } - } - } - - -} - -void CVolumetricMovement::SetBoundaryDerivatives(CGeometry *geometry, CConfig *config){ - unsigned short iDim, iMarker; - unsigned long iPoint, total_index, iVertex; - - su2double * VarCoord; - unsigned short Kind_SU2 = config->GetKind_SU2(); - if ((config->GetDirectDiff() == D_DESIGN) && (Kind_SU2 == SU2_CFD)){ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_DV(iMarker) == YES)) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint*nDim + iDim; - LinSysRes[total_index] = SU2_TYPE::GetDerivative(VarCoord[iDim]); - LinSysSol[total_index] = SU2_TYPE::GetDerivative(VarCoord[iDim]); - } - } - } - } - if (LinSysRes.norm() == 0.0) cout << "Warning: Derivatives are zero!" << endl; - } else if (Kind_SU2 == SU2_DOT) { - - for (iPoint = 0; iPoint < nPoint; iPoint++){ - for (iDim = 0; iDim < nDim; iDim++){ - total_index = iPoint*nDim + iDim; - LinSysRes[total_index] = SU2_TYPE::GetValue(geometry->GetSensitivity(iPoint, iDim)); - LinSysSol[total_index] = SU2_TYPE::GetValue(geometry->GetSensitivity(iPoint, iDim)); - } - } - } -} - -void CVolumetricMovement::UpdateGridCoord_Derivatives(CGeometry *geometry, CConfig *config){ - unsigned short iDim, iMarker; - unsigned long iPoint, total_index, iVertex; - su2double *new_coord = new su2double[3]; - - unsigned short Kind_SU2 = config->GetKind_SU2(); - - /*--- Update derivatives of the grid coordinates using the solution of the linear system - after grid deformation (LinSysSol contains the derivatives of the x, y, z displacements). ---*/ - if ((config->GetDirectDiff() == D_DESIGN) && (Kind_SU2 == SU2_CFD)){ - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++){ - new_coord[0] = 0.0; new_coord[1] = 0.0; new_coord[2] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint*nDim + iDim; - new_coord[iDim] = geometry->node[iPoint]->GetCoord(iDim); - SU2_TYPE::SetDerivative(new_coord[iDim], SU2_TYPE::GetValue(LinSysSol[total_index])); - } - geometry->node[iPoint]->SetCoord(new_coord); - } - } else if (Kind_SU2 == SU2_DOT){ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_DV(iMarker) == YES) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if (geometry->node[iPoint]->GetDomain()){ - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint*nDim + iDim; - geometry->SetSensitivity(iPoint,iDim, LinSysSol[total_index]); - } - } - } - } - } - } - - delete [] new_coord; -} - -void CVolumetricMovement::SetDomainDisplacements(CGeometry *geometry, CConfig *config) { - - unsigned short iDim, nDim = geometry->GetnDim(); - unsigned long iPoint, total_index; - su2double *Coord, *MinCoordValues, *MaxCoordValues, *Hold_GridFixed_Coord; - - MinCoordValues = new su2double [nDim]; - MaxCoordValues = new su2double [nDim]; - - for (iDim = 0; iDim < nDim; iDim++) { - MinCoordValues[iDim] = 0.0; - MaxCoordValues[iDim] = 0.0; - } - - Hold_GridFixed_Coord = config->GetHold_GridFixed_Coord(); - - MinCoordValues[0] = Hold_GridFixed_Coord[0]; - MinCoordValues[1] = Hold_GridFixed_Coord[1]; - MinCoordValues[2] = Hold_GridFixed_Coord[2]; - MaxCoordValues[0] = Hold_GridFixed_Coord[3]; - MaxCoordValues[1] = Hold_GridFixed_Coord[4]; - MaxCoordValues[2] = Hold_GridFixed_Coord[5]; - - /*--- Set to zero displacements of all the points that are not going to be moved - except the surfaces ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - Coord = geometry->node[iPoint]->GetCoord(); - for (iDim = 0; iDim < nDim; iDim++) { - if ((Coord[iDim] < MinCoordValues[iDim]) || (Coord[iDim] > MaxCoordValues[iDim])) { - total_index = iPoint*nDim + iDim; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - StiffMatrix.DeleteValsRowi(total_index); - } - } - } - - delete [] MinCoordValues; - delete [] MaxCoordValues; - -} - -void CVolumetricMovement::Rigid_Rotation(CGeometry *geometry, CConfig *config, - unsigned short iZone, unsigned long iter) { - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Local variables ---*/ - unsigned short iDim, nDim; - unsigned long iPoint; - su2double r[3] = {0.0,0.0,0.0}, rotCoord[3] = {0.0,0.0,0.0}, *Coord; - su2double Center[3] = {0.0,0.0,0.0}, Omega[3] = {0.0,0.0,0.0}, Lref; - su2double dt, Center_Moment[3] = {0.0,0.0,0.0}; - su2double *GridVel, newGridVel[3] = {0.0,0.0,0.0}; - su2double rotMatrix[3][3] = {{0.0,0.0,0.0}, {0.0,0.0,0.0}, {0.0,0.0,0.0}}; - su2double dtheta, dphi, dpsi, cosTheta, sinTheta; - su2double cosPhi, sinPhi, cosPsi, sinPsi; - bool time_spectral = (config->GetUnsteady_Simulation() == TIME_SPECTRAL); - bool adjoint = config->GetAdjoint(); - - /*--- Problem dimension and physical time step ---*/ - nDim = geometry->GetnDim(); - dt = config->GetDelta_UnstTimeND(); - Lref = config->GetLength_Ref(); - - /*--- For time-spectral, motion is the same in each zone (at each instance). - * This is used for calls to the config container ---*/ - if (time_spectral) - iZone = ZONE_0; - - /*--- For the unsteady adjoint, use reverse time ---*/ - if (adjoint) { - /*--- Set the first adjoint mesh position to the final direct one ---*/ - if (iter == 0) dt = ((su2double)config->GetnExtIter()-1)*dt; - /*--- Reverse the rotation direction for the adjoint ---*/ - else dt = -1.0*dt; - } else { - /*--- No rotation at all for the first direct solution ---*/ - if (iter == 0) dt = 0; - } - - /*--- Center of rotation & angular velocity vector from config ---*/ - - Center[0] = config->GetMotion_Origin_X(iZone); - Center[1] = config->GetMotion_Origin_Y(iZone); - Center[2] = config->GetMotion_Origin_Z(iZone); - Omega[0] = (config->GetRotation_Rate_X(iZone)/config->GetOmega_Ref()); - Omega[1] = (config->GetRotation_Rate_Y(iZone)/config->GetOmega_Ref()); - Omega[2] = (config->GetRotation_Rate_Z(iZone)/config->GetOmega_Ref()); - - /*-- Set dt for time-spectral cases ---*/ - if (time_spectral) { - /*--- period of oscillation & compute time interval using nTimeInstances ---*/ - su2double period = config->GetTimeSpectral_Period(); - dt = period * (su2double)iter/(su2double)(config->GetnTimeInstances()); - } - - /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ - - dtheta = Omega[0]*dt; - dphi = Omega[1]*dt; - dpsi = Omega[2]*dt; - - if (rank == MASTER_NODE && iter == 0) { - cout << " Angular velocity: (" << Omega[0] << ", " << Omega[1]; - cout << ", " << Omega[2] << ") rad/s." << endl; - } - - /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ - - cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); - sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ - - rotMatrix[0][0] = cosPhi*cosPsi; - rotMatrix[1][0] = cosPhi*sinPsi; - rotMatrix[2][0] = -sinPhi; - - rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; - rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; - rotMatrix[2][1] = sinTheta*cosPhi; - - rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Loop over and rotate each node in the volume mesh ---*/ - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Coordinates of the current point ---*/ - Coord = geometry->node[iPoint]->GetCoord(); - GridVel = geometry->node[iPoint]->GetGridVel(); - - /*--- Calculate non-dim. position from rotation center ---*/ - r[0] = (Coord[0]-Center[0])/Lref; - r[1] = (Coord[1]-Center[1])/Lref; - if (nDim == 3) r[2] = (Coord[2]-Center[2])/Lref; - - /*--- Compute transformed point coordinates ---*/ - rotCoord[0] = rotMatrix[0][0]*r[0] - + rotMatrix[0][1]*r[1] - + rotMatrix[0][2]*r[2]; - - rotCoord[1] = rotMatrix[1][0]*r[0] - + rotMatrix[1][1]*r[1] - + rotMatrix[1][2]*r[2]; - - rotCoord[2] = rotMatrix[2][0]*r[0] - + rotMatrix[2][1]*r[1] - + rotMatrix[2][2]*r[2]; - - /*--- Cross Product of angular velocity and distance from center. - Note that we have assumed the grid velocities have been set to - an initial value in the plunging routine. ---*/ - - newGridVel[0] = GridVel[0] + Omega[1]*rotCoord[2] - Omega[2]*rotCoord[1]; - newGridVel[1] = GridVel[1] + Omega[2]*rotCoord[0] - Omega[0]*rotCoord[2]; - newGridVel[2] = GridVel[2] + Omega[0]*rotCoord[1] - Omega[1]*rotCoord[0]; - - /*--- Store new node location & grid velocity. Add center. - Do not store the grid velocity if this is an adjoint calculation.---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - geometry->node[iPoint]->SetCoord(iDim, rotCoord[iDim] + Center[iDim]); - if (!adjoint) geometry->node[iPoint]->SetGridVel(iDim, newGridVel[iDim]); - - } - } - - /*--- Set the moment computation center to the new location after - incrementing the position with the rotation. ---*/ - - for (unsigned short jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { - - Center_Moment[0] = config->GetRefOriginMoment_X(jMarker); - Center_Moment[1] = config->GetRefOriginMoment_Y(jMarker); - Center_Moment[2] = config->GetRefOriginMoment_Z(jMarker); - - /*--- Calculate non-dim. position from rotation center ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - r[iDim] = (Center_Moment[iDim]-Center[iDim])/Lref; - if (nDim == 2) r[nDim] = 0.0; - - /*--- Compute transformed point coordinates ---*/ - - rotCoord[0] = rotMatrix[0][0]*r[0] - + rotMatrix[0][1]*r[1] - + rotMatrix[0][2]*r[2]; - - rotCoord[1] = rotMatrix[1][0]*r[0] - + rotMatrix[1][1]*r[1] - + rotMatrix[1][2]*r[2]; - - rotCoord[2] = rotMatrix[2][0]*r[0] - + rotMatrix[2][1]*r[1] - + rotMatrix[2][2]*r[2]; - - config->SetRefOriginMoment_X(jMarker, Center[0]+rotCoord[0]); - config->SetRefOriginMoment_Y(jMarker, Center[1]+rotCoord[1]); - config->SetRefOriginMoment_Z(jMarker, Center[2]+rotCoord[2]); - } - - /*--- After moving all nodes, update geometry class ---*/ - - UpdateDualGrid(geometry, config); - -} - -void CVolumetricMovement::Rigid_Pitching(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter) { - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Local variables ---*/ - su2double r[3] = {0.0,0.0,0.0}, rotCoord[3] = {0.0,0.0,0.0}, *Coord, Center[3] = {0.0,0.0,0.0}, - Omega[3] = {0.0,0.0,0.0}, Ampl[3] = {0.0,0.0,0.0}, Phase[3] = {0.0,0.0,0.0}; - su2double Lref, deltaT, alphaDot[3], *GridVel, newGridVel[3] = {0.0,0.0,0.0}; - su2double rotMatrix[3][3] = {{0.0,0.0,0.0}, {0.0,0.0,0.0}, {0.0,0.0,0.0}}; - su2double dtheta, dphi, dpsi, cosTheta, sinTheta; - su2double cosPhi, sinPhi, cosPsi, sinPsi; - su2double time_new, time_old; - su2double DEG2RAD = PI_NUMBER/180.0; - unsigned short iDim; - unsigned short nDim = geometry->GetnDim(); - unsigned long iPoint; - bool time_spectral = (config->GetUnsteady_Simulation() == TIME_SPECTRAL); - bool adjoint = config->GetAdjoint(); - - /*--- Retrieve values from the config file ---*/ - deltaT = config->GetDelta_UnstTimeND(); - Lref = config->GetLength_Ref(); - - /*--- For time-spectral, motion is the same in each zone (at each instance). ---*/ - if (time_spectral) { - iZone = ZONE_0; - } - - /*--- Pitching origin, frequency, and amplitude from config. ---*/ - Center[0] = config->GetMotion_Origin_X(iZone); - Center[1] = config->GetMotion_Origin_Y(iZone); - Center[2] = config->GetMotion_Origin_Z(iZone); - Omega[0] = (config->GetPitching_Omega_X(iZone)/config->GetOmega_Ref()); - Omega[1] = (config->GetPitching_Omega_Y(iZone)/config->GetOmega_Ref()); - Omega[2] = (config->GetPitching_Omega_Z(iZone)/config->GetOmega_Ref()); - Ampl[0] = config->GetPitching_Ampl_X(iZone)*DEG2RAD; - Ampl[1] = config->GetPitching_Ampl_Y(iZone)*DEG2RAD; - Ampl[2] = config->GetPitching_Ampl_Z(iZone)*DEG2RAD; - Phase[0] = config->GetPitching_Phase_X(iZone)*DEG2RAD; - Phase[1] = config->GetPitching_Phase_Y(iZone)*DEG2RAD; - Phase[2] = config->GetPitching_Phase_Z(iZone)*DEG2RAD; - - if (time_spectral) { - /*--- period of oscillation & compute time interval using nTimeInstances ---*/ - su2double period = config->GetTimeSpectral_Period(); - deltaT = period/(su2double)(config->GetnTimeInstances()); - } - - /*--- Compute delta time based on physical time step ---*/ - if (adjoint) { - /*--- For the unsteady adjoint, we integrate backwards through - physical time, so perform mesh motion in reverse. ---*/ - unsigned long nFlowIter = config->GetnExtIter(); - unsigned long directIter = nFlowIter - iter - 1; - time_new = static_cast(directIter)*deltaT; - time_old = time_new; - if (iter != 0) time_old = (static_cast(directIter)+1.0)*deltaT; - } else { - /*--- Forward time for the direct problem ---*/ - time_new = static_cast(iter)*deltaT; - if (time_spectral) { - /*--- For time-spectral, begin movement from the zero position ---*/ - time_old = 0.0; - } else { - time_old = time_new; - if (iter != 0) time_old = (static_cast(iter)-1.0)*deltaT; - } - } - - /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ - - dtheta = -Ampl[0]*(sin(Omega[0]*time_new + Phase[0]) - sin(Omega[0]*time_old + Phase[0])); - dphi = -Ampl[1]*(sin(Omega[1]*time_new + Phase[1]) - sin(Omega[1]*time_old + Phase[1])); - dpsi = -Ampl[2]*(sin(Omega[2]*time_new + Phase[2]) - sin(Omega[2]*time_old + Phase[2])); - - /*--- Angular velocity at the new time ---*/ - - alphaDot[0] = -Omega[0]*Ampl[0]*cos(Omega[0]*time_new); - alphaDot[1] = -Omega[1]*Ampl[1]*cos(Omega[1]*time_new); - alphaDot[2] = -Omega[2]*Ampl[2]*cos(Omega[2]*time_new); - - if (rank == MASTER_NODE && iter == 0) { - cout << " Pitching frequency: (" << Omega[0] << ", " << Omega[1]; - cout << ", " << Omega[2] << ") rad/s." << endl; - cout << " Pitching amplitude: (" << Ampl[0]/DEG2RAD << ", "; - cout << Ampl[1]/DEG2RAD << ", " << Ampl[2]/DEG2RAD; - cout << ") degrees."<< endl; - cout << " Pitching phase lag: (" << Phase[0]/DEG2RAD << ", "; - cout << Phase[1]/DEG2RAD <<", "<< Phase[2]/DEG2RAD; - cout << ") degrees."<< endl; - } - - /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ - - cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); - sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ - - rotMatrix[0][0] = cosPhi*cosPsi; - rotMatrix[1][0] = cosPhi*sinPsi; - rotMatrix[2][0] = -sinPhi; - - rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; - rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; - rotMatrix[2][1] = sinTheta*cosPhi; - - rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Loop over and rotate each node in the volume mesh ---*/ - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Coordinates of the current point ---*/ - Coord = geometry->node[iPoint]->GetCoord(); - GridVel = geometry->node[iPoint]->GetGridVel(); - - /*--- Calculate non-dim. position from rotation center ---*/ - for (iDim = 0; iDim < nDim; iDim++) - r[iDim] = (Coord[iDim]-Center[iDim])/Lref; - if (nDim == 2) r[nDim] = 0.0; - - /*--- Compute transformed point coordinates ---*/ - rotCoord[0] = rotMatrix[0][0]*r[0] - + rotMatrix[0][1]*r[1] - + rotMatrix[0][2]*r[2]; - - rotCoord[1] = rotMatrix[1][0]*r[0] - + rotMatrix[1][1]*r[1] - + rotMatrix[1][2]*r[2]; - - rotCoord[2] = rotMatrix[2][0]*r[0] - + rotMatrix[2][1]*r[1] - + rotMatrix[2][2]*r[2]; - - /*--- Cross Product of angular velocity and distance from center. - Note that we have assumed the grid velocities have been set to - an initial value in the plunging routine. ---*/ - - newGridVel[0] = GridVel[0] + alphaDot[1]*rotCoord[2] - alphaDot[2]*rotCoord[1]; - newGridVel[1] = GridVel[1] + alphaDot[2]*rotCoord[0] - alphaDot[0]*rotCoord[2]; - newGridVel[2] = GridVel[2] + alphaDot[0]*rotCoord[1] - alphaDot[1]*rotCoord[0]; - - /*--- Store new node location & grid velocity. Add center location. - Do not store the grid velocity if this is an adjoint calculation.---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - geometry->node[iPoint]->SetCoord(iDim, rotCoord[iDim]+Center[iDim]); - if (!adjoint) geometry->node[iPoint]->SetGridVel(iDim, newGridVel[iDim]); - } - } - - /*--- For pitching we don't update the motion origin and moment reference origin. ---*/ - - /*--- After moving all nodes, update geometry class ---*/ - - UpdateDualGrid(geometry, config); - -} - -void CVolumetricMovement::Rigid_Plunging(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter) { - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Local variables ---*/ - su2double deltaX[3], newCoord[3], Center[3], *Coord, Omega[3], Ampl[3], Lref; - su2double *GridVel, newGridVel[3], xDot[3]; - su2double deltaT, time_new, time_old; - unsigned short iDim, nDim = geometry->GetnDim(); - unsigned long iPoint; - bool time_spectral = (config->GetUnsteady_Simulation() == TIME_SPECTRAL); - bool adjoint = config->GetAdjoint(); - - /*--- Retrieve values from the config file ---*/ - deltaT = config->GetDelta_UnstTimeND(); - Lref = config->GetLength_Ref(); - - /*--- For time-spectral, motion is the same in each zone (at each instance). ---*/ - if (time_spectral) { - iZone = ZONE_0; - } - - /*--- Plunging frequency and amplitude from config. ---*/ - Center[0] = config->GetMotion_Origin_X(iZone); - Center[1] = config->GetMotion_Origin_Y(iZone); - Center[2] = config->GetMotion_Origin_Z(iZone); - Omega[0] = (config->GetPlunging_Omega_X(iZone)/config->GetOmega_Ref()); - Omega[1] = (config->GetPlunging_Omega_Y(iZone)/config->GetOmega_Ref()); - Omega[2] = (config->GetPlunging_Omega_Z(iZone)/config->GetOmega_Ref()); - Ampl[0] = config->GetPlunging_Ampl_X(iZone)/Lref; - Ampl[1] = config->GetPlunging_Ampl_Y(iZone)/Lref; - Ampl[2] = config->GetPlunging_Ampl_Z(iZone)/Lref; - - if (time_spectral) { - /*--- period of oscillation & time interval using nTimeInstances ---*/ - su2double period = config->GetTimeSpectral_Period(); - deltaT = period/(su2double)(config->GetnTimeInstances()); - } - - /*--- Compute delta time based on physical time step ---*/ - if (adjoint) { - /*--- For the unsteady adjoint, we integrate backwards through - physical time, so perform mesh motion in reverse. ---*/ - unsigned long nFlowIter = config->GetnExtIter(); - unsigned long directIter = nFlowIter - iter - 1; - time_new = static_cast(directIter)*deltaT; - time_old = time_new; - if (iter != 0) time_old = (static_cast(directIter)+1.0)*deltaT; - } else { - /*--- Forward time for the direct problem ---*/ - time_new = static_cast(iter)*deltaT; - if (time_spectral) { - /*--- For time-spectral, begin movement from the zero position ---*/ - time_old = 0.0; - } else { - time_old = time_new; - if (iter != 0) time_old = (static_cast(iter)-1.0)*deltaT; - } - } - - /*--- Compute delta change in the position in the x, y, & z directions. ---*/ - deltaX[0] = -Ampl[0]*(sin(Omega[0]*time_new) - sin(Omega[0]*time_old)); - deltaX[1] = -Ampl[1]*(sin(Omega[1]*time_new) - sin(Omega[1]*time_old)); - deltaX[2] = -Ampl[2]*(sin(Omega[2]*time_new) - sin(Omega[2]*time_old)); - - /*--- Compute grid velocity due to plunge in the x, y, & z directions. ---*/ - xDot[0] = -Ampl[0]*Omega[0]*(cos(Omega[0]*time_new)); - xDot[1] = -Ampl[1]*Omega[1]*(cos(Omega[1]*time_new)); - xDot[2] = -Ampl[2]*Omega[2]*(cos(Omega[2]*time_new)); - - if (rank == MASTER_NODE && iter == 0) { - cout << " Plunging frequency: (" << Omega[0] << ", " << Omega[1]; - cout << ", " << Omega[2] << ") rad/s." << endl; - cout << " Plunging amplitude: (" << Ampl[0] << ", "; - cout << Ampl[1] << ", " << Ampl[2] << ") m."<< endl; - } - - /*--- Loop over and move each node in the volume mesh ---*/ - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Coordinates of the current point ---*/ - Coord = geometry->node[iPoint]->GetCoord(); - GridVel = geometry->node[iPoint]->GetGridVel(); - - /*--- Increment the node position using the delta values. ---*/ - for (iDim = 0; iDim < nDim; iDim++) - newCoord[iDim] = Coord[iDim] + deltaX[iDim]; - - /*--- Cross Product of angular velocity and distance from center. - Note that we have assumed the grid velocities have been set to - an initial value in the plunging routine. ---*/ - - newGridVel[0] = GridVel[0] + xDot[0]; - newGridVel[1] = GridVel[1] + xDot[1]; - newGridVel[2] = GridVel[2] + xDot[2]; - - /*--- Store new node location & grid velocity. Do not store the grid - velocity if this is an adjoint calculation. ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - geometry->node[iPoint]->SetCoord(iDim, newCoord[iDim]); - if (!adjoint) geometry->node[iPoint]->SetGridVel(iDim, newGridVel[iDim]); - } - } - - /*--- Set the mesh motion center to the new location after - incrementing the position with the rigid translation. This - new location will be used for subsequent pitching/rotation.---*/ - - config->SetMotion_Origin_X(iZone, Center[0]+deltaX[0]); - config->SetMotion_Origin_Y(iZone, Center[1]+deltaX[1]); - config->SetMotion_Origin_Z(iZone, Center[2]+deltaX[2]); - - /*--- As the body origin may have moved, print it to the console ---*/ - -// if (rank == MASTER_NODE) { -// cout << " Body origin: (" << Center[0]+deltaX[0]; -// cout << ", " << Center[1]+deltaX[1] << ", " << Center[2]+deltaX[2]; -// cout << ")." << endl; -// } - - /*--- Set the moment computation center to the new location after - incrementing the position with the plunging. ---*/ - - for (unsigned short jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { - Center[0] = config->GetRefOriginMoment_X(jMarker) + deltaX[0]; - Center[1] = config->GetRefOriginMoment_Y(jMarker) + deltaX[1]; - Center[2] = config->GetRefOriginMoment_Z(jMarker) + deltaX[2]; - config->SetRefOriginMoment_X(jMarker, Center[0]); - config->SetRefOriginMoment_Y(jMarker, Center[1]); - config->SetRefOriginMoment_Z(jMarker, Center[2]); - } - - /*--- After moving all nodes, update geometry class ---*/ - - UpdateDualGrid(geometry, config); - -} - -void CVolumetricMovement::Rigid_Translation(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter) { - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Local variables ---*/ - su2double deltaX[3], newCoord[3], Center[3], *Coord; - su2double xDot[3]; - su2double deltaT, time_new, time_old; - unsigned short iDim, nDim = geometry->GetnDim(); - unsigned long iPoint; - bool time_spectral = (config->GetUnsteady_Simulation() == TIME_SPECTRAL); - bool adjoint = config->GetAdjoint(); - - /*--- Retrieve values from the config file ---*/ - deltaT = config->GetDelta_UnstTimeND(); - - /*--- For time-spectral, motion is the same in each zone (at each instance). ---*/ - if (time_spectral) { - iZone = ZONE_0; - } - - /*--- Get motion center and translation rates from config ---*/ - Center[0] = config->GetMotion_Origin_X(iZone); - Center[1] = config->GetMotion_Origin_Y(iZone); - Center[2] = config->GetMotion_Origin_Z(iZone); - xDot[0] = config->GetTranslation_Rate_X(iZone); - xDot[1] = config->GetTranslation_Rate_Y(iZone); - xDot[2] = config->GetTranslation_Rate_Z(iZone); - - if (time_spectral) { - /*--- period of oscillation & time interval using nTimeInstances ---*/ - su2double period = config->GetTimeSpectral_Period(); - deltaT = period/(su2double)(config->GetnTimeInstances()); - } - - /*--- Compute delta time based on physical time step ---*/ - if (adjoint) { - /*--- For the unsteady adjoint, we integrate backwards through - physical time, so perform mesh motion in reverse. ---*/ - unsigned long nFlowIter = config->GetnExtIter(); - unsigned long directIter = nFlowIter - iter - 1; - time_new = static_cast(directIter)*deltaT; - time_old = time_new; - if (iter != 0) time_old = (static_cast(directIter)+1.0)*deltaT; - } else { - /*--- Forward time for the direct problem ---*/ - time_new = static_cast(iter)*deltaT; - if (time_spectral) { - /*--- For time-spectral, begin movement from the zero position ---*/ - time_old = 0.0; - } else { - time_old = time_new; - if (iter != 0) time_old = (static_cast(iter)-1.0)*deltaT; - } - } - - /*--- Compute delta change in the position in the x, y, & z directions. ---*/ - deltaX[0] = xDot[0]*(time_new-time_old); - deltaX[1] = xDot[1]*(time_new-time_old); - deltaX[2] = xDot[2]*(time_new-time_old); - - if (rank == MASTER_NODE) { - cout << " New physical time: " << time_new << " seconds." << endl; - if (iter == 0) { - cout << " Translational velocity: (" << xDot[0] << ", " << xDot[1]; - cout << ", " << xDot[2] << ") m/s." << endl; - } - } - - /*--- Loop over and move each node in the volume mesh ---*/ - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Coordinates of the current point ---*/ - Coord = geometry->node[iPoint]->GetCoord(); - - /*--- Increment the node position using the delta values. ---*/ - for (iDim = 0; iDim < nDim; iDim++) - newCoord[iDim] = Coord[iDim] + deltaX[iDim]; - - /*--- Store new node location & grid velocity. Do not store the grid - velocity if this is an adjoint calculation. ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - geometry->node[iPoint]->SetCoord(iDim, newCoord[iDim]); - if (!adjoint) geometry->node[iPoint]->SetGridVel(iDim,xDot[iDim]); - } - } - - /*--- Set the mesh motion center to the new location after - incrementing the position with the rigid translation. This - new location will be used for subsequent pitching/rotation.---*/ - - config->SetMotion_Origin_X(iZone, Center[0]+deltaX[0]); - config->SetMotion_Origin_Y(iZone, Center[1]+deltaX[1]); - config->SetMotion_Origin_Z(iZone, Center[2]+deltaX[2]); - - /*--- Set the moment computation center to the new location after - incrementing the position with the translation. ---*/ - - for (unsigned short jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { - Center[0] = config->GetRefOriginMoment_X(jMarker) + deltaX[0]; - Center[1] = config->GetRefOriginMoment_Y(jMarker) + deltaX[1]; - Center[2] = config->GetRefOriginMoment_Z(jMarker) + deltaX[2]; - config->SetRefOriginMoment_X(jMarker, Center[0]); - config->SetRefOriginMoment_Y(jMarker, Center[1]); - config->SetRefOriginMoment_Z(jMarker, Center[2]); - } - - /*--- After moving all nodes, update geometry class ---*/ - - UpdateDualGrid(geometry, config); - -} - -void CVolumetricMovement::SetVolume_Scaling(CGeometry *geometry, CConfig *config, bool UpdateGeo) { - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - unsigned short iDim; - unsigned long iPoint; - su2double newCoord[3] = {0.0,0.0,0.0}, *Coord; - - /*--- The scaling factor is the only input to this option. Currently, - the mesh must be scaled the same amount in all three directions. ---*/ - su2double Scale = config->GetDV_Value(0); - if (rank == MASTER_NODE) { - cout << "Scaling the mesh by a constant factor of " << Scale << "." << endl; - } - - /*--- Loop over and move each node in the volume mesh ---*/ - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Coordinates of the current point ---*/ - Coord = geometry->node[iPoint]->GetCoord(); - - /*--- Scale the node position by the specified factor. ---*/ - for (iDim = 0; iDim < nDim; iDim++) - newCoord[iDim] = Scale*Coord[iDim]; - - /*--- Store the new node location. ---*/ - for (iDim = 0; iDim < nDim; iDim++) { - geometry->node[iPoint]->SetCoord(iDim, newCoord[iDim]); - } - } - - /*--- After moving all nodes, update geometry class ---*/ - if (UpdateGeo) UpdateDualGrid(geometry, config); - -} - -void CVolumetricMovement::SetVolume_Translation(CGeometry *geometry, CConfig *config, bool UpdateGeo) { - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - unsigned short iDim; - unsigned long iPoint; - su2double *Coord, deltaX[3] = {0.0,0.0,0.0}, newCoord[3] = {0.0,0.0,0.0}; - - /*--- Get the unit vector and magnitude of displacement. Note that we - assume this is the first DV entry since it is for mesh translation. - Create the displacement vector from the magnitude and direction. ---*/ - - su2double Ampl = config->GetDV_Value(0); - su2double length = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - deltaX[iDim] = config->GetParamDV(0, iDim); - length += deltaX[iDim]*deltaX[iDim]; - } - length = sqrt(length); - for (iDim = 0; iDim < nDim; iDim++) - deltaX[iDim] = Ampl*deltaX[iDim]/length; - if (rank == MASTER_NODE) { - cout << "Translational displacement: (" << deltaX[0] << ", "; - cout << deltaX[1] << ", " << deltaX[2] << ")." << endl; - } - - /*--- Loop over and move each node in the volume mesh ---*/ - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Coordinates of the current point ---*/ - Coord = geometry->node[iPoint]->GetCoord(); - - /*--- Increment the node position using the delta values. ---*/ - for (iDim = 0; iDim < nDim; iDim++) - newCoord[iDim] = Coord[iDim] + deltaX[iDim]; - - /*--- Store new node location. ---*/ - for (iDim = 0; iDim < nDim; iDim++) { - geometry->node[iPoint]->SetCoord(iDim, newCoord[iDim]); - } - } - - /*--- After moving all nodes, update geometry class ---*/ - if (UpdateGeo) UpdateDualGrid(geometry, config); - -} - -void CVolumetricMovement::SetVolume_Rotation(CGeometry *geometry, CConfig *config, bool UpdateGeo) { - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - unsigned short iDim; - unsigned long iPoint; - su2double x, y, z; - su2double *Coord, deltaX[3] = {0.0,0.0,0.0}, newCoord[3] = {0.0,0.0,0.0}; - - /*--- xyz-coordinates of a point on the line of rotation. */ - su2double a = config->GetParamDV(0, 0); - su2double b = config->GetParamDV(0, 1); - su2double c = 0.0; - if (geometry->GetnDim() == 3) c = config->GetParamDV(0,2); - - /*--- xyz-coordinate of the line's direction vector. ---*/ - su2double u = config->GetParamDV(0, 3)-config->GetParamDV(0, 0); - su2double v = config->GetParamDV(0, 4)-config->GetParamDV(0, 1); - su2double w = 1.0; - if (geometry->GetnDim() == 3) - w = config->GetParamDV(0, 5)-config->GetParamDV(0, 2); - - /*--- The angle of rotation. ---*/ - su2double theta = config->GetDV_Value(0)*PI_NUMBER/180.0; - - /*--- Print to the console. ---*/ - if (rank == MASTER_NODE) { - cout << "Rotation axis vector: (" << u << ", "; - cout << v << ", " << w << ")." << endl; - cout << "Angle of rotation: " << config->GetDV_Value(0); - cout << " degrees." << endl; - } - - /*--- Intermediate values used in computations. ---*/ - su2double u2=u*u; su2double v2=v*v; su2double w2=w*w; - su2double cosT = cos(theta); su2double sinT = sin(theta); - su2double l2 = u2 + v2 + w2; su2double l = sqrt(l2); - - /*--- Loop over and move each node in the volume mesh ---*/ - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Coordinates of the current point ---*/ - Coord = geometry->node[iPoint]->GetCoord(); - - /*--- Displacement for this point due to the rotation. ---*/ - x = Coord[0]; y = Coord[1]; z = 0.0; - if (geometry->GetnDim() == 3) z = Coord[2]; - - deltaX[0] = a*(v2 + w2) + u*(-b*v - c*w + u*x + v*y + w*z) - + (-a*(v2 + w2) + u*(b*v + c*w - v*y - w*z) + (v2 + w2)*x)*cosT - + l*(-c*v + b*w - w*y + v*z)*sinT; - deltaX[0] = deltaX[0]/l2 - x; - - deltaX[1] = b*(u2 + w2) + v*(-a*u - c*w + u*x + v*y + w*z) - + (-b*(u2 + w2) + v*(a*u + c*w - u*x - w*z) + (u2 + w2)*y)*cosT - + l*(c*u - a*w + w*x - u*z)*sinT; - deltaX[1] = deltaX[1]/l2 - y; - - deltaX[2] = c*(u2 + v2) + w*(-a*u - b*v + u*x + v*y + w*z) - + (-c*(u2 + v2) + w*(a*u + b*v - u*x - v*y) + (u2 + v2)*z)*cosT - + l*(-b*u + a*v - v*x + u*y)*sinT; - if (geometry->GetnDim() == 3) deltaX[2] = deltaX[2]/l2 - z; - else deltaX[2] = 0.0; - - /*--- Increment the node position using the delta values. ---*/ - for (iDim = 0; iDim < nDim; iDim++) - newCoord[iDim] = Coord[iDim] + deltaX[iDim]; - - /*--- Store new node location. ---*/ - for (iDim = 0; iDim < nDim; iDim++) { - geometry->node[iPoint]->SetCoord(iDim, newCoord[iDim]); - } - } - - /*--- After moving all nodes, update geometry class ---*/ - if (UpdateGeo) UpdateDualGrid(geometry, config); - -} - -CSurfaceMovement::CSurfaceMovement(void) : CGridMovement() { - nFFDBox = 0; - nLevel = 0; - FFDBoxDefinition = false; -} - -CSurfaceMovement::~CSurfaceMovement(void) {} - -void CSurfaceMovement::SetSurface_Deformation(CGeometry *geometry, CConfig *config) { - - unsigned short iFFDBox, iDV, iLevel, iChild, iParent, jFFDBox, iMarker; - int rank = MASTER_NODE; - string FFDBoxTag; - bool allmoving; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Setting the Free Form Deformation ---*/ - - if (config->GetDesign_Variable(0) == FFD_SETTING) { - - /*--- Definition of the FFD deformation class ---*/ - - FFDBox = new CFreeFormDefBox*[MAX_NUMBER_FFD]; - - /*--- Read the FFD information from the config file ---*/ - - ReadFFDInfo(geometry, config, FFDBox); - - /*--- If there is a FFDBox in the input file ---*/ - - if (nFFDBox != 0) { - - /*--- If the FFDBox was not defined in the input file ---*/ - - if ((rank == MASTER_NODE) && (GetnFFDBox() != 0)) - cout << endl <<"----------------- FFD technique (cartesian -> parametric) ---------------" << endl; - - /*--- Create a unitary FFDBox as baseline for other FFDBoxes shapes ---*/ - - CFreeFormDefBox FFDBox_unitary(1,1,1); - FFDBox_unitary.SetUnitCornerPoints(); - - /*--- Compute the control points of the unitary box, in this case the degree is 1 and the order is 2 ---*/ - - FFDBox_unitary.SetControlPoints_Parallelepiped(); - - for (iFFDBox = 0; iFFDBox < GetnFFDBox(); iFFDBox++) { - - /*--- Compute the support control points for the final FFD using the unitary box ---*/ - - FFDBox_unitary.SetSupportCP(FFDBox[iFFDBox]); - - /*--- Compute control points in the support box ---*/ - - FFDBox_unitary.SetSupportCPChange(FFDBox[iFFDBox]); - - /*--- Compute the parametric coordinates, it also find the points in - the FFDBox using the parametrics coordinates ---*/ - - SetParametricCoord(geometry, config, FFDBox[iFFDBox], iFFDBox); - - /*--- Output original FFD FFDBox ---*/ - - if (rank == MASTER_NODE) { - cout << "Writing a Tecplot file of the FFD boxes." << endl; - FFDBox[iFFDBox]->SetTecplot(geometry, iFFDBox, true); - } - - } - - } - - else { - - cout << "There are not FFD boxes in the mesh file!!" << endl; - exit(EXIT_FAILURE); - - } - - } - - /*--- Free Form deformation based ---*/ - - if ((config->GetDesign_Variable(0) == FFD_CONTROL_POINT_2D) || - (config->GetDesign_Variable(0) == FFD_CAMBER_2D) || - (config->GetDesign_Variable(0) == FFD_THICKNESS_2D) || - (config->GetDesign_Variable(0) == FFD_CONTROL_POINT) || - (config->GetDesign_Variable(0) == FFD_DIHEDRAL_ANGLE) || - (config->GetDesign_Variable(0) == FFD_TWIST_ANGLE) || - (config->GetDesign_Variable(0) == FFD_ROTATION) || - (config->GetDesign_Variable(0) == FFD_CONTROL_SURFACE) || - (config->GetDesign_Variable(0) == FFD_CAMBER) || - (config->GetDesign_Variable(0) == FFD_THICKNESS)) { - - /*--- Definition of the FFD deformation class ---*/ - - FFDBox = new CFreeFormDefBox*[MAX_NUMBER_FFD]; - - /*--- Read the FFD information from the grid file ---*/ - - ReadFFDInfo(geometry, config, FFDBox, config->GetMesh_FileName()); - - /*--- If there is a FFDBox in the input file ---*/ - - if (nFFDBox != 0) { - - /*--- If the FFDBox was not defined in the input file ---*/ - - if (!GetFFDBoxDefinition()) { - - cout << endl << "There is not FFD box definition in the mesh file," << endl; - cout << "run DV_KIND=FFD_SETTING first !!" << endl; - exit(EXIT_FAILURE); - - } - - /*--- Output original FFD FFDBox ---*/ - - if (rank == MASTER_NODE) { - cout << "Writing a Tecplot file of the FFD boxes." << endl; - for (iFFDBox = 0; iFFDBox < GetnFFDBox(); iFFDBox++) { - FFDBox[iFFDBox]->SetTecplot(geometry, iFFDBox, true); - } - } - - /*--- Apply the deformation to the orifinal FFD box ---*/ - - if ((rank == MASTER_NODE) && (GetnFFDBox() != 0)) - cout << endl <<"----------------- FFD technique (parametric -> cartesian) ---------------" << endl; - - /*--- Loop over all the FFD boxes levels ---*/ - - for (iLevel = 0; iLevel < GetnLevel(); iLevel++) { - - /*--- Loop over all FFD FFDBoxes ---*/ - - for (iFFDBox = 0; iFFDBox < GetnFFDBox(); iFFDBox++) { - - /*--- Check the level of the FFD box ---*/ - - if (FFDBox[iFFDBox]->GetLevel() == iLevel) { - - - /*--- Compute intersections of the FFD box with the surface to eliminate design - variables and satisfy surface continuity ---*/ - - if (rank == MASTER_NODE) - cout << "Checking FFD box intersections with the solid surfaces." << endl; - - CheckFFDIntersections(geometry, config, FFDBox[iFFDBox], iFFDBox); - - /*--- Compute the parametric coordinates of the child box - control points (using the parent FFDBox) ---*/ - - for (iChild = 0; iChild < FFDBox[iFFDBox]->GetnChildFFDBox(); iChild++) { - FFDBoxTag = FFDBox[iFFDBox]->GetChildFFDBoxTag(iChild); - for (jFFDBox = 0; jFFDBox < GetnFFDBox(); jFFDBox++) - if (FFDBoxTag == FFDBox[jFFDBox]->GetTag()) break; - SetParametricCoordCP(geometry, config, FFDBox[iFFDBox], FFDBox[jFFDBox]); - } - - /*--- Update the parametric coordinates if it is a child FFDBox ---*/ - - if (iLevel > 0) UpdateParametricCoord(geometry, config, FFDBox[iFFDBox], iFFDBox); - - /*--- Apply the design variables to the control point position ---*/ - - for (iDV = 0; iDV < config->GetnDV(); iDV++) { - switch ( config->GetDesign_Variable(iDV) ) { - case FFD_CONTROL_POINT_2D : SetFFDCPChange_2D(geometry, config, FFDBox[iFFDBox], iDV, false); break; - case FFD_CAMBER_2D : SetFFDCamber_2D(geometry, config, FFDBox[iFFDBox], iDV, false); break; - case FFD_THICKNESS_2D : SetFFDThickness_2D(geometry, config, FFDBox[iFFDBox], iDV, false); break; - case FFD_CONTROL_POINT : SetFFDCPChange(geometry, config, FFDBox[iFFDBox], iDV, false); break; - case FFD_DIHEDRAL_ANGLE : SetFFDDihedralAngle(geometry, config, FFDBox[iFFDBox], iDV, false); break; - case FFD_TWIST_ANGLE : SetFFDTwistAngle(geometry, config, FFDBox[iFFDBox], iDV, false); break; - case FFD_ROTATION : SetFFDRotation(geometry, config, FFDBox[iFFDBox], iDV, false); break; - case FFD_CONTROL_SURFACE : SetFFDControl_Surface(geometry, config, FFDBox[iFFDBox], iDV, false); break; - case FFD_CAMBER : SetFFDCamber(geometry, config, FFDBox[iFFDBox], iDV, false); break; - case FFD_THICKNESS : SetFFDThickness(geometry, config, FFDBox[iFFDBox], iDV, false); break; - } - } - - /*--- Recompute cartesian coordinates using the new control point location ---*/ - - SetCartesianCoord(geometry, config, FFDBox[iFFDBox], iFFDBox); - - /*--- Reparametrization of the parent FFD box ---*/ - - for (iParent = 0; iParent < FFDBox[iFFDBox]->GetnParentFFDBox(); iParent++) { - FFDBoxTag = FFDBox[iFFDBox]->GetParentFFDBoxTag(iParent); - for (jFFDBox = 0; jFFDBox < GetnFFDBox(); jFFDBox++) - if (FFDBoxTag == FFDBox[jFFDBox]->GetTag()) break; - UpdateParametricCoord(geometry, config, FFDBox[jFFDBox], jFFDBox); - } - - /*--- Compute the new location of the control points of the child boxes - (using the parent FFDBox) ---*/ - - for (iChild = 0; iChild < FFDBox[iFFDBox]->GetnChildFFDBox(); iChild++) { - FFDBoxTag = FFDBox[iFFDBox]->GetChildFFDBoxTag(iChild); - for (jFFDBox = 0; jFFDBox < GetnFFDBox(); jFFDBox++) - if (FFDBoxTag == FFDBox[jFFDBox]->GetTag()) break; - GetCartesianCoordCP(geometry, config, FFDBox[iFFDBox], FFDBox[jFFDBox]); - } - } - } - - /*--- Output the deformed FFD Boxes ---*/ - - if (rank == MASTER_NODE) { - cout << "Writing a Tecplot file of the FFD boxes." << endl; - for (iFFDBox = 0; iFFDBox < GetnFFDBox(); iFFDBox++) { - FFDBox[iFFDBox]->SetTecplot(geometry, iFFDBox, false); - } - } - - } - } - - else { - - cout << "There are not FFD boxes in the mesh file!!" << endl; - exit(EXIT_FAILURE); - - } - - } - - /*--- External surface file based ---*/ - - else if (config->GetDesign_Variable(0) == SURFACE_FILE) { - - /*--- Check whether a surface file exists for input ---*/ - ofstream Surface_File; - string filename = config->GetMotion_FileName(); - Surface_File.open(filename.c_str(), ios::in); - - /*--- A surface file does not exist, so write a new one for the - markers that are specified as part of the motion. ---*/ - if (Surface_File.fail()) { - - if (rank == MASTER_NODE) - cout << "No surface file found. Writing a new file: " << filename << "." << endl; - - Surface_File.open(filename.c_str(), ios::out); - Surface_File.precision(15); - unsigned long iMarker, jPoint, GlobalIndex, iVertex; su2double *Coords; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_DV(iMarker) == YES) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - jPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - GlobalIndex = geometry->node[jPoint]->GetGlobalIndex(); - Coords = geometry->node[jPoint]->GetCoord(); - Surface_File << GlobalIndex << "\t" << Coords[0] << "\t" << Coords[1]; - if (geometry->GetnDim() == 2) Surface_File << endl; - else Surface_File << "\t" << Coords[2] << endl; - } - } - } - Surface_File.close(); - - /*--- A surface file exists, so read in the coordinates ---*/ - - } - - else { - Surface_File.close(); - if (rank == MASTER_NODE) cout << "Updating the surface coordinates from the input file." << endl; - SetExternal_Deformation(geometry, config, ZONE_0, 0); - } - - } - - /*--- 2D airfoil Hicks-Henne bump functions ---*/ - - else if (config->GetDesign_Variable(0) == HICKS_HENNE) { - - /*--- Apply rotation, displacement and stretching design variables (this - should be done before the bump function design variables) ---*/ - - for (iDV = 0; iDV < config->GetnDV(); iDV++) { - switch ( config->GetDesign_Variable(iDV) ) { - case SCALE : SetScale(geometry, config, iDV, false); break; - case TRANSLATION : SetTranslation(geometry, config, iDV, false); break; - case ROTATION : SetRotation(geometry, config, iDV, false); break; - } - } - - /*--- Apply the design variables to the control point position ---*/ - - for (iDV = 0; iDV < config->GetnDV(); iDV++) { - switch ( config->GetDesign_Variable(iDV) ) { - case HICKS_HENNE : SetHicksHenne(geometry, config, iDV, false); break; - } - } - - } - - /*--- NACA_4Digits design variable ---*/ - - else if (config->GetDesign_Variable(0) == NACA_4DIGITS) { SetNACA_4Digits(geometry, config); } - - /*--- Parabolic airfoil design variable ---*/ - - else if (config->GetDesign_Variable(0) == PARABOLIC) { SetParabolic(geometry, config); } - - /*--- Airfoil from file design variable ---*/ - - else if (config->GetDesign_Variable(0) == AIRFOIL) { SetAirfoil(geometry, config); } - - /*--- FFD setting ---*/ - - else if (config->GetDesign_Variable(0) == FFD_SETTING) { - if (rank == MASTER_NODE) - cout << "No surface deformation (setting FFD)." << endl; - } - - /*--- Scale, Translate, and Rotate will be done with rigid mesh transforms. ---*/ - - else if ((config->GetDesign_Variable(0) == ROTATION) || - (config->GetDesign_Variable(0) == TRANSLATION) || - (config->GetDesign_Variable(0) == SCALE)) { - - /*--- If all markers are deforming, use volume method. - If only some are deforming, use surface method ---*/ - - /*--- iDV was uninitialized, so hard-coding to one. Check intended - behavior (might want to loop over all iDV in case we have trans & rotate. ---*/ - iDV = 0; - allmoving = true; - - /*--- Loop over markers ---*/ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++){ - if (config->GetMarker_All_DV(iMarker) == NO) - allmoving = false; - } - - if (!allmoving){ - /*---Only some markers are moving, use the surface method ---*/ - if (config->GetDesign_Variable(0) == ROTATION) - SetRotation(geometry, config, iDV, false); - if (config->GetDesign_Variable(0) == SCALE) - SetScale(geometry, config, iDV, false); - if (config->GetDesign_Variable(0) == TRANSLATION) - SetTranslation(geometry, config, iDV, false); - } - else{ - if (rank == MASTER_NODE) - cout << "No surface deformation (scaling, rotation, or translation)." << endl; - } - } - - /*--- Design variable not implement ---*/ - - else { - if (rank == MASTER_NODE) - cout << "Design Variable not implement yet" << endl; - } - -} - - -void CSurfaceMovement::SetSurface_Derivative(CGeometry *geometry, CConfig *config){ - - su2double DV_Value = 0.0; - - unsigned short iDV = 0; - - for (iDV = 0; iDV < config->GetnDV(); iDV++){ - - DV_Value = config->GetDV_Value(iDV); - - /*--- If value of the design variable is not 0.0 we apply the differentation. - * Note if multiple variables are non-zero, we end up with the sum of all the derivatives. ---*/ - - if (DV_Value != 0.0){ - - DV_Value = 0.0; - - SU2_TYPE::SetDerivative(DV_Value, 1.0); - - config->SetDV_Value(iDV, DV_Value); - } - } - - /*--- Run the surface deformation with DV_Value = 0.0 (no deformation at all) ---*/ - - SetSurface_Deformation(geometry, config); -} - -void CSurfaceMovement::CopyBoundary(CGeometry *geometry, CConfig *config) { - - unsigned short iMarker; - unsigned long iVertex, iPoint; - su2double *Coord; - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Coord = geometry->node[iPoint]->GetCoord(); - geometry->vertex[iMarker][iVertex]->SetCoord(Coord); - } - } - -} - -void CSurfaceMovement::SetParametricCoord(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iFFDBox) { - - unsigned short iMarker, iDim, iOrder, jOrder, kOrder, lOrder, mOrder, nOrder; - unsigned long iVertex, iPoint, TotalVertex = 0; - su2double *CartCoordNew, *ParamCoord, CartCoord[3], ParamCoordGuess[3], MaxDiff, my_MaxDiff = 0.0, Diff, *Coord; - int rank; - unsigned short nDim = geometry->GetnDim(); - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#else - rank = MASTER_NODE; -#endif - - /*--- Change order and control points reduce the - complexity of the point inversion (this only works with boxes, - and we maintain an internal copy) ---*/ - - for (iOrder = 0; iOrder < 2; iOrder++) { - for (jOrder = 0; jOrder < 2; jOrder++) { - for (kOrder = 0; kOrder < 2; kOrder++) { - - lOrder = 0; mOrder = 0; nOrder = 0; - if (iOrder == 1) {lOrder = FFDBox->GetlOrder()-1;} - if (jOrder == 1) {mOrder = FFDBox->GetmOrder()-1;} - if (kOrder == 1) {nOrder = FFDBox->GetnOrder()-1;} - - Coord = FFDBox->GetCoordControlPoints(lOrder, mOrder, nOrder); - - FFDBox->SetCoordControlPoints(Coord, iOrder, jOrder, kOrder); - - } - } - } - - FFDBox->SetlOrder(2); FFDBox->SetmOrder(2); FFDBox->SetnOrder(2); - FFDBox->SetnControlPoints(); - - /*--- Point inversion algorithm with a basic box ---*/ - - ParamCoordGuess[0] = 0.5; ParamCoordGuess[1] = 0.5; ParamCoordGuess[2] = 0.5; - CartCoord[0] = 0.0; CartCoord[1] = 0.0; CartCoord[2] = 0.0; - - /*--- Count the number of vertices ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_DV(iMarker) == YES) - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) - TotalVertex++; - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if (config->GetMarker_All_DV(iMarker) == YES) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - /*--- Get the cartesian coordinates ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - CartCoord[iDim] = geometry->vertex[iMarker][iVertex]->GetCoord(iDim); - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - /*--- If the point is inside the FFD, compute the value of the parametric coordinate ---*/ - - if (FFDBox->GetPointFFD(geometry, config, iPoint)) { - - /*--- Find the parametric coordinate ---*/ - - ParamCoord = FFDBox->GetParametricCoord_Iterative(iPoint, CartCoord, ParamCoordGuess, config); - - /*--- If the parametric coordinates are in (0,1) the point belongs to the FFDBox ---*/ - - if (((ParamCoord[0] >= - EPS) && (ParamCoord[0] <= 1.0 + EPS)) && - ((ParamCoord[1] >= - EPS) && (ParamCoord[1] <= 1.0 + EPS)) && - ((ParamCoord[2] >= - EPS) && (ParamCoord[2] <= 1.0 + EPS))) { - - /*--- Set the value of the parametric coordinate ---*/ - - FFDBox->Set_MarkerIndex(iMarker); - FFDBox->Set_VertexIndex(iVertex); - FFDBox->Set_PointIndex(iPoint); - FFDBox->Set_ParametricCoord(ParamCoord); - FFDBox->Set_CartesianCoord(CartCoord); - - /*--- Compute the cartesian coordinates using the parametric coordinates - to check that everithing is right ---*/ - - CartCoordNew = FFDBox->EvalCartesianCoord(ParamCoord); - - /*--- Compute max difference between original value and the recomputed value ---*/ - - Diff = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Diff += (CartCoordNew[iDim]-CartCoord[iDim])*(CartCoordNew[iDim]-CartCoord[iDim]); - Diff = sqrt(Diff); - my_MaxDiff = max(my_MaxDiff, Diff); - - ParamCoordGuess[0] = ParamCoord[0]; ParamCoordGuess[1] = ParamCoord[1]; ParamCoordGuess[2] = ParamCoord[2]; - - } - else { - cout << "Please check this point: (" << ParamCoord[0] <<" "<< ParamCoord[1] <<" "<< ParamCoord[2] <<") <-> (" - << CartCoord[0] <<" "<< CartCoord[1] <<" "<< CartCoord[2] <<")."<< endl; - } - - } - } - } - } - -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&my_MaxDiff, &MaxDiff, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); -#else - MaxDiff = my_MaxDiff; -#endif - - if (rank == MASTER_NODE) - cout << "Compute parametric coord | FFD box: " << FFDBox->GetTag() << ". Max Diff: " << MaxDiff <<"."<< endl; - - - /*--- After the point inversion, copy the original information back ---*/ - - FFDBox->SetOriginalControlPoints(); - -} - -void CSurfaceMovement::SetParametricCoordCP(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBoxParent, CFreeFormDefBox *FFDBoxChild) { - unsigned short iOrder, jOrder, kOrder; - su2double *CartCoord, *ParamCoord, ParamCoordGuess[3]; - int rank; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#else - rank = MASTER_NODE; -#endif - - for (iOrder = 0; iOrder < FFDBoxChild->GetlOrder(); iOrder++) - for (jOrder = 0; jOrder < FFDBoxChild->GetmOrder(); jOrder++) - for (kOrder = 0; kOrder < FFDBoxChild->GetnOrder(); kOrder++) { - CartCoord = FFDBoxChild->GetCoordControlPoints(iOrder, jOrder, kOrder); - ParamCoord = FFDBoxParent->GetParametricCoord_Iterative(0, CartCoord, ParamCoordGuess, config); - FFDBoxChild->SetParCoordControlPoints(ParamCoord, iOrder, jOrder, kOrder); - } - - if (rank == MASTER_NODE) - cout << "Compute parametric coord (CP) | FFD parent box: " << FFDBoxParent->GetTag() << ". FFD child box: " << FFDBoxChild->GetTag() <<"."<< endl; - - -} - -void CSurfaceMovement::GetCartesianCoordCP(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBoxParent, CFreeFormDefBox *FFDBoxChild) { - unsigned short iOrder, jOrder, kOrder, iDim; - su2double *CartCoord, *ParamCoord; - int rank; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#else - rank = MASTER_NODE; -#endif - - for (iOrder = 0; iOrder < FFDBoxChild->GetlOrder(); iOrder++) - for (jOrder = 0; jOrder < FFDBoxChild->GetmOrder(); jOrder++) - for (kOrder = 0; kOrder < FFDBoxChild->GetnOrder(); kOrder++) { - ParamCoord = FFDBoxChild->GetParCoordControlPoints(iOrder, jOrder, kOrder); - - /*--- Clip the value of the parametric coordinates (just in case) ---*/ - for (iDim = 0; iDim < 3; iDim++) { - if (ParamCoord[iDim] >= 1.0) ParamCoord[iDim] = 1.0; - if (ParamCoord[iDim] <= 0.0) ParamCoord[iDim] = 0.0; - } - - CartCoord = FFDBoxParent->EvalCartesianCoord(ParamCoord); - FFDBoxChild->SetCoordControlPoints(CartCoord, iOrder, jOrder, kOrder); - FFDBoxChild->SetCoordControlPoints_Copy(CartCoord, iOrder, jOrder, kOrder); - - } - - if (rank == MASTER_NODE) - cout << "Update cartesian coord (CP) | FFD parent box: " << FFDBoxParent->GetTag() << ". FFD child box: " << FFDBoxChild->GetTag() <<"."<< endl; - -} - -void CSurfaceMovement::CheckFFDIntersections(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iFFDBox) { - - su2double *Coord_0, *Coord_1; - unsigned short iMarker, iNode, jNode, lDegree, mDegree, nDegree; - unsigned long iElem, iPoint, jPoint; - - unsigned short Kind_SU2 = config->GetKind_SU2(); - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - lDegree = FFDBox->GetlOrder()-1; - mDegree = FFDBox->GetmOrder()-1; - nDegree = FFDBox->GetnOrder()-1; - - /*--- Check intersection with plane i=0 ---*/ - - su2double *IPlane_Coord_0_A = FFDBox->GetCoordControlPoints(0, 0, 0); - su2double *IPlane_Coord_1_A = FFDBox->GetCoordControlPoints(0, 0, nDegree); - su2double *IPlane_Coord_2_A = FFDBox->GetCoordControlPoints(0, mDegree, 0); - - su2double *IPlane_Coord_0_A_ = FFDBox->GetCoordControlPoints(0, mDegree, nDegree); - su2double *IPlane_Coord_1_A_ = FFDBox->GetCoordControlPoints(0, mDegree, 0); - su2double *IPlane_Coord_2_A_ = FFDBox->GetCoordControlPoints(0, 0, nDegree); - - /*--- Check intersection with plane i=lDegree ---*/ - - su2double *IPlane_Coord_0_B = FFDBox->GetCoordControlPoints(lDegree, 0, 0); - su2double *IPlane_Coord_1_B = FFDBox->GetCoordControlPoints(lDegree, 0, nDegree); - su2double *IPlane_Coord_2_B = FFDBox->GetCoordControlPoints(lDegree, mDegree, 0); - - su2double *IPlane_Coord_0_B_ = FFDBox->GetCoordControlPoints(lDegree, mDegree, nDegree); - su2double *IPlane_Coord_1_B_ = FFDBox->GetCoordControlPoints(lDegree, mDegree, 0); - su2double *IPlane_Coord_2_B_ = FFDBox->GetCoordControlPoints(lDegree, 0, nDegree); - - /*--- Check intersection with plane j=0 ---*/ - - su2double *JPlane_Coord_0_A = FFDBox->GetCoordControlPoints(0, 0, 0); - su2double *JPlane_Coord_1_A = FFDBox->GetCoordControlPoints(0, 0, nDegree); - su2double *JPlane_Coord_2_A = FFDBox->GetCoordControlPoints(lDegree, 0, 0); - - su2double *JPlane_Coord_0_A_ = FFDBox->GetCoordControlPoints(lDegree, 0, nDegree); - su2double *JPlane_Coord_1_A_ = FFDBox->GetCoordControlPoints(lDegree, 0, 0); - su2double *JPlane_Coord_2_A_ = FFDBox->GetCoordControlPoints(0, 0, nDegree); - - /*--- Check intersection with plane j=mDegree ---*/ - - su2double *JPlane_Coord_0_B = FFDBox->GetCoordControlPoints(0, mDegree, 0); - su2double *JPlane_Coord_1_B = FFDBox->GetCoordControlPoints(0, mDegree, nDegree); - su2double *JPlane_Coord_2_B = FFDBox->GetCoordControlPoints(lDegree, mDegree, 0); - - su2double *JPlane_Coord_0_B_ = FFDBox->GetCoordControlPoints(lDegree, mDegree, nDegree); - su2double *JPlane_Coord_1_B_ = FFDBox->GetCoordControlPoints(lDegree, mDegree, 0); - su2double *JPlane_Coord_2_B_ = FFDBox->GetCoordControlPoints(0, mDegree, nDegree); - - /*--- Check intersection with plane k=0 ---*/ - - su2double *KPlane_Coord_0_A = FFDBox->GetCoordControlPoints(0, 0, 0); - su2double *KPlane_Coord_1_A = FFDBox->GetCoordControlPoints(0, mDegree, 0); - su2double *KPlane_Coord_2_A = FFDBox->GetCoordControlPoints(lDegree, 0, 0); - - su2double *KPlane_Coord_0_A_ = FFDBox->GetCoordControlPoints(lDegree, mDegree, 0); - su2double *KPlane_Coord_1_A_ = FFDBox->GetCoordControlPoints(lDegree, 0, 0); - su2double *KPlane_Coord_2_A_ = FFDBox->GetCoordControlPoints(0, mDegree, 0); - - /*--- Check intersection with plane k=nDegree ---*/ - - su2double *KPlane_Coord_0_B = FFDBox->GetCoordControlPoints(0, 0, nDegree); - su2double *KPlane_Coord_1_B = FFDBox->GetCoordControlPoints(0, mDegree, nDegree); - su2double *KPlane_Coord_2_B = FFDBox->GetCoordControlPoints(lDegree, 0, nDegree); - - su2double *KPlane_Coord_0_B_ = FFDBox->GetCoordControlPoints(lDegree, mDegree, nDegree); - su2double *KPlane_Coord_1_B_ = FFDBox->GetCoordControlPoints(lDegree, 0, nDegree); - su2double *KPlane_Coord_2_B_ = FFDBox->GetCoordControlPoints(0, mDegree, nDegree); - - /*--- Loop over all the grid triangles ---*/ - - bool IPlane_Intersect_A = false, IPlane_Intersect_B = false; - bool JPlane_Intersect_A = false, JPlane_Intersect_B = false; - bool KPlane_Intersect_A = false, KPlane_Intersect_B = false; - - /*--- Only the markers in the moving list ---*/ - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_CFD)) || - ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DEF)) || - ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_GEO)) || - ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DOT)) || - ((config->GetMarker_All_DV(iMarker) == YES) && (config->GetDirectDiff() == D_DESIGN))) { - for (iElem = 0; iElem < geometry->GetnElem_Bound(iMarker); iElem++) { - for (iNode = 0; iNode < geometry->bound[iMarker][iElem]->GetnNodes(); iNode++) { - iPoint = geometry->bound[iMarker][iElem]->GetNode(iNode); - for (jNode = 0; jNode < geometry->bound[iMarker][iElem]->GetnNodes(); jNode++) { - jPoint = geometry->bound[iMarker][iElem]->GetNode(jNode); - - if (jPoint > iPoint) { - - Coord_0 = geometry->node[iPoint]->GetCoord(); - Coord_1 = geometry->node[jPoint]->GetCoord(); - - if (!IPlane_Intersect_A) { - if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, IPlane_Coord_0_A, IPlane_Coord_1_A, IPlane_Coord_2_A)) { IPlane_Intersect_A = true; } - if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, IPlane_Coord_0_A_, IPlane_Coord_1_A_, IPlane_Coord_2_A_)) { IPlane_Intersect_A = true; } - } - - if (!IPlane_Intersect_B) { - if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, IPlane_Coord_0_B, IPlane_Coord_1_B, IPlane_Coord_2_B)) { IPlane_Intersect_B = true; } - if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, IPlane_Coord_0_B_, IPlane_Coord_1_B_, IPlane_Coord_2_B_)) { IPlane_Intersect_B = true; } - } - - if (!JPlane_Intersect_A) { - if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, JPlane_Coord_0_A, JPlane_Coord_1_A, JPlane_Coord_2_A)) { JPlane_Intersect_A = true; } - if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, JPlane_Coord_0_A_, JPlane_Coord_1_A_, JPlane_Coord_2_A_)) { JPlane_Intersect_A = true; } - } - - if (!JPlane_Intersect_B) { - if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, JPlane_Coord_0_B, JPlane_Coord_1_B, JPlane_Coord_2_B)) { JPlane_Intersect_B = true; } - if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, JPlane_Coord_0_B_, JPlane_Coord_1_B_, JPlane_Coord_2_B_)) { JPlane_Intersect_B = true; } - } - - if (!KPlane_Intersect_A) { - if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, KPlane_Coord_0_A, KPlane_Coord_1_A, KPlane_Coord_2_A)) { KPlane_Intersect_A = true; } - if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, KPlane_Coord_0_A_, KPlane_Coord_1_A_, KPlane_Coord_2_A_)) { KPlane_Intersect_A = true; } - } - - if (!KPlane_Intersect_B) { - if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, KPlane_Coord_0_B, KPlane_Coord_1_B, KPlane_Coord_2_B)) { KPlane_Intersect_B = true; } - if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, KPlane_Coord_0_B_, KPlane_Coord_1_B_, KPlane_Coord_2_B_)) { KPlane_Intersect_B = true; } - } - - } - } - } - } - } - } - - /*--- Comunicate the planes that interesect the surface ---*/ - - unsigned short MyCode[6] = {0,0,0,0,0,0}, Code[6] = {0,0,0,0,0,0}; - - if (IPlane_Intersect_A) MyCode[0] = 1; - if (IPlane_Intersect_B) MyCode[1] = 1; - if (JPlane_Intersect_A) MyCode[2] = 1; - if (JPlane_Intersect_B) MyCode[3] = 1; - if (KPlane_Intersect_A) MyCode[4] = 1; - if (KPlane_Intersect_B) MyCode[5] = 1; - -#ifdef HAVE_MPI - - /*--- Add SU2_MPI::Allreduce information using all the nodes ---*/ - - SU2_MPI::Allreduce(&MyCode, &Code, 6, MPI_UNSIGNED_SHORT, MPI_SUM, MPI_COMM_WORLD); - -#else - - Code[0] = MyCode[0]; Code[1] = MyCode[1]; Code[2] = MyCode[2]; - Code[3] = MyCode[3]; Code[4] = MyCode[4]; Code[5] = MyCode[5]; - -#endif - - if (Code[0] != 0) IPlane_Intersect_A = true; else IPlane_Intersect_A = false; - if (Code[1] != 0) IPlane_Intersect_B = true; else IPlane_Intersect_B = false; - if (Code[2] != 0) JPlane_Intersect_A = true; else JPlane_Intersect_A = false; - if (Code[3] != 0) JPlane_Intersect_B = true; else JPlane_Intersect_B = false; - if (Code[4] != 0) KPlane_Intersect_A = true; else KPlane_Intersect_A = false; - if (Code[5] != 0) KPlane_Intersect_B = true; else KPlane_Intersect_B = false; - - /*--- Screen output ---*/ - - if (rank == MASTER_NODE) { - - if (IPlane_Intersect_A || IPlane_Intersect_B || - JPlane_Intersect_A || JPlane_Intersect_B || - KPlane_Intersect_A || KPlane_Intersect_B ) { - cout << "The FFD planes "; - if (IPlane_Intersect_A) cout << "i=0, "; - if (IPlane_Intersect_B) cout << "i="<< lDegree << ", "; - if (JPlane_Intersect_A) cout << "j=0, "; - if (JPlane_Intersect_B) cout << "j="<< mDegree << ", "; - if (KPlane_Intersect_A) cout << "k=0, "; - if (KPlane_Intersect_B) cout << "k="<< nDegree << ", "; - cout << "intersect solid surfaces." << endl; - } - - } - - /*--- Fix the FFD planes based on the intersections with solid surfaces, - and the continuity level, check that we have enough degree for the continuity - that we are looking for ---*/ - - if (IPlane_Intersect_A) { FFDBox->Set_Fix_IPlane(0); FFDBox->Set_Fix_IPlane(1); } - if (IPlane_Intersect_B) { FFDBox->Set_Fix_IPlane(lDegree); FFDBox->Set_Fix_IPlane(lDegree-1); } - - if (JPlane_Intersect_A) { FFDBox->Set_Fix_JPlane(0); FFDBox->Set_Fix_JPlane(1); } - if (JPlane_Intersect_B) { FFDBox->Set_Fix_JPlane(mDegree); FFDBox->Set_Fix_JPlane(mDegree-1); } - - if (KPlane_Intersect_A) { FFDBox->Set_Fix_KPlane(0); FFDBox->Set_Fix_KPlane(1); } - if (KPlane_Intersect_B) { FFDBox->Set_Fix_KPlane(nDegree); FFDBox->Set_Fix_KPlane(nDegree-1); } - - if (config->GetFFD_Continuity() == DERIVATIVE_2ND) { - - if ((IPlane_Intersect_A) && (lDegree > 1)) { FFDBox->Set_Fix_IPlane(2); } - if ((IPlane_Intersect_B) && (lDegree > 1)) { FFDBox->Set_Fix_IPlane(lDegree-2); } - - if ((JPlane_Intersect_A) && (mDegree > 1)) { FFDBox->Set_Fix_JPlane(2); } - if ((JPlane_Intersect_B) && (mDegree > 1)) { FFDBox->Set_Fix_JPlane(mDegree-2); } - - if ((KPlane_Intersect_A) && (nDegree > 1)) { FFDBox->Set_Fix_KPlane(2); } - if ((KPlane_Intersect_B) && (nDegree > 1)) { FFDBox->Set_Fix_KPlane(nDegree-2); } - - } - -} - -void CSurfaceMovement::UpdateParametricCoord(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iFFDBox) { - unsigned short iMarker, iDim; - unsigned long iVertex, iPoint, iSurfacePoints; - su2double CartCoord[3] = {0.0,0.0,0.0}, *CartCoordNew, *CartCoordOld; - su2double *ParamCoord, *var_coord, ParamCoordGuess[3] = {0.0,0.0,0.0}; - su2double MaxDiff, my_MaxDiff = 0.0, Diff; - int rank; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#else - rank = MASTER_NODE; -#endif - - /*--- Recompute the parametric coordinates ---*/ - - for (iSurfacePoints = 0; iSurfacePoints < FFDBox->GetnSurfacePoint(); iSurfacePoints++) { - - /*--- Get the marker of the surface point ---*/ - - iMarker = FFDBox->Get_MarkerIndex(iSurfacePoints); - - if (config->GetMarker_All_DV(iMarker) == YES) { - - /*--- Get the vertex of the surface point ---*/ - - iVertex = FFDBox->Get_VertexIndex(iSurfacePoints); - iPoint = FFDBox->Get_PointIndex(iSurfacePoints); - - /*--- Get the parametric and cartesians coordinates of the - surface point (they don't mach) ---*/ - - ParamCoord = FFDBox->Get_ParametricCoord(iSurfacePoints); - - /*--- Compute and set the cartesian coord using the variation computed - with the previous deformation ---*/ - - var_coord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); - CartCoordOld = geometry->node[iPoint]->GetCoord(); - for (iDim = 0; iDim < 3; iDim++) - CartCoord[iDim] = CartCoordOld[iDim] + var_coord[iDim]; - FFDBox->Set_CartesianCoord(CartCoord, iSurfacePoints); - - /*--- Find the parametric coordinate using as ParamCoordGuess the previous value ---*/ - - ParamCoordGuess[0] = ParamCoord[0]; ParamCoordGuess[1] = ParamCoord[1]; ParamCoordGuess[2] = ParamCoord[2]; - ParamCoord = FFDBox->GetParametricCoord_Iterative(iPoint, CartCoord, ParamCoordGuess, config); - - /*--- Set the new value of the parametric coordinates ---*/ - - FFDBox->Set_ParametricCoord(ParamCoord, iSurfacePoints); - - /*--- Compute the cartesian coordinates using the parametric coordinates - to check that everithing is right ---*/ - - CartCoordNew = FFDBox->EvalCartesianCoord(ParamCoord); - - /*--- Compute max difference between original value and the recomputed value ---*/ - - Diff = 0.0; - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) - Diff += (CartCoordNew[iDim]-CartCoord[iDim])*(CartCoordNew[iDim]-CartCoord[iDim]); - Diff = sqrt(Diff); - my_MaxDiff = max(my_MaxDiff, Diff); - - } - } - -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&my_MaxDiff, &MaxDiff, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); -#else - MaxDiff = my_MaxDiff; -#endif - - if (rank == MASTER_NODE) - cout << "Update parametric coord | FFD box: " << FFDBox->GetTag() << ". Max Diff: " << MaxDiff <<"."<< endl; - -} - -void CSurfaceMovement::SetCartesianCoord(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iFFDBox) { - - su2double *CartCoordNew, Diff, my_MaxDiff = 0.0, MaxDiff, - *ParamCoord, VarCoord[3] = {0.0, 0.0, 0.0}, CartCoordOld[3] = {0.0, 0.0, 0.0}; - unsigned short iMarker, iDim; - unsigned long iVertex, iPoint, iSurfacePoints; - int rank; - - unsigned short nDim = geometry->GetnDim(); - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#else - rank = MASTER_NODE; -#endif - - /*--- Recompute the cartesians coordinates ---*/ - - for (iSurfacePoints = 0; iSurfacePoints < FFDBox->GetnSurfacePoint(); iSurfacePoints++) { - - /*--- Get the marker of the surface point ---*/ - - iMarker = FFDBox->Get_MarkerIndex(iSurfacePoints); - - if (config->GetMarker_All_DV(iMarker) == YES) { - - /*--- Get the vertex of the surface point ---*/ - - iVertex = FFDBox->Get_VertexIndex(iSurfacePoints); - iPoint = FFDBox->Get_PointIndex(iSurfacePoints); - - /*--- Set to zero the variation of the coordinates ---*/ - - geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - - /*--- Get the parametric coordinate of the surface point ---*/ - - ParamCoord = FFDBox->Get_ParametricCoord(iSurfacePoints); - - /*--- Compute the new cartesian coordinate, and set the value in - the FFDBox structure ---*/ - - CartCoordNew = FFDBox->EvalCartesianCoord(ParamCoord); - FFDBox->Set_CartesianCoord(CartCoordNew, iSurfacePoints); - - /*--- Get the original cartesian coordinates of the surface point ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - CartCoordOld[iDim] = geometry->node[iPoint]->GetCoord(iDim); - } - - /*--- Set the value of the variation of the coordinates ---*/ - - Diff = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - VarCoord[iDim] = CartCoordNew[iDim] - CartCoordOld[iDim]; - if ((fabs(VarCoord[iDim]) <= EPS) && (config->GetDirectDiff() != D_DESIGN) && (!config->GetDiscrete_Adjoint())) - VarCoord[iDim] = 0.0; - Diff += (VarCoord[iDim]*VarCoord[iDim]); - } - Diff = sqrt(Diff); - - my_MaxDiff = max(my_MaxDiff, Diff); - - /*--- Set the variation of the coordinates ---*/ - - geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - - } - } - -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&my_MaxDiff, &MaxDiff, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); -#else - MaxDiff = my_MaxDiff; -#endif - - if (rank == MASTER_NODE) - cout << "Update cartesian coord | FFD box: " << FFDBox->GetTag() << ". Max Diff: " << MaxDiff <<"."<< endl; - -} - - -void CSurfaceMovement::SetFFDCPChange_2D(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, - unsigned short iDV, bool ResetDef) { - - su2double movement[3] = {0.0,0.0,0.0}, Ampl; - unsigned short index[3], i, j; - string design_FFDBox; - - /*--- Set control points to its original value (even if the - design variable is not in this box) ---*/ - - if (ResetDef == true) FFDBox->SetOriginalControlPoints(); - - design_FFDBox = config->GetFFDTag(iDV); - - if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { - - /*--- Compute deformation ---*/ - - Ampl = config->GetDV_Value(iDV); - - movement[0] = config->GetParamDV(iDV, 3)*Ampl; - movement[1] = config->GetParamDV(iDV, 4)*Ampl; - movement[2] = 0.0; - - index[0] = SU2_TYPE::Int(config->GetParamDV(iDV, 1)); - index[1] = SU2_TYPE::Int(config->GetParamDV(iDV, 2)); - - /*--- Lower surface ---*/ - - index[2] = 0; - - if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) == -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) != -1)) { - for (i = 0; i < FFDBox->GetlOrder(); i++) { - index[0] = i; - FFDBox->SetControlPoints(index, movement); - } - } - - if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) != -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) == -1)) { - for (j = 0; j < FFDBox->GetmOrder(); j++) { - index[1] = j; - FFDBox->SetControlPoints(index, movement); - } - } - - if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) == -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) == -1)) { - for (i = 0; i < FFDBox->GetlOrder(); i++) { - index[0] = i; - for (j = 0; j < FFDBox->GetmOrder(); j++) { - index[1] = j; - FFDBox->SetControlPoints(index, movement); - } - } - } - if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) != -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) != -1)) { - - FFDBox->SetControlPoints(index, movement); - } - - - /*--- Upper surface ---*/ - - index[2] = 1; - - if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) == -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) != -1)) { - for (i = 0; i < FFDBox->GetlOrder(); i++) { - index[0] = i; - FFDBox->SetControlPoints(index, movement); - } - } - - if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) != -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) == -1)) { - for (j = 0; j < FFDBox->GetmOrder(); j++) { - index[1] = j; - FFDBox->SetControlPoints(index, movement); - } - } - - if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) == -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) == -1)) { - for (i = 0; i < FFDBox->GetlOrder(); i++) { - index[0] = i; - for (j = 0; j < FFDBox->GetmOrder(); j++) { - index[1] = j; - FFDBox->SetControlPoints(index, movement); - } - } - } - if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) != -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) != -1)) { - - FFDBox->SetControlPoints(index, movement); - } - } - -} - -void CSurfaceMovement::SetFFDCPChange(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, - unsigned short iDV, bool ResetDef) { - - su2double movement[3] = {0.0,0.0,0.0}, Ampl; - unsigned short index[3], i, j, k, iPlane; - string design_FFDBox; - - /*--- Set control points to its original value (even if the - design variable is not in this box) ---*/ - - if (ResetDef == true) FFDBox->SetOriginalControlPoints(); - - design_FFDBox = config->GetFFDTag(iDV); - - if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { - - /*--- Compute deformation ---*/ - - Ampl = config->GetDV_Value(iDV); - - movement[0] = config->GetParamDV(iDV, 4)*Ampl; - movement[1] = config->GetParamDV(iDV, 5)*Ampl; - movement[2] = config->GetParamDV(iDV, 6)*Ampl; - - index[0] = SU2_TYPE::Int(config->GetParamDV(iDV, 1)); - index[1] = SU2_TYPE::Int(config->GetParamDV(iDV, 2)); - index[2] = SU2_TYPE::Int(config->GetParamDV(iDV, 3)); - - /*--- Check that it is possible to move the control point ---*/ - - for (iPlane = 0 ; iPlane < FFDBox->Get_nFix_IPlane(); iPlane++) { - if (index[0] == FFDBox->Get_Fix_IPlane(iPlane)) return; - } - - for (iPlane = 0 ; iPlane < FFDBox->Get_nFix_JPlane(); iPlane++) { - if (index[1] == FFDBox->Get_Fix_JPlane(iPlane)) return; - } - - for (iPlane = 0 ; iPlane < FFDBox->Get_nFix_KPlane(); iPlane++) { - if (index[2] == FFDBox->Get_Fix_KPlane(iPlane)) return; - } - - if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) == -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) != -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 3)) != -1)) { - for (i = 0; i < FFDBox->GetlOrder(); i++) { - index[0] = i; - FFDBox->SetControlPoints(index, movement); - } - } - - if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) != -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) == -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 3)) != -1)) { - for (j = 0; j < FFDBox->GetmOrder(); j++) { - index[1] = j; - FFDBox->SetControlPoints(index, movement); - } - } - - if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) != -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) != -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 3)) == -1)) { - for (k = 0; k < FFDBox->GetnOrder(); k++) { - index[2] = k; - FFDBox->SetControlPoints(index, movement); - } - } - - if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) == -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) == -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 3)) != -1)) { - for (i = 0; i < FFDBox->GetlOrder(); i++) { - index[0] = i; - for (j = 0; j < FFDBox->GetmOrder(); j++) { - index[1] = j; - FFDBox->SetControlPoints(index, movement); - } - } - } - - if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) != -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) == -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 3)) == -1)) { - for (j = 0; j < FFDBox->GetmOrder(); j++) { - index[1] = j; - for (k = 0; k < FFDBox->GetnOrder(); k++) { - index[2] = k; - FFDBox->SetControlPoints(index, movement); - } - } - } - - if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) == -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) != -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 3)) == -1)) { - for (i = 0; i < FFDBox->GetlOrder(); i++) { - index[0] = i; - for (k = 0; k < FFDBox->GetnOrder(); k++) { - index[2] = k; - FFDBox->SetControlPoints(index, movement); - } - } - } - - if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) != -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) != -1) && - (SU2_TYPE::Int(config->GetParamDV(iDV, 3)) != -1)) { - FFDBox->SetControlPoints(index, movement); - } - - } - -} - -void CSurfaceMovement::SetFFDCamber_2D(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, - unsigned short iDV, bool ResetDef) { - su2double Ampl, movement[3] = {0.0,0.0,0.0}; - unsigned short index[3], kIndex; - string design_FFDBox; - - /*--- Set control points to its original value (even if the - design variable is not in this box) ---*/ - - if (ResetDef == true) FFDBox->SetOriginalControlPoints(); - - design_FFDBox = config->GetFFDTag(iDV); - - if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { - - for (kIndex = 0; kIndex < 2; kIndex++) { - - Ampl = config->GetDV_Value(iDV); - - movement[0] = 0.0; - if (kIndex == 0) movement[1] = Ampl; - else movement[1] = Ampl; - movement[2] = 0.0; - - index[0] = SU2_TYPE::Int(config->GetParamDV(iDV, 1)); index[1] = kIndex; index[2] = 0; - FFDBox->SetControlPoints(index, movement); - - index[2] = 1; - FFDBox->SetControlPoints(index, movement); - - } - - } - -} - -void CSurfaceMovement::SetFFDThickness_2D(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, - unsigned short iDV, bool ResetDef) { - su2double Ampl, movement[3]= {0.0,0.0,0.0}; - unsigned short index[3], kIndex; - string design_FFDBox; - - /*--- Set control points to its original value (even if the - design variable is not in this box) ---*/ - - if (ResetDef == true) FFDBox->SetOriginalControlPoints(); - - design_FFDBox = config->GetFFDTag(iDV); - - if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { - - for (kIndex = 0; kIndex < 2; kIndex++) { - - Ampl = config->GetDV_Value(iDV); - - movement[0] = 0.0; - if (kIndex == 0) movement[1] = -Ampl; - else movement[1] = Ampl; - movement[2] = 0.0; - - index[0] = SU2_TYPE::Int(config->GetParamDV(iDV, 1)); index[1] = kIndex; index[2] = 0; - FFDBox->SetControlPoints(index, movement); - - index[2] = 1; - FFDBox->SetControlPoints(index, movement); - - } - - } - -} - -void CSurfaceMovement::SetFFDCamber(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, - unsigned short iDV, bool ResetDef) { - su2double Ampl, movement[3] = {0.0,0.0,0.0}; - unsigned short index[3], kIndex; - string design_FFDBox; - - /*--- Set control points to its original value (even if the - design variable is not in this box) ---*/ - - if (ResetDef == true) FFDBox->SetOriginalControlPoints(); - - design_FFDBox = config->GetFFDTag(iDV); - - if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { - - for (kIndex = 0; kIndex < 2; kIndex++) { - - Ampl = config->GetDV_Value(iDV); - - index[0] = SU2_TYPE::Int(config->GetParamDV(iDV, 1)); - index[1] = SU2_TYPE::Int(config->GetParamDV(iDV, 2)); - index[2] = kIndex; - - movement[0] = 0.0; movement[1] = 0.0; - if (kIndex == 0) movement[2] = Ampl; - else movement[2] = Ampl; - - FFDBox->SetControlPoints(index, movement); - - } - - } - -} - -void CSurfaceMovement::SetFFDThickness(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, - unsigned short iDV, bool ResetDef) { - su2double Ampl, movement[3] = {0.0,0.0,0.0}; - unsigned short index[3], kIndex; - string design_FFDBox; - - /*--- Set control points to its original value (even if the - design variable is not in this box) ---*/ - - if (ResetDef == true) FFDBox->SetOriginalControlPoints(); - - design_FFDBox = config->GetFFDTag(iDV); - - if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { - - for (kIndex = 0; kIndex < 2; kIndex++) { - - Ampl = config->GetDV_Value(iDV); - - index[0] = SU2_TYPE::Int(config->GetParamDV(iDV, 1)); - index[1] = SU2_TYPE::Int(config->GetParamDV(iDV, 2)); - index[2] = kIndex; - - movement[0] = 0.0; movement[1] = 0.0; - if (kIndex == 0) movement[2] = -Ampl; - else movement[2] = Ampl; - - FFDBox->SetControlPoints(index, movement); - - } - - } - -} - - -void CSurfaceMovement::SetFFDDihedralAngle(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, - unsigned short iDV, bool ResetDef) { - unsigned short iOrder, jOrder, kOrder, index[3]; - su2double movement[3] = {0.0,0.0,0.0}, theta; - string design_FFDBox; - - /*--- Set control points to its original value (even if the - design variable is not in this box) ---*/ - - if (ResetDef == true) FFDBox->SetOriginalControlPoints(); - - design_FFDBox = config->GetFFDTag(iDV); - - if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { - - /*--- The angle of rotation. ---*/ - - theta = config->GetDV_Value(iDV)*PI_NUMBER/180.0; - - /*--- Change the value of the control point if move is true ---*/ - for (iOrder = 0; iOrder < FFDBox->GetlOrder(); iOrder++) - for (jOrder = 0; jOrder < FFDBox->GetmOrder(); jOrder++) - for (kOrder = 0; kOrder < FFDBox->GetnOrder(); kOrder++) { - index[0] = iOrder; index[1] = jOrder; index[2] = kOrder; - su2double *coord = FFDBox->GetCoordControlPoints(iOrder, jOrder, kOrder); - movement[0] = 0.0; movement[1] = 0.0; movement[2] = coord[1]*tan(theta); - - FFDBox->SetControlPoints(index, movement); - } - - } - -} - -void CSurfaceMovement::SetFFDTwistAngle(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, - unsigned short iDV, bool ResetDef) { - unsigned short iOrder, jOrder, kOrder; - su2double x, y, z, movement[3] = {0.0,0.0,0.0}; - unsigned short index[3]; - string design_FFDBox; - - /*--- Set control points to its original value (even if the - design variable is not in this box) ---*/ - - if (ResetDef == true) FFDBox->SetOriginalControlPoints(); - - design_FFDBox = config->GetFFDTag(iDV); - - if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { - - /*--- xyz-coordinates of a point on the line of rotation. ---*/ - - su2double a = config->GetParamDV(iDV, 1); - su2double b = config->GetParamDV(iDV, 2); - su2double c = config->GetParamDV(iDV, 3); - - /*--- xyz-coordinate of the line's direction vector. ---*/ - - su2double u = config->GetParamDV(iDV, 4)-config->GetParamDV(iDV, 1); - su2double v = config->GetParamDV(iDV, 5)-config->GetParamDV(iDV, 2); - su2double w = config->GetParamDV(iDV, 6)-config->GetParamDV(iDV, 3); - - /*--- The angle of rotation. ---*/ - - su2double theta = config->GetDV_Value(iDV)*PI_NUMBER/180.0; - - /*--- An intermediate value used in computations. ---*/ - - su2double u2=u*u; su2double v2=v*v; su2double w2=w*w; - su2double l2 = u2 + v2 + w2; su2double l = sqrt(l2); - su2double cosT; su2double sinT; - - /*--- Change the value of the control point if move is true ---*/ - - for (iOrder = 0; iOrder < FFDBox->GetlOrder(); iOrder++) - for (jOrder = 0; jOrder < FFDBox->GetmOrder(); jOrder++) - for (kOrder = 0; kOrder < FFDBox->GetnOrder(); kOrder++) { - index[0] = iOrder; index[1] = jOrder; index[2] = kOrder; - su2double *coord = FFDBox->GetCoordControlPoints(iOrder, jOrder, kOrder); - x = coord[0]; y = coord[1]; z = coord[2]; - - su2double factor = 0.0; - if ( y < config->GetParamDV(iDV, 2) ) - factor = 0.0; - if (( y >= config->GetParamDV(iDV, 2)) && ( y <= config->GetParamDV(iDV, 5)) ) - factor = (y-config->GetParamDV(iDV, 2)) / (config->GetParamDV(iDV, 5)-config->GetParamDV(iDV, 2)); - if ( y > config->GetParamDV(iDV, 5) ) - factor = 1.0; - - cosT = cos(theta*factor); - sinT = sin(theta*factor); - - movement[0] = a*(v2 + w2) + u*(-b*v - c*w + u*x + v*y + w*z) - + (-a*(v2 + w2) + u*(b*v + c*w - v*y - w*z) + (v2 + w2)*x)*cosT - + l*(-c*v + b*w - w*y + v*z)*sinT; - movement[0] = movement[0]/l2 - x; - - movement[1] = b*(u2 + w2) + v*(-a*u - c*w + u*x + v*y + w*z) - + (-b*(u2 + w2) + v*(a*u + c*w - u*x - w*z) + (u2 + w2)*y)*cosT - + l*(c*u - a*w + w*x - u*z)*sinT; - movement[1] = movement[1]/l2 - y; - - movement[2] = c*(u2 + v2) + w*(-a*u - b*v + u*x + v*y + w*z) - + (-c*(u2 + v2) + w*(a*u + b*v - u*x - v*y) + (u2 + v2)*z)*cosT - + l*(-b*u + a*v - v*x + u*y)*sinT; - movement[2] = movement[2]/l2 - z; - - FFDBox->SetControlPoints(index, movement); - - } - - } - -} - - -void CSurfaceMovement::SetFFDRotation(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, - unsigned short iDV, bool ResetDef) { - unsigned short iOrder, jOrder, kOrder; - su2double movement[3] = {0.0,0.0,0.0}, x, y, z; - unsigned short index[3]; - string design_FFDBox; - - /*--- Set control points to its original value (even if the - design variable is not in this box) ---*/ - - if (ResetDef == true) FFDBox->SetOriginalControlPoints(); - - design_FFDBox = config->GetFFDTag(iDV); - - if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { - - /*--- xyz-coordinates of a point on the line of rotation. ---*/ - - su2double a = config->GetParamDV(iDV, 1); - su2double b = config->GetParamDV(iDV, 2); - su2double c = config->GetParamDV(iDV, 3); - - /*--- xyz-coordinate of the line's direction vector. ---*/ - - su2double u = config->GetParamDV(iDV, 4)-config->GetParamDV(iDV, 1); - su2double v = config->GetParamDV(iDV, 5)-config->GetParamDV(iDV, 2); - su2double w = config->GetParamDV(iDV, 6)-config->GetParamDV(iDV, 3); - - /*--- The angle of rotation. ---*/ - - su2double theta = config->GetDV_Value(iDV)*PI_NUMBER/180.0; - - /*--- An intermediate value used in computations. ---*/ - - su2double u2=u*u; su2double v2=v*v; su2double w2=w*w; - su2double cosT = cos(theta); su2double sinT = sin(theta); - su2double l2 = u2 + v2 + w2; su2double l = sqrt(l2); - - /*--- Change the value of the control point if move is true ---*/ - - for (iOrder = 0; iOrder < FFDBox->GetlOrder(); iOrder++) - for (jOrder = 0; jOrder < FFDBox->GetmOrder(); jOrder++) - for (kOrder = 0; kOrder < FFDBox->GetnOrder(); kOrder++) { - index[0] = iOrder; index[1] = jOrder; index[2] = kOrder; - su2double *coord = FFDBox->GetCoordControlPoints(iOrder, jOrder, kOrder); - x = coord[0]; y = coord[1]; z = coord[2]; - movement[0] = a*(v2 + w2) + u*(-b*v - c*w + u*x + v*y + w*z) - + (-a*(v2 + w2) + u*(b*v + c*w - v*y - w*z) + (v2 + w2)*x)*cosT - + l*(-c*v + b*w - w*y + v*z)*sinT; - movement[0] = movement[0]/l2 - x; - - movement[1] = b*(u2 + w2) + v*(-a*u - c*w + u*x + v*y + w*z) - + (-b*(u2 + w2) + v*(a*u + c*w - u*x - w*z) + (u2 + w2)*y)*cosT - + l*(c*u - a*w + w*x - u*z)*sinT; - movement[1] = movement[1]/l2 - y; - - movement[2] = c*(u2 + v2) + w*(-a*u - b*v + u*x + v*y + w*z) - + (-c*(u2 + v2) + w*(a*u + b*v - u*x - v*y) + (u2 + v2)*z)*cosT - + l*(-b*u + a*v - v*x + u*y)*sinT; - movement[2] = movement[2]/l2 - z; - - FFDBox->SetControlPoints(index, movement); - - } - } - -} - -void CSurfaceMovement::SetFFDControl_Surface(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, - unsigned short iDV, bool ResetDef) { - unsigned short iOrder, jOrder, kOrder; - su2double movement[3] = {0.0,0.0,0.0}, x, y, z; - unsigned short index[3]; - string design_FFDBox; - - /*--- Set control points to its original value (even if the - design variable is not in this box) ---*/ - - if (ResetDef == true) FFDBox->SetOriginalControlPoints(); - - design_FFDBox = config->GetFFDTag(iDV); - - if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { - - /*--- xyz-coordinates of a point on the line of rotation. ---*/ - - su2double a = config->GetParamDV(iDV, 1); - su2double b = config->GetParamDV(iDV, 2); - su2double c = config->GetParamDV(iDV, 3); - - /*--- xyz-coordinate of the line's direction vector. ---*/ - - su2double u = config->GetParamDV(iDV, 4)-config->GetParamDV(iDV, 1); - su2double v = config->GetParamDV(iDV, 5)-config->GetParamDV(iDV, 2); - su2double w = config->GetParamDV(iDV, 6)-config->GetParamDV(iDV, 3); - - /*--- The angle of rotation. ---*/ - - su2double theta = -config->GetDV_Value(iDV)*PI_NUMBER/180.0; - - /*--- An intermediate value used in computations. ---*/ - - su2double u2=u*u; su2double v2=v*v; su2double w2=w*w; - su2double cosT = cos(theta); su2double sinT = sin(theta); - su2double l2 = u2 + v2 + w2; su2double l = sqrt(l2); - - /*--- Change the value of the control point if move is true ---*/ - - for (iOrder = 0; iOrder < FFDBox->GetlOrder()-2; iOrder++) - for (jOrder = 2; jOrder < FFDBox->GetmOrder()-2; jOrder++) - for (kOrder = 0; kOrder < FFDBox->GetnOrder(); kOrder++) { - index[0] = iOrder; index[1] = jOrder; index[2] = kOrder; - su2double *coord = FFDBox->GetCoordControlPoints(iOrder, jOrder, kOrder); - x = coord[0]; y = coord[1]; z = coord[2]; - movement[0] = a*(v2 + w2) + u*(-b*v - c*w + u*x + v*y + w*z) - + (-a*(v2 + w2) + u*(b*v + c*w - v*y - w*z) + (v2 + w2)*x)*cosT - + l*(-c*v + b*w - w*y + v*z)*sinT; - movement[0] = movement[0]/l2 - x; - - movement[1] = b*(u2 + w2) + v*(-a*u - c*w + u*x + v*y + w*z) - + (-b*(u2 + w2) + v*(a*u + c*w - u*x - w*z) + (u2 + w2)*y)*cosT - + l*(c*u - a*w + w*x - u*z)*sinT; - movement[1] = movement[1]/l2 - y; - - movement[2] = c*(u2 + v2) + w*(-a*u - b*v + u*x + v*y + w*z) - + (-c*(u2 + v2) + w*(a*u + b*v - u*x - v*y) + (u2 + v2)*z)*cosT - + l*(-b*u + a*v - v*x + u*y)*sinT; - movement[2] = movement[2]/l2 - z; - - FFDBox->SetControlPoints(index, movement); - - } - } - -} - -void CSurfaceMovement::SetHicksHenne(CGeometry *boundary, CConfig *config, unsigned short iDV, bool ResetDef) { - unsigned long iVertex; - unsigned short iMarker; - su2double VarCoord[3] = {0.0,0.0,0.0}, VarCoord_[3] = {0.0,0.0,0.0}, *Coord_, *Normal_, ek, fk, BumpSize = 1.0, - BumpLoc = 0.0, Coord[3] = {0.0,0.0,0.0}, Normal[3] = {0.0,0.0,0.0}, - xCoord, TPCoord[2] = {0.0, 0.0}, LPCoord[2] = {0.0, 0.0}, Distance, Chord, AoA, ValCos, ValSin; - - bool upper = true, double_surface = false; - - /*--- Reset airfoil deformation if first deformation or if it required by the solver ---*/ - - if ((iDV == 0) || (ResetDef == true)) { - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - boundary->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - } - } - - /*--- Compute the angle of attack to apply the deformation ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_DV(iMarker) == YES) { - Coord_ = boundary->vertex[iMarker][0]->GetCoord(); - TPCoord[0] = Coord_[0]; TPCoord[1] = Coord_[1]; - for (iVertex = 1; iVertex < boundary->nVertex[iMarker]; iVertex++) { - Coord_ = boundary->vertex[iMarker][iVertex]->GetCoord(); - if (Coord_[0] > TPCoord[0]) { TPCoord[0] = Coord_[0]; TPCoord[1] = Coord_[1]; } - } - } - } - -#ifdef HAVE_MPI - - int iProcessor, nProcessor; - su2double *Buffer_Send_Coord, *Buffer_Receive_Coord; - - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); - - Buffer_Receive_Coord = new su2double [nProcessor*2]; - Buffer_Send_Coord = new su2double [2]; - - Buffer_Send_Coord[0] = TPCoord[0]; Buffer_Send_Coord[1] = TPCoord[1]; - - SU2_MPI::Allgather(Buffer_Send_Coord, 2, MPI_DOUBLE, Buffer_Receive_Coord, 2, MPI_DOUBLE, MPI_COMM_WORLD); - - TPCoord[0] = Buffer_Receive_Coord[0]; TPCoord[1] = Buffer_Receive_Coord[1]; - for (iProcessor = 1; iProcessor < nProcessor; iProcessor++) { - Coord[0] = Buffer_Receive_Coord[iProcessor*2 + 0]; - Coord[1] = Buffer_Receive_Coord[iProcessor*2 + 1]; - if (Coord[0] > TPCoord[0]) { TPCoord[0] = Coord[0]; TPCoord[1] = Coord[1]; } - } - - delete[] Buffer_Send_Coord; delete[] Buffer_Receive_Coord; - -#endif - - - Chord = 0.0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_DV(iMarker) == YES) { - for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { - Coord_ = boundary->vertex[iMarker][iVertex]->GetCoord(); - Distance = sqrt(pow(Coord_[0] - TPCoord[0], 2.0) + pow(Coord_[1] - TPCoord[1], 2.0)); - if (Chord < Distance) { Chord = Distance; LPCoord[0] = Coord_[0]; LPCoord[1] = Coord_[1]; } - } - } - } - -#ifdef HAVE_MPI - - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); - - Buffer_Receive_Coord = new su2double [nProcessor*2]; - Buffer_Send_Coord = new su2double [2]; - - Buffer_Send_Coord[0] = LPCoord[0]; Buffer_Send_Coord[1] = LPCoord[1]; - - SU2_MPI::Allgather(Buffer_Send_Coord, 2, MPI_DOUBLE, Buffer_Receive_Coord, 2, MPI_DOUBLE, MPI_COMM_WORLD); - - Chord = 0.0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - Coord[0] = Buffer_Receive_Coord[iProcessor*2 + 0]; - Coord[1] = Buffer_Receive_Coord[iProcessor*2 + 1]; - Distance = sqrt(pow(Coord[0] - TPCoord[0], 2.0) + pow(Coord[1] - TPCoord[1], 2.0)); - if (Chord < Distance) { Chord = Distance; LPCoord[0] = Coord[0]; LPCoord[1] = Coord[1]; } - } - - delete[] Buffer_Send_Coord; delete[] Buffer_Receive_Coord; - -#endif - - //AoA = atan((LPCoord[1] - TPCoord[1]) / (TPCoord[0] - LPCoord[0]))*180/PI_NUMBER; - AoA = 0.0; - - /*--- Perform multiple airfoil deformation ---*/ - - su2double Ampl = config->GetDV_Value(iDV); - su2double xk = config->GetParamDV(iDV, 1); - const su2double t2 = 3.0; - - if (config->GetParamDV(iDV, 0) == NO) { upper = false; double_surface = true; } - if (config->GetParamDV(iDV, 0) == YES) { upper = true; double_surface = true; } - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - - if (config->GetMarker_All_DV(iMarker) == YES) { - - Coord_ = boundary->vertex[iMarker][iVertex]->GetCoord(); - Normal_ = boundary->vertex[iMarker][iVertex]->GetNormal(); - - /*--- The Hicks Henne bump functions should be applied to a basic airfoil without AoA, - and unitary chord, a tranformation is required ---*/ - - ValCos = cos(AoA*PI_NUMBER/180.0); - ValSin = sin(AoA*PI_NUMBER/180.0); - - Coord[0] = Coord_[0]*ValCos - Coord_[1]*ValSin; - Coord[0] = max(0.0, Coord[0]); // Coord x should be always positive - Coord[1] = Coord_[1]*ValCos + Coord_[0]*ValSin; - - Normal[0] = Normal_[0]*ValCos - Normal_[1]*ValSin; - Normal[1] = Normal_[1]*ValCos + Normal_[0]*ValSin; - - /*--- Bump computation ---*/ - - if (double_surface) { - ek = log10(0.5)/log10(xk); - fk = pow( sin( PI_NUMBER * pow(Coord[0], ek) ) , t2); - - /*--- Upper and lower surface ---*/ - - if (( upper) && (Normal[1] > 0)) { VarCoord[1] = Ampl*fk; } - if ((!upper) && (Normal[1] < 0)) { VarCoord[1] = -Ampl*fk; } - - } - else { - xCoord = Coord[0] - BumpLoc; - ek = log10(0.5)/log10(xk/BumpSize); - fk = pow( sin( PI_NUMBER * pow(xCoord/BumpSize, ek)), t2); - - /*--- Only one surface ---*/ - - if ((xCoord <= 0.0) || (xCoord >= BumpSize)) VarCoord[1] = 0.0; - else VarCoord[1] = Ampl*fk; - - - } - } - - /*--- Apply the transformation to the coordinate variation ---*/ - - ValCos = cos(-AoA*PI_NUMBER/180.0); - ValSin = sin(-AoA*PI_NUMBER/180.0); - - VarCoord_[0] = VarCoord[0]*ValCos - VarCoord[1]*ValSin; - VarCoord_[1] = VarCoord[1]*ValCos + VarCoord[0]*ValSin; - - boundary->vertex[iMarker][iVertex]->AddVarCoord(VarCoord_); - - } - } - -} - -void CSurfaceMovement::SetRotation(CGeometry *boundary, CConfig *config, unsigned short iDV, bool ResetDef) { - unsigned long iVertex; - unsigned short iMarker; - su2double VarCoord[3] = {0.0,0.0,0.0}, *Coord; - su2double movement[3] = {0.0,0.0,0.0}, x, y, z; - - /*--- Reset airfoil deformation if first deformation or if it required by the solver ---*/ - - if ((iDV == 0) || (ResetDef == true)) { - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - boundary->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - } - } - - /*--- xyz-coordinates of a point on the line of rotation. */ - - su2double a = config->GetParamDV(iDV, 0); - su2double b = config->GetParamDV(iDV, 1); - su2double c = 0.0; - if (boundary->GetnDim() == 3) c = config->GetParamDV(0,2); - - /*--- xyz-coordinate of the line's direction vector. ---*/ - - su2double u = config->GetParamDV(iDV, 3)-config->GetParamDV(iDV, 0); - su2double v = config->GetParamDV(iDV, 4)-config->GetParamDV(iDV, 1); - su2double w = 1.0; - if (boundary->GetnDim() == 3) w = config->GetParamDV(iDV, 5)-config->GetParamDV(iDV, 2); - - /*--- The angle of rotation. ---*/ - - su2double theta = config->GetDV_Value(iDV)*PI_NUMBER/180.0; - - /*--- An intermediate value used in computations. ---*/ - - su2double u2=u*u; su2double v2=v*v; su2double w2=w*w; - su2double cosT = cos(theta); su2double sinT = sin(theta); - su2double l2 = u2 + v2 + w2; su2double l = sqrt(l2); - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - if (config->GetMarker_All_DV(iMarker) == YES) { - Coord = boundary->vertex[iMarker][iVertex]->GetCoord(); - x = Coord[0]; y = Coord[1]; z = Coord[2]; - - movement[0] = a*(v2 + w2) + u*(-b*v - c*w + u*x + v*y + w*z) - + (-a*(v2 + w2) + u*(b*v + c*w - v*y - w*z) + (v2 + w2)*x)*cosT - + l*(-c*v + b*w - w*y + v*z)*sinT; - movement[0] = movement[0]/l2 - x; - - movement[1] = b*(u2 + w2) + v*(-a*u - c*w + u*x + v*y + w*z) - + (-b*(u2 + w2) + v*(a*u + c*w - u*x - w*z) + (u2 + w2)*y)*cosT - + l*(c*u - a*w + w*x - u*z)*sinT; - movement[1] = movement[1]/l2 - y; - - movement[2] = c*(u2 + v2) + w*(-a*u - b*v + u*x + v*y + w*z) - + (-c*(u2 + v2) + w*(a*u + b*v - u*x - v*y) + (u2 + v2)*z)*cosT - + l*(-b*u + a*v - v*x + u*y)*sinT; - if (boundary->GetnDim() == 3) movement[2] = movement[2]/l2 - z; - else movement[2] = 0.0; - - VarCoord[0] = movement[0]; - VarCoord[1] = movement[1]; - if (boundary->GetnDim() == 3) VarCoord[2] = movement[2]; - - } - boundary->vertex[iMarker][iVertex]->AddVarCoord(VarCoord); - } -} - -void CSurfaceMovement::SetTranslation(CGeometry *boundary, CConfig *config, unsigned short iDV, bool ResetDef) { - unsigned long iVertex; - unsigned short iMarker; - su2double VarCoord[3] = {0.0,0.0,0.0}; - su2double Ampl = config->GetDV_Value(iDV); - - /*--- Reset airfoil deformation if first deformation or if it required by the solver ---*/ - - if ((iDV == 0) || (ResetDef == true)) { - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - boundary->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - } - } - - su2double xDispl = config->GetParamDV(iDV, 0); - su2double yDispl = config->GetParamDV(iDV, 1); - su2double zDispl = 0; - if (boundary->GetnDim() == 3) zDispl = config->GetParamDV(iDV, 2); - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - if (config->GetMarker_All_DV(iMarker) == YES) { - VarCoord[0] = Ampl*xDispl; - VarCoord[1] = Ampl*yDispl; - if (boundary->GetnDim() == 3) VarCoord[2] = Ampl*zDispl; - } - boundary->vertex[iMarker][iVertex]->AddVarCoord(VarCoord); - } - -} - -void CSurfaceMovement::SetScale(CGeometry *boundary, CConfig *config, unsigned short iDV, bool ResetDef) { - unsigned long iVertex; - unsigned short iMarker; - su2double VarCoord[3] = {0.0,0.0,0.0}, x, y, z, *Coord; - su2double Ampl = config->GetDV_Value(iDV); - - /*--- Reset airfoil deformation if first deformation or if it required by the solver ---*/ - - if ((iDV == 0) || (ResetDef == true)) { - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - boundary->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - } - } - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - if (config->GetMarker_All_DV(iMarker) == YES) { - Coord = boundary->vertex[iMarker][iVertex]->GetCoord(); - x = Coord[0]; y = Coord[1]; z = Coord[2]; - VarCoord[0] = (Ampl-1.0)*x; - VarCoord[1] = (Ampl-1.0)*y; - if (boundary->GetnDim() == 3) VarCoord[2] = (Ampl-1.0)*z; - } - boundary->vertex[iMarker][iVertex]->AddVarCoord(VarCoord); - } - -} - -void CSurfaceMovement::Moving_Walls(CGeometry *geometry, CConfig *config, - unsigned short iZone, unsigned long iter) { - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Local variables ---*/ - unsigned short iMarker, jMarker, iDim, nDim = geometry->GetnDim(); - unsigned long iPoint, iVertex; - su2double xDot[3] = {0.0,0.0,0.0}, *Coord, Center[3] = {0.0,0.0,0.0}, Omega[3] = {0.0,0.0,0.0}, r[3] = {0.0,0.0,0.0}, GridVel[3] = {0.0,0.0,0.0}; - su2double L_Ref = config->GetLength_Ref(); - su2double Omega_Ref = config->GetOmega_Ref(); - su2double Vel_Ref = config->GetVelocity_Ref(); - string Marker_Tag; - - /*--- Store grid velocity for each node on the moving surface(s). - Sum and store the x, y, & z velocities due to translation and rotation. ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_Moving(iMarker) == YES) { - - /*--- Identify iMarker from the list of those under MARKER_MOVING ---*/ - - Marker_Tag = config->GetMarker_All_TagBound(iMarker); - jMarker = config->GetMarker_Moving(Marker_Tag); - - /*--- Get prescribed wall speed from config for this marker ---*/ - - Center[0] = config->GetMotion_Origin_X(jMarker); - Center[1] = config->GetMotion_Origin_Y(jMarker); - Center[2] = config->GetMotion_Origin_Z(jMarker); - Omega[0] = config->GetRotation_Rate_X(jMarker)/Omega_Ref; - Omega[1] = config->GetRotation_Rate_Y(jMarker)/Omega_Ref; - Omega[2] = config->GetRotation_Rate_Z(jMarker)/Omega_Ref; - xDot[0] = config->GetTranslation_Rate_X(jMarker)/Vel_Ref; - xDot[1] = config->GetTranslation_Rate_Y(jMarker)/Vel_Ref; - xDot[2] = config->GetTranslation_Rate_Z(jMarker)/Vel_Ref; - - if (rank == MASTER_NODE && iter == 0) { - cout << " Storing grid velocity for marker: "; - cout << Marker_Tag << "." << endl; - cout << " Translational velocity: (" << xDot[0] << ", " << xDot[1]; - cout << ", " << xDot[2] << ") m/s." << endl; - cout << " Angular velocity: (" << Omega[0] << ", " << Omega[1]; - cout << ", " << Omega[2] << ") rad/s about origin: (" << Center[0]; - cout << ", " << Center[1] << ", " << Center[2] << ")." << endl; - } - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - /*--- Get the index and coordinates of the current point ---*/ - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Coord = geometry->node[iPoint]->GetCoord(); - - /*--- Calculate non-dim. position from rotation center ---*/ - for (iDim = 0; iDim < nDim; iDim++) - r[iDim] = (Coord[iDim]-Center[iDim])/L_Ref; - if (nDim == 2) r[nDim] = 0.0; - - /*--- Cross Product of angular velocity and distance from center to - get the rotational velocity. Note that we are adding on the velocity - due to pure translation as well. ---*/ - - GridVel[0] = xDot[0] + Omega[1]*r[2] - Omega[2]*r[1]; - GridVel[1] = xDot[1] + Omega[2]*r[0] - Omega[0]*r[2]; - GridVel[2] = xDot[2] + Omega[0]*r[1] - Omega[1]*r[0]; - - /*--- Store the moving wall velocity for this node ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - geometry->node[iPoint]->SetGridVel(iDim, GridVel[iDim]); - - } - } - } -} - -void CSurfaceMovement::Surface_Translating(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone) { - - su2double deltaT, time_new, time_old; - su2double Center[3] = {0.0,0.0,0.0}, VarCoord[3] = {0.0,0.0,0.0}; - su2double xDot[3] = {0.0,0.0,0.0}; - unsigned short iMarker, jMarker, Moving; - unsigned long iVertex; - string Marker_Tag, Moving_Tag; - int rank; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#else - rank = MASTER_NODE; -#endif - - /*--- Initialize the delta variation in coordinates ---*/ - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - - /*--- Retrieve values from the config file ---*/ - - deltaT = config->GetDelta_UnstTimeND(); - - /*--- Compute delta time based on physical time step ---*/ - time_new = static_cast(iter)*deltaT; - if (iter == 0) { - time_old = time_new; - } else { - time_old = static_cast(iter-1)*deltaT; - } - - /*--- Store displacement of each node on the translating surface ---*/ - /*--- Loop over markers and find the particular marker(s) (surface) to translate ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Moving = config->GetMarker_All_Moving(iMarker); - if (Moving == YES) { - for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { - - Moving_Tag = config->GetMarker_Moving(jMarker); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); - - if (Marker_Tag == Moving_Tag) { - - /*--- Translation velocity from config. ---*/ - - xDot[0] = config->GetTranslation_Rate_X(jMarker); - xDot[1] = config->GetTranslation_Rate_Y(jMarker); - xDot[2] = config->GetTranslation_Rate_Z(jMarker); - - /*--- Print some information to the console. Be verbose at the first - iteration only (mostly for debugging purposes). ---*/ - // Note that the MASTER_NODE might not contain all the markers being moved. - - if (rank == MASTER_NODE) { - cout << " Storing translating displacement for marker: "; - cout << Marker_Tag << "." << endl; - if (iter == 0) { - cout << " Translational velocity: (" << xDot[0] << ", " << xDot[1]; - cout << ", " << xDot[2] << ") m/s." << endl; - } - } - - /*--- Compute delta change in the position in the x, y, & z directions. ---*/ - - VarCoord[0] = xDot[0]*(time_new-time_old); - VarCoord[1] = xDot[1]*(time_new-time_old); - VarCoord[2] = xDot[2]*(time_new-time_old); - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - /*--- Set node displacement for volume deformation ---*/ - geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - - } - } - } - } - } - - /*--- When updating the origins it is assumed that all markers have the - same translational velocity, because we use the last VarCoord set ---*/ - - /*--- Set the mesh motion center to the new location after - incrementing the position with the translation. This new - location will be used for subsequent mesh motion for the given marker.---*/ - - for (jMarker=0; jMarkerGetnMarker_Moving(); jMarker++) { - - /*-- Check if we want to update the motion origin for the given marker ---*/ - - if (config->GetMoveMotion_Origin(jMarker) == YES) { - Center[0] = config->GetMotion_Origin_X(jMarker) + VarCoord[0]; - Center[1] = config->GetMotion_Origin_Y(jMarker) + VarCoord[1]; - Center[2] = config->GetMotion_Origin_Z(jMarker) + VarCoord[2]; - config->SetMotion_Origin_X(jMarker, Center[0]); - config->SetMotion_Origin_Y(jMarker, Center[1]); - config->SetMotion_Origin_Z(jMarker, Center[2]); - } - } - - /*--- Set the moment computation center to the new location after - incrementing the position with the translation. ---*/ - - for (jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { - Center[0] = config->GetRefOriginMoment_X(jMarker) + VarCoord[0]; - Center[1] = config->GetRefOriginMoment_Y(jMarker) + VarCoord[1]; - Center[2] = config->GetRefOriginMoment_Z(jMarker) + VarCoord[2]; - config->SetRefOriginMoment_X(jMarker, Center[0]); - config->SetRefOriginMoment_Y(jMarker, Center[1]); - config->SetRefOriginMoment_Z(jMarker, Center[2]); - } -} - -void CSurfaceMovement::Surface_Plunging(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone) { - - su2double deltaT, time_new, time_old, Lref; - su2double Center[3], VarCoord[3], Omega[3], Ampl[3]; - su2double DEG2RAD = PI_NUMBER/180.0; - unsigned short iMarker, jMarker, Moving; - unsigned long iVertex; - string Marker_Tag, Moving_Tag; - int rank; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#else - rank = MASTER_NODE; -#endif - - /*--- Initialize the delta variation in coordinates ---*/ - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - - /*--- Retrieve values from the config file ---*/ - - deltaT = config->GetDelta_UnstTimeND(); - Lref = config->GetLength_Ref(); - - /*--- Compute delta time based on physical time step ---*/ - time_new = static_cast(iter)*deltaT; - if (iter == 0) { - time_old = time_new; - } else { - time_old = static_cast(iter-1)*deltaT; - } - - /*--- Store displacement of each node on the plunging surface ---*/ - /*--- Loop over markers and find the particular marker(s) (surface) to plunge ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Moving = config->GetMarker_All_Moving(iMarker); - if (Moving == YES) { - for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { - - Moving_Tag = config->GetMarker_Moving(jMarker); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); - - if (Marker_Tag == Moving_Tag) { - - /*--- Plunging frequency and amplitude from config. ---*/ - - Omega[0] = config->GetPlunging_Omega_X(jMarker)/config->GetOmega_Ref(); - Omega[1] = config->GetPlunging_Omega_Y(jMarker)/config->GetOmega_Ref(); - Omega[2] = config->GetPlunging_Omega_Z(jMarker)/config->GetOmega_Ref(); - Ampl[0] = config->GetPlunging_Ampl_X(jMarker)/Lref; - Ampl[1] = config->GetPlunging_Ampl_Y(jMarker)/Lref; - Ampl[2] = config->GetPlunging_Ampl_Z(jMarker)/Lref; - - /*--- Print some information to the console. Be verbose at the first - iteration only (mostly for debugging purposes). ---*/ - // Note that the MASTER_NODE might not contain all the markers being moved. - - if (rank == MASTER_NODE) { - cout << " Storing plunging displacement for marker: "; - cout << Marker_Tag << "." << endl; - if (iter == 0) { - cout << " Plunging frequency: (" << Omega[0] << ", " << Omega[1]; - cout << ", " << Omega[2] << ") rad/s." << endl; - cout << " Plunging amplitude: (" << Ampl[0]/DEG2RAD; - cout << ", " << Ampl[1]/DEG2RAD << ", " << Ampl[2]/DEG2RAD; - cout << ") degrees."<< endl; - } - } - - /*--- Compute delta change in the position in the x, y, & z directions. ---*/ - - VarCoord[0] = -Ampl[0]*(sin(Omega[0]*time_new) - sin(Omega[0]*time_old)); - VarCoord[1] = -Ampl[1]*(sin(Omega[1]*time_new) - sin(Omega[1]*time_old)); - VarCoord[2] = -Ampl[2]*(sin(Omega[2]*time_new) - sin(Omega[2]*time_old)); - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - /*--- Set node displacement for volume deformation ---*/ - geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - - } - } - } - } - } - - /*--- When updating the origins it is assumed that all markers have the - same plunging movement, because we use the last VarCoord set ---*/ - - /*--- Set the mesh motion center to the new location after - incrementing the position with the translation. This new - location will be used for subsequent mesh motion for the given marker.---*/ - - for (jMarker=0; jMarkerGetnMarker_Moving(); jMarker++) { - - /*-- Check if we want to update the motion origin for the given marker ---*/ - - if (config->GetMoveMotion_Origin(jMarker) == YES) { - Center[0] = config->GetMotion_Origin_X(jMarker) + VarCoord[0]; - Center[1] = config->GetMotion_Origin_Y(jMarker) + VarCoord[1]; - Center[2] = config->GetMotion_Origin_Z(jMarker) + VarCoord[2]; - config->SetMotion_Origin_X(jMarker, Center[0]); - config->SetMotion_Origin_Y(jMarker, Center[1]); - config->SetMotion_Origin_Z(jMarker, Center[2]); - } - } - - /*--- Set the moment computation center to the new location after - incrementing the position with the plunging. ---*/ - - for (jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { - Center[0] = config->GetRefOriginMoment_X(jMarker) + VarCoord[0]; - Center[1] = config->GetRefOriginMoment_Y(jMarker) + VarCoord[1]; - Center[2] = config->GetRefOriginMoment_Z(jMarker) + VarCoord[2]; - config->SetRefOriginMoment_X(jMarker, Center[0]); - config->SetRefOriginMoment_Y(jMarker, Center[1]); - config->SetRefOriginMoment_Z(jMarker, Center[2]); - } -} - -void CSurfaceMovement::Surface_Pitching(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone) { - - su2double deltaT, time_new, time_old, Lref, *Coord; - su2double Center[3], VarCoord[3], Omega[3], Ampl[3], Phase[3]; - su2double rotCoord[3], r[3] = {0.0,0.0,0.0}; - su2double rotMatrix[3][3] = {{0.0,0.0,0.0}, {0.0,0.0,0.0}, {0.0,0.0,0.0}}; - su2double dtheta, dphi, dpsi, cosTheta, sinTheta; - su2double cosPhi, sinPhi, cosPsi, sinPsi; - su2double DEG2RAD = PI_NUMBER/180.0; - unsigned short iMarker, jMarker, Moving, iDim, nDim = geometry->GetnDim(); - unsigned long iPoint, iVertex; - string Marker_Tag, Moving_Tag; - int rank; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#else - rank = MASTER_NODE; -#endif - - /*--- Initialize the delta variation in coordinates ---*/ - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - - /*--- Retrieve values from the config file ---*/ - - deltaT = config->GetDelta_UnstTimeND(); - Lref = config->GetLength_Ref(); - - /*--- Compute delta time based on physical time step ---*/ - time_new = static_cast(iter)*deltaT; - if (iter == 0) { - time_old = time_new; - } else { - time_old = static_cast(iter-1)*deltaT; - } - - /*--- Store displacement of each node on the pitching surface ---*/ - /*--- Loop over markers and find the particular marker(s) (surface) to pitch ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Moving = config->GetMarker_All_Moving(iMarker); - if (Moving == YES) { - for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { - - Moving_Tag = config->GetMarker_Moving(jMarker); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); - - if (Marker_Tag == Moving_Tag) { - - /*--- Pitching origin, frequency, and amplitude from config. ---*/ - - Center[0] = config->GetMotion_Origin_X(jMarker); - Center[1] = config->GetMotion_Origin_Y(jMarker); - Center[2] = config->GetMotion_Origin_Z(jMarker); - Omega[0] = config->GetPitching_Omega_X(jMarker)/config->GetOmega_Ref(); - Omega[1] = config->GetPitching_Omega_Y(jMarker)/config->GetOmega_Ref(); - Omega[2] = config->GetPitching_Omega_Z(jMarker)/config->GetOmega_Ref(); - Ampl[0] = config->GetPitching_Ampl_X(jMarker)*DEG2RAD; - Ampl[1] = config->GetPitching_Ampl_Y(jMarker)*DEG2RAD; - Ampl[2] = config->GetPitching_Ampl_Z(jMarker)*DEG2RAD; - Phase[0] = config->GetPitching_Phase_X(jMarker)*DEG2RAD; - Phase[1] = config->GetPitching_Phase_Y(jMarker)*DEG2RAD; - Phase[2] = config->GetPitching_Phase_Z(jMarker)*DEG2RAD; - - /*--- Print some information to the console. Be verbose at the first - iteration only (mostly for debugging purposes). ---*/ - // Note that the MASTER_NODE might not contain all the markers being moved. - - if (rank == MASTER_NODE) { - cout << " Storing pitching displacement for marker: "; - cout << Marker_Tag << "." << endl; - if (iter == 0) { - cout << " Pitching frequency: (" << Omega[0] << ", " << Omega[1]; - cout << ", " << Omega[2] << ") rad/s about origin: (" << Center[0]; - cout << ", " << Center[1] << ", " << Center[2] << ")." << endl; - cout << " Pitching amplitude about origin: (" << Ampl[0]/DEG2RAD; - cout << ", " << Ampl[1]/DEG2RAD << ", " << Ampl[2]/DEG2RAD; - cout << ") degrees."<< endl; - cout << " Pitching phase lag about origin: (" << Phase[0]/DEG2RAD; - cout << ", " << Phase[1]/DEG2RAD <<", "<< Phase[2]/DEG2RAD; - cout << ") degrees."<< endl; - } - } - - /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ - - dtheta = -Ampl[0]*(sin(Omega[0]*time_new + Phase[0]) - - sin(Omega[0]*time_old + Phase[0])); - dphi = -Ampl[1]*(sin(Omega[1]*time_new + Phase[1]) - - sin(Omega[1]*time_old + Phase[1])); - dpsi = -Ampl[2]*(sin(Omega[2]*time_new + Phase[2]) - - sin(Omega[2]*time_old + Phase[2])); - - /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ - - cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); - sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ - - rotMatrix[0][0] = cosPhi*cosPsi; - rotMatrix[1][0] = cosPhi*sinPsi; - rotMatrix[2][0] = -sinPhi; - - rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; - rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; - rotMatrix[2][1] = sinTheta*cosPhi; - - rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[2][2] = cosTheta*cosPhi; - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - /*--- Index and coordinates of the current point ---*/ - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Coord = geometry->node[iPoint]->GetCoord(); - - /*--- Calculate non-dim. position from rotation center ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - r[iDim] = (Coord[iDim]-Center[iDim])/Lref; - if (nDim == 2) r[nDim] = 0.0; - - /*--- Compute transformed point coordinates ---*/ - - rotCoord[0] = rotMatrix[0][0]*r[0] - + rotMatrix[0][1]*r[1] - + rotMatrix[0][2]*r[2] + Center[0]; - - rotCoord[1] = rotMatrix[1][0]*r[0] - + rotMatrix[1][1]*r[1] - + rotMatrix[1][2]*r[2] + Center[1]; - - rotCoord[2] = rotMatrix[2][0]*r[0] - + rotMatrix[2][1]*r[1] - + rotMatrix[2][2]*r[2] + Center[2]; - - /*--- Calculate delta change in the x, y, & z directions ---*/ - for (iDim = 0; iDim < nDim; iDim++) - VarCoord[iDim] = (rotCoord[iDim]-Coord[iDim])/Lref; - if (nDim == 2) VarCoord[nDim] = 0.0; - - /*--- Set node displacement for volume deformation ---*/ - geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - - } - } - } - } - } - /*--- For pitching we don't update the motion origin and moment reference origin. ---*/ -} - -void CSurfaceMovement::Surface_Rotating(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone) { - - su2double deltaT, time_new, time_old, Lref, *Coord; - su2double Center[3] = {0.0,0.0,0.0}, VarCoord[3] = {0.0,0.0,0.0}, Omega[3] = {0.0,0.0,0.0}, - rotCoord[3] = {0.0,0.0,0.0}, r[3] = {0.0,0.0,0.0}, Center_Aux[3] = {0.0,0.0,0.0}; - su2double rotMatrix[3][3] = {{0.0,0.0,0.0}, {0.0,0.0,0.0}, {0.0,0.0,0.0}}; - su2double dtheta, dphi, dpsi, cosTheta, sinTheta; - su2double cosPhi, sinPhi, cosPsi, sinPsi; - unsigned short iMarker, jMarker, Moving, iDim, nDim = geometry->GetnDim(); - unsigned long iPoint, iVertex; - string Marker_Tag, Moving_Tag; - int rank; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#else - rank = MASTER_NODE; -#endif - - /*--- Initialize the delta variation in coordinates ---*/ - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - - /*--- Retrieve values from the config file ---*/ - - deltaT = config->GetDelta_UnstTimeND(); - Lref = config->GetLength_Ref(); - - /*--- Compute delta time based on physical time step ---*/ - time_new = static_cast(iter)*deltaT; - if (iter == 0) { - time_old = time_new; - } else { - time_old = static_cast(iter-1)*deltaT; - } - - /*--- Store displacement of each node on the rotating surface ---*/ - /*--- Loop over markers and find the particular marker(s) (surface) to rotate ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Moving = config->GetMarker_All_Moving(iMarker); - if (Moving == YES) { - for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { - - Moving_Tag = config->GetMarker_Moving(jMarker); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); - - if (Marker_Tag == Moving_Tag) { - - /*--- Rotation origin and angular velocity from config. ---*/ - - Center[0] = config->GetMotion_Origin_X(jMarker); - Center[1] = config->GetMotion_Origin_Y(jMarker); - Center[2] = config->GetMotion_Origin_Z(jMarker); - Omega[0] = config->GetRotation_Rate_X(jMarker)/config->GetOmega_Ref(); - Omega[1] = config->GetRotation_Rate_Y(jMarker)/config->GetOmega_Ref(); - Omega[2] = config->GetRotation_Rate_Z(jMarker)/config->GetOmega_Ref(); - - /*--- Print some information to the console. Be verbose at the first - iteration only (mostly for debugging purposes). ---*/ - // Note that the MASTER_NODE might not contain all the markers being moved. - - if (rank == MASTER_NODE) { - cout << " Storing rotating displacement for marker: "; - cout << Marker_Tag << "." << endl; - if (iter == 0) { - cout << " Angular velocity: (" << Omega[0] << ", " << Omega[1]; - cout << ", " << Omega[2] << ") rad/s about origin: (" << Center[0]; - cout << ", " << Center[1] << ", " << Center[2] << ")." << endl; - } - } - - /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ - - dtheta = Omega[0]*(time_new-time_old); - dphi = Omega[1]*(time_new-time_old); - dpsi = Omega[2]*(time_new-time_old); - - /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ - - cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); - sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ - - rotMatrix[0][0] = cosPhi*cosPsi; - rotMatrix[1][0] = cosPhi*sinPsi; - rotMatrix[2][0] = -sinPhi; - - rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; - rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; - rotMatrix[2][1] = sinTheta*cosPhi; - - rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[2][2] = cosTheta*cosPhi; - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - /*--- Index and coordinates of the current point ---*/ - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Coord = geometry->node[iPoint]->GetCoord(); - - /*--- Calculate non-dim. position from rotation center ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - r[iDim] = (Coord[iDim]-Center[iDim])/Lref; - if (nDim == 2) r[nDim] = 0.0; - - /*--- Compute transformed point coordinates ---*/ - - rotCoord[0] = rotMatrix[0][0]*r[0] - + rotMatrix[0][1]*r[1] - + rotMatrix[0][2]*r[2] + Center[0]; - - rotCoord[1] = rotMatrix[1][0]*r[0] - + rotMatrix[1][1]*r[1] - + rotMatrix[1][2]*r[2] + Center[1]; - - rotCoord[2] = rotMatrix[2][0]*r[0] - + rotMatrix[2][1]*r[1] - + rotMatrix[2][2]*r[2] + Center[2]; - - /*--- Calculate delta change in the x, y, & z directions ---*/ - for (iDim = 0; iDim < nDim; iDim++) - VarCoord[iDim] = (rotCoord[iDim]-Coord[iDim])/Lref; - if (nDim == 2) VarCoord[nDim] = 0.0; - - /*--- Set node displacement for volume deformation ---*/ - geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - - } - } - } - } - } - - /*--- When updating the origins it is assumed that all markers have the - same rotation movement, because we use the last markers rotation matrix and center ---*/ - - /*--- Set the mesh motion center to the new location after - incrementing the position with the rotation. This new - location will be used for subsequent mesh motion for the given marker.---*/ - - for (jMarker=0; jMarkerGetnMarker_Moving(); jMarker++) { - - /*-- Check if we want to update the motion origin for the given marker ---*/ - - if (config->GetMoveMotion_Origin(jMarker) == YES) { - - Center_Aux[0] = config->GetMotion_Origin_X(jMarker); - Center_Aux[1] = config->GetMotion_Origin_Y(jMarker); - Center_Aux[2] = config->GetMotion_Origin_Z(jMarker); - - /*--- Calculate non-dim. position from rotation center ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - r[iDim] = (Center_Aux[iDim]-Center[iDim])/Lref; - if (nDim == 2) r[nDim] = 0.0; - - /*--- Compute transformed point coordinates ---*/ - - rotCoord[0] = rotMatrix[0][0]*r[0] - + rotMatrix[0][1]*r[1] - + rotMatrix[0][2]*r[2] + Center[0]; - - rotCoord[1] = rotMatrix[1][0]*r[0] - + rotMatrix[1][1]*r[1] - + rotMatrix[1][2]*r[2] + Center[1]; - - rotCoord[2] = rotMatrix[2][0]*r[0] - + rotMatrix[2][1]*r[1] - + rotMatrix[2][2]*r[2] + Center[2]; - - /*--- Calculate delta change in the x, y, & z directions ---*/ - for (iDim = 0; iDim < nDim; iDim++) - VarCoord[iDim] = (rotCoord[iDim]-Center_Aux[iDim])/Lref; - if (nDim == 2) VarCoord[nDim] = 0.0; - config->SetMotion_Origin_X(jMarker, Center_Aux[0]+VarCoord[0]); - config->SetMotion_Origin_Y(jMarker, Center_Aux[1]+VarCoord[1]); - config->SetMotion_Origin_Z(jMarker, Center_Aux[2]+VarCoord[2]); - } - } - - /*--- Set the moment computation center to the new location after - incrementing the position with the rotation. ---*/ - - for (jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { - - Center_Aux[0] = config->GetRefOriginMoment_X(jMarker); - Center_Aux[1] = config->GetRefOriginMoment_Y(jMarker); - Center_Aux[2] = config->GetRefOriginMoment_Z(jMarker); - - /*--- Calculate non-dim. position from rotation center ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - r[iDim] = (Center_Aux[iDim]-Center[iDim])/Lref; - if (nDim == 2) r[nDim] = 0.0; - - /*--- Compute transformed point coordinates ---*/ - - rotCoord[0] = rotMatrix[0][0]*r[0] - + rotMatrix[0][1]*r[1] - + rotMatrix[0][2]*r[2] + Center[0]; - - rotCoord[1] = rotMatrix[1][0]*r[0] - + rotMatrix[1][1]*r[1] - + rotMatrix[1][2]*r[2] + Center[1]; - - rotCoord[2] = rotMatrix[2][0]*r[0] - + rotMatrix[2][1]*r[1] - + rotMatrix[2][2]*r[2] + Center[2]; - - /*--- Calculate delta change in the x, y, & z directions ---*/ - for (iDim = 0; iDim < nDim; iDim++) - VarCoord[iDim] = (rotCoord[iDim]-Center_Aux[iDim])/Lref; - if (nDim == 2) VarCoord[nDim] = 0.0; - - config->SetRefOriginMoment_X(jMarker, Center_Aux[0]+VarCoord[0]); - config->SetRefOriginMoment_Y(jMarker, Center_Aux[1]+VarCoord[1]); - config->SetRefOriginMoment_Z(jMarker, Center_Aux[2]+VarCoord[2]); - } -} - -void CSurfaceMovement::AeroelasticDeform(CGeometry *geometry, CConfig *config, unsigned long ExtIter, unsigned short iMarker, unsigned short iMarker_Monitoring, vector& displacements) { - - /* The sign conventions of these are those of the Typical Section Wing Model, below the signs are corrected */ - su2double dh = -displacements[0]; // relative plunge - su2double dalpha = -displacements[1]; // relative pitch - su2double dh_x, dh_y; - su2double Center[2]; - unsigned short iDim; - su2double Lref = config->GetLength_Ref(); - su2double *Coord; - unsigned long iPoint, iVertex; - su2double x_new, y_new; - su2double VarCoord[3]; - string Monitoring_Tag = config->GetMarker_Monitoring(iMarker_Monitoring); - - /*--- Calculate the plunge displacement for the Typical Section Wing Model taking into account rotation ---*/ - if (config->GetKind_GridMovement(ZONE_0) == AEROELASTIC_RIGID_MOTION) { - su2double Omega, dt, psi; - dt = config->GetDelta_UnstTimeND(); - Omega = (config->GetRotation_Rate_Z(ZONE_0)/config->GetOmega_Ref()); - psi = Omega*(dt*ExtIter); - - /*--- Correct for the airfoil starting position (This is hardcoded in here) ---*/ - if (Monitoring_Tag == "Airfoil1") { - psi = psi + 0.0; - } - else if (Monitoring_Tag == "Airfoil2") { - psi = psi + 2.0/3.0*PI_NUMBER; - } - else if (Monitoring_Tag == "Airfoil3") { - psi = psi + 4.0/3.0*PI_NUMBER; - } - else - cout << "WARNING: There is a marker that we are monitoring that doesn't match the values hardcoded above!" << endl; - - dh_x = -dh*sin(psi); - dh_y = dh*cos(psi); - - } else { - dh_x = 0; - dh_y = dh; - } - - /*--- Pitching origin from config. ---*/ - - Center[0] = config->GetRefOriginMoment_X(iMarker_Monitoring); - Center[1] = config->GetRefOriginMoment_Y(iMarker_Monitoring); - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - /*--- Coordinates of the current point ---*/ - Coord = geometry->node[iPoint]->GetCoord(); - - /*--- Calculate non-dim. position from rotation center ---*/ - su2double r[2] = {0,0}; - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) - r[iDim] = (Coord[iDim]-Center[iDim])/Lref; - - /*--- Compute delta of transformed point coordinates ---*/ - // The deltas are needed for the FEA grid deformation Method. - // rotation contribution - previous position + plunging contribution - x_new = cos(dalpha)*r[0] - sin(dalpha)*r[1] -r[0] + dh_x; - y_new = sin(dalpha)*r[0] + cos(dalpha)*r[1] -r[1] + dh_y; - - VarCoord[0] = x_new; - VarCoord[1] = y_new; - VarCoord[2] = 0.0; - - /*--- Store new delta node locations for the surface ---*/ - geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - } - /*--- Set the elastic axis to the new location after incrementing the position with the plunge ---*/ - config->SetRefOriginMoment_X(iMarker_Monitoring, Center[0]+dh_x); - config->SetRefOriginMoment_Y(iMarker_Monitoring, Center[1]+dh_y); - - -} - -void CSurfaceMovement::SetBoundary_Flutter3D(CGeometry *geometry, CConfig *config, - CFreeFormDefBox **FFDBox, unsigned long iter, unsigned short iZone) { - - su2double omega, deltaT; - su2double alpha, alpha_new, alpha_old; - su2double time_new, time_old; - su2double Omega[3], Ampl[3]; - su2double DEG2RAD = PI_NUMBER/180.0; - int rank; - bool adjoint = config->GetAdjoint(); - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#else - rank = MASTER_NODE; -#endif - - /*--- Retrieve values from the config file ---*/ - - deltaT = config->GetDelta_UnstTimeND(); - - /*--- Pitching origin, frequency, and amplitude from config. ---*/ - - Omega[0] = (config->GetPitching_Omega_X(iZone)/config->GetOmega_Ref()); - Omega[1] = (config->GetPitching_Omega_Y(iZone)/config->GetOmega_Ref()); - Omega[2] = (config->GetPitching_Omega_Z(iZone)/config->GetOmega_Ref()); - Ampl[0] = config->GetPitching_Ampl_X(iZone)*DEG2RAD; - Ampl[1] = config->GetPitching_Ampl_Y(iZone)*DEG2RAD; - Ampl[2] = config->GetPitching_Ampl_Z(iZone)*DEG2RAD; - - /*--- Compute delta time based on physical time step ---*/ - - if (adjoint) { - - /*--- For the unsteady adjoint, we integrate backwards through - physical time, so perform mesh motion in reverse. ---*/ - - unsigned long nFlowIter = config->GetnExtIter(); - unsigned long directIter = nFlowIter - iter - 1; - time_new = static_cast(directIter)*deltaT; - time_old = time_new; - if (iter != 0) time_old = (static_cast(directIter)+1.0)*deltaT; - } else { - - /*--- Forward time for the direct problem ---*/ - - time_new = static_cast(iter)*deltaT; - time_old = time_new; - if (iter != 0) time_old = (static_cast(iter)-1.0)*deltaT; - } - - /*--- Update the pitching angle at this time step. Flip sign for - nose-up positive convention. ---*/ - - omega = Omega[2]; - alpha_new = Ampl[2]*sin(omega*time_new); - alpha_old = Ampl[2]*sin(omega*time_old); - alpha = (1E-10 + (alpha_new - alpha_old))*(-PI_NUMBER/180.0); - - if (rank == MASTER_NODE) - cout << "New dihedral angle (alpha): " << alpha_new/DEG2RAD << " degrees." << endl; - - unsigned short iOrder, jOrder, kOrder; - short iFFDBox; - su2double movement[3] = {0.0,0.0,0.0}; - bool *move = new bool [nFFDBox]; - unsigned short *index = new unsigned short[3]; - - move[0] = true; move[1] = true; move[2] = true; - - /*--- Change the value of the control point if move is true ---*/ - - for (iFFDBox = 0; iFFDBox < nFFDBox; iFFDBox++) - if (move[iFFDBox]) - for (iOrder = 0; iOrder < FFDBox[iFFDBox]->GetlOrder(); iOrder++) - for (jOrder = 0; jOrder < FFDBox[iFFDBox]->GetmOrder(); jOrder++) - for (kOrder = 0; kOrder < FFDBox[iFFDBox]->GetnOrder(); kOrder++) { - index[0] = iOrder; index[1] = jOrder; index[2] = kOrder; - su2double *coord = FFDBox[iFFDBox]->GetCoordControlPoints(iOrder, jOrder, kOrder); - movement[0] = 0.0; movement[1] = 0.0; movement[2] = coord[1]*tan(alpha); - FFDBox[iFFDBox]->SetControlPoints(index, movement); - } - - /*--- Recompute cartesian coordinates using the new control points position ---*/ - - for (iFFDBox = 0; iFFDBox < nFFDBox; iFFDBox++) - SetCartesianCoord(geometry, config, FFDBox[iFFDBox], iFFDBox); - -} - -void CSurfaceMovement::SetExternal_Deformation(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter) { - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Local variables ---*/ - - unsigned short iDim, nDim; - unsigned long iPoint = 0, flowIter = 0; - unsigned long jPoint, GlobalIndex; - su2double VarCoord[3], *Coord_Old = NULL, *Coord_New = NULL, Center[3] = {0.0,0.0,0.0}; - su2double Lref = config->GetLength_Ref(); - su2double NewCoord[3] = {0.0,0.0,0.0}, rotMatrix[3][3] = {{0.0,0.0,0.0}, {0.0,0.0,0.0}, {0.0,0.0,0.0}}; - su2double r[3] = {0.0,0.0,0.0}, rotCoord[3] = {0.0,0.0,0.0}; - unsigned long iVertex; - unsigned short iMarker; - char buffer[50]; - string motion_filename, UnstExt, text_line; - ifstream motion_file; - bool unsteady = config->GetUnsteady_Simulation(); - bool adjoint = config->GetAdjoint(); - - /*--- Load stuff from config ---*/ - - nDim = geometry->GetnDim(); - motion_filename = config->GetMotion_FileName(); - - /*--- Set the extension for the correct unsteady mesh motion file ---*/ - - if (unsteady) { - if (adjoint) { - /*--- For the unsteady adjoint, we integrate backwards through - physical time, so perform mesh motion in reverse. ---*/ - unsigned long nFlowIter = config->GetnExtIter() - 1; - flowIter = nFlowIter - iter; - unsigned short lastindex = motion_filename.find_last_of("."); - motion_filename = motion_filename.substr(0, lastindex); - if ((SU2_TYPE::Int(flowIter) >= 0) && (SU2_TYPE::Int(flowIter) < 10)) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(flowIter)); - if ((SU2_TYPE::Int(flowIter) >= 10) && (SU2_TYPE::Int(flowIter) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(flowIter)); - if ((SU2_TYPE::Int(flowIter) >= 100) && (SU2_TYPE::Int(flowIter) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(flowIter)); - if ((SU2_TYPE::Int(flowIter) >= 1000) && (SU2_TYPE::Int(flowIter) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(flowIter)); - if (SU2_TYPE::Int(flowIter) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(flowIter)); - UnstExt = string(buffer); - motion_filename.append(UnstExt); - } else { - /*--- Forward time for the direct problem ---*/ - flowIter = iter; - unsigned short lastindex = motion_filename.find_last_of("."); - motion_filename = motion_filename.substr(0, lastindex); - if ((SU2_TYPE::Int(flowIter) >= 0) && (SU2_TYPE::Int(flowIter) < 10)) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(flowIter)); - if ((SU2_TYPE::Int(flowIter) >= 10) && (SU2_TYPE::Int(flowIter) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(flowIter)); - if ((SU2_TYPE::Int(flowIter) >= 100) && (SU2_TYPE::Int(flowIter) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(flowIter)); - if ((SU2_TYPE::Int(flowIter) >= 1000) && (SU2_TYPE::Int(flowIter) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(flowIter)); - if (SU2_TYPE::Int(flowIter) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(flowIter)); - UnstExt = string(buffer); - motion_filename.append(UnstExt); - } - - if (rank == MASTER_NODE) - cout << "Reading in the arbitrary mesh motion from direct iteration " << flowIter << "." << endl; - } - - /*--- Open the motion file ---*/ - - motion_file.open(motion_filename.data(), ios::in); - /*--- Throw error if there is no file ---*/ - if (motion_file.fail()) { - cout << "There is no mesh motion file!" << endl; - exit(EXIT_FAILURE); - } - - /*--- Read in and store the new mesh node locations ---*/ - - while (getline(motion_file, text_line)) { - istringstream point_line(text_line); - if (nDim == 2) point_line >> iPoint >> NewCoord[0] >> NewCoord[1]; - if (nDim == 3) point_line >> iPoint >> NewCoord[0] >> NewCoord[1] >> NewCoord[2]; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_Moving(iMarker) == YES) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - jPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - GlobalIndex = geometry->node[jPoint]->GetGlobalIndex(); - if (GlobalIndex == iPoint) { - geometry->vertex[iMarker][iVertex]->SetVarCoord(NewCoord); - break; - } - } - } - } - } - /*--- Close the restart file ---*/ - motion_file.close(); - - /*--- If rotating as well, prepare the rotation matrix ---*/ - - if (config->GetGrid_Movement() && - config->GetKind_GridMovement(iZone) == EXTERNAL_ROTATION) { - - /*--- Variables needed only for rotation ---*/ - - su2double Omega[3], dt; - su2double dtheta, dphi, dpsi, cosTheta, sinTheta; - su2double cosPhi, sinPhi, cosPsi, sinPsi; - - /*--- Center of rotation & angular velocity vector from config ---*/ - Center[0] = config->GetMotion_Origin_X(iZone); - Center[1] = config->GetMotion_Origin_Y(iZone); - Center[2] = config->GetMotion_Origin_Z(iZone); - - /*--- Angular velocity vector from config ---*/ - - dt = static_cast(iter)*config->GetDelta_UnstTimeND(); - Omega[0] = config->GetRotation_Rate_X(iZone); - Omega[1] = config->GetRotation_Rate_Y(iZone); - Omega[2] = config->GetRotation_Rate_Z(iZone); - - /*--- For the unsteady adjoint, use reverse time ---*/ - if (adjoint) { - /*--- Set the first adjoint mesh position to the final direct one ---*/ - if (iter == 0) dt = ((su2double)config->GetnExtIter()-1) * dt; - /*--- Reverse the rotation direction for the adjoint ---*/ - else dt = -1.0*dt; - } else { - /*--- No rotation at all for the first direct solution ---*/ - if (iter == 0) dt = 0; - } - - /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ - - dtheta = Omega[0]*dt; - dphi = Omega[1]*dt; - dpsi = Omega[2]*dt; - - /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ - - cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); - sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ - - rotMatrix[0][0] = cosPhi*cosPsi; - rotMatrix[1][0] = cosPhi*sinPsi; - rotMatrix[2][0] = -sinPhi; - - rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; - rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; - rotMatrix[2][1] = sinTheta*cosPhi; - - rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[2][2] = cosTheta*cosPhi; - - } - - /*--- Loop through to find only moving surface markers ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_Moving(iMarker) == YES) { - - /*--- Loop over all surface points for this marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - /*--- Get current and new coordinates from file ---*/ - - Coord_Old = geometry->node[iPoint]->GetCoord(); - Coord_New = geometry->vertex[iMarker][iVertex]->GetVarCoord(); - - /*--- If we're also rotating, multiply each point by the - rotation matrix. It is assumed that the coordinates in - Coord_Old have already been rotated using SetRigid_Rotation(). ---*/ - - if (config->GetGrid_Movement() && - config->GetKind_GridMovement(iZone) == EXTERNAL_ROTATION) { - - /*--- Calculate non-dim. position from rotation center ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - r[iDim] = (Coord_New[iDim]-Center[iDim])/Lref; - if (nDim == 2) r[nDim] = 0.0; - - /*--- Compute transformed point coordinates ---*/ - - rotCoord[0] = rotMatrix[0][0]*r[0] - + rotMatrix[0][1]*r[1] - + rotMatrix[0][2]*r[2] + Center[0]; - - rotCoord[1] = rotMatrix[1][0]*r[0] - + rotMatrix[1][1]*r[1] - + rotMatrix[1][2]*r[2] + Center[1]; - - rotCoord[2] = rotMatrix[2][0]*r[0] - + rotMatrix[2][1]*r[1] - + rotMatrix[2][2]*r[2] + Center[2]; - - /*--- Copy rotated coords back to original array for consistency ---*/ - for (iDim = 0; iDim < nDim; iDim++) - Coord_New[iDim] = rotCoord[iDim]; - } - - /*--- Calculate delta change in the x, y, & z directions ---*/ - for (iDim = 0; iDim < nDim; iDim++) - VarCoord[iDim] = (Coord_New[iDim]-Coord_Old[iDim])/Lref; - if (nDim == 2) VarCoord[nDim] = 0.0; - - /*--- Set position changes to be applied by the spring analogy ---*/ - geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - - } - } - } -} - -void CSurfaceMovement::SetNACA_4Digits(CGeometry *boundary, CConfig *config) { - unsigned long iVertex; - unsigned short iMarker; - su2double VarCoord[3], *Coord, *Normal, Ycurv, Yesp; - - if (config->GetnDV() != 1) { cout << "This kind of design variable is not prepared for multiple deformations."; cin.get(); } - - su2double Ya = config->GetParamDV(0,0) / 100.0; /*--- Maximum camber as a fraction of the chord - (100 m is the first of the four digits) ---*/ - su2double Xa = config->GetParamDV(0,1) / 10.0; /*--- Location of maximum camber as a fraction of - the chord (10 p is the second digit in the NACA xxxx description) ---*/ - su2double t = config->GetParamDV(0,2) / 100.0; /*--- Maximum thickness as a fraction of the - chord (so 100 t gives the last two digits in - the NACA 4-digit denomination) ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - if (config->GetMarker_All_DV(iMarker) == YES) { - Coord = boundary->vertex[iMarker][iVertex]->GetCoord(); - Normal = boundary->vertex[iMarker][iVertex]->GetNormal(); - - if (Coord[0] < Xa) Ycurv = (2.0*Xa*Coord[0]-pow(Coord[0],2.0))*(Ya/pow(Xa,2.0)); - else Ycurv = ((1.0-2.0*Xa)+2.0*Xa*Coord[0]-pow(Coord[0],2.0))*(Ya/pow((1.0-Xa), 2.0)); - - Yesp = t*(1.4845*sqrt(Coord[0])-0.6300*Coord[0]-1.7580*pow(Coord[0],2.0)+ - 1.4215*pow(Coord[0],3.0)-0.518*pow(Coord[0],4.0)); - - if (Normal[1] > 0) VarCoord[1] = (Ycurv + Yesp) - Coord[1]; - if (Normal[1] < 0) VarCoord[1] = (Ycurv - Yesp) - Coord[1]; - - } - boundary->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - } -} - -void CSurfaceMovement::SetParabolic(CGeometry *boundary, CConfig *config) { - unsigned long iVertex; - unsigned short iMarker; - su2double VarCoord[3], *Coord, *Normal; - - if (config->GetnDV() != 1) { cout << "This kind of design variable is not prepared for multiple deformations."; cin.get(); } - - su2double c = config->GetParamDV(0,0); /*--- Center of the parabola ---*/ - su2double t = config->GetParamDV(0,1) / 100.0; /*--- Thickness of the parabola ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - if (config->GetMarker_All_DV(iMarker) == YES) { - Coord = boundary->vertex[iMarker][iVertex]->GetCoord(); - Normal = boundary->vertex[iMarker][iVertex]->GetNormal(); - - if (Normal[1] > 0) { - VarCoord[1] = t*(Coord[0]*Coord[0]-Coord[0])/(2.0*(c*c-c)) - Coord[1]; - } - if (Normal[1] < 0) { - VarCoord[1] = t*(Coord[0]-Coord[0]*Coord[0])/(2.0*(c*c-c)) - Coord[1]; - } - } - boundary->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - } -} - -void CSurfaceMovement::SetAirfoil(CGeometry *boundary, CConfig *config) { - unsigned long iVertex, n_Airfoil = 0; - unsigned short iMarker, nUpper, nLower, iUpper, iLower, iVar, iDim; - su2double *VarCoord, *Coord, NewYCoord, NewXCoord, *Coord_i, *Coord_ip1, yp1, ypn, - Airfoil_Coord[2]= {0.0,0.0}, factor, coeff = 10000, Upper, Lower, Arch = 0.0, TotalArch = 0.0, - x_i, x_ip1, y_i, y_ip1; - passivedouble AirfoilScale; - vector Svalue, Xcoord, Ycoord, Xcoord2, Ycoord2, Xcoord_Aux, Ycoord_Aux; - bool AddBegin = true, AddEnd = true; - char AirfoilFile[256], AirfoilFormat[15], MeshOrientation[15], AirfoilClose[15]; - ifstream airfoil_file; - string text_line; - int ierr = 0; - - unsigned short nDim = boundary->GetnDim(); - - VarCoord = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim++) - VarCoord[iDim] = 0.0; - - /*--- Get the SU2 module. SU2_CFD will use this routine for dynamically - deforming meshes (MARKER_MOVING), while SU2_DEF will use it for deforming - meshes after imposing design variable surface deformations (DV_MARKER). ---*/ - - unsigned short Kind_SU2 = config->GetKind_SU2(); - - /*--- Read the coordinates. Two main formats: - - Selig are in an x, y format starting from trailing edge, along the upper surface to the leading - edge and back around the lower surface to trailing edge. - - Lednicer are upper surface points leading edge to trailing edge and then lower surface leading - edge to trailing edge. - ---*/ - - /*--- Open the restart file, throw an error if this fails. ---*/ - - cout << "Enter the name of file with the airfoil information: "; - ierr = scanf("%s", AirfoilFile); - if (ierr == 0) { cout << "No input read!! "<< endl; exit(EXIT_FAILURE); } - airfoil_file.open(AirfoilFile, ios::in); - if (airfoil_file.fail()) { - cout << "There is no airfoil file!! "<< endl; - exit(EXIT_FAILURE); - } - cout << "Enter the format of the airfoil (Selig or Lednicer): "; - ierr = scanf("%s", AirfoilFormat); - if (ierr == 0) { cout << "No input read!! "<< endl; exit(EXIT_FAILURE); } - - cout << "Thickness scaling (1.0 means no scaling)?: "; - ierr = scanf("%lf", &AirfoilScale); - if (ierr == 0) { cout << "No input read!! "<< endl; exit(EXIT_FAILURE); } - - cout << "Close the airfoil (Yes or No)?: "; - ierr = scanf("%s", AirfoilClose); - if (ierr == 0) { cout << "No input read!! "<< endl; exit(EXIT_FAILURE); } - - cout << "Surface mesh orientation (clockwise, or anticlockwise): "; - ierr = scanf("%s", MeshOrientation); - if (ierr == 0) { cout << "No input read!! "<< endl; exit(EXIT_FAILURE); } - - /*--- The first line is the header ---*/ - - getline (airfoil_file, text_line); - cout << "File info: " << text_line << endl; - - if (strcmp (AirfoilFormat,"Selig") == 0) { - - while (getline (airfoil_file, text_line)) { - istringstream point_line(text_line); - - /*--- Read the x & y coordinates from this line of the file (anticlockwise) ---*/ - - point_line >> Airfoil_Coord[0] >> Airfoil_Coord[1]; - - /*--- Close the arifoil ---*/ - - if (strcmp (AirfoilClose,"Yes") == 0) - factor = -atan(coeff*(Airfoil_Coord[0]-1.0))*2.0/PI_NUMBER; - else factor = 1.0; - - /*--- Store the coordinates in vectors ---*/ - - Xcoord.push_back(Airfoil_Coord[0]); - Ycoord.push_back(Airfoil_Coord[1]*factor*AirfoilScale); - } - - } - if (strcmp (AirfoilFormat,"Lednicer") == 0) { - - /*--- The second line is the number of points ---*/ - - getline(airfoil_file, text_line); - istringstream point_line(text_line); - point_line >> Upper >> Lower; - - nUpper = SU2_TYPE::Int(Upper); - nLower = SU2_TYPE::Int(Lower); - - Xcoord.resize(nUpper+nLower-1); - Ycoord.resize(nUpper+nLower-1); - - /*--- White line ---*/ - - getline (airfoil_file, text_line); - - for (iUpper = 0; iUpper < nUpper; iUpper++) { - getline (airfoil_file, text_line); - istringstream point_line(text_line); - point_line >> Airfoil_Coord[0] >> Airfoil_Coord[1]; - Xcoord[nUpper-iUpper-1] = Airfoil_Coord[0]; - - if (strcmp (AirfoilClose,"Yes") == 0) - factor = -atan(coeff*(Airfoil_Coord[0]-1.0))*2.0/PI_NUMBER; - else factor = 1.0; - - Ycoord[nUpper-iUpper-1] = Airfoil_Coord[1]*AirfoilScale*factor; - } - - getline (airfoil_file, text_line); - - for (iLower = 0; iLower < nLower; iLower++) { - getline (airfoil_file, text_line); - istringstream point_line(text_line); - point_line >> Airfoil_Coord[0] >> Airfoil_Coord[1]; - - if (strcmp (AirfoilClose,"Yes") == 0) - factor = -atan(coeff*(Airfoil_Coord[0]-1.0))*2.0/PI_NUMBER; - else factor = 1.0; - - Xcoord[nUpper+iLower-1] = Airfoil_Coord[0]; - Ycoord[nUpper+iLower-1] = Airfoil_Coord[1]*AirfoilScale*factor; - } - - } - - /*--- Check the coordinate (1,0) at the beginning and end of the file ---*/ - - if (Xcoord[0] == 1.0) AddBegin = false; - if (Xcoord[Xcoord.size()-1] == 1.0) AddEnd = false; - - if (AddBegin) { Xcoord.insert(Xcoord.begin(), 1.0); Ycoord.insert(Ycoord.begin(), 0.0);} - if (AddEnd) { Xcoord.push_back(1.0); Ycoord.push_back(0.0);} - - /*--- Change the orientation (depend on the input file, and the mesh file) ---*/ - - if (strcmp (MeshOrientation,"clockwise") == 0) { - for (iVar = 0; iVar < Xcoord.size(); iVar++) { - Xcoord_Aux.push_back(Xcoord[iVar]); - Ycoord_Aux.push_back(Ycoord[iVar]); - } - - for (iVar = 0; iVar < Xcoord.size(); iVar++) { - Xcoord[iVar] = Xcoord_Aux[Xcoord.size()-iVar-1]; - Ycoord[iVar] = Ycoord_Aux[Xcoord.size()-iVar-1]; - } - } - - /*--- Compute the total arch length ---*/ - - Arch = 0.0; Svalue.push_back(Arch); - - for (iVar = 0; iVar < Xcoord.size()-1; iVar++) { - x_i = Xcoord[iVar]; x_ip1 = Xcoord[iVar+1]; - y_i = Ycoord[iVar]; y_ip1 = Ycoord[iVar+1]; - Arch += sqrt((x_ip1-x_i)*(x_ip1-x_i)+(y_ip1-y_i)*(y_ip1-y_i)); - Svalue.push_back(Arch); - } - x_i = Xcoord[Xcoord.size()-1]; x_ip1 = Xcoord[0]; - y_i = Ycoord[Xcoord.size()-1]; y_ip1 = Ycoord[0]; - Arch += sqrt((x_ip1-x_i)*(x_ip1-x_i)+(y_ip1-y_i)*(y_ip1-y_i)); - - /*--- Non dimensionalization ---*/ - - for (iVar = 0; iVar < Svalue.size(); iVar++) { Svalue[iVar] /= Arch; } - - /*--- Close the restart file ---*/ - - airfoil_file.close(); - - /*--- Create a spline for X and Y coordiantes using the arch length ---*/ - - n_Airfoil = Svalue.size(); - yp1 = (Xcoord[1]-Xcoord[0])/(Svalue[1]-Svalue[0]); - ypn = (Xcoord[n_Airfoil-1]-Xcoord[n_Airfoil-2])/(Svalue[n_Airfoil-1]-Svalue[n_Airfoil-2]); - - Xcoord2.resize(n_Airfoil+1); - boundary->SetSpline(Svalue, Xcoord, n_Airfoil, yp1, ypn, Xcoord2); - - n_Airfoil = Svalue.size(); - yp1 = (Ycoord[1]-Ycoord[0])/(Svalue[1]-Svalue[0]); - ypn = (Ycoord[n_Airfoil-1]-Ycoord[n_Airfoil-2])/(Svalue[n_Airfoil-1]-Svalue[n_Airfoil-2]); - - Ycoord2.resize(n_Airfoil+1); - boundary->SetSpline(Svalue, Ycoord, n_Airfoil, yp1, ypn, Ycoord2); - - TotalArch = 0.0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_CFD)) || - ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DEF))) { - for (iVertex = 0; iVertex < boundary->nVertex[iMarker]-1; iVertex++) { - Coord_i = boundary->vertex[iMarker][iVertex]->GetCoord(); - Coord_ip1 = boundary->vertex[iMarker][iVertex+1]->GetCoord(); - - x_i = Coord_i[0]; x_ip1 = Coord_ip1[0]; - y_i = Coord_i[1]; y_ip1 = Coord_ip1[1]; - - TotalArch += sqrt((x_ip1-x_i)*(x_ip1-x_i)+(y_ip1-y_i)*(y_ip1-y_i)); - } - Coord_i = boundary->vertex[iMarker][boundary->nVertex[iMarker]-1]->GetCoord(); - Coord_ip1 = boundary->vertex[iMarker][0]->GetCoord(); - x_i = Coord_i[0]; x_ip1 = Coord_ip1[0]; - y_i = Coord_i[1]; y_ip1 = Coord_ip1[1]; - TotalArch += sqrt((x_ip1-x_i)*(x_ip1-x_i)+(y_ip1-y_i)*(y_ip1-y_i)); - } - } - - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Arch = 0.0; - for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_CFD)) || - ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DEF))) { - Coord = boundary->vertex[iMarker][iVertex]->GetCoord(); - - if (iVertex == 0) Arch = 0.0; - else { - Coord_i = boundary->vertex[iMarker][iVertex-1]->GetCoord(); - Coord_ip1 = boundary->vertex[iMarker][iVertex]->GetCoord(); - x_i = Coord_i[0]; x_ip1 = Coord_ip1[0]; - y_i = Coord_i[1]; y_ip1 = Coord_ip1[1]; - Arch += sqrt((x_ip1-x_i)*(x_ip1-x_i)+(y_ip1-y_i)*(y_ip1-y_i))/TotalArch; - } - - NewXCoord = boundary->GetSpline(Svalue, Xcoord, Xcoord2, n_Airfoil, Arch); - NewYCoord = boundary->GetSpline(Svalue, Ycoord, Ycoord2, n_Airfoil, Arch); - - /*--- Store the delta change in the x & y coordinates ---*/ - - VarCoord[0] = NewXCoord - Coord[0]; - VarCoord[1] = NewYCoord - Coord[1]; - } - - boundary->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - - } - } - - delete [] VarCoord; - -} - -void CSurfaceMovement::ReadFFDInfo(CGeometry *geometry, CConfig *config, CFreeFormDefBox **FFDBox, string val_mesh_filename) { - - string text_line, iTag; - ifstream mesh_file; - su2double coord[3]; - unsigned short degree[3], iFFDBox, iCornerPoints, iControlPoints, iMarker, iDegree, jDegree, kDegree, - iChar, LevelFFDBox, nParentFFDBox, iParentFFDBox, nChildFFDBox, iChildFFDBox, nMarker, *nCornerPoints, - *nControlPoints; - unsigned long iSurfacePoints, iPoint, jPoint, iVertex, nVertex, nPoint, iElem = 0, - nElem, my_nSurfPoints, nSurfPoints, *nSurfacePoints; - - unsigned short nDim = geometry->GetnDim(); - int rank = MASTER_NODE; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - char *cstr = new char [val_mesh_filename.size()+1]; - strcpy (cstr, val_mesh_filename.c_str()); - - mesh_file.open(cstr, ios::in); - if (mesh_file.fail()) { - cout << "There is no geometry file (ReadFFDInfo)!!" << endl; - exit(EXIT_FAILURE); - } - - while (getline (mesh_file, text_line)) { - - /*--- Read the inner elements ---*/ - - string::size_type position = text_line.find ("NELEM=",0); - if (position != string::npos) { - text_line.erase (0,6); nElem = atoi(text_line.c_str()); - for (iElem = 0; iElem < nElem; iElem++) { - getline(mesh_file, text_line); - } - } - - /*--- Read the inner points ---*/ - - position = text_line.find ("NPOIN=",0); - if (position != string::npos) { - text_line.erase (0,6); nPoint = atoi(text_line.c_str()); - for (iPoint = 0; iPoint < nPoint; iPoint++) { - getline(mesh_file, text_line); - } - } - - /*--- Read the boundaries ---*/ - - position = text_line.find ("NMARK=",0); - if (position != string::npos) { - text_line.erase (0,6); nMarker = atoi(text_line.c_str()); - for (iMarker = 0; iMarker < nMarker; iMarker++) { - getline(mesh_file, text_line); - getline(mesh_file, text_line); - text_line.erase (0,13); nVertex = atoi(text_line.c_str()); - for (iVertex = 0; iVertex < nVertex; iVertex++) { - getline(mesh_file, text_line); - } - } - } - - /*--- Read the FFDBox information ---*/ - - position = text_line.find ("FFD_NBOX=",0); - if (position != string::npos) { - text_line.erase (0,9); - nFFDBox = atoi(text_line.c_str()); - - if (rank == MASTER_NODE) cout << nFFDBox << " Free Form Deformation boxes." << endl; - - nCornerPoints = new unsigned short[nFFDBox]; - nControlPoints = new unsigned short[nFFDBox]; - nSurfacePoints = new unsigned long[nFFDBox]; - - getline (mesh_file, text_line); - text_line.erase (0,11); - nLevel = atoi(text_line.c_str()); - - if (rank == MASTER_NODE) cout << nLevel << " Free Form Deformation nested levels." << endl; - - for (iFFDBox = 0 ; iFFDBox < nFFDBox; iFFDBox++) { - - /*--- Read the name of the FFD box ---*/ - - getline (mesh_file, text_line); - text_line.erase (0,8); - - /*--- Remove extra data from the FFDBox name ---*/ - - string::size_type position; - for (iChar = 0; iChar < 20; iChar++) { - position = text_line.find( " ", 0 ); - if (position != string::npos) text_line.erase (position,1); - position = text_line.find( "\r", 0 ); - if (position != string::npos) text_line.erase (position,1); - position = text_line.find( "\n", 0 ); - if (position != string::npos) text_line.erase (position,1); - } - - string TagFFDBox = text_line.c_str(); - - if (rank == MASTER_NODE) cout << "FFD box tag: " << TagFFDBox <<". "; - - /*--- Read the level of the FFD box ---*/ - - getline (mesh_file, text_line); - text_line.erase (0,10); - LevelFFDBox = atoi(text_line.c_str()); - - if (rank == MASTER_NODE) cout << "FFD box level: " << LevelFFDBox <<". "; - - /*--- Read the degree of the FFD box ---*/ - - getline (mesh_file, text_line); - text_line.erase (0,13); degree[0] = atoi(text_line.c_str()); - getline (mesh_file, text_line); - text_line.erase (0,13); degree[1] = atoi(text_line.c_str()); - - if (nDim == 2) { - degree[2] = 1; - } - else { - getline (mesh_file, text_line); - text_line.erase (0,13); degree[2] = atoi(text_line.c_str()); - } - - if (rank == MASTER_NODE) { - cout << "Degrees: " << degree[0] << ", " << degree[1]; - if (nDim == 3) cout << ", " << degree[2]; - cout << ". " << endl; - } - - FFDBox[iFFDBox] = new CFreeFormDefBox(SU2_TYPE::Int(degree[0]), SU2_TYPE::Int(degree[1]), SU2_TYPE::Int(degree[2])); - FFDBox[iFFDBox]->SetTag(TagFFDBox); FFDBox[iFFDBox]->SetLevel(LevelFFDBox); - - /*--- Read the number of parents boxes ---*/ - - getline (mesh_file, text_line); - text_line.erase (0,12); - nParentFFDBox = atoi(text_line.c_str()); - if (rank == MASTER_NODE) cout << "Number of parent boxes: " << nParentFFDBox <<". "; - for (iParentFFDBox = 0; iParentFFDBox < nParentFFDBox; iParentFFDBox++) { - getline(mesh_file, text_line); - - /*--- Remove extra data from the FFDBox name ---*/ - - string::size_type position; - for (iChar = 0; iChar < 20; iChar++) { - position = text_line.find( " ", 0 ); - if (position != string::npos) text_line.erase (position,1); - position = text_line.find( "\r", 0 ); - if (position != string::npos) text_line.erase (position,1); - position = text_line.find( "\n", 0 ); - if (position != string::npos) text_line.erase (position,1); - } - - string ParentFFDBox = text_line.c_str(); - FFDBox[iFFDBox]->SetParentFFDBox(ParentFFDBox); - } - - /*--- Read the number of children boxes ---*/ - - getline (mesh_file, text_line); - text_line.erase (0,13); - nChildFFDBox = atoi(text_line.c_str()); - if (rank == MASTER_NODE) cout << "Number of child boxes: " << nChildFFDBox <<"." << endl; - - for (iChildFFDBox = 0; iChildFFDBox < nChildFFDBox; iChildFFDBox++) { - getline(mesh_file, text_line); - - /*--- Remove extra data from the FFDBox name ---*/ - - string::size_type position; - for (iChar = 0; iChar < 20; iChar++) { - position = text_line.find( " ", 0 ); - if (position != string::npos) text_line.erase (position,1); - position = text_line.find( "\r", 0 ); - if (position != string::npos) text_line.erase (position,1); - position = text_line.find( "\n", 0 ); - if (position != string::npos) text_line.erase (position,1); - } - - string ChildFFDBox = text_line.c_str(); - FFDBox[iFFDBox]->SetChildFFDBox(ChildFFDBox); - } - - /*--- Read the number of the corner points ---*/ - - getline (mesh_file, text_line); - text_line.erase (0,18); nCornerPoints[iFFDBox] = atoi(text_line.c_str()); - if (rank == MASTER_NODE) cout << "Corner points: " << nCornerPoints[iFFDBox] <<". "; - if (nDim == 2) nCornerPoints[iFFDBox] = nCornerPoints[iFFDBox]*SU2_TYPE::Int(2); - - /*--- Read the coordinates of the corner points ---*/ - - for (iCornerPoints = 0; iCornerPoints < nCornerPoints[iFFDBox]; iCornerPoints++) { - - if (nDim == 2) { - if (iCornerPoints < nCornerPoints[iFFDBox]/SU2_TYPE::Int(2)) { - getline(mesh_file, text_line); istringstream FFDBox_line(text_line); - FFDBox_line >> coord[0]; FFDBox_line >> coord[1]; coord[2] = -0.5; - } - else { - coord[0] = FFDBox[iFFDBox]->GetCoordCornerPoints(0, iCornerPoints-nCornerPoints[iFFDBox]/SU2_TYPE::Int(2)); - coord[1] = FFDBox[iFFDBox]->GetCoordCornerPoints(1, iCornerPoints-nCornerPoints[iFFDBox]/SU2_TYPE::Int(2)); - coord[2] = 0.5; - } - } - else { - getline(mesh_file, text_line); istringstream FFDBox_line(text_line); - FFDBox_line >> coord[0]; FFDBox_line >> coord[1]; FFDBox_line >> coord[2]; - } - - FFDBox[iFFDBox]->SetCoordCornerPoints(coord, iCornerPoints); - - } - - /*--- Read the number of the control points ---*/ - - getline (mesh_file, text_line); - text_line.erase (0,19); nControlPoints[iFFDBox] = atoi(text_line.c_str()); - - if (rank == MASTER_NODE) cout << "Control points: " << nControlPoints[iFFDBox] <<". "; - - /*--- Method to identify if there is a FFDBox definition ---*/ - - if (nControlPoints[iFFDBox] != 0) FFDBoxDefinition = true; - - /*--- Read the coordinates of the control points ---*/ - - for (iControlPoints = 0; iControlPoints < nControlPoints[iFFDBox]; iControlPoints++) { - getline(mesh_file, text_line); istringstream FFDBox_line(text_line); - FFDBox_line >> iDegree; FFDBox_line >> jDegree; FFDBox_line >> kDegree; - FFDBox_line >> coord[0]; FFDBox_line >> coord[1]; FFDBox_line >> coord[2]; - FFDBox[iFFDBox]->SetCoordControlPoints(coord, iDegree, jDegree, kDegree); - FFDBox[iFFDBox]->SetCoordControlPoints_Copy(coord, iDegree, jDegree, kDegree); - } - - getline (mesh_file, text_line); - text_line.erase (0,19); nSurfacePoints[iFFDBox] = atoi(text_line.c_str()); - - /*--- The surface points parametric coordinates, all the nodes read the FFD - information but they only store their part ---*/ - - my_nSurfPoints = 0; - for (iSurfacePoints = 0; iSurfacePoints < nSurfacePoints[iFFDBox]; iSurfacePoints++) { - getline(mesh_file, text_line); istringstream FFDBox_line(text_line); - FFDBox_line >> iTag; FFDBox_line >> iPoint; - - if (config->GetMarker_All_TagBound(iTag) != -1) { - - iMarker = config->GetMarker_All_TagBound(iTag); - FFDBox_line >> coord[0]; FFDBox_line >> coord[1]; FFDBox_line >> coord[2]; - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - jPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if (iPoint == geometry->node[jPoint]->GetGlobalIndex()) { - FFDBox[iFFDBox]->Set_MarkerIndex(iMarker); - FFDBox[iFFDBox]->Set_VertexIndex(iVertex); - FFDBox[iFFDBox]->Set_PointIndex(jPoint); - FFDBox[iFFDBox]->Set_ParametricCoord(coord); - FFDBox[iFFDBox]->Set_CartesianCoord(geometry->node[jPoint]->GetCoord()); - my_nSurfPoints++; - } - } - - } - - } - - nSurfacePoints[iFFDBox] = my_nSurfPoints; - -#ifdef HAVE_MPI - nSurfPoints = 0; - SU2_MPI::Allreduce(&my_nSurfPoints, &nSurfPoints, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - if (rank == MASTER_NODE) cout << "Surface points: " << nSurfPoints <<"."<< endl; -#else - nSurfPoints = my_nSurfPoints; - if (rank == MASTER_NODE) cout << "Surface points: " << nSurfPoints <<"."<< endl; -#endif - - } - - delete [] nCornerPoints; - delete [] nControlPoints; - delete [] nSurfacePoints; - } - } - mesh_file.close(); - - if (nFFDBox == 0) { - if (rank == MASTER_NODE) cout <<"There is no FFD box definition. Just in case, check the .su2 file" << endl; - } - -} - -void CSurfaceMovement::ReadFFDInfo(CGeometry *geometry, CConfig *config, CFreeFormDefBox **FFDBox) { - - string text_line, iTag; - ifstream mesh_file; - su2double coord[3]; - unsigned short degree[3], iFFDBox, iCornerPoints, LevelFFDBox, nParentFFDBox, - iParentFFDBox, nChildFFDBox, iChildFFDBox, *nCornerPoints; - - unsigned short nDim = geometry->GetnDim(); - int rank = MASTER_NODE; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - - /*--- Read the FFDBox information from the config file ---*/ - - nFFDBox = config->GetnFFDBox(); - - if (rank == MASTER_NODE) cout << nFFDBox << " Free Form Deformation boxes." << endl; - - nCornerPoints = new unsigned short[nFFDBox]; - - nLevel = 1; // Nested FFD is not active - - if (rank == MASTER_NODE) cout << nLevel << " Free Form Deformation nested levels." << endl; - - for (iFFDBox = 0 ; iFFDBox < nFFDBox; iFFDBox++) { - - /*--- Read the name of the FFD box ---*/ - - string TagFFDBox = config->GetTagFFDBox(iFFDBox); - - if (rank == MASTER_NODE) cout << "FFD box tag: " << TagFFDBox <<". "; - - /*--- Read the level of the FFD box ---*/ - - LevelFFDBox = 0; // Nested FFD is not active - - if (rank == MASTER_NODE) cout << "FFD box level: " << LevelFFDBox <<". "; - - /*--- Read the degree of the FFD box ---*/ - - degree[0] = config->GetDegreeFFDBox(iFFDBox, 0); - degree[1] = config->GetDegreeFFDBox(iFFDBox, 1); - - if (nDim == 2) { degree[2] = 1; } - else { degree[2] = config->GetDegreeFFDBox(iFFDBox, 2); } - - if (rank == MASTER_NODE) { - cout << "Degrees: " << degree[0] << ", " << degree[1]; - if (nDim == 3) cout << ", " << degree[2]; - cout << ". " << endl; - } - - FFDBox[iFFDBox] = new CFreeFormDefBox(SU2_TYPE::Int(degree[0]), SU2_TYPE::Int(degree[1]), SU2_TYPE::Int(degree[2])); - FFDBox[iFFDBox]->SetTag(TagFFDBox); FFDBox[iFFDBox]->SetLevel(LevelFFDBox); - - /*--- Read the number of parents boxes ---*/ - - nParentFFDBox = 0; // Nested FFD is not active - if (rank == MASTER_NODE) cout << "Number of parent boxes: " << nParentFFDBox <<". "; - - for (iParentFFDBox = 0; iParentFFDBox < nParentFFDBox; iParentFFDBox++) { - string ParentFFDBox = "NONE"; // Nested FFD is not active - FFDBox[iFFDBox]->SetParentFFDBox(ParentFFDBox); - } - - /*--- Read the number of children boxes ---*/ - - nChildFFDBox = 0; // Nested FFD is not active - if (rank == MASTER_NODE) cout << "Number of child boxes: " << nChildFFDBox <<"." << endl; - - for (iChildFFDBox = 0; iChildFFDBox < nChildFFDBox; iChildFFDBox++) { - string ChildFFDBox = "NONE"; // Nested FFD is not active - FFDBox[iFFDBox]->SetChildFFDBox(ChildFFDBox); - } - - /*--- Read the number of the corner points ---*/ - - nCornerPoints[iFFDBox] = 8; - - /*--- Read the coordinates of the corner points ---*/ - - for (iCornerPoints = 0; iCornerPoints < nCornerPoints[iFFDBox]; iCornerPoints++) { - - if (nDim == 2) { - if (iCornerPoints < nCornerPoints[iFFDBox]/SU2_TYPE::Int(2)) { - coord[0] = config->GetCoordFFDBox(iFFDBox, iCornerPoints*3); - coord[1] = config->GetCoordFFDBox(iFFDBox, iCornerPoints*3+1); - coord[2] = -0.5; - } - else { - coord[0] = FFDBox[iFFDBox]->GetCoordCornerPoints(0, iCornerPoints-nCornerPoints[iFFDBox]/SU2_TYPE::Int(2)); - coord[1] = FFDBox[iFFDBox]->GetCoordCornerPoints(1, iCornerPoints-nCornerPoints[iFFDBox]/SU2_TYPE::Int(2)); - coord[2] = 0.5; - } - } - else { - coord[0] = config->GetCoordFFDBox(iFFDBox, iCornerPoints*3); - coord[1] = config->GetCoordFFDBox(iFFDBox, iCornerPoints*3+1); - coord[2] = config->GetCoordFFDBox(iFFDBox, iCornerPoints*3+2); - } - - FFDBox[iFFDBox]->SetCoordCornerPoints(coord, iCornerPoints); - - } - - /*--- Method to identify if there is a FFDBox definition ---*/ - - FFDBoxDefinition = false; - - } - - delete [] nCornerPoints; - - if (nFFDBox == 0) { - if (rank == MASTER_NODE) cout <<"There is no FFD box definition. Check the config file." << endl; -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - } - -} - -void CSurfaceMovement::MergeFFDInfo(CGeometry *geometry, CConfig *config) { - - /*--- Local variables needed on all processors ---*/ - - unsigned long iPoint; - unsigned short iFFDBox; - -#ifndef HAVE_MPI - - /*--- In serial, the single process has access to all geometry, so simply - load the coordinates into the data structure. ---*/ - - /*--- Total number of points in each FFD box. ---*/ - - for (iFFDBox = 0 ; iFFDBox < nFFDBox; iFFDBox++) { - - /*--- Loop over the mesh to collect the coords of the local points. ---*/ - - for (iPoint = 0; iPoint < FFDBox[iFFDBox]->GetnSurfacePoint(); iPoint++) { - - /*--- Retrieve the current parametric coordinates at this node. ---*/ - - GlobalCoordX[iFFDBox].push_back(FFDBox[iFFDBox]->Get_ParametricCoord(iPoint)[0]); - GlobalCoordY[iFFDBox].push_back(FFDBox[iFFDBox]->Get_ParametricCoord(iPoint)[1]); - GlobalCoordZ[iFFDBox].push_back(FFDBox[iFFDBox]->Get_ParametricCoord(iPoint)[2]); - GlobalPoint[iFFDBox].push_back(FFDBox[iFFDBox]->Get_PointIndex(iPoint)); - - /*--- Marker of the boundary in the local domain. ---*/ - - unsigned short MarkerIndex = FFDBox[iFFDBox]->Get_MarkerIndex(iPoint); - string TagBound = config->GetMarker_All_TagBound(MarkerIndex); - - /*--- Find the Marker of the boundary in the config file. ---*/ - - unsigned short MarkerIndex_CfgFile = config->GetMarker_CfgFile_TagBound(TagBound); - string TagBound_CfgFile = config->GetMarker_CfgFile_TagBound(MarkerIndex_CfgFile); - - /*--- Set the value of the tag at this node. ---*/ - - GlobalTag[iFFDBox].push_back(TagBound_CfgFile); - - } - - } - -#else - - /*--- MPI preprocessing ---*/ - - int iProcessor, nProcessor, rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); - - /*--- Local variables needed for merging the geometry with MPI. ---*/ - - unsigned long jPoint, iPointLocal; - unsigned long Buffer_Send_nPoint[1], *Buffer_Recv_nPoint = NULL; - unsigned long nLocalPoint = 0, MaxLocalPoint = 0; - unsigned long nBuffer_Scalar = 0; - - if (rank == MASTER_NODE) Buffer_Recv_nPoint = new unsigned long[nProcessor]; - - for (iFFDBox = 0 ; iFFDBox < nFFDBox; iFFDBox++) { - - nLocalPoint = 0; - for (iPoint = 0; iPoint < FFDBox[iFFDBox]->GetnSurfacePoint(); iPoint++) { - - iPointLocal = FFDBox[iFFDBox]->Get_PointIndex(iPoint); - - if (iPointLocal < geometry->GetnPointDomain()) { - nLocalPoint++; - } - - } - Buffer_Send_nPoint[0] = nLocalPoint; - - /*--- Communicate the total number of nodes on this domain. ---*/ - - SU2_MPI::Gather(&Buffer_Send_nPoint, 1, MPI_UNSIGNED_LONG, - Buffer_Recv_nPoint, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalPoint, &MaxLocalPoint, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - - nBuffer_Scalar = MaxLocalPoint; - - /*--- Send and Recv buffers. ---*/ - - su2double *Buffer_Send_X = new su2double[MaxLocalPoint]; - su2double *Buffer_Recv_X = NULL; - - su2double *Buffer_Send_Y = new su2double[MaxLocalPoint]; - su2double *Buffer_Recv_Y = NULL; - - su2double *Buffer_Send_Z = new su2double[MaxLocalPoint]; - su2double *Buffer_Recv_Z = NULL; - - unsigned long *Buffer_Send_Point = new unsigned long[MaxLocalPoint]; - unsigned long *Buffer_Recv_Point = NULL; - - unsigned short *Buffer_Send_MarkerIndex_CfgFile = new unsigned short[MaxLocalPoint]; - unsigned short *Buffer_Recv_MarkerIndex_CfgFile = NULL; - - /*--- Prepare the receive buffers in the master node only. ---*/ - - if (rank == MASTER_NODE) { - - Buffer_Recv_X = new su2double[nProcessor*MaxLocalPoint]; - Buffer_Recv_Y = new su2double[nProcessor*MaxLocalPoint]; - Buffer_Recv_Z = new su2double[nProcessor*MaxLocalPoint]; - Buffer_Recv_Point = new unsigned long[nProcessor*MaxLocalPoint]; - Buffer_Recv_MarkerIndex_CfgFile = new unsigned short[nProcessor*MaxLocalPoint]; - - } - - /*--- Main communication routine. Loop over each coordinate and perform - the MPI comm. Temporary 1-D buffers are used to send the coordinates at - all nodes on each partition to the master node. These are then unpacked - by the master and sorted by global index in one large n-dim. array. ---*/ - - /*--- Loop over this partition to collect the coords of the local points. ---*/ - - jPoint = 0; - for (iPoint = 0; iPoint < FFDBox[iFFDBox]->GetnSurfacePoint(); iPoint++) { - - iPointLocal = FFDBox[iFFDBox]->Get_PointIndex(iPoint); - - if (iPointLocal < geometry->GetnPointDomain()) { - - /*--- Load local coords into the temporary send buffer. ---*/ - - Buffer_Send_X[jPoint] = FFDBox[iFFDBox]->Get_ParametricCoord(iPoint)[0]; - Buffer_Send_Y[jPoint] = FFDBox[iFFDBox]->Get_ParametricCoord(iPoint)[1]; - Buffer_Send_Z[jPoint] = FFDBox[iFFDBox]->Get_ParametricCoord(iPoint)[2]; - - /*--- Store the global index for this local node. ---*/ - - Buffer_Send_Point[jPoint] = geometry->node[FFDBox[iFFDBox]->Get_PointIndex(iPoint)]->GetGlobalIndex(); - - /*--- Marker of the boundary in the local domain. ---*/ - - unsigned short MarkerIndex = FFDBox[iFFDBox]->Get_MarkerIndex(iPoint); - string TagBound = config->GetMarker_All_TagBound(MarkerIndex); - - /*--- Find the Marker of the boundary in the config file.---*/ - - unsigned short MarkerIndex_CfgFile = config->GetMarker_CfgFile_TagBound(TagBound); - Buffer_Send_MarkerIndex_CfgFile[jPoint] = MarkerIndex_CfgFile; - - jPoint++; - - } - - } - - /*--- Gather the coordinate data on the master node using MPI. ---*/ - - SU2_MPI::Gather(Buffer_Send_X, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_X, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Y, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Y, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Z, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Z, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Point, nBuffer_Scalar, MPI_UNSIGNED_LONG, Buffer_Recv_Point, nBuffer_Scalar, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_MarkerIndex_CfgFile, nBuffer_Scalar, MPI_UNSIGNED_SHORT, Buffer_Recv_MarkerIndex_CfgFile, nBuffer_Scalar, MPI_UNSIGNED_SHORT, MASTER_NODE, MPI_COMM_WORLD); - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - - jPoint = 0; - - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - - GlobalCoordX[iFFDBox].push_back(Buffer_Recv_X[jPoint]); - GlobalCoordY[iFFDBox].push_back(Buffer_Recv_Y[jPoint]); - GlobalCoordZ[iFFDBox].push_back(Buffer_Recv_Z[jPoint]); - GlobalPoint[iFFDBox].push_back(Buffer_Recv_Point[jPoint]); - - string TagBound_CfgFile = config->GetMarker_CfgFile_TagBound(Buffer_Recv_MarkerIndex_CfgFile[jPoint]); - GlobalTag[iFFDBox].push_back(TagBound_CfgFile); - jPoint++; - - } - - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - - jPoint = (iProcessor+1)*nBuffer_Scalar; - - } - } - - /*--- Immediately release the temporary data buffers. ---*/ - - delete [] Buffer_Send_X; - delete [] Buffer_Send_Y; - delete [] Buffer_Send_Z; - delete [] Buffer_Send_Point; - delete [] Buffer_Send_MarkerIndex_CfgFile; - - if (rank == MASTER_NODE) { - delete [] Buffer_Recv_X; - delete [] Buffer_Recv_Y; - delete [] Buffer_Recv_Z; - delete [] Buffer_Recv_Point; - delete [] Buffer_Recv_MarkerIndex_CfgFile; - } - - } - - if (rank == MASTER_NODE) { - delete [] Buffer_Recv_nPoint; - } - -#endif - -} - -void CSurfaceMovement::WriteFFDInfo(CGeometry *geometry, CConfig *config) { - - - unsigned short iOrder, jOrder, kOrder, iFFDBox, iCornerPoints, iParentFFDBox, iChildFFDBox; - unsigned long iSurfacePoints; - char cstr[MAX_STRING_SIZE], mesh_file[MAX_STRING_SIZE]; - string str; - ofstream output_file; - su2double *coord; - string text_line; - - int rank = MASTER_NODE; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - unsigned short nDim = geometry->GetnDim(); - - /*--- Merge the FFD info ---*/ - - MergeFFDInfo(geometry, config); - - /*--- Attach to the mesh file the FFD information ---*/ - - if (rank == MASTER_NODE) { - - /*--- Read the name of the output file ---*/ - - str = config->GetMesh_Out_FileName(); - strcpy (mesh_file, str.c_str()); - strcpy (cstr, mesh_file); - - output_file.precision(15); - output_file.open(cstr, ios::out | ios::app); - - if (nFFDBox != 0) { - output_file << "FFD_NBOX= " << nFFDBox << endl; - output_file << "FFD_NLEVEL= " << nLevel << endl; - } - - for (iFFDBox = 0 ; iFFDBox < nFFDBox; iFFDBox++) { - - output_file << "FFD_TAG= " << FFDBox[iFFDBox]->GetTag() << endl; - output_file << "FFD_LEVEL= " << FFDBox[iFFDBox]->GetLevel() << endl; - - output_file << "FFD_DEGREE_I= " << FFDBox[iFFDBox]->GetlOrder()-1 << endl; - output_file << "FFD_DEGREE_J= " << FFDBox[iFFDBox]->GetmOrder()-1 << endl; - if (nDim == 3) output_file << "FFD_DEGREE_K= " << FFDBox[iFFDBox]->GetnOrder()-1 << endl; - - output_file << "FFD_PARENTS= " << FFDBox[iFFDBox]->GetnParentFFDBox() << endl; - for (iParentFFDBox = 0; iParentFFDBox < FFDBox[iFFDBox]->GetnParentFFDBox(); iParentFFDBox++) - output_file << FFDBox[iFFDBox]->GetParentFFDBoxTag(iParentFFDBox) << endl; - output_file << "FFD_CHILDREN= " << FFDBox[iFFDBox]->GetnChildFFDBox() << endl; - for (iChildFFDBox = 0; iChildFFDBox < FFDBox[iFFDBox]->GetnChildFFDBox(); iChildFFDBox++) - output_file << FFDBox[iFFDBox]->GetChildFFDBoxTag(iChildFFDBox) << endl; - - if (nDim == 2) { - output_file << "FFD_CORNER_POINTS= " << FFDBox[iFFDBox]->GetnCornerPoints()/SU2_TYPE::Int(2) << endl; - for (iCornerPoints = 0; iCornerPoints < FFDBox[iFFDBox]->GetnCornerPoints()/SU2_TYPE::Int(2); iCornerPoints++) { - coord = FFDBox[iFFDBox]->GetCoordCornerPoints(iCornerPoints); - output_file << coord[0] << "\t" << coord[1] << endl; - } - } - else { - output_file << "FFD_CORNER_POINTS= " << FFDBox[iFFDBox]->GetnCornerPoints() << endl; - for (iCornerPoints = 0; iCornerPoints < FFDBox[iFFDBox]->GetnCornerPoints(); iCornerPoints++) { - coord = FFDBox[iFFDBox]->GetCoordCornerPoints(iCornerPoints); - output_file << coord[0] << "\t" << coord[1] << "\t" << coord[2] << endl; - } - } - - /*--- Writing control points ---*/ - - if (FFDBox[iFFDBox]->GetnControlPoints() == 0) { - output_file << "FFD_CONTROL_POINTS= 0" << endl; - } - else { - output_file << "FFD_CONTROL_POINTS= " << FFDBox[iFFDBox]->GetnControlPoints() << endl; - for (iOrder = 0; iOrder < FFDBox[iFFDBox]->GetlOrder(); iOrder++) - for (jOrder = 0; jOrder < FFDBox[iFFDBox]->GetmOrder(); jOrder++) - for (kOrder = 0; kOrder < FFDBox[iFFDBox]->GetnOrder(); kOrder++) { - coord = FFDBox[iFFDBox]->GetCoordControlPoints(iOrder, jOrder, kOrder); - output_file << iOrder << "\t" << jOrder << "\t" << kOrder << "\t" << coord[0] << "\t" << coord[1] << "\t" << coord[2] << endl; - } - } - - /*--- Writing surface points ---*/ - - if (FFDBox[iFFDBox]->GetnControlPoints() == 0) { - output_file << "FFD_SURFACE_POINTS= 0" << endl; - } - else { - output_file << "FFD_SURFACE_POINTS= " << GlobalTag[iFFDBox].size() << endl; - - for (iSurfacePoints = 0; iSurfacePoints < GlobalTag[iFFDBox].size(); iSurfacePoints++) { - output_file << scientific << GlobalTag[iFFDBox][iSurfacePoints] << "\t" << GlobalPoint[iFFDBox][iSurfacePoints] - << "\t" << GlobalCoordX[iFFDBox][iSurfacePoints] << "\t" << GlobalCoordY[iFFDBox][iSurfacePoints] - << "\t" << GlobalCoordZ[iFFDBox][iSurfacePoints] << endl; - } - - } - - } - - output_file.close(); - - } - -} - -CFreeFormDefBox::CFreeFormDefBox(void) : CGridMovement() { } - -CFreeFormDefBox::CFreeFormDefBox(unsigned short val_lDegree, unsigned short val_mDegree, unsigned short val_nDegree) : CGridMovement() { - - unsigned short iCornerPoints, iOrder, jOrder, kOrder, iDim; - - /*--- FFD is always 3D (even in 2D problems) ---*/ - - nDim = 3; - nCornerPoints = 8; - - /*--- Allocate Corners points ---*/ - - Coord_Corner_Points = new su2double* [nCornerPoints]; - for (iCornerPoints = 0; iCornerPoints < nCornerPoints; iCornerPoints++) - Coord_Corner_Points[iCornerPoints] = new su2double [nDim]; - - ParamCoord = new su2double[nDim]; ParamCoord_ = new su2double[nDim]; - cart_coord = new su2double[nDim]; cart_coord_ = new su2double[nDim]; - Gradient = new su2double[nDim]; - - lDegree = val_lDegree; lOrder = lDegree+1; - mDegree = val_mDegree; mOrder = mDegree+1; - nDegree = val_nDegree; nOrder = nDegree+1; - nControlPoints = lOrder*mOrder*nOrder; - - lDegree_Copy = val_lDegree; lOrder_Copy = lDegree+1; - mDegree_Copy = val_mDegree; mOrder_Copy = mDegree+1; - nDegree_Copy = val_nDegree; nOrder_Copy = nDegree+1; - nControlPoints_Copy = lOrder_Copy*mOrder_Copy*nOrder_Copy; - - Coord_Control_Points = new su2double*** [lOrder]; - ParCoord_Control_Points = new su2double*** [lOrder]; - Coord_Control_Points_Copy = new su2double*** [lOrder]; - for (iOrder = 0; iOrder < lOrder; iOrder++) { - Coord_Control_Points[iOrder] = new su2double** [mOrder]; - ParCoord_Control_Points[iOrder] = new su2double** [mOrder]; - Coord_Control_Points_Copy[iOrder] = new su2double** [mOrder]; - for (jOrder = 0; jOrder < mOrder; jOrder++) { - Coord_Control_Points[iOrder][jOrder] = new su2double* [nOrder]; - ParCoord_Control_Points[iOrder][jOrder] = new su2double* [nOrder]; - Coord_Control_Points_Copy[iOrder][jOrder] = new su2double* [nOrder]; - for (kOrder = 0; kOrder < nOrder; kOrder++) { - Coord_Control_Points[iOrder][jOrder][kOrder] = new su2double [nDim]; - ParCoord_Control_Points[iOrder][jOrder][kOrder] = new su2double [nDim]; - Coord_Control_Points_Copy[iOrder][jOrder][kOrder] = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) { - Coord_Control_Points[iOrder][jOrder][kOrder][iDim] = 0.0; - ParCoord_Control_Points[iOrder][jOrder][kOrder][iDim] = 0.0; - Coord_Control_Points_Copy[iOrder][jOrder][kOrder][iDim] = 0.0; - } - } - } - } - -} - -CFreeFormDefBox::~CFreeFormDefBox(void) { - unsigned short iOrder, jOrder, kOrder, iCornerPoints; - - for (iOrder = 0; iOrder < lOrder; iOrder++) - for (jOrder = 0; jOrder < mOrder; jOrder++) - for (kOrder = 0; kOrder < nOrder; kOrder++) { - delete [] Coord_Control_Points[iOrder][jOrder][kOrder]; - delete [] ParCoord_Control_Points[iOrder][jOrder][kOrder]; - delete [] Coord_Control_Points_Copy[iOrder][jOrder][kOrder]; - } - delete [] Coord_Control_Points; - delete [] ParCoord_Control_Points; - delete [] Coord_Control_Points_Copy; - - delete [] ParamCoord; - delete [] cart_coord; - delete [] Gradient; - - for (iCornerPoints = 0; iCornerPoints < nCornerPoints; iCornerPoints++) - delete [] Coord_Corner_Points[iCornerPoints]; - delete [] Coord_Corner_Points; -} - -void CFreeFormDefBox::SetUnitCornerPoints(void) { - - unsigned short iDim; - su2double *coord = new su2double [nDim]; - - for (iDim = 0; iDim < nDim; iDim++) coord[iDim] = 0.0; - - coord [0] = 0.0; coord [1] = 0.0; coord [2] = 0.0; this->SetCoordCornerPoints(coord, 0); - coord [0] = 1.0; coord [1] = 0.0; coord [2] = 0.0; this->SetCoordCornerPoints(coord, 1); - coord [0] = 1.0; coord [1] = 1.0; coord [2] = 0.0; this->SetCoordCornerPoints(coord, 2); - coord [0] = 0.0; coord [1] = 1.0; coord [2] = 0.0; this->SetCoordCornerPoints(coord, 3); - coord [0] = 0.0; coord [1] = 0.0; coord [2] = 1.0; this->SetCoordCornerPoints(coord, 4); - coord [0] = 1.0; coord [1] = 0.0; coord [2] = 1.0; this->SetCoordCornerPoints(coord, 5); - coord [0] = 1.0; coord [1] = 1.0; coord [2] = 1.0; this->SetCoordCornerPoints(coord, 6); - coord [0] = 0.0; coord [1] = 1.0; coord [2] = 1.0; this->SetCoordCornerPoints(coord, 7); - - delete [] coord; - -} - -void CFreeFormDefBox::SetControlPoints_Parallelepiped (void) { - unsigned short iDim, iDegree, jDegree, kDegree; - - /*--- Set base control points according to the notation of Vtk for hexahedrons ---*/ - for (iDim = 0; iDim < nDim; iDim++) { - Coord_Control_Points [0] [0] [0] [iDim] = Coord_Corner_Points[0][iDim]; - Coord_Control_Points [lOrder-1] [0] [0] [iDim] = Coord_Corner_Points[1][iDim]; - Coord_Control_Points [lOrder-1] [mOrder-1] [0] [iDim] = Coord_Corner_Points[2][iDim]; - Coord_Control_Points [0] [mOrder-1] [0] [iDim] = Coord_Corner_Points[3][iDim]; - Coord_Control_Points [0] [0] [nOrder-1] [iDim] = Coord_Corner_Points[4][iDim]; - Coord_Control_Points [lOrder-1] [0] [nOrder-1] [iDim] = Coord_Corner_Points[5][iDim]; - Coord_Control_Points [lOrder-1] [mOrder-1] [nOrder-1] [iDim] = Coord_Corner_Points[6][iDim]; - Coord_Control_Points [0] [mOrder-1] [nOrder-1] [iDim] = Coord_Corner_Points[7][iDim]; - } - - /*--- Fill the rest of the cubic matrix of control points with uniform spacing (parallelepiped) ---*/ - for (iDegree = 0; iDegree <= lDegree; iDegree++) - for (jDegree = 0; jDegree <= mDegree; jDegree++) - for (kDegree = 0; kDegree <= nDegree; kDegree++) { - Coord_Control_Points[iDegree][jDegree][kDegree][0] = Coord_Corner_Points[0][0] - + su2double(iDegree)/su2double(lDegree)*(Coord_Corner_Points[1][0]-Coord_Corner_Points[0][0]); - Coord_Control_Points[iDegree][jDegree][kDegree][1] = Coord_Corner_Points[0][1] - + su2double(jDegree)/su2double(mDegree)*(Coord_Corner_Points[3][1]-Coord_Corner_Points[0][1]); - Coord_Control_Points[iDegree][jDegree][kDegree][2] = Coord_Corner_Points[0][2] - + su2double(kDegree)/su2double(nDegree)*(Coord_Corner_Points[4][2]-Coord_Corner_Points[0][2]); - } -} - -void CFreeFormDefBox::SetSupportCP(CFreeFormDefBox *FFDBox) { - unsigned short iDim, iOrder, jOrder, kOrder; - unsigned short lOrder = FFDBox->GetlOrder(); - unsigned short mOrder = FFDBox->GetmOrder(); - unsigned short nOrder = FFDBox->GetnOrder(); - - Coord_SupportCP = new su2double*** [lOrder]; - for (iOrder = 0; iOrder < lOrder; iOrder++) { - Coord_SupportCP[iOrder] = new su2double** [mOrder]; - for (jOrder = 0; jOrder < mOrder; jOrder++) { - Coord_SupportCP[iOrder][jOrder] = new su2double* [nOrder]; - for (kOrder = 0; kOrder < nOrder; kOrder++) - Coord_SupportCP[iOrder][jOrder][kOrder] = new su2double [nDim]; - } - } - - /*--- Set base support control points according to the notation of Vtk for hexahedrons ---*/ - for (iDim = 0; iDim < nDim; iDim++) { - Coord_SupportCP [0] [0] [0] [iDim] = Coord_Corner_Points[0][iDim]; - Coord_SupportCP [lOrder-1] [0] [0] [iDim] = Coord_Corner_Points[1][iDim]; - Coord_SupportCP [lOrder-1] [mOrder-1] [0] [iDim] = Coord_Corner_Points[2][iDim]; - Coord_SupportCP [0] [mOrder-1] [0] [iDim] = Coord_Corner_Points[3][iDim]; - Coord_SupportCP [0] [0] [nOrder-1] [iDim] = Coord_Corner_Points[4][iDim]; - Coord_SupportCP [lOrder-1] [0] [nOrder-1] [iDim] = Coord_Corner_Points[5][iDim]; - Coord_SupportCP [lOrder-1] [mOrder-1] [nOrder-1] [iDim] = Coord_Corner_Points[6][iDim]; - Coord_SupportCP [0] [mOrder-1] [nOrder-1] [iDim] = Coord_Corner_Points[7][iDim]; - } - - /*--- Fill the rest of the cubic matrix of support control points with uniform spacing ---*/ - for (iOrder = 0; iOrder < lOrder; iOrder++) - for (jOrder = 0; jOrder < mOrder; jOrder++) - for (kOrder = 0; kOrder < nOrder; kOrder++) { - Coord_SupportCP[iOrder][jOrder][kOrder][0] = Coord_Corner_Points[0][0] - + su2double(iOrder)/su2double(lOrder-1)*(Coord_Corner_Points[1][0]-Coord_Corner_Points[0][0]); - Coord_SupportCP[iOrder][jOrder][kOrder][1] = Coord_Corner_Points[0][1] - + su2double(jOrder)/su2double(mOrder-1)*(Coord_Corner_Points[3][1]-Coord_Corner_Points[0][1]); - Coord_SupportCP[iOrder][jOrder][kOrder][2] = Coord_Corner_Points[0][2] - + su2double(kOrder)/su2double(nOrder-1)*(Coord_Corner_Points[4][2]-Coord_Corner_Points[0][2]); - } -} - -void CFreeFormDefBox::SetSupportCPChange(CFreeFormDefBox *FFDBox) { - unsigned short iDim, iOrder, jOrder, kOrder; - su2double *CartCoordNew, *ParamCoord; - unsigned short lOrder = FFDBox->GetlOrder(); - unsigned short mOrder = FFDBox->GetmOrder(); - unsigned short nOrder = FFDBox->GetnOrder(); - - su2double ****ParamCoord_SupportCP = new su2double*** [lOrder]; - for (iOrder = 0; iOrder < lOrder; iOrder++) { - ParamCoord_SupportCP[iOrder] = new su2double** [mOrder]; - for (jOrder = 0; jOrder < mOrder; jOrder++) { - ParamCoord_SupportCP[iOrder][jOrder] = new su2double* [nOrder]; - for (kOrder = 0; kOrder < nOrder; kOrder++) - ParamCoord_SupportCP[iOrder][jOrder][kOrder] = new su2double [nDim]; - } - } - - for (iOrder = 0; iOrder < lOrder; iOrder++) - for (jOrder = 0; jOrder < mOrder; jOrder++) - for (kOrder = 0; kOrder < nOrder; kOrder++) - for (iDim = 0; iDim < nDim; iDim++) - ParamCoord_SupportCP[iOrder][jOrder][kOrder][iDim] = - Coord_SupportCP[iOrder][jOrder][kOrder][iDim]; - - for (iDim = 0; iDim < nDim; iDim++) { - Coord_Control_Points[0][0][0][iDim] = FFDBox->GetCoordCornerPoints(iDim, 0); - Coord_Control_Points[1][0][0][iDim] = FFDBox->GetCoordCornerPoints(iDim, 1); - Coord_Control_Points[1][1][0][iDim] = FFDBox->GetCoordCornerPoints(iDim, 2); - Coord_Control_Points[0][1][0][iDim] = FFDBox->GetCoordCornerPoints(iDim, 3); - Coord_Control_Points[0][0][1][iDim] = FFDBox->GetCoordCornerPoints(iDim, 4); - Coord_Control_Points[1][0][1][iDim] = FFDBox->GetCoordCornerPoints(iDim, 5); - Coord_Control_Points[1][1][1][iDim] = FFDBox->GetCoordCornerPoints(iDim, 6); - Coord_Control_Points[0][1][1][iDim] = FFDBox->GetCoordCornerPoints(iDim, 7); - } - - for (iOrder = 0; iOrder < FFDBox->GetlOrder(); iOrder++) { - for (jOrder = 0; jOrder < FFDBox->GetmOrder(); jOrder++) { - for (kOrder = 0; kOrder < FFDBox->GetnOrder(); kOrder++) { - ParamCoord = ParamCoord_SupportCP[iOrder][jOrder][kOrder]; - CartCoordNew = EvalCartesianCoord(ParamCoord); - FFDBox->SetCoordControlPoints(CartCoordNew, iOrder, jOrder, kOrder); - FFDBox->SetCoordControlPoints_Copy(CartCoordNew, iOrder, jOrder, kOrder); - } - } - } - -} - -void CFreeFormDefBox::SetTecplot(CGeometry *geometry, unsigned short iFFDBox, bool original) { - - ofstream FFDBox_file; - char FFDBox_filename[MAX_STRING_SIZE]; - bool new_file; - unsigned short iDim, iDegree, jDegree, kDegree; - - nDim = geometry->GetnDim(); - - SPRINTF (FFDBox_filename, "ffd_boxes.dat"); - - if ((original) && (iFFDBox == 0)) new_file = true; - else new_file = false; - - if (new_file) { - FFDBox_file.open(FFDBox_filename, ios::out); - FFDBox_file << "TITLE = \"Visualization of the FFD boxes generated by SU2_DEF.\"" << endl; - if (nDim == 2) FFDBox_file << "VARIABLES = \"x\", \"y\"" << endl; - else FFDBox_file << "VARIABLES = \"x\", \"y\", \"z\"" << endl; - } - else FFDBox_file.open(FFDBox_filename, ios::out | ios::app); - - FFDBox_file << "ZONE T= \"" << Tag; - if (original) FFDBox_file << " (Original FFD)\""; - else FFDBox_file << " (Deformed FFD)\""; - if (nDim == 2) FFDBox_file << ", I="< val_n) { value = 0; return value; } - if (val_i == 0) { - if (val_t == 0) value = 1; - else if (val_t == 1) value = 0; - else value = Binomial(val_n, val_i)*(pow(val_t, val_i)) * pow(1.0 - val_t, val_n - val_i); - } - else if (val_i == val_n) { - if (val_t == 0) value = 0; - else if (val_t == 1) value = 1; - else value = pow(val_t, val_n); - } - else value = Binomial(val_n, val_i)*(pow(val_t, val_i)) * pow(1.0-val_t, val_n - val_i); - - return value; -} - -su2double CFreeFormDefBox::GetBernsteinDerivative(short val_n, short val_i, - su2double val_t, short val_order) { - su2double value = 0.0; - - /*--- Verify this subroutine, it provides negative val_n, - which is a wrong value for GetBernstein ---*/ - - if (val_order == 0) { - value = GetBernstein(val_n, val_i, val_t); return value; - } - - if (val_i == 0) { - value = val_n*(-GetBernsteinDerivative(val_n-1, val_i, val_t, val_order-1)); return value; - } - else { - if (val_n == 0) { - value = val_t; return value; - } - else { - value = val_n*(GetBernsteinDerivative(val_n-1, val_i-1, val_t, val_order-1) - GetBernsteinDerivative(val_n-1, val_i, val_t, val_order-1)); - return value; - } - } - - return value; -} - -su2double *CFreeFormDefBox::GetFFDGradient(su2double *val_coord, su2double *xyz) { - - unsigned short iDim, jDim, lmn[3]; - - /*--- Set the Degree of the Berstein polynomials ---*/ - - lmn[0] = lDegree; lmn[1] = mDegree; lmn[2] = nDegree; - - for (iDim = 0; iDim < nDim; iDim++) Gradient[iDim] = 0.0; - - for (iDim = 0; iDim < nDim; iDim++) - for (jDim = 0; jDim < nDim; jDim++) - Gradient[jDim] += GetDerivative2(val_coord, iDim, xyz, lmn) * - GetDerivative3(val_coord, iDim, jDim, lmn); - - return Gradient; - -} - -void CFreeFormDefBox::GetFFDHessian(su2double *uvw, su2double *xyz, su2double **val_Hessian) { - - unsigned short iDim, jDim, lmn[3]; - - /*--- Set the Degree of the Berstein polynomials ---*/ - - lmn[0] = lDegree; lmn[1] = mDegree; lmn[2] = nDegree; - - for (iDim = 0; iDim < nDim; iDim++) - for (jDim = 0; jDim < nDim; jDim++) - val_Hessian[iDim][jDim] = 0.0; - - /*--- Note that being all the functions linear combinations of polynomials, they are C^\infty, - and the Hessian will be symmetric; no need to compute the under-diagonal part, for example ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - val_Hessian[0][0] += 2.0 * GetDerivative3(uvw, iDim,0, lmn) * GetDerivative3(uvw, iDim,0, lmn) + - GetDerivative2(uvw, iDim,xyz, lmn) * GetDerivative5(uvw, iDim,0,0, lmn); - - val_Hessian[1][1] += 2.0 * GetDerivative3(uvw, iDim,1, lmn) * GetDerivative3(uvw, iDim,1, lmn) + - GetDerivative2(uvw, iDim,xyz, lmn) * GetDerivative5(uvw, iDim,1,1, lmn); - - val_Hessian[2][2] += 2.0 * GetDerivative3(uvw, iDim,2, lmn) * GetDerivative3(uvw, iDim,2, lmn) + - GetDerivative2(uvw, iDim,xyz, lmn) * GetDerivative5(uvw, iDim,2,2, lmn); - - val_Hessian[0][1] += 2.0 * GetDerivative3(uvw, iDim,0, lmn) * GetDerivative3(uvw, iDim,1, lmn) + - GetDerivative2(uvw, iDim,xyz, lmn) * GetDerivative5(uvw, iDim,0,1, lmn); - - val_Hessian[0][2] += 2.0 * GetDerivative3(uvw, iDim,0, lmn) * GetDerivative3(uvw, iDim,2, lmn) + - GetDerivative2(uvw, iDim,xyz, lmn) * GetDerivative5(uvw, iDim,0,2, lmn); - - val_Hessian[1][2] += 2.0 * GetDerivative3(uvw, iDim,1, lmn) * GetDerivative3(uvw, iDim,2, lmn) + - GetDerivative2(uvw, iDim,xyz, lmn) * GetDerivative5(uvw, iDim,1,2, lmn); - } - - val_Hessian[1][0] = val_Hessian[0][1]; - val_Hessian[2][0] = val_Hessian[0][2]; - val_Hessian[2][1] = val_Hessian[1][2]; - -} - -su2double *CFreeFormDefBox::GetParametricCoord_Iterative(unsigned long iPoint, su2double *xyz, su2double *ParamCoordGuess, CConfig *config) { - - su2double *IndepTerm, SOR_Factor = 1.0, MinNormError, NormError, Determinant, AdjHessian[3][3], Temp[3] = {0.0,0.0,0.0}; - unsigned short iDim, jDim, RandonCounter; - unsigned long iter; - - su2double tol = config->GetFFD_Tol(); - unsigned short it_max = config->GetnFFD_Iter(); - unsigned short Random_Trials = 500; - - /*--- Allocate the Hessian ---*/ - - Hessian = new su2double* [nDim]; - IndepTerm = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) { - Hessian[iDim] = new su2double[nDim]; - ParamCoord[iDim] = ParamCoordGuess[iDim]; - IndepTerm [iDim] = 0.0; - } - - RandonCounter = 0; MinNormError = 1E6; - - /*--- External iteration ---*/ - - for (iter = 0; iter < (unsigned long)it_max*Random_Trials; iter++) { - - /*--- The independent term of the solution of our system is -Gradient(sol_old) ---*/ - - Gradient = GetFFDGradient(ParamCoord, xyz); - - for (iDim = 0; iDim < nDim; iDim++) IndepTerm[iDim] = - Gradient[iDim]; - - /*--- Hessian = The Matrix of our system, getHessian(sol_old,xyz,...) ---*/ - - GetFFDHessian(ParamCoord, xyz, Hessian); - - /*--- Adjoint to Hessian ---*/ - - AdjHessian[0][0] = Hessian[1][1]*Hessian[2][2]-Hessian[1][2]*Hessian[2][1]; - AdjHessian[0][1] = Hessian[0][2]*Hessian[2][1]-Hessian[0][1]*Hessian[2][2]; - AdjHessian[0][2] = Hessian[0][1]*Hessian[1][2]-Hessian[0][2]*Hessian[1][1]; - AdjHessian[1][0] = Hessian[1][2]*Hessian[2][0]-Hessian[1][0]*Hessian[2][2]; - AdjHessian[1][1] = Hessian[0][0]*Hessian[2][2]-Hessian[0][2]*Hessian[2][0]; - AdjHessian[1][2] = Hessian[0][2]*Hessian[1][0]-Hessian[0][0]*Hessian[1][2]; - AdjHessian[2][0] = Hessian[1][0]*Hessian[2][1]-Hessian[1][1]*Hessian[2][0]; - AdjHessian[2][1] = Hessian[0][1]*Hessian[2][0]-Hessian[0][0]*Hessian[2][1]; - AdjHessian[2][2] = Hessian[0][0]*Hessian[1][1]-Hessian[0][1]*Hessian[1][0]; - - /*--- Determinant of Hessian ---*/ - - Determinant = Hessian[0][0]*AdjHessian[0][0]+Hessian[0][1]*AdjHessian[1][0]+Hessian[0][2]*AdjHessian[2][0]; - - /*--- Hessian inverse ---*/ - - if (Determinant != 0) { - for (iDim = 0; iDim < nDim; iDim++) { - Temp[iDim] = 0.0; - for (jDim = 0; jDim < nDim; jDim++) { - Temp[iDim] += AdjHessian[iDim][jDim]*IndepTerm[jDim]/Determinant; - } - } - for (iDim = 0; iDim < nDim; iDim++) { - IndepTerm[iDim] = Temp[iDim]; - } - } - - /*--- Update with Successive over-relaxation ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - ParamCoord[iDim] = (1.0-SOR_Factor)*ParamCoord[iDim] + SOR_Factor*(ParamCoord[iDim] + IndepTerm[iDim]); - } - - /*--- If the gradient is small, we have converged ---*/ - - if ((fabs(IndepTerm[0]) < tol) && (fabs(IndepTerm[1]) < tol) && (fabs(IndepTerm[2]) < tol)) break; - - /*--- Compute the norm of the error ---*/ - - NormError = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - NormError += IndepTerm[iDim]*IndepTerm[iDim]; - NormError = sqrt(NormError); - - MinNormError = min(NormError, MinNormError); - - /*--- If we have no convergence with Random_Trials iterations probably we are in a local minima. ---*/ - - if (((iter % it_max) == 0) && (iter != 0)) { - - RandonCounter++; - if (RandonCounter == Random_Trials) { - cout << endl << "Unknown point: "<< iPoint <<" (" << xyz[0] <<", "<< xyz[1] <<", "<< xyz[2] <<"). Min Error: "<< MinNormError <<". Iter: "<< iter <<"."<< endl; - } - else { - SOR_Factor = 0.1; - for (iDim = 0; iDim < nDim; iDim++) - ParamCoord[iDim] = su2double(rand())/su2double(RAND_MAX); - } - - } - - } - - for (iDim = 0; iDim < nDim; iDim++) - delete [] Hessian[iDim]; - delete [] Hessian; - delete [] IndepTerm; - - /*--- The code has hit the max number of iterations ---*/ - - if (iter == (unsigned long)it_max*Random_Trials) { - cout << "Unknown point: (" << xyz[0] <<", "<< xyz[1] <<", "<< xyz[2] <<"). Increase the value of FFD_ITERATIONS." << endl; - } - - /*--- Real Solution is now ParamCoord; Return it ---*/ - - return ParamCoord; - -} - -unsigned long CFreeFormDefBox::Binomial(unsigned short n, unsigned short m) { - - unsigned short i, j; - unsigned long binomial[1000]; - - binomial[0] = 1; - for (i = 1; i <= n; ++i) { - binomial[i] = 1; - for (j = i-1U; j > 0; --j) { - binomial[j] += binomial[j-1U]; - } - } - - return binomial[m]; - -} - -bool CFreeFormDefBox::GetPointFFD(CGeometry *geometry, CConfig *config, unsigned long iPoint) { - su2double Coord[3] = {0.0, 0.0, 0.0}; - unsigned short iVar, jVar, iDim; - bool Inside = false; - - unsigned short Index[5][7] = { - {0, 1, 2, 5, 0, 1, 2}, - {0, 2, 7, 5, 0, 2, 7}, - {0, 2, 3, 7, 0, 2, 3}, - {0, 5, 7, 4, 0, 5, 7}, - {2, 7, 5, 6, 2, 7, 5}}; - unsigned short nDim = geometry->GetnDim(); - - for (iDim = 0; iDim < nDim; iDim++) - Coord[iDim] = geometry->node[iPoint]->GetCoord(iDim); - - /*--- 1st tetrahedron {V0, V1, V2, V5} - 2nd tetrahedron {V0, V2, V7, V5} - 3th tetrahedron {V0, V2, V3, V7} - 4th tetrahedron {V0, V5, V7, V4} - 5th tetrahedron {V2, V7, V5, V6} ---*/ - - for (iVar = 0; iVar < 5; iVar++) { - Inside = true; - for (jVar = 0; jVar < 4; jVar++) { - su2double Distance_Point = geometry->Point2Plane_Distance(Coord, - Coord_Corner_Points[Index[iVar][jVar+1]], - Coord_Corner_Points[Index[iVar][jVar+2]], - Coord_Corner_Points[Index[iVar][jVar+3]]); - - su2double Distance_Vertex = geometry->Point2Plane_Distance(Coord_Corner_Points[Index[iVar][jVar]], - Coord_Corner_Points[Index[iVar][jVar+1]], - Coord_Corner_Points[Index[iVar][jVar+2]], - Coord_Corner_Points[Index[iVar][jVar+3]]); - if (Distance_Point*Distance_Vertex < 0.0) Inside = false; - } - if (Inside) break; - } - - return Inside; - -} - -void CFreeFormDefBox::SetDeformationZone(CGeometry *geometry, CConfig *config, unsigned short iFFDBox) { - su2double *Coord; - unsigned short iMarker, iVar, jVar; - unsigned long iVertex, iPoint; - bool Inside = false; - - unsigned short Index[5][7] = { - {0, 1, 2, 5, 0, 1, 2}, - {0, 2, 7, 5, 0, 2, 7}, - {0, 2, 3, 7, 0, 2, 3}, - {0, 5, 7, 4, 0, 5, 7}, - {2, 7, 5, 6, 2, 7, 5}}; - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_DV(iMarker) == YES) - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - geometry->node[iPoint]->SetMove(false); - - Coord = geometry->node[iPoint]->GetCoord(); - - /*--- 1st tetrahedron {V0, V1, V2, V5} - 2nd tetrahedron {V0, V2, V7, V5} - 3th tetrahedron {V0, V2, V3, V7} - 4th tetrahedron {V0, V5, V7, V4} - 5th tetrahedron {V2, V7, V5, V6} ---*/ - - for (iVar = 0; iVar < 5; iVar++) { - Inside = true; - for (jVar = 0; jVar < 4; jVar++) { - su2double Distance_Point = geometry->Point2Plane_Distance(Coord, - Coord_Corner_Points[Index[iVar][jVar+1]], - Coord_Corner_Points[Index[iVar][jVar+2]], - Coord_Corner_Points[Index[iVar][jVar+3]]); - su2double Distance_Vertex = geometry->Point2Plane_Distance(Coord_Corner_Points[Index[iVar][jVar]], - Coord_Corner_Points[Index[iVar][jVar+1]], - Coord_Corner_Points[Index[iVar][jVar+2]], - Coord_Corner_Points[Index[iVar][jVar+3]]); - if (Distance_Point*Distance_Vertex < 0.0) Inside = false; - } - if (Inside) break; - } - - if (Inside) { - geometry->node[iPoint]->SetMove(true); - } - - } -} - -su2double CFreeFormDefBox::GetDerivative1(su2double *uvw, unsigned short val_diff, unsigned short *ijk, unsigned short *lmn) { - - unsigned short iDim; - su2double value = 0.0; - - value = GetBernsteinDerivative(lmn[val_diff], ijk[val_diff], uvw[val_diff], 1); - for (iDim = 0; iDim < nDim; iDim++) - if (iDim != val_diff) - value *= GetBernstein(lmn[iDim], ijk[iDim], uvw[iDim]); - - return value; - -} - -su2double CFreeFormDefBox::GetDerivative2 (su2double *uvw, unsigned short dim, su2double *xyz, unsigned short *lmn) { - - unsigned short iDegree, jDegree, kDegree; - su2double value = 0.0; - - for (iDegree = 0; iDegree <= lmn[0]; iDegree++) - for (jDegree = 0; jDegree <= lmn[1]; jDegree++) - for (kDegree = 0; kDegree <= lmn[2]; kDegree++) { - value += Coord_Control_Points[iDegree][jDegree][kDegree][dim] - * GetBernstein(lmn[0], iDegree, uvw[0]) - * GetBernstein(lmn[1], jDegree, uvw[1]) - * GetBernstein(lmn[2], kDegree, uvw[2]); - } - - return 2.0*(value - xyz[dim]); -} - -su2double CFreeFormDefBox::GetDerivative3(su2double *uvw, unsigned short dim, unsigned short diff_this, unsigned short *lmn) { - - unsigned short iDegree, jDegree, kDegree, iDim; - su2double value = 0; - - unsigned short *ijk = new unsigned short[nDim]; - - for (iDim = 0; iDim < nDim; iDim++) ijk[iDim] = 0; - - for (iDegree = 0; iDegree <= lmn[0]; iDegree++) - for (jDegree = 0; jDegree <= lmn[1]; jDegree++) - for (kDegree = 0; kDegree <= lmn[2]; kDegree++) { - ijk[0] = iDegree; ijk[1] = jDegree; ijk[2] = kDegree; - value += Coord_Control_Points[iDegree][jDegree][kDegree][dim] * - GetDerivative1(uvw, diff_this, ijk, lmn); - } - - delete [] ijk; - - return value; -} - -su2double CFreeFormDefBox::GetDerivative4(su2double *uvw, unsigned short val_diff, unsigned short val_diff2, - unsigned short *ijk, unsigned short *lmn) { - unsigned short iDim; - su2double value = 0.0; - - if (val_diff == val_diff2) { - value = GetBernsteinDerivative(lmn[val_diff], ijk[val_diff], uvw[val_diff], 2); - for (iDim = 0; iDim < nDim; iDim++) - if (iDim != val_diff) - value *= GetBernstein(lmn[iDim], ijk[iDim], uvw[iDim]); - } - else { - value = GetBernsteinDerivative(lmn[val_diff], ijk[val_diff], uvw[val_diff], 1) * - GetBernsteinDerivative(lmn[val_diff2], ijk[val_diff2], uvw[val_diff2], 1); - for (iDim = 0; iDim < nDim; iDim++) - if ((iDim != val_diff) && (iDim != val_diff2)) - value *= GetBernstein(lmn[iDim], ijk[iDim], uvw[iDim]); - } - - return value; -} - -su2double CFreeFormDefBox::GetDerivative5(su2double *uvw, unsigned short dim, unsigned short diff_this, unsigned short diff_this_also, - unsigned short *lmn) { - - unsigned short iDegree, jDegree, kDegree, iDim; - su2double value = 0.0; - - unsigned short *ijk = new unsigned short[nDim]; - - for (iDim = 0; iDim < nDim; iDim++) ijk[iDim] = 0; - - for (iDegree = 0; iDegree <= lmn[0]; iDegree++) - for (jDegree = 0; jDegree <= lmn[1]; jDegree++) - for (kDegree = 0; kDegree <= lmn[2]; kDegree++) { - ijk[0] = iDegree; ijk[1] = jDegree; ijk[2] = kDegree; - value += Coord_Control_Points[iDegree][jDegree][kDegree][dim] * - GetDerivative4(uvw, diff_this, diff_this_also, ijk, lmn); - } - - delete [] ijk; - - return value; -} +/*! + * \file grid_movement_structure.cpp + * \brief Subroutines for doing the grid movement using different strategies + * \author F. Palacios, T. Economon, S. Padron + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#include "../include/grid_movement_structure.hpp" +#include + +using namespace std; + +CGridMovement::CGridMovement(void) { } + +CGridMovement::~CGridMovement(void) { } + +CVolumetricMovement::CVolumetricMovement(CGeometry *geometry, CConfig *config) : CGridMovement() { + + /*--- Initialize the number of spatial dimensions, length of the state + vector (same as spatial dimensions for grid deformation), and grid nodes. ---*/ + + nDim = geometry->GetnDim(); + nVar = geometry->GetnDim(); + nPoint = geometry->GetnPoint(); + nPointDomain = geometry->GetnPointDomain(); + + /*--- Initialize matrix, solution, and r.h.s. structures for the linear solver. ---*/ + + config->SetKind_Linear_Solver_Prec(LU_SGS); + LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); + LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); + StiffMatrix.Initialize(nPoint, nPointDomain, nVar, nVar, false, geometry, config); + +} + +CVolumetricMovement::~CVolumetricMovement(void) { + + +} + + +void CVolumetricMovement::UpdateGridCoord(CGeometry *geometry, CConfig *config) { + + unsigned short iDim; + unsigned long iPoint, total_index; + su2double new_coord; + + /*--- Update the grid coordinates using the solution of the linear system + after grid deformation (LinSysSol contains the x, y, z displacements). ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint++) + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint*nDim + iDim; + new_coord = geometry->node[iPoint]->GetCoord(iDim)+LinSysSol[total_index]; + if (fabs(new_coord) < EPS*EPS) new_coord = 0.0; + geometry->node[iPoint]->SetCoord(iDim, new_coord); + } + +} + +void CVolumetricMovement::UpdateDualGrid(CGeometry *geometry, CConfig *config) { + + /*--- After moving all nodes, update the dual mesh. Recompute the edges and + dual mesh control volumes in the domain and on the boundaries. ---*/ + + geometry->SetCoord_CG(); + geometry->SetControlVolume(config, UPDATE); + geometry->SetBoundControlVolume(config, UPDATE); + +} + +void CVolumetricMovement::UpdateMultiGrid(CGeometry **geometry, CConfig *config) { + + unsigned short iMGfine, iMGlevel, nMGlevel = config->GetnMGLevels(); + + /*--- Update the multigrid structure after moving the finest grid, + including computing the grid velocities on the coarser levels. ---*/ + + for (iMGlevel = 1; iMGlevel <= nMGlevel; iMGlevel++) { + iMGfine = iMGlevel-1; + geometry[iMGlevel]->SetControlVolume(config, geometry[iMGfine], UPDATE); + geometry[iMGlevel]->SetBoundControlVolume(config, geometry[iMGfine],UPDATE); + geometry[iMGlevel]->SetCoord(geometry[iMGfine]); + if (config->GetGrid_Movement()) + geometry[iMGlevel]->SetRestricted_GridVelocity(geometry[iMGfine], config); + } + +} + +void CVolumetricMovement::SetVolume_Deformation(CGeometry *geometry, CConfig *config, bool UpdateGeo, bool Derivative) { + + unsigned long IterLinSol = 0, Smoothing_Iter, iNonlinear_Iter, MaxIter = 0, RestartIter = 50, Tot_Iter = 0, Nonlinear_Iter = 0; + unsigned long iPoint, iDim; + su2double MinVolume, NumError, Tol_Factor, Residual = 0.0, Residual_Init = 0.0; + bool Screen_Output; + bool fsi=config->GetFSI_Simulation(); + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Retrieve number or iterations, tol, output, etc. from config ---*/ + + Smoothing_Iter = config->GetGridDef_Linear_Iter(); + Screen_Output = config->GetDeform_Output(); + Tol_Factor = config->GetDeform_Tol_Factor(); + Nonlinear_Iter = config->GetGridDef_Nonlinear_Iter(); + + /*--- Disable the screen output if we're running SU2_CFD ---*/ + + if (config->GetKind_SU2() == SU2_CFD && !Derivative) Screen_Output = false; + + /*--- Set the number of nonlinear iterations to 1 if Derivative computation is enabled ---*/ + + if (Derivative) Nonlinear_Iter = 1; + + /*--- Loop over the total number of grid deformation iterations. The surface + deformation can be divided into increments to help with stability. In + particular, the linear elasticity equations hold only for small deformations. ---*/ + + for (iNonlinear_Iter = 0; iNonlinear_Iter < Nonlinear_Iter; iNonlinear_Iter++) { + + /*--- Initialize vector and sparse matrix ---*/ + + LinSysSol.SetValZero(); + LinSysRes.SetValZero(); + StiffMatrix.SetValZero(); + + /*--- Compute the stiffness matrix entries for all nodes/elements in the + mesh. FEA uses a finite element method discretization of the linear + elasticity equations (transfers element stiffnesses to point-to-point). ---*/ + + MinVolume = SetFEAMethodContributions_Elem(geometry, config); + + /*--- Compute the tolerance of the linear solver using MinLength ---*/ + + NumError = MinVolume * Tol_Factor; + + /*--- Set the boundary displacements (as prescribed by the design variable + perturbations controlling the surface shape) as a Dirichlet BC. ---*/ + + SetBoundaryDisplacements(geometry, config); + + /*--- Set the boundary derivatives (overrides the actual displacements) ---*/ + + if (Derivative){ + SetBoundaryDerivatives(geometry, config); + } + + /*--- Fix the location of any points in the domain, if requested. ---*/ + + if (config->GetHold_GridFixed()) + SetDomainDisplacements(geometry, config); + + CMatrixVectorProduct* mat_vec = NULL; + CPreconditioner* precond = NULL; + + /*--- Communicate any prescribed boundary displacements via MPI, + so that all nodes have the same solution and r.h.s. entries + across all partitions. ---*/ + + StiffMatrix.SendReceive_Solution(LinSysSol, geometry, config); + StiffMatrix.SendReceive_Solution(LinSysRes, geometry, config); + + /*--- Definition of the preconditioner matrix vector multiplication, and linear solver ---*/ + + /*--- If we want no derivatives or the direct derivatives, + * we solve the system using the normal matrix vector product and preconditioner. + * For the mesh sensitivities using the discrete adjoint method we solve the system using the transposed matrix, + * hence we need the corresponding matrix vector product and the preconditioner. ---*/ + if (!Derivative || ((config->GetKind_SU2() == SU2_CFD) && Derivative)){ + mat_vec = new CSysMatrixVectorProduct(StiffMatrix, geometry, config); + precond = new CLU_SGSPreconditioner(StiffMatrix, geometry, config); + + } else if (Derivative && (config->GetKind_SU2() == SU2_DOT)) { + /*--- Build the ILU preconditioner for the transposed system ---*/ + + StiffMatrix.BuildILUPreconditioner(true); + mat_vec = new CSysMatrixVectorProductTransposed(StiffMatrix, geometry, config); + precond = new CILUPreconditioner(StiffMatrix, geometry, config); + } + + CSysSolve *system = new CSysSolve(); + + switch (config->GetDeform_Linear_Solver()) { + + /*--- Solve the linear system (GMRES with restart) ---*/ + + case RESTARTED_FGMRES: + + Tot_Iter = 0; MaxIter = RestartIter; + + system->FGMRES_LinSolver(LinSysRes, LinSysSol, *mat_vec, *precond, NumError, 1, &Residual_Init, false); + + if ((rank == MASTER_NODE) && Screen_Output) { + cout << "\n# FGMRES (with restart) residual history" << endl; + cout << "# Residual tolerance target = " << NumError << endl; + cout << "# Initial residual norm = " << Residual_Init << endl; + } + + if (rank == MASTER_NODE) { cout << " " << Tot_Iter << " " << Residual_Init/Residual_Init << endl; } + + while (Tot_Iter < Smoothing_Iter) { + + if (IterLinSol + RestartIter > Smoothing_Iter) + MaxIter = Smoothing_Iter - IterLinSol; + + IterLinSol = system->FGMRES_LinSolver(LinSysRes, LinSysSol, *mat_vec, *precond, NumError, MaxIter, &Residual, false); + Tot_Iter += IterLinSol; + + if ((rank == MASTER_NODE) && Screen_Output) { cout << " " << Tot_Iter << " " << Residual/Residual_Init << endl; } + + if (Residual < Residual_Init*NumError) { break; } + + } + + if ((rank == MASTER_NODE) && Screen_Output) { + cout << "# FGMRES (with restart) final (true) residual:" << endl; + cout << "# Iteration = " << Tot_Iter << ": |res|/|res0| = " << Residual/Residual_Init << ".\n" << endl; + } + + break; + + /*--- Solve the linear system (GMRES) ---*/ + + case FGMRES: + + Tot_Iter = system->FGMRES_LinSolver(LinSysRes, LinSysSol, *mat_vec, *precond, NumError, Smoothing_Iter, &Residual, Screen_Output); + + break; + + /*--- Solve the linear system (BCGSTAB) ---*/ + + case BCGSTAB: + + Tot_Iter = system->BCGSTAB_LinSolver(LinSysRes, LinSysSol, *mat_vec, *precond, NumError, Smoothing_Iter, &Residual, Screen_Output); + + break; + + } + + /*--- Deallocate memory needed by the Krylov linear solver ---*/ + + delete system; + delete mat_vec; + delete precond; + + /*--- Update the grid coordinates and cell volumes using the solution + of the linear system (usol contains the x, y, z displacements). ---*/ + + if (!Derivative){ + UpdateGridCoord(geometry, config); + }else{ + UpdateGridCoord_Derivatives(geometry, config); + } + + if (UpdateGeo) + UpdateDualGrid(geometry, config); + + /*--- Check for failed deformation (negative volumes). ---*/ + + MinVolume = Check_Grid(geometry); + + if (rank == MASTER_NODE) { + cout << "Non-linear iter.: " << iNonlinear_Iter+1 << "/" << Nonlinear_Iter + << ". Linear iter.: " << Tot_Iter << ". "; + if (nDim == 2) cout << "Min. area: " << MinVolume << ". Error: " << Residual << "." << endl; + else cout << "Min. volume: " << MinVolume << ". Error: " << Residual << "." << endl; + } + + } + + if (fsi){ + /*--- Grid velocity (there is a function that does this -> Modify) ---*/ + + /*--- Local variables ---*/ + + su2double *Coord_nP1 = NULL, *Coord_n = NULL, *Coord_nM1 = NULL; + su2double TimeStep, GridVel = 0.0; + + /*--- Compute the velocity of each node in the volume mesh ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + + /*--- Coordinates of the current point at n+1, n, & n-1 time levels ---*/ + + Coord_nM1 = geometry->node[iPoint]->GetCoord_n1(); + Coord_n = geometry->node[iPoint]->GetCoord_n(); + Coord_nP1 = geometry->node[iPoint]->GetCoord(); + + /*--- Unsteady time step ---*/ + + TimeStep = config->GetDelta_UnstTimeND(); + + /*--- Compute mesh velocity with 1st or 2nd-order approximation ---*/ + + for(iDim = 0; iDim < nDim; iDim++) { + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + GridVel = ( Coord_nP1[iDim] - Coord_n[iDim] ) / TimeStep; + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + GridVel = ( 3.0*Coord_nP1[iDim] - 4.0*Coord_n[iDim] + + 1.0*Coord_nM1[iDim] ) / (2.0*TimeStep); + + /*--- Store grid velocity for this point ---*/ + + geometry->node[iPoint]->SetGridVel(iDim, GridVel); + } + } + + } + + +} + +su2double CVolumetricMovement::Check_Grid(CGeometry *geometry) { + + unsigned long iElem, ElemCounter = 0, PointCorners[8]; + su2double Area = 0.0, Volume = 0.0, MaxArea = -1E22, MaxVolume = -1E22, MinArea = 1E22, MinVolume = 1E22, CoordCorners[8][3]; + unsigned short nNodes = 0, iNodes, iDim; + bool RightVol = true; + + int rank = MASTER_NODE; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Load up each triangle and tetrahedron to check for negative volumes. ---*/ + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) nNodes = 3; + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) nNodes = 4; + if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) nNodes = 4; + if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) nNodes = 5; + if (geometry->elem[iElem]->GetVTK_Type() == PRISM) nNodes = 6; + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) nNodes = 8; + + for (iNodes = 0; iNodes < nNodes; iNodes++) { + PointCorners[iNodes] = geometry->elem[iElem]->GetNode(iNodes); + for (iDim = 0; iDim < nDim; iDim++) { + CoordCorners[iNodes][iDim] = geometry->node[PointCorners[iNodes]]->GetCoord(iDim); + } + } + + /*--- Triangles ---*/ + + if (nDim == 2) { + + if (nNodes == 3) Area = GetTriangle_Area(CoordCorners); + if (nNodes == 4) Area = GetQuadrilateral_Area(CoordCorners); + + if (Area >= -EPS) RightVol = true; + else RightVol = false;; + + MaxArea = max(MaxArea, Area); + MinArea = min(MinArea, Area); + + } + + /*--- Tetrahedra ---*/ + + if (nDim == 3) { + + if (nNodes == 4) Volume = GetTetra_Volume(CoordCorners); + if (nNodes == 5) Volume = GetPyram_Volume(CoordCorners); + if (nNodes == 6) Volume = GetPrism_Volume(CoordCorners); + if (nNodes == 8) Volume = GetHexa_Volume(CoordCorners); + + if (Volume >= -EPS) RightVol = true; + else RightVol = false;; + + MaxVolume = max(MaxVolume, Volume); + MinVolume = min(MinVolume, Volume); + + } + + if (!RightVol) ElemCounter++; + + } + +#ifdef HAVE_MPI + unsigned long ElemCounter_Local = ElemCounter; ElemCounter = 0; + su2double MaxVolume_Local = MaxVolume; MaxVolume = 0.0; + su2double MinVolume_Local = MinVolume; MinVolume = 0.0; + SU2_MPI::Allreduce(&ElemCounter_Local, &ElemCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MaxVolume_Local, &MaxVolume, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MinVolume_Local, &MinVolume, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); +#endif + + if ((ElemCounter != 0) && (rank == MASTER_NODE)) + cout <<"There are " << ElemCounter << " elements with negative volume.\n" << endl; + + if (nDim == 2) return MinArea; + else return MinVolume; + +} + +void CVolumetricMovement::ComputeDeforming_Wall_Distance(CGeometry *geometry, CConfig *config) { + + su2double *coord, dist2, dist; + unsigned short iDim, iMarker; + unsigned long iPoint, iVertex, nVertex_SolidWall; + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + if (rank == MASTER_NODE) + cout << "Computing distances to the nearest deforming surface." << endl; + + /*--- Get the SU2 module. SU2_CFD will use this routine for dynamically + deforming meshes (MARKER_MOVING), while SU2_DEF will use it for deforming + meshes after imposing design variable surface deformations (DV_MARKER). ---*/ + + unsigned short Kind_SU2 = config->GetKind_SU2(); + +#ifndef HAVE_MPI + + /*--- Compute the total number of nodes on deforming boundaries ---*/ + + nVertex_SolidWall = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_CFD)) || + ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DEF))) + nVertex_SolidWall += geometry->GetnVertex(iMarker); + + /*--- Allocate an array to hold boundary node coordinates ---*/ + + su2double **Coord_bound; + Coord_bound = new su2double* [nVertex_SolidWall]; + for (iVertex = 0; iVertex < nVertex_SolidWall; iVertex++) + Coord_bound[iVertex] = new su2double [nDim]; + + /*--- Retrieve and store the coordinates of the deforming boundary nodes ---*/ + + nVertex_SolidWall = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_CFD)) || + ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DEF))) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + for (iDim = 0; iDim < nDim; iDim++) + Coord_bound[nVertex_SolidWall][iDim] = geometry->node[iPoint]->GetCoord(iDim); + nVertex_SolidWall++; + } + } + + /*--- Loop over all interior mesh nodes and compute the distances to each + of the deforming boundary nodes. Store the minimum distance to the wall for + each interior mesh node. Store the global minimum distance. ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + coord = geometry->node[iPoint]->GetCoord(); + dist = 1E20; + for (iVertex = 0; iVertex < nVertex_SolidWall; iVertex++) { + dist2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + dist2 += (coord[iDim]-Coord_bound[iVertex][iDim]) + *(coord[iDim]-Coord_bound[iVertex][iDim]); + if (dist2 < dist) dist = dist2; + } + geometry->node[iPoint]->SetWall_Distance(sqrt(dist)); + } + + /*--- Deallocate the vector of boundary coordinates. ---*/ + + for (iVertex = 0; iVertex < nVertex_SolidWall; iVertex++) + delete[] Coord_bound[iVertex]; + delete[] Coord_bound; + + +#else + + /*--- Variables and buffers needed for MPI ---*/ + + int iProcessor, nProcessor; + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); + + unsigned long nLocalVertex_NS = 0, nGlobalVertex_NS = 0, MaxLocalVertex_NS = 0; + unsigned long *Buffer_Send_nVertex = new unsigned long [1]; + unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor]; + + /*--- Count the total number of nodes on deforming boundaries within the + local partition. ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_CFD)) || + ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DEF))) + nLocalVertex_NS += geometry->GetnVertex(iMarker); + + /*--- Communicate to all processors the total number of deforming boundary + nodes, the maximum number of deforming boundary nodes on any single + partition, and the number of deforming nodes on each partition. ---*/ + + Buffer_Send_nVertex[0] = nLocalVertex_NS; + SU2_MPI::Allreduce(&nLocalVertex_NS, &nGlobalVertex_NS, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&nLocalVertex_NS, &MaxLocalVertex_NS, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + /*--- Create and initialize to zero some buffers to hold the coordinates + of the boundary nodes that are communicated from each partition (all-to-all). ---*/ + + su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_NS*nDim]; + su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_NS*nDim]; + unsigned long nBuffer = MaxLocalVertex_NS*nDim; + + for (iVertex = 0; iVertex < MaxLocalVertex_NS; iVertex++) + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; + + /*--- Retrieve and store the coordinates of the deforming boundary nodes on + the local partition and broadcast them to all partitions. ---*/ + + nVertex_SolidWall = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_CFD)) || + ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DEF))) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[nVertex_SolidWall*nDim+iDim] = geometry->node[iPoint]->GetCoord(iDim); + nVertex_SolidWall++; + } + + SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer, MPI_DOUBLE, MPI_COMM_WORLD); + + /*--- Loop over all interior mesh nodes on the local partition and compute + the distances to each of the deforming boundary nodes in the entire mesh. + Store the minimum distance to the wall for each interior mesh node. ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + coord = geometry->node[iPoint]->GetCoord(); + dist = 1E20; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) + for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { + dist2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + dist2 += (coord[iDim]-Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_NS+iVertex)*nDim+iDim])* + (coord[iDim]-Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_NS+iVertex)*nDim+iDim]); + if (dist2 < dist) dist = dist2; + } + geometry->node[iPoint]->SetWall_Distance(sqrt(dist)); + } + + /*--- Deallocate the buffers needed for the MPI communication. ---*/ + + delete[] Buffer_Send_Coord; + delete[] Buffer_Receive_Coord; + delete[] Buffer_Send_nVertex; + delete[] Buffer_Receive_nVertex; + +#endif + +} + +su2double CVolumetricMovement::SetFEAMethodContributions_Elem(CGeometry *geometry, CConfig *config) { + + unsigned short iVar, iDim, nNodes = 0, iNodes, StiffMatrix_nElem = 0; + unsigned long Point_0, Point_1, iElem, iEdge, ElemCounter = 0, PointCorners[8]; + su2double *Coord_0, *Coord_1, Length, MinLength = 1E10, **StiffMatrix_Elem = NULL, Scale, CoordCorners[8][3]; + su2double *Edge_Vector = new su2double [nDim]; + + /*--- Allocate maximum size (quadrilateral and hexahedron) ---*/ + + if (nDim == 2) StiffMatrix_nElem = 8; + else StiffMatrix_nElem = 24; + + StiffMatrix_Elem = new su2double* [StiffMatrix_nElem]; + for (iVar = 0; iVar < StiffMatrix_nElem; iVar++) + StiffMatrix_Elem[iVar] = new su2double [StiffMatrix_nElem]; + + /*--- Check the minimum edge length in the entire mesh. ---*/ + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Points in edge and coordinates ---*/ + + Point_0 = geometry->edge[iEdge]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); + Point_1 = geometry->edge[iEdge]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); + + /*--- Compute Edge_Vector ---*/ + + Length = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Edge_Vector[iDim] = Coord_1[iDim] - Coord_0[iDim]; + Length += Edge_Vector[iDim]*Edge_Vector[iDim]; + } + Length = sqrt(Length); + MinLength = min(Length, MinLength); + + } + + /*--- Compute min volume in the entire mesh. ---*/ + + Scale = Check_Grid(geometry); + + /*--- Compute the distance to the nearest deforming surface if needed + as part of the stiffness calculation. In this case, we can scale based + on the minimum edge length. ---*/ + + if (config->GetDeform_Stiffness_Type() == WALL_DISTANCE) { + ComputeDeforming_Wall_Distance(geometry, config); + Scale = MinLength; + } + + /*--- Compute contributions from each element by forming the stiffness matrix (FEA) ---*/ + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) nNodes = 3; + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) nNodes = 4; + if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) nNodes = 4; + if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) nNodes = 5; + if (geometry->elem[iElem]->GetVTK_Type() == PRISM) nNodes = 6; + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) nNodes = 8; + + for (iNodes = 0; iNodes < nNodes; iNodes++) { + PointCorners[iNodes] = geometry->elem[iElem]->GetNode(iNodes); + for (iDim = 0; iDim < nDim; iDim++) { + CoordCorners[iNodes][iDim] = geometry->node[PointCorners[iNodes]]->GetCoord(iDim); + } + } + + if (nDim == 2) SetFEA_StiffMatrix2D(geometry, config, StiffMatrix_Elem, PointCorners, CoordCorners, nNodes, Scale); + if (nDim == 3) SetFEA_StiffMatrix3D(geometry, config, StiffMatrix_Elem, PointCorners, CoordCorners, nNodes, Scale); + + AddFEA_StiffMatrix(geometry, StiffMatrix_Elem, PointCorners, nNodes); + + } + +#ifdef HAVE_MPI + unsigned long ElemCounter_Local = ElemCounter; ElemCounter = 0; + SU2_MPI::Allreduce(&ElemCounter_Local, &ElemCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); +#endif + + /*--- Deallocate memory and exit ---*/ + + for (iVar = 0; iVar < StiffMatrix_nElem; iVar++) + delete [] StiffMatrix_Elem[iVar]; + delete [] StiffMatrix_Elem; + + delete [] Edge_Vector; + + /*--- If there are no degenerate cells, use the minimum volume instead ---*/ + if (ElemCounter == 0) MinLength = Scale; + +#ifdef HAVE_MPI + su2double MinLength_Local = MinLength; MinLength = 0.0; + SU2_MPI::Allreduce(&MinLength_Local, &MinLength, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); +#endif + + return MinLength; +} + +su2double CVolumetricMovement::ShapeFunc_Triangle(su2double Xi, su2double Eta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { + + int i, j, k; + su2double c0, c1, xsj; + su2double xs[3][3], ad[3][3]; + + /*--- Shape functions ---*/ + + DShapeFunction[0][3] = Xi; + DShapeFunction[1][3] = Eta; + DShapeFunction[2][3] = 1-Xi-Eta; + + /*--- dN/d xi, dN/d eta ---*/ + + DShapeFunction[0][0] = 1.0; DShapeFunction[0][1] = 0.0; + DShapeFunction[1][0] = 0.0; DShapeFunction[1][1] = 1.0; + DShapeFunction[2][0] = -1.0; DShapeFunction[2][1] = -1.0; + + /*--- Jacobian transformation ---*/ + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + xs[i][j] = 0.0; + for (k = 0; k < 3; k++) { + xs[i][j] = xs[i][j]+CoordCorners[k][j]*DShapeFunction[k][i]; + } + } + } + + /*--- Adjoint to Jacobian ---*/ + + ad[0][0] = xs[1][1]; + ad[0][1] = -xs[0][1]; + ad[1][0] = -xs[1][0]; + ad[1][1] = xs[0][0]; + + /*--- Determinant of Jacobian ---*/ + + xsj = ad[0][0]*ad[1][1]-ad[0][1]*ad[1][0]; + + /*--- Jacobian inverse ---*/ + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + xs[i][j] = ad[i][j]/xsj; + } + } + + /*--- Derivatives with repect to global coordinates ---*/ + + for (k = 0; k < 3; k++) { + c0 = xs[0][0]*DShapeFunction[k][0]+xs[0][1]*DShapeFunction[k][1]; // dN/dx + c1 = xs[1][0]*DShapeFunction[k][0]+xs[1][1]*DShapeFunction[k][1]; // dN/dy + DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi + DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta + } + + return xsj; + +} + +su2double CVolumetricMovement::ShapeFunc_Quadrilateral(su2double Xi, su2double Eta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { + + int i, j, k; + su2double c0, c1, xsj; + su2double xs[3][3], ad[3][3]; + + /*--- Shape functions ---*/ + + DShapeFunction[0][3] = 0.25*(1.0-Xi)*(1.0-Eta); + DShapeFunction[1][3] = 0.25*(1.0+Xi)*(1.0-Eta); + DShapeFunction[2][3] = 0.25*(1.0+Xi)*(1.0+Eta); + DShapeFunction[3][3] = 0.25*(1.0-Xi)*(1.0+Eta); + + /*--- dN/d xi, dN/d eta ---*/ + + DShapeFunction[0][0] = -0.25*(1.0-Eta); DShapeFunction[0][1] = -0.25*(1.0-Xi); + DShapeFunction[1][0] = 0.25*(1.0-Eta); DShapeFunction[1][1] = -0.25*(1.0+Xi); + DShapeFunction[2][0] = 0.25*(1.0+Eta); DShapeFunction[2][1] = 0.25*(1.0+Xi); + DShapeFunction[3][0] = -0.25*(1.0+Eta); DShapeFunction[3][1] = 0.25*(1.0-Xi); + + /*--- Jacobian transformation ---*/ + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + xs[i][j] = 0.0; + for (k = 0; k < 4; k++) { + xs[i][j] = xs[i][j]+CoordCorners[k][j]*DShapeFunction[k][i]; + } + } + } + + /*--- Adjoint to Jacobian ---*/ + + ad[0][0] = xs[1][1]; + ad[0][1] = -xs[0][1]; + ad[1][0] = -xs[1][0]; + ad[1][1] = xs[0][0]; + + /*--- Determinant of Jacobian ---*/ + + xsj = ad[0][0]*ad[1][1]-ad[0][1]*ad[1][0]; + + /*--- Jacobian inverse ---*/ + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + xs[i][j] = ad[i][j]/xsj; + } + } + + /*--- Derivatives with repect to global coordinates ---*/ + + for (k = 0; k < 4; k++) { + c0 = xs[0][0]*DShapeFunction[k][0]+xs[0][1]*DShapeFunction[k][1]; // dN/dx + c1 = xs[1][0]*DShapeFunction[k][0]+xs[1][1]*DShapeFunction[k][1]; // dN/dy + DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi + DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta + } + + return xsj; + +} + +su2double CVolumetricMovement::ShapeFunc_Tetra(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { + + int i, j, k; + su2double c0, c1, c2, xsj; + su2double xs[3][3], ad[3][3]; + + /*--- Shape functions ---*/ + + DShapeFunction[0][3] = Xi; + DShapeFunction[1][3] = Zeta; + DShapeFunction[2][3] = 1.0 - Xi - Eta - Zeta; + DShapeFunction[3][3] = Eta; + + /*--- dN/d xi, dN/d eta, dN/d zeta ---*/ + + DShapeFunction[0][0] = 1.0; DShapeFunction[0][1] = 0.0; DShapeFunction[0][2] = 0.0; + DShapeFunction[1][0] = 0.0; DShapeFunction[1][1] = 0.0; DShapeFunction[1][2] = 1.0; + DShapeFunction[2][0] = -1.0; DShapeFunction[2][1] = -1.0; DShapeFunction[2][2] = -1.0; + DShapeFunction[3][0] = 0.0; DShapeFunction[3][1] = 1.0; DShapeFunction[3][2] = 0.0; + + /*--- Jacobian transformation ---*/ + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + xs[i][j] = 0.0; + for (k = 0; k < 4; k++) { + xs[i][j] = xs[i][j]+CoordCorners[k][j]*DShapeFunction[k][i]; + } + } + } + + /*--- Adjoint to Jacobian ---*/ + + ad[0][0] = xs[1][1]*xs[2][2]-xs[1][2]*xs[2][1]; + ad[0][1] = xs[0][2]*xs[2][1]-xs[0][1]*xs[2][2]; + ad[0][2] = xs[0][1]*xs[1][2]-xs[0][2]*xs[1][1]; + ad[1][0] = xs[1][2]*xs[2][0]-xs[1][0]*xs[2][2]; + ad[1][1] = xs[0][0]*xs[2][2]-xs[0][2]*xs[2][0]; + ad[1][2] = xs[0][2]*xs[1][0]-xs[0][0]*xs[1][2]; + ad[2][0] = xs[1][0]*xs[2][1]-xs[1][1]*xs[2][0]; + ad[2][1] = xs[0][1]*xs[2][0]-xs[0][0]*xs[2][1]; + ad[2][2] = xs[0][0]*xs[1][1]-xs[0][1]*xs[1][0]; + + /*--- Determinant of Jacobian ---*/ + + xsj = xs[0][0]*ad[0][0]+xs[0][1]*ad[1][0]+xs[0][2]*ad[2][0]; + + /*--- Jacobian inverse ---*/ + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + xs[i][j] = ad[i][j]/xsj; + } + } + + /*--- Derivatives with repect to global coordinates ---*/ + + for (k = 0; k < 4; k++) { + c0 = xs[0][0]*DShapeFunction[k][0]+xs[0][1]*DShapeFunction[k][1]+xs[0][2]*DShapeFunction[k][2]; // dN/dx + c1 = xs[1][0]*DShapeFunction[k][0]+xs[1][1]*DShapeFunction[k][1]+xs[1][2]*DShapeFunction[k][2]; // dN/dy + c2 = xs[2][0]*DShapeFunction[k][0]+xs[2][1]*DShapeFunction[k][1]+xs[2][2]*DShapeFunction[k][2]; // dN/dz + DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi + DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta + DShapeFunction[k][2] = c2; // store dN/dz instead of dN/d zeta + } + + return xsj; + +} + +su2double CVolumetricMovement::ShapeFunc_Pyram(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { + + int i, j, k; + su2double c0, c1, c2, xsj; + su2double xs[3][3], ad[3][3]; + + /*--- Shape functions ---*/ + + DShapeFunction[0][3] = 0.125*(1.0-Xi)*(1.0-Eta)*(1.0-Zeta); + DShapeFunction[1][3] = 0.125*(1.0+Xi)*(1.0-Eta)*(1.0-Zeta); + DShapeFunction[2][3] = 0.125*(1.0+Xi)*(1.0+Eta)*(1.0-Zeta); + DShapeFunction[3][3] = 0.125*(1.0-Xi)*(1.0+Eta)*(1.0-Zeta); + DShapeFunction[4][3] = 0.5*(1.0+Zeta); + + /*--- dN/d xi ---*/ + + DShapeFunction[0][0] = -0.125*(1.0-Eta)*(1.0-Zeta); + DShapeFunction[1][0] = 0.125*(1.0-Eta)*(1.0-Zeta); + DShapeFunction[2][0] = 0.125*(1.0+Eta)*(1.0-Zeta); + DShapeFunction[3][0] = -0.125*(1.0+Eta)*(1.0-Zeta); + DShapeFunction[4][0] = 0.0; + + /*--- dN/d eta ---*/ + + DShapeFunction[0][1] = -0.125*(1.0-Xi)*(1.0-Zeta); + DShapeFunction[1][1] = -0.125*(1.0+Xi)*(1.0-Zeta); + DShapeFunction[2][1] = 0.125*(1.0+Xi)*(1.0-Zeta); + DShapeFunction[3][1] = 0.125*(1.0-Xi)*(1.0-Zeta); + DShapeFunction[4][1] = 0.0; + + /*--- dN/d zeta ---*/ + + DShapeFunction[0][2] = -0.125*(1.0-Xi)*(1.0-Eta); + DShapeFunction[1][2] = -0.125*(1.0+Xi)*(1.0-Eta); + DShapeFunction[2][2] = -0.125*(1.0+Xi)*(1.0+Eta); + DShapeFunction[3][2] = -0.125*(1.0-Xi)*(1.0+Eta); + DShapeFunction[4][2] = 0.5; + + /*--- Jacobian transformation ---*/ + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + xs[i][j] = 0.0; + for (k = 0; k < 5; k++) { + xs[i][j] = xs[i][j]+CoordCorners[k][j]*DShapeFunction[k][i]; + } + } + } + + /*--- Adjoint to Jacobian ---*/ + + ad[0][0] = xs[1][1]*xs[2][2]-xs[1][2]*xs[2][1]; + ad[0][1] = xs[0][2]*xs[2][1]-xs[0][1]*xs[2][2]; + ad[0][2] = xs[0][1]*xs[1][2]-xs[0][2]*xs[1][1]; + ad[1][0] = xs[1][2]*xs[2][0]-xs[1][0]*xs[2][2]; + ad[1][1] = xs[0][0]*xs[2][2]-xs[0][2]*xs[2][0]; + ad[1][2] = xs[0][2]*xs[1][0]-xs[0][0]*xs[1][2]; + ad[2][0] = xs[1][0]*xs[2][1]-xs[1][1]*xs[2][0]; + ad[2][1] = xs[0][1]*xs[2][0]-xs[0][0]*xs[2][1]; + ad[2][2] = xs[0][0]*xs[1][1]-xs[0][1]*xs[1][0]; + + /*--- Determinant of Jacobian ---*/ + + xsj = xs[0][0]*ad[0][0]+xs[0][1]*ad[1][0]+xs[0][2]*ad[2][0]; + + /*--- Jacobian inverse ---*/ + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + xs[i][j] = ad[i][j]/xsj; + } + } + + /*--- Derivatives with repect to global coordinates ---*/ + + for (k = 0; k < 5; k++) { + c0 = xs[0][0]*DShapeFunction[k][0]+xs[0][1]*DShapeFunction[k][1]+xs[0][2]*DShapeFunction[k][2]; // dN/dx + c1 = xs[1][0]*DShapeFunction[k][0]+xs[1][1]*DShapeFunction[k][1]+xs[1][2]*DShapeFunction[k][2]; // dN/dy + c2 = xs[2][0]*DShapeFunction[k][0]+xs[2][1]*DShapeFunction[k][1]+xs[2][2]*DShapeFunction[k][2]; // dN/dz + DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi + DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta + DShapeFunction[k][2] = c2; // store dN/dz instead of dN/d zeta + } + + return xsj; + +} + +su2double CVolumetricMovement::ShapeFunc_Prism(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { + + int i, j, k; + su2double c0, c1, c2, xsj; + su2double xs[3][3], ad[3][3]; + + /*--- Shape functions ---*/ + + DShapeFunction[0][3] = 0.5*Eta*(1.0-Xi); + DShapeFunction[1][3] = 0.5*Zeta*(1.0-Xi); + DShapeFunction[2][3] = 0.5*(1.0-Eta-Zeta)*(1.0-Xi); + DShapeFunction[3][3] = 0.5*Eta*(Xi+1.0); + DShapeFunction[4][3] = 0.5*Zeta*(Xi+1.0); + DShapeFunction[5][3] = 0.5*(1.0-Eta-Zeta)*(Xi+1.0); + + /*--- dN/d Xi, dN/d Eta, dN/d Zeta ---*/ + + DShapeFunction[0][0] = -0.5*Eta; DShapeFunction[0][1] = 0.5*(1.0-Xi); DShapeFunction[0][2] = 0.0; + DShapeFunction[1][0] = -0.5*Zeta; DShapeFunction[1][1] = 0.0; DShapeFunction[1][2] = 0.5*(1.0-Xi); + DShapeFunction[2][0] = -0.5*(1.0-Eta-Zeta); DShapeFunction[2][1] = -0.5*(1.0-Xi); DShapeFunction[2][2] = -0.5*(1.0-Xi); + DShapeFunction[3][0] = 0.5*Eta; DShapeFunction[3][1] = 0.5*(Xi+1.0); DShapeFunction[3][2] = 0.0; + DShapeFunction[4][0] = 0.5*Zeta; DShapeFunction[4][1] = 0.0; DShapeFunction[4][2] = 0.5*(Xi+1.0); + DShapeFunction[5][0] = 0.5*(1.0-Eta-Zeta); DShapeFunction[5][1] = -0.5*(Xi+1.0); DShapeFunction[5][2] = -0.5*(Xi+1.0); + + /*--- Jacobian transformation ---*/ + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + xs[i][j] = 0.0; + for (k = 0; k < 6; k++) { + xs[i][j] = xs[i][j]+CoordCorners[k][j]*DShapeFunction[k][i]; + } + } + } + + /*--- Adjoint to Jacobian ---*/ + + ad[0][0] = xs[1][1]*xs[2][2]-xs[1][2]*xs[2][1]; + ad[0][1] = xs[0][2]*xs[2][1]-xs[0][1]*xs[2][2]; + ad[0][2] = xs[0][1]*xs[1][2]-xs[0][2]*xs[1][1]; + ad[1][0] = xs[1][2]*xs[2][0]-xs[1][0]*xs[2][2]; + ad[1][1] = xs[0][0]*xs[2][2]-xs[0][2]*xs[2][0]; + ad[1][2] = xs[0][2]*xs[1][0]-xs[0][0]*xs[1][2]; + ad[2][0] = xs[1][0]*xs[2][1]-xs[1][1]*xs[2][0]; + ad[2][1] = xs[0][1]*xs[2][0]-xs[0][0]*xs[2][1]; + ad[2][2] = xs[0][0]*xs[1][1]-xs[0][1]*xs[1][0]; + + /*--- Determinant of Jacobian ---*/ + + xsj = xs[0][0]*ad[0][0]+xs[0][1]*ad[1][0]+xs[0][2]*ad[2][0]; + + /*--- Jacobian inverse ---*/ + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + xs[i][j] = ad[i][j]/xsj; + } + } + + /*--- Derivatives with repect to global coordinates ---*/ + + for (k = 0; k < 6; k++) { + c0 = xs[0][0]*DShapeFunction[k][0]+xs[0][1]*DShapeFunction[k][1]+xs[0][2]*DShapeFunction[k][2]; // dN/dx + c1 = xs[1][0]*DShapeFunction[k][0]+xs[1][1]*DShapeFunction[k][1]+xs[1][2]*DShapeFunction[k][2]; // dN/dy + c2 = xs[2][0]*DShapeFunction[k][0]+xs[2][1]*DShapeFunction[k][1]+xs[2][2]*DShapeFunction[k][2]; // dN/dz + DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi + DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta + DShapeFunction[k][2] = c2; // store dN/dz instead of dN/d zeta + } + + return xsj; + +} + +su2double CVolumetricMovement::ShapeFunc_Hexa(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { + + int i, j, k; + su2double c0, c1, c2, xsj; + su2double xs[3][3], ad[3][3]; + + + /*--- Shape functions ---*/ + + DShapeFunction[0][3] = 0.125*(1.0-Xi)*(1.0-Eta)*(1.0-Zeta); + DShapeFunction[1][3] = 0.125*(1.0+Xi)*(1.0-Eta)*(1.0-Zeta); + DShapeFunction[2][3] = 0.125*(1.0+Xi)*(1.0+Eta)*(1.0-Zeta); + DShapeFunction[3][3] = 0.125*(1.0-Xi)*(1.0+Eta)*(1.0-Zeta); + DShapeFunction[4][3] = 0.125*(1.0-Xi)*(1.0-Eta)*(1.0+Zeta); + DShapeFunction[5][3] = 0.125*(1.0+Xi)*(1.0-Eta)*(1.0+Zeta); + DShapeFunction[6][3] = 0.125*(1.0+Xi)*(1.0+Eta)*(1.0+Zeta); + DShapeFunction[7][3] = 0.125*(1.0-Xi)*(1.0+Eta)*(1.0+Zeta); + + /*--- dN/d xi ---*/ + + DShapeFunction[0][0] = -0.125*(1.0-Eta)*(1.0-Zeta); + DShapeFunction[1][0] = 0.125*(1.0-Eta)*(1.0-Zeta); + DShapeFunction[2][0] = 0.125*(1.0+Eta)*(1.0-Zeta); + DShapeFunction[3][0] = -0.125*(1.0+Eta)*(1.0-Zeta); + DShapeFunction[4][0] = -0.125*(1.0-Eta)*(1.0+Zeta); + DShapeFunction[5][0] = 0.125*(1.0-Eta)*(1.0+Zeta); + DShapeFunction[6][0] = 0.125*(1.0+Eta)*(1.0+Zeta); + DShapeFunction[7][0] = -0.125*(1.0+Eta)*(1.0+Zeta); + + /*--- dN/d eta ---*/ + + DShapeFunction[0][1] = -0.125*(1.0-Xi)*(1.0-Zeta); + DShapeFunction[1][1] = -0.125*(1.0+Xi)*(1.0-Zeta); + DShapeFunction[2][1] = 0.125*(1.0+Xi)*(1.0-Zeta); + DShapeFunction[3][1] = 0.125*(1.0-Xi)*(1.0-Zeta); + DShapeFunction[4][1] = -0.125*(1.0-Xi)*(1.0+Zeta); + DShapeFunction[5][1] = -0.125*(1.0+Xi)*(1.0+Zeta); + DShapeFunction[6][1] = 0.125*(1.0+Xi)*(1.0+Zeta); + DShapeFunction[7][1] = 0.125*(1.0-Xi)*(1.0+Zeta); + + /*--- dN/d zeta ---*/ + + DShapeFunction[0][2] = -0.125*(1.0-Xi)*(1.0-Eta); + DShapeFunction[1][2] = -0.125*(1.0+Xi)*(1.0-Eta); + DShapeFunction[2][2] = -0.125*(1.0+Xi)*(1.0+Eta); + DShapeFunction[3][2] = -0.125*(1.0-Xi)*(1.0+Eta); + DShapeFunction[4][2] = 0.125*(1.0-Xi)*(1.0-Eta); + DShapeFunction[5][2] = 0.125*(1.0+Xi)*(1.0-Eta); + DShapeFunction[6][2] = 0.125*(1.0+Xi)*(1.0+Eta); + DShapeFunction[7][2] = 0.125*(1.0-Xi)*(1.0+Eta); + + /*--- Jacobian transformation ---*/ + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + xs[i][j] = 0.0; + for (k = 0; k < 8; k++) { + xs[i][j] = xs[i][j]+CoordCorners[k][j]*DShapeFunction[k][i]; + } + } + } + + /*--- Adjoint to Jacobian ---*/ + + ad[0][0] = xs[1][1]*xs[2][2]-xs[1][2]*xs[2][1]; + ad[0][1] = xs[0][2]*xs[2][1]-xs[0][1]*xs[2][2]; + ad[0][2] = xs[0][1]*xs[1][2]-xs[0][2]*xs[1][1]; + ad[1][0] = xs[1][2]*xs[2][0]-xs[1][0]*xs[2][2]; + ad[1][1] = xs[0][0]*xs[2][2]-xs[0][2]*xs[2][0]; + ad[1][2] = xs[0][2]*xs[1][0]-xs[0][0]*xs[1][2]; + ad[2][0] = xs[1][0]*xs[2][1]-xs[1][1]*xs[2][0]; + ad[2][1] = xs[0][1]*xs[2][0]-xs[0][0]*xs[2][1]; + ad[2][2] = xs[0][0]*xs[1][1]-xs[0][1]*xs[1][0]; + + /*--- Determinant of Jacobian ---*/ + + xsj = xs[0][0]*ad[0][0]+xs[0][1]*ad[1][0]+xs[0][2]*ad[2][0]; + + /*--- Jacobian inverse ---*/ + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + xs[i][j] = ad[i][j]/xsj; + } + } + + /*--- Derivatives with repect to global coordinates ---*/ + + for (k = 0; k < 8; k++) { + c0 = xs[0][0]*DShapeFunction[k][0]+xs[0][1]*DShapeFunction[k][1]+xs[0][2]*DShapeFunction[k][2]; // dN/dx + c1 = xs[1][0]*DShapeFunction[k][0]+xs[1][1]*DShapeFunction[k][1]+xs[1][2]*DShapeFunction[k][2]; // dN/dy + c2 = xs[2][0]*DShapeFunction[k][0]+xs[2][1]*DShapeFunction[k][1]+xs[2][2]*DShapeFunction[k][2]; // dN/dz + DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi + DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta + DShapeFunction[k][2] = c2; // store dN/dz instead of dN/d zeta + } + + return xsj; + +} + +su2double CVolumetricMovement::GetTriangle_Area(su2double CoordCorners[8][3]) { + + unsigned short iDim; + su2double a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}; + su2double *Coord_0, *Coord_1, *Coord_2, Area; + + Coord_0 = CoordCorners[0]; + Coord_1 = CoordCorners[1]; + Coord_2 = CoordCorners[2]; + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = Coord_0[iDim]-Coord_2[iDim]; + b[iDim] = Coord_1[iDim]-Coord_2[iDim]; + } + + Area = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); + + return Area; + +} + +su2double CVolumetricMovement::GetQuadrilateral_Area(su2double CoordCorners[8][3]) { + + unsigned short iDim; + su2double a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}; + su2double *Coord_0, *Coord_1, *Coord_2, Area; + + Coord_0 = CoordCorners[0]; + Coord_1 = CoordCorners[1]; + Coord_2 = CoordCorners[2]; + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = Coord_0[iDim]-Coord_2[iDim]; + b[iDim] = Coord_1[iDim]-Coord_2[iDim]; + } + + Area = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); + + Coord_0 = CoordCorners[0]; + Coord_1 = CoordCorners[2]; + Coord_2 = CoordCorners[3]; + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = Coord_0[iDim]-Coord_2[iDim]; + b[iDim] = Coord_1[iDim]-Coord_2[iDim]; + } + + Area += 0.5*fabs(a[0]*b[1]-a[1]*b[0]); + + return Area; + +} + +su2double CVolumetricMovement::GetTetra_Volume(su2double CoordCorners[8][3]) { + + unsigned short iDim; + su2double *Coord_0, *Coord_1, *Coord_2, *Coord_3; + su2double r1[3] = {0.0,0.0,0.0}, r2[3] = {0.0,0.0,0.0}, r3[3] = {0.0,0.0,0.0}, CrossProduct[3] = {0.0,0.0,0.0}, Volume; + + Coord_0 = CoordCorners[0]; + Coord_1 = CoordCorners[1]; + Coord_2 = CoordCorners[2]; + Coord_3 = CoordCorners[3]; + + for (iDim = 0; iDim < nDim; iDim++) { + r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; + r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; + r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; + } + + CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; + CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; + CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; + + Volume = (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; + + return Volume; + +} + +su2double CVolumetricMovement::GetPyram_Volume(su2double CoordCorners[8][3]) { + + unsigned short iDim; + su2double *Coord_0, *Coord_1, *Coord_2, *Coord_3; + su2double r1[3] = {0.0,0.0,0.0}, r2[3] = {0.0,0.0,0.0}, r3[3] = {0.0,0.0,0.0}, CrossProduct[3] = {0.0,0.0,0.0}, Volume; + + Coord_0 = CoordCorners[0]; + Coord_1 = CoordCorners[1]; + Coord_2 = CoordCorners[2]; + Coord_3 = CoordCorners[4]; + + for (iDim = 0; iDim < nDim; iDim++) { + r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; + r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; + r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; + } + + CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; + CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; + CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; + + Volume = (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; + + Coord_0 = CoordCorners[0]; + Coord_1 = CoordCorners[2]; + Coord_2 = CoordCorners[3]; + Coord_3 = CoordCorners[4]; + + for (iDim = 0; iDim < nDim; iDim++) { + r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; + r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; + r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; + } + + CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; + CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; + CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; + + Volume += (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; + + return Volume; + +} + +su2double CVolumetricMovement::GetPrism_Volume(su2double CoordCorners[8][3]) { + + unsigned short iDim; + su2double *Coord_0, *Coord_1, *Coord_2, *Coord_3; + su2double r1[3] = {0.0,0.0,0.0}, r2[3] = {0.0,0.0,0.0}, r3[3] = {0.0,0.0,0.0}, CrossProduct[3] = {0.0,0.0,0.0}, Volume; + + Coord_0 = CoordCorners[0]; + Coord_1 = CoordCorners[2]; + Coord_2 = CoordCorners[1]; + Coord_3 = CoordCorners[5]; + + for (iDim = 0; iDim < nDim; iDim++) { + r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; + r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; + r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; + } + + CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; + CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; + CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; + + Volume = (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; + + Coord_0 = CoordCorners[0]; + Coord_1 = CoordCorners[5]; + Coord_2 = CoordCorners[1]; + Coord_3 = CoordCorners[4]; + + for (iDim = 0; iDim < nDim; iDim++) { + r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; + r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; + r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; + } + + CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; + CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; + CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; + + Volume += (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; + + Coord_0 = CoordCorners[0]; + Coord_1 = CoordCorners[5]; + Coord_2 = CoordCorners[4]; + Coord_3 = CoordCorners[3]; + + for (iDim = 0; iDim < nDim; iDim++) { + r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; + r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; + r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; + } + + CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; + CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; + CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; + + Volume += (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; + + return Volume; + +} + +su2double CVolumetricMovement::GetHexa_Volume(su2double CoordCorners[8][3]) { + + unsigned short iDim; + su2double *Coord_0, *Coord_1, *Coord_2, *Coord_3; + su2double r1[3] = {0.0,0.0,0.0}, r2[3] = {0.0,0.0,0.0}, r3[3] = {0.0,0.0,0.0}, CrossProduct[3] = {0.0,0.0,0.0}, Volume; + + Coord_0 = CoordCorners[0]; + Coord_1 = CoordCorners[1]; + Coord_2 = CoordCorners[2]; + Coord_3 = CoordCorners[5]; + + for (iDim = 0; iDim < nDim; iDim++) { + r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; + r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; + r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; + } + + CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; + CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; + CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; + + Volume = (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; + + Coord_0 = CoordCorners[0]; + Coord_1 = CoordCorners[2]; + Coord_2 = CoordCorners[7]; + Coord_3 = CoordCorners[5]; + + for (iDim = 0; iDim < nDim; iDim++) { + r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; + r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; + r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; + } + + CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; + CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; + CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; + + Volume += (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; + + Coord_0 = CoordCorners[0]; + Coord_1 = CoordCorners[2]; + Coord_2 = CoordCorners[3]; + Coord_3 = CoordCorners[7]; + + for (iDim = 0; iDim < nDim; iDim++) { + r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; + r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; + r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; + } + + CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; + CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; + CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; + + Volume += (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; + + Coord_0 = CoordCorners[0]; + Coord_1 = CoordCorners[5]; + Coord_2 = CoordCorners[7]; + Coord_3 = CoordCorners[4]; + + for (iDim = 0; iDim < nDim; iDim++) { + r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; + r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; + r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; + } + + CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; + CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; + CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; + + Volume += (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; + + Coord_0 = CoordCorners[2]; + Coord_1 = CoordCorners[7]; + Coord_2 = CoordCorners[5]; + Coord_3 = CoordCorners[6]; + + for (iDim = 0; iDim < nDim; iDim++) { + r1[iDim] = Coord_1[iDim] - Coord_0[iDim]; + r2[iDim] = Coord_2[iDim] - Coord_0[iDim]; + r3[iDim] = Coord_3[iDim] - Coord_0[iDim]; + } + + CrossProduct[0] = (r1[1]*r2[2] - r1[2]*r2[1])*r3[0]; + CrossProduct[1] = (r1[2]*r2[0] - r1[0]*r2[2])*r3[1]; + CrossProduct[2] = (r1[0]*r2[1] - r1[1]*r2[0])*r3[2]; + + Volume += (CrossProduct[0] + CrossProduct[1] + CrossProduct[2])/6.0; + + return Volume; + +} + +void CVolumetricMovement::SetFEA_StiffMatrix2D(CGeometry *geometry, CConfig *config, su2double **StiffMatrix_Elem, unsigned long PointCorners[8], su2double CoordCorners[8][3], unsigned short nNodes, su2double scale) { + + su2double B_Matrix[3][8], D_Matrix[3][3], Aux_Matrix[8][3]; + su2double Xi = 0.0, Eta = 0.0, Det = 0.0, E, Lambda = 0.0, Nu, Mu = 0.0, Avg_Wall_Dist; + unsigned short iNode, jNode, iVar, jVar, kVar, iGauss, nGauss = 0; + su2double DShapeFunction[8][4] = {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, + {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}}; + su2double Location[4][3], Weight[4]; + unsigned short nVar = geometry->GetnDim(); + + for (iVar = 0; iVar < nNodes*nVar; iVar++) { + for (jVar = 0; jVar < nNodes*nVar; jVar++) { + StiffMatrix_Elem[iVar][jVar] = 0.0; + } + } + + /*--- Each element uses their own stiffness which is inversely + proportional to the area/volume of the cell. Using Mu = E & Lambda = -E + is a modification to help allow rigid rotation of elements (see + "Robust Mesh Deformation using the Linear Elasticity Equations" by + R. P. Dwight. ---*/ + + /*--- Integration formulae from "Shape functions and points of + integration of the Résumé" by Josselin DELMAS (2013) ---*/ + + /*--- Triangle. Nodes of numerical integration at 1 point (order 1). ---*/ + + if (nNodes == 3) { + nGauss = 1; + Location[0][0] = 0.333333333333333; Location[0][1] = 0.333333333333333; Weight[0] = 0.5; + } + + /*--- Quadrilateral. Nodes of numerical integration at 4 points (order 2). ---*/ + + if (nNodes == 4) { + nGauss = 4; + Location[0][0] = -0.577350269189626; Location[0][1] = -0.577350269189626; Weight[0] = 1.0; + Location[1][0] = 0.577350269189626; Location[1][1] = -0.577350269189626; Weight[1] = 1.0; + Location[2][0] = 0.577350269189626; Location[2][1] = 0.577350269189626; Weight[2] = 1.0; + Location[3][0] = -0.577350269189626; Location[3][1] = 0.577350269189626; Weight[3] = 1.0; + } + + for (iGauss = 0; iGauss < nGauss; iGauss++) { + + Xi = Location[iGauss][0]; Eta = Location[iGauss][1]; + + if (nNodes == 3) Det = ShapeFunc_Triangle(Xi, Eta, CoordCorners, DShapeFunction); + if (nNodes == 4) Det = ShapeFunc_Quadrilateral(Xi, Eta, CoordCorners, DShapeFunction); + + /*--- Compute the B Matrix ---*/ + + for (iVar = 0; iVar < 3; iVar++) + for (jVar = 0; jVar < nNodes*nVar; jVar++) + B_Matrix[iVar][jVar] = 0.0; + + for (iNode = 0; iNode < nNodes; iNode++) { + B_Matrix[0][0+iNode*nVar] = DShapeFunction[iNode][0]; + B_Matrix[1][1+iNode*nVar] = DShapeFunction[iNode][1]; + + B_Matrix[2][0+iNode*nVar] = DShapeFunction[iNode][1]; + B_Matrix[2][1+iNode*nVar] = DShapeFunction[iNode][0]; + } + + /*--- Impose a type of stiffness for each element ---*/ + + switch (config->GetDeform_Stiffness_Type()) { + + case INVERSE_VOLUME: + E = scale / (Weight[iGauss] * Det) ; + Mu = E; + Lambda = -E; + break; + + case WALL_DISTANCE: + Avg_Wall_Dist = 0.0; + for (jNode = 0; jNode < nNodes; jNode++) { + Avg_Wall_Dist += geometry->node[PointCorners[jNode]]->GetWall_Distance()/((su2double)nNodes); + } + E = scale / (Weight[iGauss] * Avg_Wall_Dist); + Mu = E; + Lambda = -E; + break; + + case CONSTANT_STIFFNESS: + E=config->GetDeform_ElasticityMod(); + Nu=config->GetDeform_PoissonRatio(); + //E = 2E11; Nu = 0.30; + Mu = E / (2.0*(1.0 + Nu)); + Lambda = Nu*E/((1.0+Nu)*(1.0-2.0*Nu)); + break; + } + + /*--- Compute the D Matrix (for plane strain and 3-D)---*/ + + D_Matrix[0][0] = Lambda + 2.0*Mu; D_Matrix[0][1] = Lambda; D_Matrix[0][2] = 0.0; + D_Matrix[1][0] = Lambda; D_Matrix[1][1] = Lambda + 2.0*Mu; D_Matrix[1][2] = 0.0; + D_Matrix[2][0] = 0.0; D_Matrix[2][1] = 0.0; D_Matrix[2][2] = Mu; + + + /*--- Compute the BT.D Matrix ---*/ + + for (iVar = 0; iVar < nNodes*nVar; iVar++) { + for (jVar = 0; jVar < 3; jVar++) { + Aux_Matrix[iVar][jVar] = 0.0; + for (kVar = 0; kVar < 3; kVar++) + Aux_Matrix[iVar][jVar] += B_Matrix[kVar][iVar]*D_Matrix[kVar][jVar]; + } + } + + /*--- Compute the BT.D.B Matrix (stiffness matrix), and add to the original + matrix using Gauss integration ---*/ + + for (iVar = 0; iVar < nNodes*nVar; iVar++) { + for (jVar = 0; jVar < nNodes*nVar; jVar++) { + for (kVar = 0; kVar < 3; kVar++) { + StiffMatrix_Elem[iVar][jVar] += Weight[iGauss] * Aux_Matrix[iVar][kVar]*B_Matrix[kVar][jVar] * Det; + } + } + } + + } + +} + +void CVolumetricMovement::SetFEA_StiffMatrix3D(CGeometry *geometry, CConfig *config, su2double **StiffMatrix_Elem, unsigned long PointCorners[8], su2double CoordCorners[8][3], unsigned short nNodes, su2double scale) { + + su2double B_Matrix[6][24], D_Matrix[6][6] = {{0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}, Aux_Matrix[24][6]; + su2double Xi = 0.0, Eta = 0.0, Zeta = 0.0, Det = 0.0, Mu = 0.0, E = 0.0, Lambda = 0.0, Nu = 0.0, Avg_Wall_Dist; + unsigned short iNode, jNode, iVar, jVar, kVar, iGauss, nGauss = 0; + su2double DShapeFunction[8][4] = {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, + {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}}; + su2double Location[8][3], Weight[8]; + unsigned short nVar = geometry->GetnDim(); + + for (iVar = 0; iVar < nNodes*nVar; iVar++) { + for (jVar = 0; jVar < nNodes*nVar; jVar++) { + StiffMatrix_Elem[iVar][jVar] = 0.0; + } + } + + /*--- Each element uses their own stiffness which is inversely + proportional to the area/volume of the cell. Using Mu = E & Lambda = -E + is a modification to help allow rigid rotation of elements (see + "Robust Mesh Deformation using the Linear Elasticity Equations" by + R. P. Dwight. ---*/ + + /*--- Integration formulae from "Shape functions and points of + integration of the Résumé" by Josselin Delmas (2013) ---*/ + + /*--- Tetrahedrons. Nodes of numerical integration at 1 point (order 1). ---*/ + + if (nNodes == 4) { + nGauss = 1; + Location[0][0] = 0.25; Location[0][1] = 0.25; Location[0][2] = 0.25; Weight[0] = 0.166666666666666; + } + + /*--- Pyramids. Nodes numerical integration at 5 points. ---*/ + + if (nNodes == 5) { + nGauss = 5; + Location[0][0] = 0.5; Location[0][1] = 0.0; Location[0][2] = 0.1531754163448146; Weight[0] = 0.133333333333333; + Location[1][0] = 0.0; Location[1][1] = 0.5; Location[1][2] = 0.1531754163448146; Weight[1] = 0.133333333333333; + Location[2][0] = -0.5; Location[2][1] = 0.0; Location[2][2] = 0.1531754163448146; Weight[2] = 0.133333333333333; + Location[3][0] = 0.0; Location[3][1] = -0.5; Location[3][2] = 0.1531754163448146; Weight[3] = 0.133333333333333; + Location[4][0] = 0.0; Location[4][1] = 0.0; Location[4][2] = 0.6372983346207416; Weight[4] = 0.133333333333333; + } + + /*--- Prism. Nodes of numerical integration at 6 points (order 3 in Xi, order 2 in Eta and Mu ). ---*/ + + if (nNodes == 6) { + nGauss = 6; + Location[0][0] = 0.5; Location[0][1] = 0.5; Location[0][2] = -0.577350269189626; Weight[0] = 0.166666666666666; + Location[1][0] = -0.577350269189626; Location[1][1] = 0.0; Location[1][2] = 0.5; Weight[1] = 0.166666666666666; + Location[2][0] = 0.5; Location[2][1] = -0.577350269189626; Location[2][2] = 0.0; Weight[2] = 0.166666666666666; + Location[3][0] = 0.5; Location[3][1] = 0.5; Location[3][2] = 0.577350269189626; Weight[3] = 0.166666666666666; + Location[4][0] = 0.577350269189626; Location[4][1] = 0.0; Location[4][2] = 0.5; Weight[4] = 0.166666666666666; + Location[5][0] = 0.5; Location[5][1] = 0.577350269189626; Location[5][2] = 0.0; Weight[5] = 0.166666666666666; + } + + /*--- Hexahedrons. Nodes of numerical integration at 6 points (order 3). ---*/ + + if (nNodes == 8) { + nGauss = 8; + Location[0][0] = -0.577350269189626; Location[0][1] = -0.577350269189626; Location[0][2] = -0.577350269189626; Weight[0] = 1.0; + Location[1][0] = -0.577350269189626; Location[1][1] = -0.577350269189626; Location[1][2] = 0.577350269189626; Weight[1] = 1.0; + Location[2][0] = -0.577350269189626; Location[2][1] = 0.577350269189626; Location[2][2] = -0.577350269189626; Weight[2] = 1.0; + Location[3][0] = -0.577350269189626; Location[3][1] = 0.577350269189626; Location[3][2] = 0.577350269189626; Weight[3] = 1.0; + Location[4][0] = 0.577350269189626; Location[4][1] = -0.577350269189626; Location[4][2] = -0.577350269189626; Weight[4] = 1.0; + Location[5][0] = 0.577350269189626; Location[5][1] = -0.577350269189626; Location[5][2] = 0.577350269189626; Weight[5] = 1.0; + Location[6][0] = 0.577350269189626; Location[6][1] = 0.577350269189626; Location[6][2] = -0.577350269189626; Weight[6] = 1.0; + Location[7][0] = 0.577350269189626; Location[7][1] = 0.577350269189626; Location[7][2] = 0.577350269189626; Weight[7] = 1.0; + } + + for (iGauss = 0; iGauss < nGauss; iGauss++) { + + Xi = Location[iGauss][0]; Eta = Location[iGauss][1]; Zeta = Location[iGauss][2]; + + if (nNodes == 4) Det = ShapeFunc_Tetra(Xi, Eta, Zeta, CoordCorners, DShapeFunction); + if (nNodes == 5) Det = ShapeFunc_Pyram(Xi, Eta, Zeta, CoordCorners, DShapeFunction); + if (nNodes == 6) Det = ShapeFunc_Prism(Xi, Eta, Zeta, CoordCorners, DShapeFunction); + if (nNodes == 8) Det = ShapeFunc_Hexa(Xi, Eta, Zeta, CoordCorners, DShapeFunction); + + /*--- Compute the B Matrix ---*/ + + for (iVar = 0; iVar < 6; iVar++) + for (jVar = 0; jVar < nNodes*nVar; jVar++) + B_Matrix[iVar][jVar] = 0.0; + + for (iNode = 0; iNode < nNodes; iNode++) { + B_Matrix[0][0+iNode*nVar] = DShapeFunction[iNode][0]; + B_Matrix[1][1+iNode*nVar] = DShapeFunction[iNode][1]; + B_Matrix[2][2+iNode*nVar] = DShapeFunction[iNode][2]; + + B_Matrix[3][0+iNode*nVar] = DShapeFunction[iNode][1]; + B_Matrix[3][1+iNode*nVar] = DShapeFunction[iNode][0]; + + B_Matrix[4][1+iNode*nVar] = DShapeFunction[iNode][2]; + B_Matrix[4][2+iNode*nVar] = DShapeFunction[iNode][1]; + + B_Matrix[5][0+iNode*nVar] = DShapeFunction[iNode][2]; + B_Matrix[5][2+iNode*nVar] = DShapeFunction[iNode][0]; + } + + /*--- Impose a type of stiffness for each element ---*/ + + switch (config->GetDeform_Stiffness_Type()) { + + case INVERSE_VOLUME: + E = scale / (Weight[iGauss] * Det) ; + Mu = E; + Lambda = -E; + break; + + case WALL_DISTANCE: + Avg_Wall_Dist = 0.0; + for (jNode = 0; jNode < nNodes; jNode++) { + Avg_Wall_Dist += geometry->node[PointCorners[jNode]]->GetWall_Distance()/((su2double)nNodes); + } + E = scale / (Weight[iGauss] * Avg_Wall_Dist); + Mu = E; + Lambda = -E; + break; + + case CONSTANT_STIFFNESS: + E=config->GetDeform_ElasticityMod(); + Nu=config->GetDeform_PoissonRatio(); + //E = 2E11; Nu = 0.30; + Mu = E / (2.0*(1.0 + Nu)); + Lambda = Nu*E/((1.0+Nu)*(1.0-2.0*Nu)); + break; + } + + /*--- Compute the D Matrix (for plane strain and 3-D)---*/ + + D_Matrix[0][0] = Lambda + 2.0*Mu; D_Matrix[0][1] = Lambda; D_Matrix[0][2] = Lambda; + D_Matrix[1][0] = Lambda; D_Matrix[1][1] = Lambda + 2.0*Mu; D_Matrix[1][2] = Lambda; + D_Matrix[2][0] = Lambda; D_Matrix[2][1] = Lambda; D_Matrix[2][2] = Lambda + 2.0*Mu; + D_Matrix[3][3] = Mu; + D_Matrix[4][4] = Mu; + D_Matrix[5][5] = Mu; + + + /*--- Compute the BT.D Matrix ---*/ + + for (iVar = 0; iVar < nNodes*nVar; iVar++) { + for (jVar = 0; jVar < 6; jVar++) { + Aux_Matrix[iVar][jVar] = 0.0; + for (kVar = 0; kVar < 6; kVar++) + Aux_Matrix[iVar][jVar] += B_Matrix[kVar][iVar]*D_Matrix[kVar][jVar]; + } + } + + /*--- Compute the BT.D.B Matrix (stiffness matrix), and add to the original + matrix using Gauss integration ---*/ + + for (iVar = 0; iVar < nNodes*nVar; iVar++) { + for (jVar = 0; jVar < nNodes*nVar; jVar++) { + for (kVar = 0; kVar < 6; kVar++) { + StiffMatrix_Elem[iVar][jVar] += Weight[iGauss] * Aux_Matrix[iVar][kVar]*B_Matrix[kVar][jVar] * Det; + } + } + } + + } + +} + +void CVolumetricMovement::AddFEA_StiffMatrix(CGeometry *geometry, su2double **StiffMatrix_Elem, unsigned long PointCorners[8], unsigned short nNodes) { + + unsigned short iVar, jVar, iDim, jDim; + + unsigned short nVar = geometry->GetnDim(); + + su2double **StiffMatrix_Node; + StiffMatrix_Node = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + StiffMatrix_Node[iVar] = new su2double [nVar]; + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + StiffMatrix_Node[iVar][jVar] = 0.0; + + /*--- Transform the stiffness matrix for the hexahedral element into the + contributions for the individual nodes relative to each other. ---*/ + + for (iVar = 0; iVar < nNodes; iVar++) { + for (jVar = 0; jVar < nNodes; jVar++) { + + for (iDim = 0; iDim < nVar; iDim++) { + for (jDim = 0; jDim < nVar; jDim++) { + StiffMatrix_Node[iDim][jDim] = StiffMatrix_Elem[(iVar*nVar)+iDim][(jVar*nVar)+jDim]; + } + } + + StiffMatrix.AddBlock(PointCorners[iVar], PointCorners[jVar], StiffMatrix_Node); + + } + } + + /*--- Deallocate memory and exit ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + delete [] StiffMatrix_Node[iVar]; + delete [] StiffMatrix_Node; + +} + +void CVolumetricMovement::SetBoundaryDisplacements(CGeometry *geometry, CConfig *config) { + + unsigned short iDim, nDim = geometry->GetnDim(), iMarker, axis = 0; + unsigned long iPoint, total_index, iVertex; + su2double *VarCoord, MeanCoord[3] = {0.0,0.0,0.0}, VarIncrement = 1.0; + + /*--- Get the SU2 module. SU2_CFD will use this routine for dynamically + deforming meshes (MARKER_MOVING), while SU2_DEF will use it for deforming + meshes after imposing design variable surface deformations (DV_MARKER). ---*/ + + unsigned short Kind_SU2 = config->GetKind_SU2(); + + /*--- If requested (no by default) impose the surface deflections in + increments and solve the grid deformation equations iteratively with + successive small deformations. ---*/ + + VarIncrement = 1.0/((su2double)config->GetGridDef_Nonlinear_Iter()); + + /*--- As initialization, set to zero displacements of all the surfaces except the symmetry + plane and the receive boundaries. ---*/ + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (((config->GetMarker_All_KindBC(iMarker) != SYMMETRY_PLANE) ) + && (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE)) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint*nDim + iDim; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + StiffMatrix.DeleteValsRowi(total_index); + } + } + } + } + + /*--- Set to zero displacements of the normal component for the symmetry plane condition ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_KindBC(iMarker) == SYMMETRY_PLANE) ) { + + for (iDim = 0; iDim < nDim; iDim++) MeanCoord[iDim] = 0.0; + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + VarCoord = geometry->node[iPoint]->GetCoord(); + for (iDim = 0; iDim < nDim; iDim++) + MeanCoord[iDim] += VarCoord[iDim]*VarCoord[iDim]; + } + for (iDim = 0; iDim < nDim; iDim++) MeanCoord[iDim] = sqrt(MeanCoord[iDim]); + if (nDim==3){ + if ((MeanCoord[0] <= MeanCoord[1]) && (MeanCoord[0] <= MeanCoord[2])) axis = 0; + if ((MeanCoord[1] <= MeanCoord[0]) && (MeanCoord[1] <= MeanCoord[2])) axis = 1; + if ((MeanCoord[2] <= MeanCoord[0]) && (MeanCoord[2] <= MeanCoord[1])) axis = 2; + } + else{ + if ((MeanCoord[0] <= MeanCoord[1]) ) axis = 0; + if ((MeanCoord[1] <= MeanCoord[0]) ) axis = 1; + } + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + total_index = iPoint*nDim + axis; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + StiffMatrix.DeleteValsRowi(total_index); + } + } + } + + /*--- Set the known displacements, note that some points of the moving surfaces + could be on on the symmetry plane, we should specify DeleteValsRowi again (just in case) ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_CFD)) || + ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DEF)) || + ((config->GetDirectDiff() == D_DESIGN) && (Kind_SU2 == SU2_CFD) && (config->GetMarker_All_DV(iMarker) == YES)) || + ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DOT))) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint*nDim + iDim; + LinSysRes[total_index] = SU2_TYPE::GetValue(VarCoord[iDim] * VarIncrement); + LinSysSol[total_index] = SU2_TYPE::GetValue(VarCoord[iDim] * VarIncrement); + StiffMatrix.DeleteValsRowi(total_index); + } + } + } + } + + /*--- Don't move the nearfield plane ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint*nDim + iDim; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + StiffMatrix.DeleteValsRowi(total_index); + } + } + } + } + + /*--- Move the FSI interfaces ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_FSIinterface(iMarker) != 0) && (Kind_SU2 == SU2_CFD)) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint*nDim + iDim; + LinSysRes[total_index] = SU2_TYPE::GetValue(VarCoord[iDim] * VarIncrement); + LinSysSol[total_index] = SU2_TYPE::GetValue(VarCoord[iDim] * VarIncrement); + StiffMatrix.DeleteValsRowi(total_index); + } + } + } + } + + +} + +void CVolumetricMovement::SetBoundaryDerivatives(CGeometry *geometry, CConfig *config){ + unsigned short iDim, iMarker; + unsigned long iPoint, total_index, iVertex; + + su2double * VarCoord; + unsigned short Kind_SU2 = config->GetKind_SU2(); + if ((config->GetDirectDiff() == D_DESIGN) && (Kind_SU2 == SU2_CFD)){ + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_DV(iMarker) == YES)) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint*nDim + iDim; + LinSysRes[total_index] = SU2_TYPE::GetDerivative(VarCoord[iDim]); + LinSysSol[total_index] = SU2_TYPE::GetDerivative(VarCoord[iDim]); + } + } + } + } + if (LinSysRes.norm() == 0.0) cout << "Warning: Derivatives are zero!" << endl; + } else if (Kind_SU2 == SU2_DOT) { + + for (iPoint = 0; iPoint < nPoint; iPoint++){ + for (iDim = 0; iDim < nDim; iDim++){ + total_index = iPoint*nDim + iDim; + LinSysRes[total_index] = SU2_TYPE::GetValue(geometry->GetSensitivity(iPoint, iDim)); + LinSysSol[total_index] = SU2_TYPE::GetValue(geometry->GetSensitivity(iPoint, iDim)); + } + } + } +} + +void CVolumetricMovement::UpdateGridCoord_Derivatives(CGeometry *geometry, CConfig *config){ + unsigned short iDim, iMarker; + unsigned long iPoint, total_index, iVertex; + su2double *new_coord = new su2double[3]; + + unsigned short Kind_SU2 = config->GetKind_SU2(); + + /*--- Update derivatives of the grid coordinates using the solution of the linear system + after grid deformation (LinSysSol contains the derivatives of the x, y, z displacements). ---*/ + if ((config->GetDirectDiff() == D_DESIGN) && (Kind_SU2 == SU2_CFD)){ + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++){ + new_coord[0] = 0.0; new_coord[1] = 0.0; new_coord[2] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint*nDim + iDim; + new_coord[iDim] = geometry->node[iPoint]->GetCoord(iDim); + SU2_TYPE::SetDerivative(new_coord[iDim], SU2_TYPE::GetValue(LinSysSol[total_index])); + } + geometry->node[iPoint]->SetCoord(new_coord); + } + } else if (Kind_SU2 == SU2_DOT){ + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_DV(iMarker) == YES) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if (geometry->node[iPoint]->GetDomain()){ + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint*nDim + iDim; + geometry->SetSensitivity(iPoint,iDim, LinSysSol[total_index]); + } + } + } + } + } + } + + delete [] new_coord; +} + +void CVolumetricMovement::SetDomainDisplacements(CGeometry *geometry, CConfig *config) { + + unsigned short iDim, nDim = geometry->GetnDim(); + unsigned long iPoint, total_index; + su2double *Coord, *MinCoordValues, *MaxCoordValues, *Hold_GridFixed_Coord; + + MinCoordValues = new su2double [nDim]; + MaxCoordValues = new su2double [nDim]; + + for (iDim = 0; iDim < nDim; iDim++) { + MinCoordValues[iDim] = 0.0; + MaxCoordValues[iDim] = 0.0; + } + + Hold_GridFixed_Coord = config->GetHold_GridFixed_Coord(); + + MinCoordValues[0] = Hold_GridFixed_Coord[0]; + MinCoordValues[1] = Hold_GridFixed_Coord[1]; + MinCoordValues[2] = Hold_GridFixed_Coord[2]; + MaxCoordValues[0] = Hold_GridFixed_Coord[3]; + MaxCoordValues[1] = Hold_GridFixed_Coord[4]; + MaxCoordValues[2] = Hold_GridFixed_Coord[5]; + + /*--- Set to zero displacements of all the points that are not going to be moved + except the surfaces ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + Coord = geometry->node[iPoint]->GetCoord(); + for (iDim = 0; iDim < nDim; iDim++) { + if ((Coord[iDim] < MinCoordValues[iDim]) || (Coord[iDim] > MaxCoordValues[iDim])) { + total_index = iPoint*nDim + iDim; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + StiffMatrix.DeleteValsRowi(total_index); + } + } + } + + delete [] MinCoordValues; + delete [] MaxCoordValues; + +} + +void CVolumetricMovement::Rigid_Rotation(CGeometry *geometry, CConfig *config, + unsigned short iZone, unsigned long iter) { + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Local variables ---*/ + unsigned short iDim, nDim; + unsigned long iPoint; + su2double r[3] = {0.0,0.0,0.0}, rotCoord[3] = {0.0,0.0,0.0}, *Coord; + su2double Center[3] = {0.0,0.0,0.0}, Omega[3] = {0.0,0.0,0.0}, Lref; + su2double dt, Center_Moment[3] = {0.0,0.0,0.0}; + su2double *GridVel, newGridVel[3] = {0.0,0.0,0.0}; + su2double rotMatrix[3][3] = {{0.0,0.0,0.0}, {0.0,0.0,0.0}, {0.0,0.0,0.0}}; + su2double dtheta, dphi, dpsi, cosTheta, sinTheta; + su2double cosPhi, sinPhi, cosPsi, sinPsi; + bool time_spectral = (config->GetUnsteady_Simulation() == TIME_SPECTRAL); + bool adjoint = config->GetAdjoint(); + + /*--- Problem dimension and physical time step ---*/ + nDim = geometry->GetnDim(); + dt = config->GetDelta_UnstTimeND(); + Lref = config->GetLength_Ref(); + + /*--- For time-spectral, motion is the same in each zone (at each instance). + * This is used for calls to the config container ---*/ + if (time_spectral) + iZone = ZONE_0; + + /*--- For the unsteady adjoint, use reverse time ---*/ + if (adjoint) { + /*--- Set the first adjoint mesh position to the final direct one ---*/ + if (iter == 0) dt = ((su2double)config->GetnExtIter()-1)*dt; + /*--- Reverse the rotation direction for the adjoint ---*/ + else dt = -1.0*dt; + } else { + /*--- No rotation at all for the first direct solution ---*/ + if (iter == 0) dt = 0; + } + + /*--- Center of rotation & angular velocity vector from config ---*/ + + Center[0] = config->GetMotion_Origin_X(iZone); + Center[1] = config->GetMotion_Origin_Y(iZone); + Center[2] = config->GetMotion_Origin_Z(iZone); + Omega[0] = (config->GetRotation_Rate_X(iZone)/config->GetOmega_Ref()); + Omega[1] = (config->GetRotation_Rate_Y(iZone)/config->GetOmega_Ref()); + Omega[2] = (config->GetRotation_Rate_Z(iZone)/config->GetOmega_Ref()); + + /*-- Set dt for time-spectral cases ---*/ + if (time_spectral) { + /*--- period of oscillation & compute time interval using nTimeInstances ---*/ + su2double period = config->GetTimeSpectral_Period(); + dt = period * (su2double)iter/(su2double)(config->GetnTimeInstances()); + } + + /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ + + dtheta = Omega[0]*dt; + dphi = Omega[1]*dt; + dpsi = Omega[2]*dt; + + if (rank == MASTER_NODE && iter == 0) { + cout << " Angular velocity: (" << Omega[0] << ", " << Omega[1]; + cout << ", " << Omega[2] << ") rad/s." << endl; + } + + /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ + + cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); + sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ + + rotMatrix[0][0] = cosPhi*cosPsi; + rotMatrix[1][0] = cosPhi*sinPsi; + rotMatrix[2][0] = -sinPhi; + + rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; + rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; + rotMatrix[2][1] = sinTheta*cosPhi; + + rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Loop over and rotate each node in the volume mesh ---*/ + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Coordinates of the current point ---*/ + Coord = geometry->node[iPoint]->GetCoord(); + GridVel = geometry->node[iPoint]->GetGridVel(); + + /*--- Calculate non-dim. position from rotation center ---*/ + r[0] = (Coord[0]-Center[0])/Lref; + r[1] = (Coord[1]-Center[1])/Lref; + if (nDim == 3) r[2] = (Coord[2]-Center[2])/Lref; + + /*--- Compute transformed point coordinates ---*/ + rotCoord[0] = rotMatrix[0][0]*r[0] + + rotMatrix[0][1]*r[1] + + rotMatrix[0][2]*r[2]; + + rotCoord[1] = rotMatrix[1][0]*r[0] + + rotMatrix[1][1]*r[1] + + rotMatrix[1][2]*r[2]; + + rotCoord[2] = rotMatrix[2][0]*r[0] + + rotMatrix[2][1]*r[1] + + rotMatrix[2][2]*r[2]; + + /*--- Cross Product of angular velocity and distance from center. + Note that we have assumed the grid velocities have been set to + an initial value in the plunging routine. ---*/ + + newGridVel[0] = GridVel[0] + Omega[1]*rotCoord[2] - Omega[2]*rotCoord[1]; + newGridVel[1] = GridVel[1] + Omega[2]*rotCoord[0] - Omega[0]*rotCoord[2]; + newGridVel[2] = GridVel[2] + Omega[0]*rotCoord[1] - Omega[1]*rotCoord[0]; + + /*--- Store new node location & grid velocity. Add center. + Do not store the grid velocity if this is an adjoint calculation.---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + geometry->node[iPoint]->SetCoord(iDim, rotCoord[iDim] + Center[iDim]); + if (!adjoint) geometry->node[iPoint]->SetGridVel(iDim, newGridVel[iDim]); + + } + } + + /*--- Set the moment computation center to the new location after + incrementing the position with the rotation. ---*/ + + for (unsigned short jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { + + Center_Moment[0] = config->GetRefOriginMoment_X(jMarker); + Center_Moment[1] = config->GetRefOriginMoment_Y(jMarker); + Center_Moment[2] = config->GetRefOriginMoment_Z(jMarker); + + /*--- Calculate non-dim. position from rotation center ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + r[iDim] = (Center_Moment[iDim]-Center[iDim])/Lref; + if (nDim == 2) r[nDim] = 0.0; + + /*--- Compute transformed point coordinates ---*/ + + rotCoord[0] = rotMatrix[0][0]*r[0] + + rotMatrix[0][1]*r[1] + + rotMatrix[0][2]*r[2]; + + rotCoord[1] = rotMatrix[1][0]*r[0] + + rotMatrix[1][1]*r[1] + + rotMatrix[1][2]*r[2]; + + rotCoord[2] = rotMatrix[2][0]*r[0] + + rotMatrix[2][1]*r[1] + + rotMatrix[2][2]*r[2]; + + config->SetRefOriginMoment_X(jMarker, Center[0]+rotCoord[0]); + config->SetRefOriginMoment_Y(jMarker, Center[1]+rotCoord[1]); + config->SetRefOriginMoment_Z(jMarker, Center[2]+rotCoord[2]); + } + + /*--- After moving all nodes, update geometry class ---*/ + + UpdateDualGrid(geometry, config); + +} + +void CVolumetricMovement::Rigid_Pitching(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter) { + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Local variables ---*/ + su2double r[3] = {0.0,0.0,0.0}, rotCoord[3] = {0.0,0.0,0.0}, *Coord, Center[3] = {0.0,0.0,0.0}, + Omega[3] = {0.0,0.0,0.0}, Ampl[3] = {0.0,0.0,0.0}, Phase[3] = {0.0,0.0,0.0}; + su2double Lref, deltaT, alphaDot[3], *GridVel, newGridVel[3] = {0.0,0.0,0.0}; + su2double rotMatrix[3][3] = {{0.0,0.0,0.0}, {0.0,0.0,0.0}, {0.0,0.0,0.0}}; + su2double dtheta, dphi, dpsi, cosTheta, sinTheta; + su2double cosPhi, sinPhi, cosPsi, sinPsi; + su2double time_new, time_old; + su2double DEG2RAD = PI_NUMBER/180.0; + unsigned short iDim; + unsigned short nDim = geometry->GetnDim(); + unsigned long iPoint; + bool time_spectral = (config->GetUnsteady_Simulation() == TIME_SPECTRAL); + bool adjoint = config->GetAdjoint(); + + /*--- Retrieve values from the config file ---*/ + deltaT = config->GetDelta_UnstTimeND(); + Lref = config->GetLength_Ref(); + + /*--- For time-spectral, motion is the same in each zone (at each instance). ---*/ + if (time_spectral) { + iZone = ZONE_0; + } + + /*--- Pitching origin, frequency, and amplitude from config. ---*/ + Center[0] = config->GetMotion_Origin_X(iZone); + Center[1] = config->GetMotion_Origin_Y(iZone); + Center[2] = config->GetMotion_Origin_Z(iZone); + Omega[0] = (config->GetPitching_Omega_X(iZone)/config->GetOmega_Ref()); + Omega[1] = (config->GetPitching_Omega_Y(iZone)/config->GetOmega_Ref()); + Omega[2] = (config->GetPitching_Omega_Z(iZone)/config->GetOmega_Ref()); + Ampl[0] = config->GetPitching_Ampl_X(iZone)*DEG2RAD; + Ampl[1] = config->GetPitching_Ampl_Y(iZone)*DEG2RAD; + Ampl[2] = config->GetPitching_Ampl_Z(iZone)*DEG2RAD; + Phase[0] = config->GetPitching_Phase_X(iZone)*DEG2RAD; + Phase[1] = config->GetPitching_Phase_Y(iZone)*DEG2RAD; + Phase[2] = config->GetPitching_Phase_Z(iZone)*DEG2RAD; + + if (time_spectral) { + /*--- period of oscillation & compute time interval using nTimeInstances ---*/ + su2double period = config->GetTimeSpectral_Period(); + deltaT = period/(su2double)(config->GetnTimeInstances()); + } + + /*--- Compute delta time based on physical time step ---*/ + if (adjoint) { + /*--- For the unsteady adjoint, we integrate backwards through + physical time, so perform mesh motion in reverse. ---*/ + unsigned long nFlowIter = config->GetnExtIter(); + unsigned long directIter = nFlowIter - iter - 1; + time_new = static_cast(directIter)*deltaT; + time_old = time_new; + if (iter != 0) time_old = (static_cast(directIter)+1.0)*deltaT; + } else { + /*--- Forward time for the direct problem ---*/ + time_new = static_cast(iter)*deltaT; + if (time_spectral) { + /*--- For time-spectral, begin movement from the zero position ---*/ + time_old = 0.0; + } else { + time_old = time_new; + if (iter != 0) time_old = (static_cast(iter)-1.0)*deltaT; + } + } + + /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ + + dtheta = -Ampl[0]*(sin(Omega[0]*time_new + Phase[0]) - sin(Omega[0]*time_old + Phase[0])); + dphi = -Ampl[1]*(sin(Omega[1]*time_new + Phase[1]) - sin(Omega[1]*time_old + Phase[1])); + dpsi = -Ampl[2]*(sin(Omega[2]*time_new + Phase[2]) - sin(Omega[2]*time_old + Phase[2])); + + /*--- Angular velocity at the new time ---*/ + + alphaDot[0] = -Omega[0]*Ampl[0]*cos(Omega[0]*time_new); + alphaDot[1] = -Omega[1]*Ampl[1]*cos(Omega[1]*time_new); + alphaDot[2] = -Omega[2]*Ampl[2]*cos(Omega[2]*time_new); + + if (rank == MASTER_NODE && iter == 0) { + cout << " Pitching frequency: (" << Omega[0] << ", " << Omega[1]; + cout << ", " << Omega[2] << ") rad/s." << endl; + cout << " Pitching amplitude: (" << Ampl[0]/DEG2RAD << ", "; + cout << Ampl[1]/DEG2RAD << ", " << Ampl[2]/DEG2RAD; + cout << ") degrees."<< endl; + cout << " Pitching phase lag: (" << Phase[0]/DEG2RAD << ", "; + cout << Phase[1]/DEG2RAD <<", "<< Phase[2]/DEG2RAD; + cout << ") degrees."<< endl; + } + + /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ + + cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); + sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ + + rotMatrix[0][0] = cosPhi*cosPsi; + rotMatrix[1][0] = cosPhi*sinPsi; + rotMatrix[2][0] = -sinPhi; + + rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; + rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; + rotMatrix[2][1] = sinTheta*cosPhi; + + rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Loop over and rotate each node in the volume mesh ---*/ + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Coordinates of the current point ---*/ + Coord = geometry->node[iPoint]->GetCoord(); + GridVel = geometry->node[iPoint]->GetGridVel(); + + /*--- Calculate non-dim. position from rotation center ---*/ + for (iDim = 0; iDim < nDim; iDim++) + r[iDim] = (Coord[iDim]-Center[iDim])/Lref; + if (nDim == 2) r[nDim] = 0.0; + + /*--- Compute transformed point coordinates ---*/ + rotCoord[0] = rotMatrix[0][0]*r[0] + + rotMatrix[0][1]*r[1] + + rotMatrix[0][2]*r[2]; + + rotCoord[1] = rotMatrix[1][0]*r[0] + + rotMatrix[1][1]*r[1] + + rotMatrix[1][2]*r[2]; + + rotCoord[2] = rotMatrix[2][0]*r[0] + + rotMatrix[2][1]*r[1] + + rotMatrix[2][2]*r[2]; + + /*--- Cross Product of angular velocity and distance from center. + Note that we have assumed the grid velocities have been set to + an initial value in the plunging routine. ---*/ + + newGridVel[0] = GridVel[0] + alphaDot[1]*rotCoord[2] - alphaDot[2]*rotCoord[1]; + newGridVel[1] = GridVel[1] + alphaDot[2]*rotCoord[0] - alphaDot[0]*rotCoord[2]; + newGridVel[2] = GridVel[2] + alphaDot[0]*rotCoord[1] - alphaDot[1]*rotCoord[0]; + + /*--- Store new node location & grid velocity. Add center location. + Do not store the grid velocity if this is an adjoint calculation.---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + geometry->node[iPoint]->SetCoord(iDim, rotCoord[iDim]+Center[iDim]); + if (!adjoint) geometry->node[iPoint]->SetGridVel(iDim, newGridVel[iDim]); + } + } + + /*--- For pitching we don't update the motion origin and moment reference origin. ---*/ + + /*--- After moving all nodes, update geometry class ---*/ + + UpdateDualGrid(geometry, config); + +} + +void CVolumetricMovement::Rigid_Plunging(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter) { + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Local variables ---*/ + su2double deltaX[3], newCoord[3], Center[3], *Coord, Omega[3], Ampl[3], Lref; + su2double *GridVel, newGridVel[3], xDot[3]; + su2double deltaT, time_new, time_old; + unsigned short iDim, nDim = geometry->GetnDim(); + unsigned long iPoint; + bool time_spectral = (config->GetUnsteady_Simulation() == TIME_SPECTRAL); + bool adjoint = config->GetAdjoint(); + + /*--- Retrieve values from the config file ---*/ + deltaT = config->GetDelta_UnstTimeND(); + Lref = config->GetLength_Ref(); + + /*--- For time-spectral, motion is the same in each zone (at each instance). ---*/ + if (time_spectral) { + iZone = ZONE_0; + } + + /*--- Plunging frequency and amplitude from config. ---*/ + Center[0] = config->GetMotion_Origin_X(iZone); + Center[1] = config->GetMotion_Origin_Y(iZone); + Center[2] = config->GetMotion_Origin_Z(iZone); + Omega[0] = (config->GetPlunging_Omega_X(iZone)/config->GetOmega_Ref()); + Omega[1] = (config->GetPlunging_Omega_Y(iZone)/config->GetOmega_Ref()); + Omega[2] = (config->GetPlunging_Omega_Z(iZone)/config->GetOmega_Ref()); + Ampl[0] = config->GetPlunging_Ampl_X(iZone)/Lref; + Ampl[1] = config->GetPlunging_Ampl_Y(iZone)/Lref; + Ampl[2] = config->GetPlunging_Ampl_Z(iZone)/Lref; + + if (time_spectral) { + /*--- period of oscillation & time interval using nTimeInstances ---*/ + su2double period = config->GetTimeSpectral_Period(); + deltaT = period/(su2double)(config->GetnTimeInstances()); + } + + /*--- Compute delta time based on physical time step ---*/ + if (adjoint) { + /*--- For the unsteady adjoint, we integrate backwards through + physical time, so perform mesh motion in reverse. ---*/ + unsigned long nFlowIter = config->GetnExtIter(); + unsigned long directIter = nFlowIter - iter - 1; + time_new = static_cast(directIter)*deltaT; + time_old = time_new; + if (iter != 0) time_old = (static_cast(directIter)+1.0)*deltaT; + } else { + /*--- Forward time for the direct problem ---*/ + time_new = static_cast(iter)*deltaT; + if (time_spectral) { + /*--- For time-spectral, begin movement from the zero position ---*/ + time_old = 0.0; + } else { + time_old = time_new; + if (iter != 0) time_old = (static_cast(iter)-1.0)*deltaT; + } + } + + /*--- Compute delta change in the position in the x, y, & z directions. ---*/ + deltaX[0] = -Ampl[0]*(sin(Omega[0]*time_new) - sin(Omega[0]*time_old)); + deltaX[1] = -Ampl[1]*(sin(Omega[1]*time_new) - sin(Omega[1]*time_old)); + deltaX[2] = -Ampl[2]*(sin(Omega[2]*time_new) - sin(Omega[2]*time_old)); + + /*--- Compute grid velocity due to plunge in the x, y, & z directions. ---*/ + xDot[0] = -Ampl[0]*Omega[0]*(cos(Omega[0]*time_new)); + xDot[1] = -Ampl[1]*Omega[1]*(cos(Omega[1]*time_new)); + xDot[2] = -Ampl[2]*Omega[2]*(cos(Omega[2]*time_new)); + + if (rank == MASTER_NODE && iter == 0) { + cout << " Plunging frequency: (" << Omega[0] << ", " << Omega[1]; + cout << ", " << Omega[2] << ") rad/s." << endl; + cout << " Plunging amplitude: (" << Ampl[0] << ", "; + cout << Ampl[1] << ", " << Ampl[2] << ") m."<< endl; + } + + /*--- Loop over and move each node in the volume mesh ---*/ + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Coordinates of the current point ---*/ + Coord = geometry->node[iPoint]->GetCoord(); + GridVel = geometry->node[iPoint]->GetGridVel(); + + /*--- Increment the node position using the delta values. ---*/ + for (iDim = 0; iDim < nDim; iDim++) + newCoord[iDim] = Coord[iDim] + deltaX[iDim]; + + /*--- Cross Product of angular velocity and distance from center. + Note that we have assumed the grid velocities have been set to + an initial value in the plunging routine. ---*/ + + newGridVel[0] = GridVel[0] + xDot[0]; + newGridVel[1] = GridVel[1] + xDot[1]; + newGridVel[2] = GridVel[2] + xDot[2]; + + /*--- Store new node location & grid velocity. Do not store the grid + velocity if this is an adjoint calculation. ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + geometry->node[iPoint]->SetCoord(iDim, newCoord[iDim]); + if (!adjoint) geometry->node[iPoint]->SetGridVel(iDim, newGridVel[iDim]); + } + } + + /*--- Set the mesh motion center to the new location after + incrementing the position with the rigid translation. This + new location will be used for subsequent pitching/rotation.---*/ + + config->SetMotion_Origin_X(iZone, Center[0]+deltaX[0]); + config->SetMotion_Origin_Y(iZone, Center[1]+deltaX[1]); + config->SetMotion_Origin_Z(iZone, Center[2]+deltaX[2]); + + /*--- As the body origin may have moved, print it to the console ---*/ + +// if (rank == MASTER_NODE) { +// cout << " Body origin: (" << Center[0]+deltaX[0]; +// cout << ", " << Center[1]+deltaX[1] << ", " << Center[2]+deltaX[2]; +// cout << ")." << endl; +// } + + /*--- Set the moment computation center to the new location after + incrementing the position with the plunging. ---*/ + + for (unsigned short jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { + Center[0] = config->GetRefOriginMoment_X(jMarker) + deltaX[0]; + Center[1] = config->GetRefOriginMoment_Y(jMarker) + deltaX[1]; + Center[2] = config->GetRefOriginMoment_Z(jMarker) + deltaX[2]; + config->SetRefOriginMoment_X(jMarker, Center[0]); + config->SetRefOriginMoment_Y(jMarker, Center[1]); + config->SetRefOriginMoment_Z(jMarker, Center[2]); + } + + /*--- After moving all nodes, update geometry class ---*/ + + UpdateDualGrid(geometry, config); + +} + +void CVolumetricMovement::Rigid_Translation(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter) { + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Local variables ---*/ + su2double deltaX[3], newCoord[3], Center[3], *Coord; + su2double xDot[3]; + su2double deltaT, time_new, time_old; + unsigned short iDim, nDim = geometry->GetnDim(); + unsigned long iPoint; + bool time_spectral = (config->GetUnsteady_Simulation() == TIME_SPECTRAL); + bool adjoint = config->GetAdjoint(); + + /*--- Retrieve values from the config file ---*/ + deltaT = config->GetDelta_UnstTimeND(); + + /*--- For time-spectral, motion is the same in each zone (at each instance). ---*/ + if (time_spectral) { + iZone = ZONE_0; + } + + /*--- Get motion center and translation rates from config ---*/ + Center[0] = config->GetMotion_Origin_X(iZone); + Center[1] = config->GetMotion_Origin_Y(iZone); + Center[2] = config->GetMotion_Origin_Z(iZone); + xDot[0] = config->GetTranslation_Rate_X(iZone); + xDot[1] = config->GetTranslation_Rate_Y(iZone); + xDot[2] = config->GetTranslation_Rate_Z(iZone); + + if (time_spectral) { + /*--- period of oscillation & time interval using nTimeInstances ---*/ + su2double period = config->GetTimeSpectral_Period(); + deltaT = period/(su2double)(config->GetnTimeInstances()); + } + + /*--- Compute delta time based on physical time step ---*/ + if (adjoint) { + /*--- For the unsteady adjoint, we integrate backwards through + physical time, so perform mesh motion in reverse. ---*/ + unsigned long nFlowIter = config->GetnExtIter(); + unsigned long directIter = nFlowIter - iter - 1; + time_new = static_cast(directIter)*deltaT; + time_old = time_new; + if (iter != 0) time_old = (static_cast(directIter)+1.0)*deltaT; + } else { + /*--- Forward time for the direct problem ---*/ + time_new = static_cast(iter)*deltaT; + if (time_spectral) { + /*--- For time-spectral, begin movement from the zero position ---*/ + time_old = 0.0; + } else { + time_old = time_new; + if (iter != 0) time_old = (static_cast(iter)-1.0)*deltaT; + } + } + + /*--- Compute delta change in the position in the x, y, & z directions. ---*/ + deltaX[0] = xDot[0]*(time_new-time_old); + deltaX[1] = xDot[1]*(time_new-time_old); + deltaX[2] = xDot[2]*(time_new-time_old); + + if (rank == MASTER_NODE) { + cout << " New physical time: " << time_new << " seconds." << endl; + if (iter == 0) { + cout << " Translational velocity: (" << xDot[0] << ", " << xDot[1]; + cout << ", " << xDot[2] << ") m/s." << endl; + } + } + + /*--- Loop over and move each node in the volume mesh ---*/ + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Coordinates of the current point ---*/ + Coord = geometry->node[iPoint]->GetCoord(); + + /*--- Increment the node position using the delta values. ---*/ + for (iDim = 0; iDim < nDim; iDim++) + newCoord[iDim] = Coord[iDim] + deltaX[iDim]; + + /*--- Store new node location & grid velocity. Do not store the grid + velocity if this is an adjoint calculation. ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + geometry->node[iPoint]->SetCoord(iDim, newCoord[iDim]); + if (!adjoint) geometry->node[iPoint]->SetGridVel(iDim,xDot[iDim]); + } + } + + /*--- Set the mesh motion center to the new location after + incrementing the position with the rigid translation. This + new location will be used for subsequent pitching/rotation.---*/ + + config->SetMotion_Origin_X(iZone, Center[0]+deltaX[0]); + config->SetMotion_Origin_Y(iZone, Center[1]+deltaX[1]); + config->SetMotion_Origin_Z(iZone, Center[2]+deltaX[2]); + + /*--- Set the moment computation center to the new location after + incrementing the position with the translation. ---*/ + + for (unsigned short jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { + Center[0] = config->GetRefOriginMoment_X(jMarker) + deltaX[0]; + Center[1] = config->GetRefOriginMoment_Y(jMarker) + deltaX[1]; + Center[2] = config->GetRefOriginMoment_Z(jMarker) + deltaX[2]; + config->SetRefOriginMoment_X(jMarker, Center[0]); + config->SetRefOriginMoment_Y(jMarker, Center[1]); + config->SetRefOriginMoment_Z(jMarker, Center[2]); + } + + /*--- After moving all nodes, update geometry class ---*/ + + UpdateDualGrid(geometry, config); + +} + +void CVolumetricMovement::SetVolume_Scaling(CGeometry *geometry, CConfig *config, bool UpdateGeo) { + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + unsigned short iDim; + unsigned long iPoint; + su2double newCoord[3] = {0.0,0.0,0.0}, *Coord; + + /*--- The scaling factor is the only input to this option. Currently, + the mesh must be scaled the same amount in all three directions. ---*/ + su2double Scale = config->GetDV_Value(0); + if (rank == MASTER_NODE) { + cout << "Scaling the mesh by a constant factor of " << Scale << "." << endl; + } + + /*--- Loop over and move each node in the volume mesh ---*/ + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Coordinates of the current point ---*/ + Coord = geometry->node[iPoint]->GetCoord(); + + /*--- Scale the node position by the specified factor. ---*/ + for (iDim = 0; iDim < nDim; iDim++) + newCoord[iDim] = Scale*Coord[iDim]; + + /*--- Store the new node location. ---*/ + for (iDim = 0; iDim < nDim; iDim++) { + geometry->node[iPoint]->SetCoord(iDim, newCoord[iDim]); + } + } + + /*--- After moving all nodes, update geometry class ---*/ + if (UpdateGeo) UpdateDualGrid(geometry, config); + +} + +void CVolumetricMovement::SetVolume_Translation(CGeometry *geometry, CConfig *config, bool UpdateGeo) { + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + unsigned short iDim; + unsigned long iPoint; + su2double *Coord, deltaX[3] = {0.0,0.0,0.0}, newCoord[3] = {0.0,0.0,0.0}; + + /*--- Get the unit vector and magnitude of displacement. Note that we + assume this is the first DV entry since it is for mesh translation. + Create the displacement vector from the magnitude and direction. ---*/ + + su2double Ampl = config->GetDV_Value(0); + su2double length = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + deltaX[iDim] = config->GetParamDV(0, iDim); + length += deltaX[iDim]*deltaX[iDim]; + } + length = sqrt(length); + for (iDim = 0; iDim < nDim; iDim++) + deltaX[iDim] = Ampl*deltaX[iDim]/length; + if (rank == MASTER_NODE) { + cout << "Translational displacement: (" << deltaX[0] << ", "; + cout << deltaX[1] << ", " << deltaX[2] << ")." << endl; + } + + /*--- Loop over and move each node in the volume mesh ---*/ + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Coordinates of the current point ---*/ + Coord = geometry->node[iPoint]->GetCoord(); + + /*--- Increment the node position using the delta values. ---*/ + for (iDim = 0; iDim < nDim; iDim++) + newCoord[iDim] = Coord[iDim] + deltaX[iDim]; + + /*--- Store new node location. ---*/ + for (iDim = 0; iDim < nDim; iDim++) { + geometry->node[iPoint]->SetCoord(iDim, newCoord[iDim]); + } + } + + /*--- After moving all nodes, update geometry class ---*/ + if (UpdateGeo) UpdateDualGrid(geometry, config); + +} + +void CVolumetricMovement::SetVolume_Rotation(CGeometry *geometry, CConfig *config, bool UpdateGeo) { + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + unsigned short iDim; + unsigned long iPoint; + su2double x, y, z; + su2double *Coord, deltaX[3] = {0.0,0.0,0.0}, newCoord[3] = {0.0,0.0,0.0}; + + /*--- xyz-coordinates of a point on the line of rotation. */ + su2double a = config->GetParamDV(0, 0); + su2double b = config->GetParamDV(0, 1); + su2double c = 0.0; + if (geometry->GetnDim() == 3) c = config->GetParamDV(0,2); + + /*--- xyz-coordinate of the line's direction vector. ---*/ + su2double u = config->GetParamDV(0, 3)-config->GetParamDV(0, 0); + su2double v = config->GetParamDV(0, 4)-config->GetParamDV(0, 1); + su2double w = 1.0; + if (geometry->GetnDim() == 3) + w = config->GetParamDV(0, 5)-config->GetParamDV(0, 2); + + /*--- The angle of rotation. ---*/ + su2double theta = config->GetDV_Value(0)*PI_NUMBER/180.0; + + /*--- Print to the console. ---*/ + if (rank == MASTER_NODE) { + cout << "Rotation axis vector: (" << u << ", "; + cout << v << ", " << w << ")." << endl; + cout << "Angle of rotation: " << config->GetDV_Value(0); + cout << " degrees." << endl; + } + + /*--- Intermediate values used in computations. ---*/ + su2double u2=u*u; su2double v2=v*v; su2double w2=w*w; + su2double cosT = cos(theta); su2double sinT = sin(theta); + su2double l2 = u2 + v2 + w2; su2double l = sqrt(l2); + + /*--- Loop over and move each node in the volume mesh ---*/ + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Coordinates of the current point ---*/ + Coord = geometry->node[iPoint]->GetCoord(); + + /*--- Displacement for this point due to the rotation. ---*/ + x = Coord[0]; y = Coord[1]; z = 0.0; + if (geometry->GetnDim() == 3) z = Coord[2]; + + deltaX[0] = a*(v2 + w2) + u*(-b*v - c*w + u*x + v*y + w*z) + + (-a*(v2 + w2) + u*(b*v + c*w - v*y - w*z) + (v2 + w2)*x)*cosT + + l*(-c*v + b*w - w*y + v*z)*sinT; + deltaX[0] = deltaX[0]/l2 - x; + + deltaX[1] = b*(u2 + w2) + v*(-a*u - c*w + u*x + v*y + w*z) + + (-b*(u2 + w2) + v*(a*u + c*w - u*x - w*z) + (u2 + w2)*y)*cosT + + l*(c*u - a*w + w*x - u*z)*sinT; + deltaX[1] = deltaX[1]/l2 - y; + + deltaX[2] = c*(u2 + v2) + w*(-a*u - b*v + u*x + v*y + w*z) + + (-c*(u2 + v2) + w*(a*u + b*v - u*x - v*y) + (u2 + v2)*z)*cosT + + l*(-b*u + a*v - v*x + u*y)*sinT; + if (geometry->GetnDim() == 3) deltaX[2] = deltaX[2]/l2 - z; + else deltaX[2] = 0.0; + + /*--- Increment the node position using the delta values. ---*/ + for (iDim = 0; iDim < nDim; iDim++) + newCoord[iDim] = Coord[iDim] + deltaX[iDim]; + + /*--- Store new node location. ---*/ + for (iDim = 0; iDim < nDim; iDim++) { + geometry->node[iPoint]->SetCoord(iDim, newCoord[iDim]); + } + } + + /*--- After moving all nodes, update geometry class ---*/ + if (UpdateGeo) UpdateDualGrid(geometry, config); + +} + +CSurfaceMovement::CSurfaceMovement(void) : CGridMovement() { + nFFDBox = 0; + nLevel = 0; + FFDBoxDefinition = false; +} + +CSurfaceMovement::~CSurfaceMovement(void) {} + +void CSurfaceMovement::SetSurface_Deformation(CGeometry *geometry, CConfig *config) { + + unsigned short iFFDBox, iDV, iLevel, iChild, iParent, jFFDBox, iMarker; + int rank = MASTER_NODE; + string FFDBoxTag; + bool allmoving; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Setting the Free Form Deformation ---*/ + + if (config->GetDesign_Variable(0) == FFD_SETTING) { + + /*--- Definition of the FFD deformation class ---*/ + + FFDBox = new CFreeFormDefBox*[MAX_NUMBER_FFD]; + + /*--- Read the FFD information from the config file ---*/ + + ReadFFDInfo(geometry, config, FFDBox); + + /*--- If there is a FFDBox in the input file ---*/ + + if (nFFDBox != 0) { + + /*--- If the FFDBox was not defined in the input file ---*/ + + if ((rank == MASTER_NODE) && (GetnFFDBox() != 0)) + cout << endl <<"----------------- FFD technique (cartesian -> parametric) ---------------" << endl; + + /*--- Create a unitary FFDBox as baseline for other FFDBoxes shapes ---*/ + + CFreeFormDefBox FFDBox_unitary(1,1,1); + FFDBox_unitary.SetUnitCornerPoints(); + + /*--- Compute the control points of the unitary box, in this case the degree is 1 and the order is 2 ---*/ + + FFDBox_unitary.SetControlPoints_Parallelepiped(); + + for (iFFDBox = 0; iFFDBox < GetnFFDBox(); iFFDBox++) { + + /*--- Compute the support control points for the final FFD using the unitary box ---*/ + + FFDBox_unitary.SetSupportCP(FFDBox[iFFDBox]); + + /*--- Compute control points in the support box ---*/ + + FFDBox_unitary.SetSupportCPChange(FFDBox[iFFDBox]); + + /*--- Compute the parametric coordinates, it also find the points in + the FFDBox using the parametrics coordinates ---*/ + + SetParametricCoord(geometry, config, FFDBox[iFFDBox], iFFDBox); + + /*--- Output original FFD FFDBox ---*/ + + if (rank == MASTER_NODE) { + cout << "Writing a Tecplot file of the FFD boxes." << endl; + FFDBox[iFFDBox]->SetTecplot(geometry, iFFDBox, true); + } + + } + + } + + else { + + cout << "There are not FFD boxes in the mesh file!!" << endl; + exit(EXIT_FAILURE); + + } + + } + + /*--- Free Form deformation based ---*/ + + if ((config->GetDesign_Variable(0) == FFD_CONTROL_POINT_2D) || + (config->GetDesign_Variable(0) == FFD_CAMBER_2D) || + (config->GetDesign_Variable(0) == FFD_THICKNESS_2D) || + (config->GetDesign_Variable(0) == FFD_CONTROL_POINT) || + (config->GetDesign_Variable(0) == FFD_DIHEDRAL_ANGLE) || + (config->GetDesign_Variable(0) == FFD_TWIST_ANGLE) || + (config->GetDesign_Variable(0) == FFD_ROTATION) || + (config->GetDesign_Variable(0) == FFD_CONTROL_SURFACE) || + (config->GetDesign_Variable(0) == FFD_CAMBER) || + (config->GetDesign_Variable(0) == FFD_THICKNESS)) { + + /*--- Definition of the FFD deformation class ---*/ + + FFDBox = new CFreeFormDefBox*[MAX_NUMBER_FFD]; + + /*--- Read the FFD information from the grid file ---*/ + + ReadFFDInfo(geometry, config, FFDBox, config->GetMesh_FileName()); + + /*--- If there is a FFDBox in the input file ---*/ + + if (nFFDBox != 0) { + + /*--- If the FFDBox was not defined in the input file ---*/ + + if (!GetFFDBoxDefinition()) { + + cout << endl << "There is not FFD box definition in the mesh file," << endl; + cout << "run DV_KIND=FFD_SETTING first !!" << endl; + exit(EXIT_FAILURE); + + } + + /*--- Output original FFD FFDBox ---*/ + + if (rank == MASTER_NODE) { + cout << "Writing a Tecplot file of the FFD boxes." << endl; + for (iFFDBox = 0; iFFDBox < GetnFFDBox(); iFFDBox++) { + FFDBox[iFFDBox]->SetTecplot(geometry, iFFDBox, true); + } + } + + /*--- Apply the deformation to the orifinal FFD box ---*/ + + if ((rank == MASTER_NODE) && (GetnFFDBox() != 0)) + cout << endl <<"----------------- FFD technique (parametric -> cartesian) ---------------" << endl; + + /*--- Loop over all the FFD boxes levels ---*/ + + for (iLevel = 0; iLevel < GetnLevel(); iLevel++) { + + /*--- Loop over all FFD FFDBoxes ---*/ + + for (iFFDBox = 0; iFFDBox < GetnFFDBox(); iFFDBox++) { + + /*--- Check the level of the FFD box ---*/ + + if (FFDBox[iFFDBox]->GetLevel() == iLevel) { + + + /*--- Compute intersections of the FFD box with the surface to eliminate design + variables and satisfy surface continuity ---*/ + + if (rank == MASTER_NODE) + cout << "Checking FFD box intersections with the solid surfaces." << endl; + + CheckFFDIntersections(geometry, config, FFDBox[iFFDBox], iFFDBox); + + /*--- Compute the parametric coordinates of the child box + control points (using the parent FFDBox) ---*/ + + for (iChild = 0; iChild < FFDBox[iFFDBox]->GetnChildFFDBox(); iChild++) { + FFDBoxTag = FFDBox[iFFDBox]->GetChildFFDBoxTag(iChild); + for (jFFDBox = 0; jFFDBox < GetnFFDBox(); jFFDBox++) + if (FFDBoxTag == FFDBox[jFFDBox]->GetTag()) break; + SetParametricCoordCP(geometry, config, FFDBox[iFFDBox], FFDBox[jFFDBox]); + } + + /*--- Update the parametric coordinates if it is a child FFDBox ---*/ + + if (iLevel > 0) UpdateParametricCoord(geometry, config, FFDBox[iFFDBox], iFFDBox); + + /*--- Apply the design variables to the control point position ---*/ + + for (iDV = 0; iDV < config->GetnDV(); iDV++) { + switch ( config->GetDesign_Variable(iDV) ) { + case FFD_CONTROL_POINT_2D : SetFFDCPChange_2D(geometry, config, FFDBox[iFFDBox], iDV, false); break; + case FFD_CAMBER_2D : SetFFDCamber_2D(geometry, config, FFDBox[iFFDBox], iDV, false); break; + case FFD_THICKNESS_2D : SetFFDThickness_2D(geometry, config, FFDBox[iFFDBox], iDV, false); break; + case FFD_CONTROL_POINT : SetFFDCPChange(geometry, config, FFDBox[iFFDBox], iDV, false); break; + case FFD_DIHEDRAL_ANGLE : SetFFDDihedralAngle(geometry, config, FFDBox[iFFDBox], iDV, false); break; + case FFD_TWIST_ANGLE : SetFFDTwistAngle(geometry, config, FFDBox[iFFDBox], iDV, false); break; + case FFD_ROTATION : SetFFDRotation(geometry, config, FFDBox[iFFDBox], iDV, false); break; + case FFD_CONTROL_SURFACE : SetFFDControl_Surface(geometry, config, FFDBox[iFFDBox], iDV, false); break; + case FFD_CAMBER : SetFFDCamber(geometry, config, FFDBox[iFFDBox], iDV, false); break; + case FFD_THICKNESS : SetFFDThickness(geometry, config, FFDBox[iFFDBox], iDV, false); break; + } + } + + /*--- Recompute cartesian coordinates using the new control point location ---*/ + + SetCartesianCoord(geometry, config, FFDBox[iFFDBox], iFFDBox); + + /*--- Reparametrization of the parent FFD box ---*/ + + for (iParent = 0; iParent < FFDBox[iFFDBox]->GetnParentFFDBox(); iParent++) { + FFDBoxTag = FFDBox[iFFDBox]->GetParentFFDBoxTag(iParent); + for (jFFDBox = 0; jFFDBox < GetnFFDBox(); jFFDBox++) + if (FFDBoxTag == FFDBox[jFFDBox]->GetTag()) break; + UpdateParametricCoord(geometry, config, FFDBox[jFFDBox], jFFDBox); + } + + /*--- Compute the new location of the control points of the child boxes + (using the parent FFDBox) ---*/ + + for (iChild = 0; iChild < FFDBox[iFFDBox]->GetnChildFFDBox(); iChild++) { + FFDBoxTag = FFDBox[iFFDBox]->GetChildFFDBoxTag(iChild); + for (jFFDBox = 0; jFFDBox < GetnFFDBox(); jFFDBox++) + if (FFDBoxTag == FFDBox[jFFDBox]->GetTag()) break; + GetCartesianCoordCP(geometry, config, FFDBox[iFFDBox], FFDBox[jFFDBox]); + } + } + } + + /*--- Output the deformed FFD Boxes ---*/ + + if (rank == MASTER_NODE) { + cout << "Writing a Tecplot file of the FFD boxes." << endl; + for (iFFDBox = 0; iFFDBox < GetnFFDBox(); iFFDBox++) { + FFDBox[iFFDBox]->SetTecplot(geometry, iFFDBox, false); + } + } + + } + } + + else { + + cout << "There are not FFD boxes in the mesh file!!" << endl; + exit(EXIT_FAILURE); + + } + + } + + /*--- External surface file based ---*/ + + else if (config->GetDesign_Variable(0) == SURFACE_FILE) { + + /*--- Check whether a surface file exists for input ---*/ + ofstream Surface_File; + string filename = config->GetMotion_FileName(); + Surface_File.open(filename.c_str(), ios::in); + + /*--- A surface file does not exist, so write a new one for the + markers that are specified as part of the motion. ---*/ + if (Surface_File.fail()) { + + if (rank == MASTER_NODE) + cout << "No surface file found. Writing a new file: " << filename << "." << endl; + + Surface_File.open(filename.c_str(), ios::out); + Surface_File.precision(15); + unsigned long iMarker, jPoint, GlobalIndex, iVertex; su2double *Coords; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_DV(iMarker) == YES) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + jPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + GlobalIndex = geometry->node[jPoint]->GetGlobalIndex(); + Coords = geometry->node[jPoint]->GetCoord(); + Surface_File << GlobalIndex << "\t" << Coords[0] << "\t" << Coords[1]; + if (geometry->GetnDim() == 2) Surface_File << endl; + else Surface_File << "\t" << Coords[2] << endl; + } + } + } + Surface_File.close(); + + /*--- A surface file exists, so read in the coordinates ---*/ + + } + + else { + Surface_File.close(); + if (rank == MASTER_NODE) cout << "Updating the surface coordinates from the input file." << endl; + SetExternal_Deformation(geometry, config, ZONE_0, 0); + } + + } + + /*--- 2D airfoil Hicks-Henne bump functions ---*/ + + else if (config->GetDesign_Variable(0) == HICKS_HENNE) { + + /*--- Apply rotation, displacement and stretching design variables (this + should be done before the bump function design variables) ---*/ + + for (iDV = 0; iDV < config->GetnDV(); iDV++) { + switch ( config->GetDesign_Variable(iDV) ) { + case SCALE : SetScale(geometry, config, iDV, false); break; + case TRANSLATION : SetTranslation(geometry, config, iDV, false); break; + case ROTATION : SetRotation(geometry, config, iDV, false); break; + } + } + + /*--- Apply the design variables to the control point position ---*/ + + for (iDV = 0; iDV < config->GetnDV(); iDV++) { + switch ( config->GetDesign_Variable(iDV) ) { + case HICKS_HENNE : SetHicksHenne(geometry, config, iDV, false); break; + } + } + + } + + /*--- NACA_4Digits design variable ---*/ + + else if (config->GetDesign_Variable(0) == NACA_4DIGITS) { SetNACA_4Digits(geometry, config); } + + /*--- Parabolic airfoil design variable ---*/ + + else if (config->GetDesign_Variable(0) == PARABOLIC) { SetParabolic(geometry, config); } + + /*--- Airfoil from file design variable ---*/ + + else if (config->GetDesign_Variable(0) == AIRFOIL) { SetAirfoil(geometry, config); } + + /*--- FFD setting ---*/ + + else if (config->GetDesign_Variable(0) == FFD_SETTING) { + if (rank == MASTER_NODE) + cout << "No surface deformation (setting FFD)." << endl; + } + + /*--- Scale, Translate, and Rotate will be done with rigid mesh transforms. ---*/ + + else if ((config->GetDesign_Variable(0) == ROTATION) || + (config->GetDesign_Variable(0) == TRANSLATION) || + (config->GetDesign_Variable(0) == SCALE)) { + + /*--- If all markers are deforming, use volume method. + If only some are deforming, use surface method ---*/ + + /*--- iDV was uninitialized, so hard-coding to one. Check intended + behavior (might want to loop over all iDV in case we have trans & rotate. ---*/ + iDV = 0; + allmoving = true; + + /*--- Loop over markers ---*/ + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++){ + if (config->GetMarker_All_DV(iMarker) == NO) + allmoving = false; + } + + if (!allmoving){ + /*---Only some markers are moving, use the surface method ---*/ + if (config->GetDesign_Variable(0) == ROTATION) + SetRotation(geometry, config, iDV, false); + if (config->GetDesign_Variable(0) == SCALE) + SetScale(geometry, config, iDV, false); + if (config->GetDesign_Variable(0) == TRANSLATION) + SetTranslation(geometry, config, iDV, false); + } + else{ + if (rank == MASTER_NODE) + cout << "No surface deformation (scaling, rotation, or translation)." << endl; + } + } + + /*--- Design variable not implement ---*/ + + else { + if (rank == MASTER_NODE) + cout << "Design Variable not implement yet" << endl; + } + +} + + +void CSurfaceMovement::SetSurface_Derivative(CGeometry *geometry, CConfig *config){ + + su2double DV_Value = 0.0; + + unsigned short iDV = 0; + + for (iDV = 0; iDV < config->GetnDV(); iDV++){ + + DV_Value = config->GetDV_Value(iDV); + + /*--- If value of the design variable is not 0.0 we apply the differentation. + * Note if multiple variables are non-zero, we end up with the sum of all the derivatives. ---*/ + + if (DV_Value != 0.0){ + + DV_Value = 0.0; + + SU2_TYPE::SetDerivative(DV_Value, 1.0); + + config->SetDV_Value(iDV, DV_Value); + } + } + + /*--- Run the surface deformation with DV_Value = 0.0 (no deformation at all) ---*/ + + SetSurface_Deformation(geometry, config); +} + +void CSurfaceMovement::CopyBoundary(CGeometry *geometry, CConfig *config) { + + unsigned short iMarker; + unsigned long iVertex, iPoint; + su2double *Coord; + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Coord = geometry->node[iPoint]->GetCoord(); + geometry->vertex[iMarker][iVertex]->SetCoord(Coord); + } + } + +} + +void CSurfaceMovement::SetParametricCoord(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iFFDBox) { + + unsigned short iMarker, iDim, iOrder, jOrder, kOrder, lOrder, mOrder, nOrder; + unsigned long iVertex, iPoint, TotalVertex = 0; + su2double *CartCoordNew, *ParamCoord, CartCoord[3], ParamCoordGuess[3], MaxDiff, my_MaxDiff = 0.0, Diff, *Coord; + int rank; + unsigned short nDim = geometry->GetnDim(); + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#else + rank = MASTER_NODE; +#endif + + /*--- Change order and control points reduce the + complexity of the point inversion (this only works with boxes, + and we maintain an internal copy) ---*/ + + for (iOrder = 0; iOrder < 2; iOrder++) { + for (jOrder = 0; jOrder < 2; jOrder++) { + for (kOrder = 0; kOrder < 2; kOrder++) { + + lOrder = 0; mOrder = 0; nOrder = 0; + if (iOrder == 1) {lOrder = FFDBox->GetlOrder()-1;} + if (jOrder == 1) {mOrder = FFDBox->GetmOrder()-1;} + if (kOrder == 1) {nOrder = FFDBox->GetnOrder()-1;} + + Coord = FFDBox->GetCoordControlPoints(lOrder, mOrder, nOrder); + + FFDBox->SetCoordControlPoints(Coord, iOrder, jOrder, kOrder); + + } + } + } + + FFDBox->SetlOrder(2); FFDBox->SetmOrder(2); FFDBox->SetnOrder(2); + FFDBox->SetnControlPoints(); + + /*--- Point inversion algorithm with a basic box ---*/ + + ParamCoordGuess[0] = 0.5; ParamCoordGuess[1] = 0.5; ParamCoordGuess[2] = 0.5; + CartCoord[0] = 0.0; CartCoord[1] = 0.0; CartCoord[2] = 0.0; + + /*--- Count the number of vertices ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_DV(iMarker) == YES) + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) + TotalVertex++; + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if (config->GetMarker_All_DV(iMarker) == YES) { + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + /*--- Get the cartesian coordinates ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + CartCoord[iDim] = geometry->vertex[iMarker][iVertex]->GetCoord(iDim); + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + /*--- If the point is inside the FFD, compute the value of the parametric coordinate ---*/ + + if (FFDBox->GetPointFFD(geometry, config, iPoint)) { + + /*--- Find the parametric coordinate ---*/ + + ParamCoord = FFDBox->GetParametricCoord_Iterative(iPoint, CartCoord, ParamCoordGuess, config); + + /*--- If the parametric coordinates are in (0,1) the point belongs to the FFDBox ---*/ + + if (((ParamCoord[0] >= - EPS) && (ParamCoord[0] <= 1.0 + EPS)) && + ((ParamCoord[1] >= - EPS) && (ParamCoord[1] <= 1.0 + EPS)) && + ((ParamCoord[2] >= - EPS) && (ParamCoord[2] <= 1.0 + EPS))) { + + /*--- Set the value of the parametric coordinate ---*/ + + FFDBox->Set_MarkerIndex(iMarker); + FFDBox->Set_VertexIndex(iVertex); + FFDBox->Set_PointIndex(iPoint); + FFDBox->Set_ParametricCoord(ParamCoord); + FFDBox->Set_CartesianCoord(CartCoord); + + /*--- Compute the cartesian coordinates using the parametric coordinates + to check that everithing is right ---*/ + + CartCoordNew = FFDBox->EvalCartesianCoord(ParamCoord); + + /*--- Compute max difference between original value and the recomputed value ---*/ + + Diff = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Diff += (CartCoordNew[iDim]-CartCoord[iDim])*(CartCoordNew[iDim]-CartCoord[iDim]); + Diff = sqrt(Diff); + my_MaxDiff = max(my_MaxDiff, Diff); + + ParamCoordGuess[0] = ParamCoord[0]; ParamCoordGuess[1] = ParamCoord[1]; ParamCoordGuess[2] = ParamCoord[2]; + + } + else { + cout << "Please check this point: (" << ParamCoord[0] <<" "<< ParamCoord[1] <<" "<< ParamCoord[2] <<") <-> (" + << CartCoord[0] <<" "<< CartCoord[1] <<" "<< CartCoord[2] <<")."<< endl; + } + + } + } + } + } + +#ifdef HAVE_MPI + SU2_MPI::Allreduce(&my_MaxDiff, &MaxDiff, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); +#else + MaxDiff = my_MaxDiff; +#endif + + if (rank == MASTER_NODE) + cout << "Compute parametric coord | FFD box: " << FFDBox->GetTag() << ". Max Diff: " << MaxDiff <<"."<< endl; + + + /*--- After the point inversion, copy the original information back ---*/ + + FFDBox->SetOriginalControlPoints(); + +} + +void CSurfaceMovement::SetParametricCoordCP(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBoxParent, CFreeFormDefBox *FFDBoxChild) { + unsigned short iOrder, jOrder, kOrder; + su2double *CartCoord, *ParamCoord, ParamCoordGuess[3]; + int rank; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#else + rank = MASTER_NODE; +#endif + + for (iOrder = 0; iOrder < FFDBoxChild->GetlOrder(); iOrder++) + for (jOrder = 0; jOrder < FFDBoxChild->GetmOrder(); jOrder++) + for (kOrder = 0; kOrder < FFDBoxChild->GetnOrder(); kOrder++) { + CartCoord = FFDBoxChild->GetCoordControlPoints(iOrder, jOrder, kOrder); + ParamCoord = FFDBoxParent->GetParametricCoord_Iterative(0, CartCoord, ParamCoordGuess, config); + FFDBoxChild->SetParCoordControlPoints(ParamCoord, iOrder, jOrder, kOrder); + } + + if (rank == MASTER_NODE) + cout << "Compute parametric coord (CP) | FFD parent box: " << FFDBoxParent->GetTag() << ". FFD child box: " << FFDBoxChild->GetTag() <<"."<< endl; + + +} + +void CSurfaceMovement::GetCartesianCoordCP(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBoxParent, CFreeFormDefBox *FFDBoxChild) { + unsigned short iOrder, jOrder, kOrder, iDim; + su2double *CartCoord, *ParamCoord; + int rank; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#else + rank = MASTER_NODE; +#endif + + for (iOrder = 0; iOrder < FFDBoxChild->GetlOrder(); iOrder++) + for (jOrder = 0; jOrder < FFDBoxChild->GetmOrder(); jOrder++) + for (kOrder = 0; kOrder < FFDBoxChild->GetnOrder(); kOrder++) { + ParamCoord = FFDBoxChild->GetParCoordControlPoints(iOrder, jOrder, kOrder); + + /*--- Clip the value of the parametric coordinates (just in case) ---*/ + for (iDim = 0; iDim < 3; iDim++) { + if (ParamCoord[iDim] >= 1.0) ParamCoord[iDim] = 1.0; + if (ParamCoord[iDim] <= 0.0) ParamCoord[iDim] = 0.0; + } + + CartCoord = FFDBoxParent->EvalCartesianCoord(ParamCoord); + FFDBoxChild->SetCoordControlPoints(CartCoord, iOrder, jOrder, kOrder); + FFDBoxChild->SetCoordControlPoints_Copy(CartCoord, iOrder, jOrder, kOrder); + + } + + if (rank == MASTER_NODE) + cout << "Update cartesian coord (CP) | FFD parent box: " << FFDBoxParent->GetTag() << ". FFD child box: " << FFDBoxChild->GetTag() <<"."<< endl; + +} + +void CSurfaceMovement::CheckFFDIntersections(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iFFDBox) { + + su2double *Coord_0, *Coord_1; + unsigned short iMarker, iNode, jNode, lDegree, mDegree, nDegree; + unsigned long iElem, iPoint, jPoint; + + unsigned short Kind_SU2 = config->GetKind_SU2(); + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + lDegree = FFDBox->GetlOrder()-1; + mDegree = FFDBox->GetmOrder()-1; + nDegree = FFDBox->GetnOrder()-1; + + /*--- Check intersection with plane i=0 ---*/ + + su2double *IPlane_Coord_0_A = FFDBox->GetCoordControlPoints(0, 0, 0); + su2double *IPlane_Coord_1_A = FFDBox->GetCoordControlPoints(0, 0, nDegree); + su2double *IPlane_Coord_2_A = FFDBox->GetCoordControlPoints(0, mDegree, 0); + + su2double *IPlane_Coord_0_A_ = FFDBox->GetCoordControlPoints(0, mDegree, nDegree); + su2double *IPlane_Coord_1_A_ = FFDBox->GetCoordControlPoints(0, mDegree, 0); + su2double *IPlane_Coord_2_A_ = FFDBox->GetCoordControlPoints(0, 0, nDegree); + + /*--- Check intersection with plane i=lDegree ---*/ + + su2double *IPlane_Coord_0_B = FFDBox->GetCoordControlPoints(lDegree, 0, 0); + su2double *IPlane_Coord_1_B = FFDBox->GetCoordControlPoints(lDegree, 0, nDegree); + su2double *IPlane_Coord_2_B = FFDBox->GetCoordControlPoints(lDegree, mDegree, 0); + + su2double *IPlane_Coord_0_B_ = FFDBox->GetCoordControlPoints(lDegree, mDegree, nDegree); + su2double *IPlane_Coord_1_B_ = FFDBox->GetCoordControlPoints(lDegree, mDegree, 0); + su2double *IPlane_Coord_2_B_ = FFDBox->GetCoordControlPoints(lDegree, 0, nDegree); + + /*--- Check intersection with plane j=0 ---*/ + + su2double *JPlane_Coord_0_A = FFDBox->GetCoordControlPoints(0, 0, 0); + su2double *JPlane_Coord_1_A = FFDBox->GetCoordControlPoints(0, 0, nDegree); + su2double *JPlane_Coord_2_A = FFDBox->GetCoordControlPoints(lDegree, 0, 0); + + su2double *JPlane_Coord_0_A_ = FFDBox->GetCoordControlPoints(lDegree, 0, nDegree); + su2double *JPlane_Coord_1_A_ = FFDBox->GetCoordControlPoints(lDegree, 0, 0); + su2double *JPlane_Coord_2_A_ = FFDBox->GetCoordControlPoints(0, 0, nDegree); + + /*--- Check intersection with plane j=mDegree ---*/ + + su2double *JPlane_Coord_0_B = FFDBox->GetCoordControlPoints(0, mDegree, 0); + su2double *JPlane_Coord_1_B = FFDBox->GetCoordControlPoints(0, mDegree, nDegree); + su2double *JPlane_Coord_2_B = FFDBox->GetCoordControlPoints(lDegree, mDegree, 0); + + su2double *JPlane_Coord_0_B_ = FFDBox->GetCoordControlPoints(lDegree, mDegree, nDegree); + su2double *JPlane_Coord_1_B_ = FFDBox->GetCoordControlPoints(lDegree, mDegree, 0); + su2double *JPlane_Coord_2_B_ = FFDBox->GetCoordControlPoints(0, mDegree, nDegree); + + /*--- Check intersection with plane k=0 ---*/ + + su2double *KPlane_Coord_0_A = FFDBox->GetCoordControlPoints(0, 0, 0); + su2double *KPlane_Coord_1_A = FFDBox->GetCoordControlPoints(0, mDegree, 0); + su2double *KPlane_Coord_2_A = FFDBox->GetCoordControlPoints(lDegree, 0, 0); + + su2double *KPlane_Coord_0_A_ = FFDBox->GetCoordControlPoints(lDegree, mDegree, 0); + su2double *KPlane_Coord_1_A_ = FFDBox->GetCoordControlPoints(lDegree, 0, 0); + su2double *KPlane_Coord_2_A_ = FFDBox->GetCoordControlPoints(0, mDegree, 0); + + /*--- Check intersection with plane k=nDegree ---*/ + + su2double *KPlane_Coord_0_B = FFDBox->GetCoordControlPoints(0, 0, nDegree); + su2double *KPlane_Coord_1_B = FFDBox->GetCoordControlPoints(0, mDegree, nDegree); + su2double *KPlane_Coord_2_B = FFDBox->GetCoordControlPoints(lDegree, 0, nDegree); + + su2double *KPlane_Coord_0_B_ = FFDBox->GetCoordControlPoints(lDegree, mDegree, nDegree); + su2double *KPlane_Coord_1_B_ = FFDBox->GetCoordControlPoints(lDegree, 0, nDegree); + su2double *KPlane_Coord_2_B_ = FFDBox->GetCoordControlPoints(0, mDegree, nDegree); + + /*--- Loop over all the grid triangles ---*/ + + bool IPlane_Intersect_A = false, IPlane_Intersect_B = false; + bool JPlane_Intersect_A = false, JPlane_Intersect_B = false; + bool KPlane_Intersect_A = false, KPlane_Intersect_B = false; + + /*--- Only the markers in the moving list ---*/ + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_CFD)) || + ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DEF)) || + ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_GEO)) || + ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DOT)) || + ((config->GetMarker_All_DV(iMarker) == YES) && (config->GetDirectDiff() == D_DESIGN))) { + for (iElem = 0; iElem < geometry->GetnElem_Bound(iMarker); iElem++) { + for (iNode = 0; iNode < geometry->bound[iMarker][iElem]->GetnNodes(); iNode++) { + iPoint = geometry->bound[iMarker][iElem]->GetNode(iNode); + for (jNode = 0; jNode < geometry->bound[iMarker][iElem]->GetnNodes(); jNode++) { + jPoint = geometry->bound[iMarker][iElem]->GetNode(jNode); + + if (jPoint > iPoint) { + + Coord_0 = geometry->node[iPoint]->GetCoord(); + Coord_1 = geometry->node[jPoint]->GetCoord(); + + if (!IPlane_Intersect_A) { + if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, IPlane_Coord_0_A, IPlane_Coord_1_A, IPlane_Coord_2_A)) { IPlane_Intersect_A = true; } + if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, IPlane_Coord_0_A_, IPlane_Coord_1_A_, IPlane_Coord_2_A_)) { IPlane_Intersect_A = true; } + } + + if (!IPlane_Intersect_B) { + if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, IPlane_Coord_0_B, IPlane_Coord_1_B, IPlane_Coord_2_B)) { IPlane_Intersect_B = true; } + if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, IPlane_Coord_0_B_, IPlane_Coord_1_B_, IPlane_Coord_2_B_)) { IPlane_Intersect_B = true; } + } + + if (!JPlane_Intersect_A) { + if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, JPlane_Coord_0_A, JPlane_Coord_1_A, JPlane_Coord_2_A)) { JPlane_Intersect_A = true; } + if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, JPlane_Coord_0_A_, JPlane_Coord_1_A_, JPlane_Coord_2_A_)) { JPlane_Intersect_A = true; } + } + + if (!JPlane_Intersect_B) { + if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, JPlane_Coord_0_B, JPlane_Coord_1_B, JPlane_Coord_2_B)) { JPlane_Intersect_B = true; } + if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, JPlane_Coord_0_B_, JPlane_Coord_1_B_, JPlane_Coord_2_B_)) { JPlane_Intersect_B = true; } + } + + if (!KPlane_Intersect_A) { + if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, KPlane_Coord_0_A, KPlane_Coord_1_A, KPlane_Coord_2_A)) { KPlane_Intersect_A = true; } + if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, KPlane_Coord_0_A_, KPlane_Coord_1_A_, KPlane_Coord_2_A_)) { KPlane_Intersect_A = true; } + } + + if (!KPlane_Intersect_B) { + if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, KPlane_Coord_0_B, KPlane_Coord_1_B, KPlane_Coord_2_B)) { KPlane_Intersect_B = true; } + if (geometry->SegmentIntersectsTriangle(Coord_0, Coord_1, KPlane_Coord_0_B_, KPlane_Coord_1_B_, KPlane_Coord_2_B_)) { KPlane_Intersect_B = true; } + } + + } + } + } + } + } + } + + /*--- Comunicate the planes that interesect the surface ---*/ + + unsigned short MyCode[6] = {0,0,0,0,0,0}, Code[6] = {0,0,0,0,0,0}; + + if (IPlane_Intersect_A) MyCode[0] = 1; + if (IPlane_Intersect_B) MyCode[1] = 1; + if (JPlane_Intersect_A) MyCode[2] = 1; + if (JPlane_Intersect_B) MyCode[3] = 1; + if (KPlane_Intersect_A) MyCode[4] = 1; + if (KPlane_Intersect_B) MyCode[5] = 1; + +#ifdef HAVE_MPI + + /*--- Add SU2_MPI::Allreduce information using all the nodes ---*/ + + SU2_MPI::Allreduce(&MyCode, &Code, 6, MPI_UNSIGNED_SHORT, MPI_SUM, MPI_COMM_WORLD); + +#else + + Code[0] = MyCode[0]; Code[1] = MyCode[1]; Code[2] = MyCode[2]; + Code[3] = MyCode[3]; Code[4] = MyCode[4]; Code[5] = MyCode[5]; + +#endif + + if (Code[0] != 0) IPlane_Intersect_A = true; else IPlane_Intersect_A = false; + if (Code[1] != 0) IPlane_Intersect_B = true; else IPlane_Intersect_B = false; + if (Code[2] != 0) JPlane_Intersect_A = true; else JPlane_Intersect_A = false; + if (Code[3] != 0) JPlane_Intersect_B = true; else JPlane_Intersect_B = false; + if (Code[4] != 0) KPlane_Intersect_A = true; else KPlane_Intersect_A = false; + if (Code[5] != 0) KPlane_Intersect_B = true; else KPlane_Intersect_B = false; + + /*--- Screen output ---*/ + + if (rank == MASTER_NODE) { + + if (IPlane_Intersect_A || IPlane_Intersect_B || + JPlane_Intersect_A || JPlane_Intersect_B || + KPlane_Intersect_A || KPlane_Intersect_B ) { + cout << "The FFD planes "; + if (IPlane_Intersect_A) cout << "i=0, "; + if (IPlane_Intersect_B) cout << "i="<< lDegree << ", "; + if (JPlane_Intersect_A) cout << "j=0, "; + if (JPlane_Intersect_B) cout << "j="<< mDegree << ", "; + if (KPlane_Intersect_A) cout << "k=0, "; + if (KPlane_Intersect_B) cout << "k="<< nDegree << ", "; + cout << "intersect solid surfaces." << endl; + } + + } + + /*--- Fix the FFD planes based on the intersections with solid surfaces, + and the continuity level, check that we have enough degree for the continuity + that we are looking for ---*/ + + if (IPlane_Intersect_A) { FFDBox->Set_Fix_IPlane(0); FFDBox->Set_Fix_IPlane(1); } + if (IPlane_Intersect_B) { FFDBox->Set_Fix_IPlane(lDegree); FFDBox->Set_Fix_IPlane(lDegree-1); } + + if (JPlane_Intersect_A) { FFDBox->Set_Fix_JPlane(0); FFDBox->Set_Fix_JPlane(1); } + if (JPlane_Intersect_B) { FFDBox->Set_Fix_JPlane(mDegree); FFDBox->Set_Fix_JPlane(mDegree-1); } + + if (KPlane_Intersect_A) { FFDBox->Set_Fix_KPlane(0); FFDBox->Set_Fix_KPlane(1); } + if (KPlane_Intersect_B) { FFDBox->Set_Fix_KPlane(nDegree); FFDBox->Set_Fix_KPlane(nDegree-1); } + + if (config->GetFFD_Continuity() == DERIVATIVE_2ND) { + + if ((IPlane_Intersect_A) && (lDegree > 1)) { FFDBox->Set_Fix_IPlane(2); } + if ((IPlane_Intersect_B) && (lDegree > 1)) { FFDBox->Set_Fix_IPlane(lDegree-2); } + + if ((JPlane_Intersect_A) && (mDegree > 1)) { FFDBox->Set_Fix_JPlane(2); } + if ((JPlane_Intersect_B) && (mDegree > 1)) { FFDBox->Set_Fix_JPlane(mDegree-2); } + + if ((KPlane_Intersect_A) && (nDegree > 1)) { FFDBox->Set_Fix_KPlane(2); } + if ((KPlane_Intersect_B) && (nDegree > 1)) { FFDBox->Set_Fix_KPlane(nDegree-2); } + + } + +} + +void CSurfaceMovement::UpdateParametricCoord(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iFFDBox) { + unsigned short iMarker, iDim; + unsigned long iVertex, iPoint, iSurfacePoints; + su2double CartCoord[3] = {0.0,0.0,0.0}, *CartCoordNew, *CartCoordOld; + su2double *ParamCoord, *var_coord, ParamCoordGuess[3] = {0.0,0.0,0.0}; + su2double MaxDiff, my_MaxDiff = 0.0, Diff; + int rank; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#else + rank = MASTER_NODE; +#endif + + /*--- Recompute the parametric coordinates ---*/ + + for (iSurfacePoints = 0; iSurfacePoints < FFDBox->GetnSurfacePoint(); iSurfacePoints++) { + + /*--- Get the marker of the surface point ---*/ + + iMarker = FFDBox->Get_MarkerIndex(iSurfacePoints); + + if (config->GetMarker_All_DV(iMarker) == YES) { + + /*--- Get the vertex of the surface point ---*/ + + iVertex = FFDBox->Get_VertexIndex(iSurfacePoints); + iPoint = FFDBox->Get_PointIndex(iSurfacePoints); + + /*--- Get the parametric and cartesians coordinates of the + surface point (they don't mach) ---*/ + + ParamCoord = FFDBox->Get_ParametricCoord(iSurfacePoints); + + /*--- Compute and set the cartesian coord using the variation computed + with the previous deformation ---*/ + + var_coord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); + CartCoordOld = geometry->node[iPoint]->GetCoord(); + for (iDim = 0; iDim < 3; iDim++) + CartCoord[iDim] = CartCoordOld[iDim] + var_coord[iDim]; + FFDBox->Set_CartesianCoord(CartCoord, iSurfacePoints); + + /*--- Find the parametric coordinate using as ParamCoordGuess the previous value ---*/ + + ParamCoordGuess[0] = ParamCoord[0]; ParamCoordGuess[1] = ParamCoord[1]; ParamCoordGuess[2] = ParamCoord[2]; + ParamCoord = FFDBox->GetParametricCoord_Iterative(iPoint, CartCoord, ParamCoordGuess, config); + + /*--- Set the new value of the parametric coordinates ---*/ + + FFDBox->Set_ParametricCoord(ParamCoord, iSurfacePoints); + + /*--- Compute the cartesian coordinates using the parametric coordinates + to check that everithing is right ---*/ + + CartCoordNew = FFDBox->EvalCartesianCoord(ParamCoord); + + /*--- Compute max difference between original value and the recomputed value ---*/ + + Diff = 0.0; + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) + Diff += (CartCoordNew[iDim]-CartCoord[iDim])*(CartCoordNew[iDim]-CartCoord[iDim]); + Diff = sqrt(Diff); + my_MaxDiff = max(my_MaxDiff, Diff); + + } + } + +#ifdef HAVE_MPI + SU2_MPI::Allreduce(&my_MaxDiff, &MaxDiff, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); +#else + MaxDiff = my_MaxDiff; +#endif + + if (rank == MASTER_NODE) + cout << "Update parametric coord | FFD box: " << FFDBox->GetTag() << ". Max Diff: " << MaxDiff <<"."<< endl; + +} + +void CSurfaceMovement::SetCartesianCoord(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, unsigned short iFFDBox) { + + su2double *CartCoordNew, Diff, my_MaxDiff = 0.0, MaxDiff, + *ParamCoord, VarCoord[3] = {0.0, 0.0, 0.0}, CartCoordOld[3] = {0.0, 0.0, 0.0}; + unsigned short iMarker, iDim; + unsigned long iVertex, iPoint, iSurfacePoints; + int rank; + + unsigned short nDim = geometry->GetnDim(); + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#else + rank = MASTER_NODE; +#endif + + /*--- Recompute the cartesians coordinates ---*/ + + for (iSurfacePoints = 0; iSurfacePoints < FFDBox->GetnSurfacePoint(); iSurfacePoints++) { + + /*--- Get the marker of the surface point ---*/ + + iMarker = FFDBox->Get_MarkerIndex(iSurfacePoints); + + if (config->GetMarker_All_DV(iMarker) == YES) { + + /*--- Get the vertex of the surface point ---*/ + + iVertex = FFDBox->Get_VertexIndex(iSurfacePoints); + iPoint = FFDBox->Get_PointIndex(iSurfacePoints); + + /*--- Set to zero the variation of the coordinates ---*/ + + geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + + /*--- Get the parametric coordinate of the surface point ---*/ + + ParamCoord = FFDBox->Get_ParametricCoord(iSurfacePoints); + + /*--- Compute the new cartesian coordinate, and set the value in + the FFDBox structure ---*/ + + CartCoordNew = FFDBox->EvalCartesianCoord(ParamCoord); + FFDBox->Set_CartesianCoord(CartCoordNew, iSurfacePoints); + + /*--- Get the original cartesian coordinates of the surface point ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + CartCoordOld[iDim] = geometry->node[iPoint]->GetCoord(iDim); + } + + /*--- Set the value of the variation of the coordinates ---*/ + + Diff = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + VarCoord[iDim] = CartCoordNew[iDim] - CartCoordOld[iDim]; + if ((fabs(VarCoord[iDim]) <= EPS) && (config->GetDirectDiff() != D_DESIGN) && (!config->GetDiscrete_Adjoint())) + VarCoord[iDim] = 0.0; + Diff += (VarCoord[iDim]*VarCoord[iDim]); + } + Diff = sqrt(Diff); + + my_MaxDiff = max(my_MaxDiff, Diff); + + /*--- Set the variation of the coordinates ---*/ + + geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + + } + } + +#ifdef HAVE_MPI + SU2_MPI::Allreduce(&my_MaxDiff, &MaxDiff, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); +#else + MaxDiff = my_MaxDiff; +#endif + + if (rank == MASTER_NODE) + cout << "Update cartesian coord | FFD box: " << FFDBox->GetTag() << ". Max Diff: " << MaxDiff <<"."<< endl; + +} + + +void CSurfaceMovement::SetFFDCPChange_2D(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, + unsigned short iDV, bool ResetDef) { + + su2double movement[3] = {0.0,0.0,0.0}, Ampl; + unsigned short index[3], i, j; + string design_FFDBox; + + /*--- Set control points to its original value (even if the + design variable is not in this box) ---*/ + + if (ResetDef == true) FFDBox->SetOriginalControlPoints(); + + design_FFDBox = config->GetFFDTag(iDV); + + if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { + + /*--- Compute deformation ---*/ + + Ampl = config->GetDV_Value(iDV); + + movement[0] = config->GetParamDV(iDV, 3)*Ampl; + movement[1] = config->GetParamDV(iDV, 4)*Ampl; + movement[2] = 0.0; + + index[0] = SU2_TYPE::Int(config->GetParamDV(iDV, 1)); + index[1] = SU2_TYPE::Int(config->GetParamDV(iDV, 2)); + + /*--- Lower surface ---*/ + + index[2] = 0; + + if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) == -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) != -1)) { + for (i = 0; i < FFDBox->GetlOrder(); i++) { + index[0] = i; + FFDBox->SetControlPoints(index, movement); + } + } + + if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) != -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) == -1)) { + for (j = 0; j < FFDBox->GetmOrder(); j++) { + index[1] = j; + FFDBox->SetControlPoints(index, movement); + } + } + + if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) == -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) == -1)) { + for (i = 0; i < FFDBox->GetlOrder(); i++) { + index[0] = i; + for (j = 0; j < FFDBox->GetmOrder(); j++) { + index[1] = j; + FFDBox->SetControlPoints(index, movement); + } + } + } + if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) != -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) != -1)) { + + FFDBox->SetControlPoints(index, movement); + } + + + /*--- Upper surface ---*/ + + index[2] = 1; + + if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) == -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) != -1)) { + for (i = 0; i < FFDBox->GetlOrder(); i++) { + index[0] = i; + FFDBox->SetControlPoints(index, movement); + } + } + + if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) != -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) == -1)) { + for (j = 0; j < FFDBox->GetmOrder(); j++) { + index[1] = j; + FFDBox->SetControlPoints(index, movement); + } + } + + if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) == -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) == -1)) { + for (i = 0; i < FFDBox->GetlOrder(); i++) { + index[0] = i; + for (j = 0; j < FFDBox->GetmOrder(); j++) { + index[1] = j; + FFDBox->SetControlPoints(index, movement); + } + } + } + if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) != -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) != -1)) { + + FFDBox->SetControlPoints(index, movement); + } + } + +} + +void CSurfaceMovement::SetFFDCPChange(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, + unsigned short iDV, bool ResetDef) { + + su2double movement[3] = {0.0,0.0,0.0}, Ampl; + unsigned short index[3], i, j, k, iPlane; + string design_FFDBox; + + /*--- Set control points to its original value (even if the + design variable is not in this box) ---*/ + + if (ResetDef == true) FFDBox->SetOriginalControlPoints(); + + design_FFDBox = config->GetFFDTag(iDV); + + if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { + + /*--- Compute deformation ---*/ + + Ampl = config->GetDV_Value(iDV); + + movement[0] = config->GetParamDV(iDV, 4)*Ampl; + movement[1] = config->GetParamDV(iDV, 5)*Ampl; + movement[2] = config->GetParamDV(iDV, 6)*Ampl; + + index[0] = SU2_TYPE::Int(config->GetParamDV(iDV, 1)); + index[1] = SU2_TYPE::Int(config->GetParamDV(iDV, 2)); + index[2] = SU2_TYPE::Int(config->GetParamDV(iDV, 3)); + + /*--- Check that it is possible to move the control point ---*/ + + for (iPlane = 0 ; iPlane < FFDBox->Get_nFix_IPlane(); iPlane++) { + if (index[0] == FFDBox->Get_Fix_IPlane(iPlane)) return; + } + + for (iPlane = 0 ; iPlane < FFDBox->Get_nFix_JPlane(); iPlane++) { + if (index[1] == FFDBox->Get_Fix_JPlane(iPlane)) return; + } + + for (iPlane = 0 ; iPlane < FFDBox->Get_nFix_KPlane(); iPlane++) { + if (index[2] == FFDBox->Get_Fix_KPlane(iPlane)) return; + } + + if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) == -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) != -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 3)) != -1)) { + for (i = 0; i < FFDBox->GetlOrder(); i++) { + index[0] = i; + FFDBox->SetControlPoints(index, movement); + } + } + + if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) != -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) == -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 3)) != -1)) { + for (j = 0; j < FFDBox->GetmOrder(); j++) { + index[1] = j; + FFDBox->SetControlPoints(index, movement); + } + } + + if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) != -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) != -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 3)) == -1)) { + for (k = 0; k < FFDBox->GetnOrder(); k++) { + index[2] = k; + FFDBox->SetControlPoints(index, movement); + } + } + + if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) == -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) == -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 3)) != -1)) { + for (i = 0; i < FFDBox->GetlOrder(); i++) { + index[0] = i; + for (j = 0; j < FFDBox->GetmOrder(); j++) { + index[1] = j; + FFDBox->SetControlPoints(index, movement); + } + } + } + + if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) != -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) == -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 3)) == -1)) { + for (j = 0; j < FFDBox->GetmOrder(); j++) { + index[1] = j; + for (k = 0; k < FFDBox->GetnOrder(); k++) { + index[2] = k; + FFDBox->SetControlPoints(index, movement); + } + } + } + + if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) == -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) != -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 3)) == -1)) { + for (i = 0; i < FFDBox->GetlOrder(); i++) { + index[0] = i; + for (k = 0; k < FFDBox->GetnOrder(); k++) { + index[2] = k; + FFDBox->SetControlPoints(index, movement); + } + } + } + + if ((SU2_TYPE::Int(config->GetParamDV(iDV, 1)) != -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 2)) != -1) && + (SU2_TYPE::Int(config->GetParamDV(iDV, 3)) != -1)) { + FFDBox->SetControlPoints(index, movement); + } + + } + +} + +void CSurfaceMovement::SetFFDCamber_2D(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, + unsigned short iDV, bool ResetDef) { + su2double Ampl, movement[3] = {0.0,0.0,0.0}; + unsigned short index[3], kIndex; + string design_FFDBox; + + /*--- Set control points to its original value (even if the + design variable is not in this box) ---*/ + + if (ResetDef == true) FFDBox->SetOriginalControlPoints(); + + design_FFDBox = config->GetFFDTag(iDV); + + if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { + + for (kIndex = 0; kIndex < 2; kIndex++) { + + Ampl = config->GetDV_Value(iDV); + + movement[0] = 0.0; + if (kIndex == 0) movement[1] = Ampl; + else movement[1] = Ampl; + movement[2] = 0.0; + + index[0] = SU2_TYPE::Int(config->GetParamDV(iDV, 1)); index[1] = kIndex; index[2] = 0; + FFDBox->SetControlPoints(index, movement); + + index[2] = 1; + FFDBox->SetControlPoints(index, movement); + + } + + } + +} + +void CSurfaceMovement::SetFFDThickness_2D(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, + unsigned short iDV, bool ResetDef) { + su2double Ampl, movement[3]= {0.0,0.0,0.0}; + unsigned short index[3], kIndex; + string design_FFDBox; + + /*--- Set control points to its original value (even if the + design variable is not in this box) ---*/ + + if (ResetDef == true) FFDBox->SetOriginalControlPoints(); + + design_FFDBox = config->GetFFDTag(iDV); + + if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { + + for (kIndex = 0; kIndex < 2; kIndex++) { + + Ampl = config->GetDV_Value(iDV); + + movement[0] = 0.0; + if (kIndex == 0) movement[1] = -Ampl; + else movement[1] = Ampl; + movement[2] = 0.0; + + index[0] = SU2_TYPE::Int(config->GetParamDV(iDV, 1)); index[1] = kIndex; index[2] = 0; + FFDBox->SetControlPoints(index, movement); + + index[2] = 1; + FFDBox->SetControlPoints(index, movement); + + } + + } + +} + +void CSurfaceMovement::SetFFDCamber(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, + unsigned short iDV, bool ResetDef) { + su2double Ampl, movement[3] = {0.0,0.0,0.0}; + unsigned short index[3], kIndex; + string design_FFDBox; + + /*--- Set control points to its original value (even if the + design variable is not in this box) ---*/ + + if (ResetDef == true) FFDBox->SetOriginalControlPoints(); + + design_FFDBox = config->GetFFDTag(iDV); + + if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { + + for (kIndex = 0; kIndex < 2; kIndex++) { + + Ampl = config->GetDV_Value(iDV); + + index[0] = SU2_TYPE::Int(config->GetParamDV(iDV, 1)); + index[1] = SU2_TYPE::Int(config->GetParamDV(iDV, 2)); + index[2] = kIndex; + + movement[0] = 0.0; movement[1] = 0.0; + if (kIndex == 0) movement[2] = Ampl; + else movement[2] = Ampl; + + FFDBox->SetControlPoints(index, movement); + + } + + } + +} + +void CSurfaceMovement::SetFFDThickness(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, + unsigned short iDV, bool ResetDef) { + su2double Ampl, movement[3] = {0.0,0.0,0.0}; + unsigned short index[3], kIndex; + string design_FFDBox; + + /*--- Set control points to its original value (even if the + design variable is not in this box) ---*/ + + if (ResetDef == true) FFDBox->SetOriginalControlPoints(); + + design_FFDBox = config->GetFFDTag(iDV); + + if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { + + for (kIndex = 0; kIndex < 2; kIndex++) { + + Ampl = config->GetDV_Value(iDV); + + index[0] = SU2_TYPE::Int(config->GetParamDV(iDV, 1)); + index[1] = SU2_TYPE::Int(config->GetParamDV(iDV, 2)); + index[2] = kIndex; + + movement[0] = 0.0; movement[1] = 0.0; + if (kIndex == 0) movement[2] = -Ampl; + else movement[2] = Ampl; + + FFDBox->SetControlPoints(index, movement); + + } + + } + +} + + +void CSurfaceMovement::SetFFDDihedralAngle(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, + unsigned short iDV, bool ResetDef) { + unsigned short iOrder, jOrder, kOrder, index[3]; + su2double movement[3] = {0.0,0.0,0.0}, theta; + string design_FFDBox; + + /*--- Set control points to its original value (even if the + design variable is not in this box) ---*/ + + if (ResetDef == true) FFDBox->SetOriginalControlPoints(); + + design_FFDBox = config->GetFFDTag(iDV); + + if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { + + /*--- The angle of rotation. ---*/ + + theta = config->GetDV_Value(iDV)*PI_NUMBER/180.0; + + /*--- Change the value of the control point if move is true ---*/ + for (iOrder = 0; iOrder < FFDBox->GetlOrder(); iOrder++) + for (jOrder = 0; jOrder < FFDBox->GetmOrder(); jOrder++) + for (kOrder = 0; kOrder < FFDBox->GetnOrder(); kOrder++) { + index[0] = iOrder; index[1] = jOrder; index[2] = kOrder; + su2double *coord = FFDBox->GetCoordControlPoints(iOrder, jOrder, kOrder); + movement[0] = 0.0; movement[1] = 0.0; movement[2] = coord[1]*tan(theta); + + FFDBox->SetControlPoints(index, movement); + } + + } + +} + +void CSurfaceMovement::SetFFDTwistAngle(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, + unsigned short iDV, bool ResetDef) { + unsigned short iOrder, jOrder, kOrder; + su2double x, y, z, movement[3] = {0.0,0.0,0.0}; + unsigned short index[3]; + string design_FFDBox; + + /*--- Set control points to its original value (even if the + design variable is not in this box) ---*/ + + if (ResetDef == true) FFDBox->SetOriginalControlPoints(); + + design_FFDBox = config->GetFFDTag(iDV); + + if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { + + /*--- xyz-coordinates of a point on the line of rotation. ---*/ + + su2double a = config->GetParamDV(iDV, 1); + su2double b = config->GetParamDV(iDV, 2); + su2double c = config->GetParamDV(iDV, 3); + + /*--- xyz-coordinate of the line's direction vector. ---*/ + + su2double u = config->GetParamDV(iDV, 4)-config->GetParamDV(iDV, 1); + su2double v = config->GetParamDV(iDV, 5)-config->GetParamDV(iDV, 2); + su2double w = config->GetParamDV(iDV, 6)-config->GetParamDV(iDV, 3); + + /*--- The angle of rotation. ---*/ + + su2double theta = config->GetDV_Value(iDV)*PI_NUMBER/180.0; + + /*--- An intermediate value used in computations. ---*/ + + su2double u2=u*u; su2double v2=v*v; su2double w2=w*w; + su2double l2 = u2 + v2 + w2; su2double l = sqrt(l2); + su2double cosT; su2double sinT; + + /*--- Change the value of the control point if move is true ---*/ + + for (iOrder = 0; iOrder < FFDBox->GetlOrder(); iOrder++) + for (jOrder = 0; jOrder < FFDBox->GetmOrder(); jOrder++) + for (kOrder = 0; kOrder < FFDBox->GetnOrder(); kOrder++) { + index[0] = iOrder; index[1] = jOrder; index[2] = kOrder; + su2double *coord = FFDBox->GetCoordControlPoints(iOrder, jOrder, kOrder); + x = coord[0]; y = coord[1]; z = coord[2]; + + su2double factor = 0.0; + if ( y < config->GetParamDV(iDV, 2) ) + factor = 0.0; + if (( y >= config->GetParamDV(iDV, 2)) && ( y <= config->GetParamDV(iDV, 5)) ) + factor = (y-config->GetParamDV(iDV, 2)) / (config->GetParamDV(iDV, 5)-config->GetParamDV(iDV, 2)); + if ( y > config->GetParamDV(iDV, 5) ) + factor = 1.0; + + cosT = cos(theta*factor); + sinT = sin(theta*factor); + + movement[0] = a*(v2 + w2) + u*(-b*v - c*w + u*x + v*y + w*z) + + (-a*(v2 + w2) + u*(b*v + c*w - v*y - w*z) + (v2 + w2)*x)*cosT + + l*(-c*v + b*w - w*y + v*z)*sinT; + movement[0] = movement[0]/l2 - x; + + movement[1] = b*(u2 + w2) + v*(-a*u - c*w + u*x + v*y + w*z) + + (-b*(u2 + w2) + v*(a*u + c*w - u*x - w*z) + (u2 + w2)*y)*cosT + + l*(c*u - a*w + w*x - u*z)*sinT; + movement[1] = movement[1]/l2 - y; + + movement[2] = c*(u2 + v2) + w*(-a*u - b*v + u*x + v*y + w*z) + + (-c*(u2 + v2) + w*(a*u + b*v - u*x - v*y) + (u2 + v2)*z)*cosT + + l*(-b*u + a*v - v*x + u*y)*sinT; + movement[2] = movement[2]/l2 - z; + + FFDBox->SetControlPoints(index, movement); + + } + + } + +} + + +void CSurfaceMovement::SetFFDRotation(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, + unsigned short iDV, bool ResetDef) { + unsigned short iOrder, jOrder, kOrder; + su2double movement[3] = {0.0,0.0,0.0}, x, y, z; + unsigned short index[3]; + string design_FFDBox; + + /*--- Set control points to its original value (even if the + design variable is not in this box) ---*/ + + if (ResetDef == true) FFDBox->SetOriginalControlPoints(); + + design_FFDBox = config->GetFFDTag(iDV); + + if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { + + /*--- xyz-coordinates of a point on the line of rotation. ---*/ + + su2double a = config->GetParamDV(iDV, 1); + su2double b = config->GetParamDV(iDV, 2); + su2double c = config->GetParamDV(iDV, 3); + + /*--- xyz-coordinate of the line's direction vector. ---*/ + + su2double u = config->GetParamDV(iDV, 4)-config->GetParamDV(iDV, 1); + su2double v = config->GetParamDV(iDV, 5)-config->GetParamDV(iDV, 2); + su2double w = config->GetParamDV(iDV, 6)-config->GetParamDV(iDV, 3); + + /*--- The angle of rotation. ---*/ + + su2double theta = config->GetDV_Value(iDV)*PI_NUMBER/180.0; + + /*--- An intermediate value used in computations. ---*/ + + su2double u2=u*u; su2double v2=v*v; su2double w2=w*w; + su2double cosT = cos(theta); su2double sinT = sin(theta); + su2double l2 = u2 + v2 + w2; su2double l = sqrt(l2); + + /*--- Change the value of the control point if move is true ---*/ + + for (iOrder = 0; iOrder < FFDBox->GetlOrder(); iOrder++) + for (jOrder = 0; jOrder < FFDBox->GetmOrder(); jOrder++) + for (kOrder = 0; kOrder < FFDBox->GetnOrder(); kOrder++) { + index[0] = iOrder; index[1] = jOrder; index[2] = kOrder; + su2double *coord = FFDBox->GetCoordControlPoints(iOrder, jOrder, kOrder); + x = coord[0]; y = coord[1]; z = coord[2]; + movement[0] = a*(v2 + w2) + u*(-b*v - c*w + u*x + v*y + w*z) + + (-a*(v2 + w2) + u*(b*v + c*w - v*y - w*z) + (v2 + w2)*x)*cosT + + l*(-c*v + b*w - w*y + v*z)*sinT; + movement[0] = movement[0]/l2 - x; + + movement[1] = b*(u2 + w2) + v*(-a*u - c*w + u*x + v*y + w*z) + + (-b*(u2 + w2) + v*(a*u + c*w - u*x - w*z) + (u2 + w2)*y)*cosT + + l*(c*u - a*w + w*x - u*z)*sinT; + movement[1] = movement[1]/l2 - y; + + movement[2] = c*(u2 + v2) + w*(-a*u - b*v + u*x + v*y + w*z) + + (-c*(u2 + v2) + w*(a*u + b*v - u*x - v*y) + (u2 + v2)*z)*cosT + + l*(-b*u + a*v - v*x + u*y)*sinT; + movement[2] = movement[2]/l2 - z; + + FFDBox->SetControlPoints(index, movement); + + } + } + +} + +void CSurfaceMovement::SetFFDControl_Surface(CGeometry *geometry, CConfig *config, CFreeFormDefBox *FFDBox, + unsigned short iDV, bool ResetDef) { + unsigned short iOrder, jOrder, kOrder; + su2double movement[3] = {0.0,0.0,0.0}, x, y, z; + unsigned short index[3]; + string design_FFDBox; + + /*--- Set control points to its original value (even if the + design variable is not in this box) ---*/ + + if (ResetDef == true) FFDBox->SetOriginalControlPoints(); + + design_FFDBox = config->GetFFDTag(iDV); + + if (design_FFDBox.compare(FFDBox->GetTag()) == 0) { + + /*--- xyz-coordinates of a point on the line of rotation. ---*/ + + su2double a = config->GetParamDV(iDV, 1); + su2double b = config->GetParamDV(iDV, 2); + su2double c = config->GetParamDV(iDV, 3); + + /*--- xyz-coordinate of the line's direction vector. ---*/ + + su2double u = config->GetParamDV(iDV, 4)-config->GetParamDV(iDV, 1); + su2double v = config->GetParamDV(iDV, 5)-config->GetParamDV(iDV, 2); + su2double w = config->GetParamDV(iDV, 6)-config->GetParamDV(iDV, 3); + + /*--- The angle of rotation. ---*/ + + su2double theta = -config->GetDV_Value(iDV)*PI_NUMBER/180.0; + + /*--- An intermediate value used in computations. ---*/ + + su2double u2=u*u; su2double v2=v*v; su2double w2=w*w; + su2double cosT = cos(theta); su2double sinT = sin(theta); + su2double l2 = u2 + v2 + w2; su2double l = sqrt(l2); + + /*--- Change the value of the control point if move is true ---*/ + + for (iOrder = 0; iOrder < FFDBox->GetlOrder()-2; iOrder++) + for (jOrder = 2; jOrder < FFDBox->GetmOrder()-2; jOrder++) + for (kOrder = 0; kOrder < FFDBox->GetnOrder(); kOrder++) { + index[0] = iOrder; index[1] = jOrder; index[2] = kOrder; + su2double *coord = FFDBox->GetCoordControlPoints(iOrder, jOrder, kOrder); + x = coord[0]; y = coord[1]; z = coord[2]; + movement[0] = a*(v2 + w2) + u*(-b*v - c*w + u*x + v*y + w*z) + + (-a*(v2 + w2) + u*(b*v + c*w - v*y - w*z) + (v2 + w2)*x)*cosT + + l*(-c*v + b*w - w*y + v*z)*sinT; + movement[0] = movement[0]/l2 - x; + + movement[1] = b*(u2 + w2) + v*(-a*u - c*w + u*x + v*y + w*z) + + (-b*(u2 + w2) + v*(a*u + c*w - u*x - w*z) + (u2 + w2)*y)*cosT + + l*(c*u - a*w + w*x - u*z)*sinT; + movement[1] = movement[1]/l2 - y; + + movement[2] = c*(u2 + v2) + w*(-a*u - b*v + u*x + v*y + w*z) + + (-c*(u2 + v2) + w*(a*u + b*v - u*x - v*y) + (u2 + v2)*z)*cosT + + l*(-b*u + a*v - v*x + u*y)*sinT; + movement[2] = movement[2]/l2 - z; + + FFDBox->SetControlPoints(index, movement); + + } + } + +} + +void CSurfaceMovement::SetHicksHenne(CGeometry *boundary, CConfig *config, unsigned short iDV, bool ResetDef) { + unsigned long iVertex; + unsigned short iMarker; + su2double VarCoord[3] = {0.0,0.0,0.0}, VarCoord_[3] = {0.0,0.0,0.0}, *Coord_, *Normal_, ek, fk, BumpSize = 1.0, + BumpLoc = 0.0, Coord[3] = {0.0,0.0,0.0}, Normal[3] = {0.0,0.0,0.0}, + xCoord, TPCoord[2] = {0.0, 0.0}, LPCoord[2] = {0.0, 0.0}, Distance, Chord, AoA, ValCos, ValSin; + + bool upper = true, double_surface = false; + + /*--- Reset airfoil deformation if first deformation or if it required by the solver ---*/ + + if ((iDV == 0) || (ResetDef == true)) { + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { + VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; + boundary->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + } + } + + /*--- Compute the angle of attack to apply the deformation ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_DV(iMarker) == YES) { + Coord_ = boundary->vertex[iMarker][0]->GetCoord(); + TPCoord[0] = Coord_[0]; TPCoord[1] = Coord_[1]; + for (iVertex = 1; iVertex < boundary->nVertex[iMarker]; iVertex++) { + Coord_ = boundary->vertex[iMarker][iVertex]->GetCoord(); + if (Coord_[0] > TPCoord[0]) { TPCoord[0] = Coord_[0]; TPCoord[1] = Coord_[1]; } + } + } + } + +#ifdef HAVE_MPI + + int iProcessor, nProcessor; + su2double *Buffer_Send_Coord, *Buffer_Receive_Coord; + + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); + + Buffer_Receive_Coord = new su2double [nProcessor*2]; + Buffer_Send_Coord = new su2double [2]; + + Buffer_Send_Coord[0] = TPCoord[0]; Buffer_Send_Coord[1] = TPCoord[1]; + + SU2_MPI::Allgather(Buffer_Send_Coord, 2, MPI_DOUBLE, Buffer_Receive_Coord, 2, MPI_DOUBLE, MPI_COMM_WORLD); + + TPCoord[0] = Buffer_Receive_Coord[0]; TPCoord[1] = Buffer_Receive_Coord[1]; + for (iProcessor = 1; iProcessor < nProcessor; iProcessor++) { + Coord[0] = Buffer_Receive_Coord[iProcessor*2 + 0]; + Coord[1] = Buffer_Receive_Coord[iProcessor*2 + 1]; + if (Coord[0] > TPCoord[0]) { TPCoord[0] = Coord[0]; TPCoord[1] = Coord[1]; } + } + + delete[] Buffer_Send_Coord; delete[] Buffer_Receive_Coord; + +#endif + + + Chord = 0.0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_DV(iMarker) == YES) { + for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { + Coord_ = boundary->vertex[iMarker][iVertex]->GetCoord(); + Distance = sqrt(pow(Coord_[0] - TPCoord[0], 2.0) + pow(Coord_[1] - TPCoord[1], 2.0)); + if (Chord < Distance) { Chord = Distance; LPCoord[0] = Coord_[0]; LPCoord[1] = Coord_[1]; } + } + } + } + +#ifdef HAVE_MPI + + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); + + Buffer_Receive_Coord = new su2double [nProcessor*2]; + Buffer_Send_Coord = new su2double [2]; + + Buffer_Send_Coord[0] = LPCoord[0]; Buffer_Send_Coord[1] = LPCoord[1]; + + SU2_MPI::Allgather(Buffer_Send_Coord, 2, MPI_DOUBLE, Buffer_Receive_Coord, 2, MPI_DOUBLE, MPI_COMM_WORLD); + + Chord = 0.0; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + Coord[0] = Buffer_Receive_Coord[iProcessor*2 + 0]; + Coord[1] = Buffer_Receive_Coord[iProcessor*2 + 1]; + Distance = sqrt(pow(Coord[0] - TPCoord[0], 2.0) + pow(Coord[1] - TPCoord[1], 2.0)); + if (Chord < Distance) { Chord = Distance; LPCoord[0] = Coord[0]; LPCoord[1] = Coord[1]; } + } + + delete[] Buffer_Send_Coord; delete[] Buffer_Receive_Coord; + +#endif + + //AoA = atan((LPCoord[1] - TPCoord[1]) / (TPCoord[0] - LPCoord[0]))*180/PI_NUMBER; + AoA = 0.0; + + /*--- Perform multiple airfoil deformation ---*/ + + su2double Ampl = config->GetDV_Value(iDV); + su2double xk = config->GetParamDV(iDV, 1); + const su2double t2 = 3.0; + + if (config->GetParamDV(iDV, 0) == NO) { upper = false; double_surface = true; } + if (config->GetParamDV(iDV, 0) == YES) { upper = true; double_surface = true; } + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { + VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; + + if (config->GetMarker_All_DV(iMarker) == YES) { + + Coord_ = boundary->vertex[iMarker][iVertex]->GetCoord(); + Normal_ = boundary->vertex[iMarker][iVertex]->GetNormal(); + + /*--- The Hicks Henne bump functions should be applied to a basic airfoil without AoA, + and unitary chord, a tranformation is required ---*/ + + ValCos = cos(AoA*PI_NUMBER/180.0); + ValSin = sin(AoA*PI_NUMBER/180.0); + + Coord[0] = Coord_[0]*ValCos - Coord_[1]*ValSin; + Coord[0] = max(0.0, Coord[0]); // Coord x should be always positive + Coord[1] = Coord_[1]*ValCos + Coord_[0]*ValSin; + + Normal[0] = Normal_[0]*ValCos - Normal_[1]*ValSin; + Normal[1] = Normal_[1]*ValCos + Normal_[0]*ValSin; + + /*--- Bump computation ---*/ + + if (double_surface) { + ek = log10(0.5)/log10(xk); + fk = pow( sin( PI_NUMBER * pow(Coord[0], ek) ) , t2); + + /*--- Upper and lower surface ---*/ + + if (( upper) && (Normal[1] > 0)) { VarCoord[1] = Ampl*fk; } + if ((!upper) && (Normal[1] < 0)) { VarCoord[1] = -Ampl*fk; } + + } + else { + xCoord = Coord[0] - BumpLoc; + ek = log10(0.5)/log10(xk/BumpSize); + fk = pow( sin( PI_NUMBER * pow(xCoord/BumpSize, ek)), t2); + + /*--- Only one surface ---*/ + + if ((xCoord <= 0.0) || (xCoord >= BumpSize)) VarCoord[1] = 0.0; + else VarCoord[1] = Ampl*fk; + + + } + } + + /*--- Apply the transformation to the coordinate variation ---*/ + + ValCos = cos(-AoA*PI_NUMBER/180.0); + ValSin = sin(-AoA*PI_NUMBER/180.0); + + VarCoord_[0] = VarCoord[0]*ValCos - VarCoord[1]*ValSin; + VarCoord_[1] = VarCoord[1]*ValCos + VarCoord[0]*ValSin; + + boundary->vertex[iMarker][iVertex]->AddVarCoord(VarCoord_); + + } + } + +} + +void CSurfaceMovement::SetRotation(CGeometry *boundary, CConfig *config, unsigned short iDV, bool ResetDef) { + unsigned long iVertex; + unsigned short iMarker; + su2double VarCoord[3] = {0.0,0.0,0.0}, *Coord; + su2double movement[3] = {0.0,0.0,0.0}, x, y, z; + + /*--- Reset airfoil deformation if first deformation or if it required by the solver ---*/ + + if ((iDV == 0) || (ResetDef == true)) { + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { + VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; + boundary->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + } + } + + /*--- xyz-coordinates of a point on the line of rotation. */ + + su2double a = config->GetParamDV(iDV, 0); + su2double b = config->GetParamDV(iDV, 1); + su2double c = 0.0; + if (boundary->GetnDim() == 3) c = config->GetParamDV(0,2); + + /*--- xyz-coordinate of the line's direction vector. ---*/ + + su2double u = config->GetParamDV(iDV, 3)-config->GetParamDV(iDV, 0); + su2double v = config->GetParamDV(iDV, 4)-config->GetParamDV(iDV, 1); + su2double w = 1.0; + if (boundary->GetnDim() == 3) w = config->GetParamDV(iDV, 5)-config->GetParamDV(iDV, 2); + + /*--- The angle of rotation. ---*/ + + su2double theta = config->GetDV_Value(iDV)*PI_NUMBER/180.0; + + /*--- An intermediate value used in computations. ---*/ + + su2double u2=u*u; su2double v2=v*v; su2double w2=w*w; + su2double cosT = cos(theta); su2double sinT = sin(theta); + su2double l2 = u2 + v2 + w2; su2double l = sqrt(l2); + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { + VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; + if (config->GetMarker_All_DV(iMarker) == YES) { + Coord = boundary->vertex[iMarker][iVertex]->GetCoord(); + x = Coord[0]; y = Coord[1]; z = Coord[2]; + + movement[0] = a*(v2 + w2) + u*(-b*v - c*w + u*x + v*y + w*z) + + (-a*(v2 + w2) + u*(b*v + c*w - v*y - w*z) + (v2 + w2)*x)*cosT + + l*(-c*v + b*w - w*y + v*z)*sinT; + movement[0] = movement[0]/l2 - x; + + movement[1] = b*(u2 + w2) + v*(-a*u - c*w + u*x + v*y + w*z) + + (-b*(u2 + w2) + v*(a*u + c*w - u*x - w*z) + (u2 + w2)*y)*cosT + + l*(c*u - a*w + w*x - u*z)*sinT; + movement[1] = movement[1]/l2 - y; + + movement[2] = c*(u2 + v2) + w*(-a*u - b*v + u*x + v*y + w*z) + + (-c*(u2 + v2) + w*(a*u + b*v - u*x - v*y) + (u2 + v2)*z)*cosT + + l*(-b*u + a*v - v*x + u*y)*sinT; + if (boundary->GetnDim() == 3) movement[2] = movement[2]/l2 - z; + else movement[2] = 0.0; + + VarCoord[0] = movement[0]; + VarCoord[1] = movement[1]; + if (boundary->GetnDim() == 3) VarCoord[2] = movement[2]; + + } + boundary->vertex[iMarker][iVertex]->AddVarCoord(VarCoord); + } +} + +void CSurfaceMovement::SetTranslation(CGeometry *boundary, CConfig *config, unsigned short iDV, bool ResetDef) { + unsigned long iVertex; + unsigned short iMarker; + su2double VarCoord[3] = {0.0,0.0,0.0}; + su2double Ampl = config->GetDV_Value(iDV); + + /*--- Reset airfoil deformation if first deformation or if it required by the solver ---*/ + + if ((iDV == 0) || (ResetDef == true)) { + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { + VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; + boundary->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + } + } + + su2double xDispl = config->GetParamDV(iDV, 0); + su2double yDispl = config->GetParamDV(iDV, 1); + su2double zDispl = 0; + if (boundary->GetnDim() == 3) zDispl = config->GetParamDV(iDV, 2); + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { + VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; + if (config->GetMarker_All_DV(iMarker) == YES) { + VarCoord[0] = Ampl*xDispl; + VarCoord[1] = Ampl*yDispl; + if (boundary->GetnDim() == 3) VarCoord[2] = Ampl*zDispl; + } + boundary->vertex[iMarker][iVertex]->AddVarCoord(VarCoord); + } + +} + +void CSurfaceMovement::SetScale(CGeometry *boundary, CConfig *config, unsigned short iDV, bool ResetDef) { + unsigned long iVertex; + unsigned short iMarker; + su2double VarCoord[3] = {0.0,0.0,0.0}, x, y, z, *Coord; + su2double Ampl = config->GetDV_Value(iDV); + + /*--- Reset airfoil deformation if first deformation or if it required by the solver ---*/ + + if ((iDV == 0) || (ResetDef == true)) { + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { + VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; + boundary->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + } + } + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { + VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; + if (config->GetMarker_All_DV(iMarker) == YES) { + Coord = boundary->vertex[iMarker][iVertex]->GetCoord(); + x = Coord[0]; y = Coord[1]; z = Coord[2]; + VarCoord[0] = (Ampl-1.0)*x; + VarCoord[1] = (Ampl-1.0)*y; + if (boundary->GetnDim() == 3) VarCoord[2] = (Ampl-1.0)*z; + } + boundary->vertex[iMarker][iVertex]->AddVarCoord(VarCoord); + } + +} + +void CSurfaceMovement::Moving_Walls(CGeometry *geometry, CConfig *config, + unsigned short iZone, unsigned long iter) { + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Local variables ---*/ + unsigned short iMarker, jMarker, iDim, nDim = geometry->GetnDim(); + unsigned long iPoint, iVertex; + su2double xDot[3] = {0.0,0.0,0.0}, *Coord, Center[3] = {0.0,0.0,0.0}, Omega[3] = {0.0,0.0,0.0}, r[3] = {0.0,0.0,0.0}, GridVel[3] = {0.0,0.0,0.0}; + su2double L_Ref = config->GetLength_Ref(); + su2double Omega_Ref = config->GetOmega_Ref(); + su2double Vel_Ref = config->GetVelocity_Ref(); + string Marker_Tag; + + /*--- Store grid velocity for each node on the moving surface(s). + Sum and store the x, y, & z velocities due to translation and rotation. ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_Moving(iMarker) == YES) { + + /*--- Identify iMarker from the list of those under MARKER_MOVING ---*/ + + Marker_Tag = config->GetMarker_All_TagBound(iMarker); + jMarker = config->GetMarker_Moving(Marker_Tag); + + /*--- Get prescribed wall speed from config for this marker ---*/ + + Center[0] = config->GetMotion_Origin_X(jMarker); + Center[1] = config->GetMotion_Origin_Y(jMarker); + Center[2] = config->GetMotion_Origin_Z(jMarker); + Omega[0] = config->GetRotation_Rate_X(jMarker)/Omega_Ref; + Omega[1] = config->GetRotation_Rate_Y(jMarker)/Omega_Ref; + Omega[2] = config->GetRotation_Rate_Z(jMarker)/Omega_Ref; + xDot[0] = config->GetTranslation_Rate_X(jMarker)/Vel_Ref; + xDot[1] = config->GetTranslation_Rate_Y(jMarker)/Vel_Ref; + xDot[2] = config->GetTranslation_Rate_Z(jMarker)/Vel_Ref; + + if (rank == MASTER_NODE && iter == 0) { + cout << " Storing grid velocity for marker: "; + cout << Marker_Tag << "." << endl; + cout << " Translational velocity: (" << xDot[0] << ", " << xDot[1]; + cout << ", " << xDot[2] << ") m/s." << endl; + cout << " Angular velocity: (" << Omega[0] << ", " << Omega[1]; + cout << ", " << Omega[2] << ") rad/s about origin: (" << Center[0]; + cout << ", " << Center[1] << ", " << Center[2] << ")." << endl; + } + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + /*--- Get the index and coordinates of the current point ---*/ + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Coord = geometry->node[iPoint]->GetCoord(); + + /*--- Calculate non-dim. position from rotation center ---*/ + for (iDim = 0; iDim < nDim; iDim++) + r[iDim] = (Coord[iDim]-Center[iDim])/L_Ref; + if (nDim == 2) r[nDim] = 0.0; + + /*--- Cross Product of angular velocity and distance from center to + get the rotational velocity. Note that we are adding on the velocity + due to pure translation as well. ---*/ + + GridVel[0] = xDot[0] + Omega[1]*r[2] - Omega[2]*r[1]; + GridVel[1] = xDot[1] + Omega[2]*r[0] - Omega[0]*r[2]; + GridVel[2] = xDot[2] + Omega[0]*r[1] - Omega[1]*r[0]; + + /*--- Store the moving wall velocity for this node ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + geometry->node[iPoint]->SetGridVel(iDim, GridVel[iDim]); + + } + } + } +} + +void CSurfaceMovement::Surface_Translating(CGeometry *geometry, CConfig *config, + unsigned long iter, unsigned short iZone) { + + su2double deltaT, time_new, time_old; + su2double Center[3] = {0.0,0.0,0.0}, VarCoord[3] = {0.0,0.0,0.0}; + su2double xDot[3] = {0.0,0.0,0.0}; + unsigned short iMarker, jMarker, Moving; + unsigned long iVertex; + string Marker_Tag, Moving_Tag; + int rank; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#else + rank = MASTER_NODE; +#endif + + /*--- Initialize the delta variation in coordinates ---*/ + VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; + + /*--- Retrieve values from the config file ---*/ + + deltaT = config->GetDelta_UnstTimeND(); + + /*--- Compute delta time based on physical time step ---*/ + time_new = static_cast(iter)*deltaT; + if (iter == 0) { + time_old = time_new; + } else { + time_old = static_cast(iter-1)*deltaT; + } + + /*--- Store displacement of each node on the translating surface ---*/ + /*--- Loop over markers and find the particular marker(s) (surface) to translate ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + Moving = config->GetMarker_All_Moving(iMarker); + if (Moving == YES) { + for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { + + Moving_Tag = config->GetMarker_Moving(jMarker); + Marker_Tag = config->GetMarker_All_TagBound(iMarker); + + if (Marker_Tag == Moving_Tag) { + + /*--- Translation velocity from config. ---*/ + + xDot[0] = config->GetTranslation_Rate_X(jMarker); + xDot[1] = config->GetTranslation_Rate_Y(jMarker); + xDot[2] = config->GetTranslation_Rate_Z(jMarker); + + /*--- Print some information to the console. Be verbose at the first + iteration only (mostly for debugging purposes). ---*/ + // Note that the MASTER_NODE might not contain all the markers being moved. + + if (rank == MASTER_NODE) { + cout << " Storing translating displacement for marker: "; + cout << Marker_Tag << "." << endl; + if (iter == 0) { + cout << " Translational velocity: (" << xDot[0] << ", " << xDot[1]; + cout << ", " << xDot[2] << ") m/s." << endl; + } + } + + /*--- Compute delta change in the position in the x, y, & z directions. ---*/ + + VarCoord[0] = xDot[0]*(time_new-time_old); + VarCoord[1] = xDot[1]*(time_new-time_old); + VarCoord[2] = xDot[2]*(time_new-time_old); + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + /*--- Set node displacement for volume deformation ---*/ + geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + + } + } + } + } + } + + /*--- When updating the origins it is assumed that all markers have the + same translational velocity, because we use the last VarCoord set ---*/ + + /*--- Set the mesh motion center to the new location after + incrementing the position with the translation. This new + location will be used for subsequent mesh motion for the given marker.---*/ + + for (jMarker=0; jMarkerGetnMarker_Moving(); jMarker++) { + + /*-- Check if we want to update the motion origin for the given marker ---*/ + + if (config->GetMoveMotion_Origin(jMarker) == YES) { + Center[0] = config->GetMotion_Origin_X(jMarker) + VarCoord[0]; + Center[1] = config->GetMotion_Origin_Y(jMarker) + VarCoord[1]; + Center[2] = config->GetMotion_Origin_Z(jMarker) + VarCoord[2]; + config->SetMotion_Origin_X(jMarker, Center[0]); + config->SetMotion_Origin_Y(jMarker, Center[1]); + config->SetMotion_Origin_Z(jMarker, Center[2]); + } + } + + /*--- Set the moment computation center to the new location after + incrementing the position with the translation. ---*/ + + for (jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { + Center[0] = config->GetRefOriginMoment_X(jMarker) + VarCoord[0]; + Center[1] = config->GetRefOriginMoment_Y(jMarker) + VarCoord[1]; + Center[2] = config->GetRefOriginMoment_Z(jMarker) + VarCoord[2]; + config->SetRefOriginMoment_X(jMarker, Center[0]); + config->SetRefOriginMoment_Y(jMarker, Center[1]); + config->SetRefOriginMoment_Z(jMarker, Center[2]); + } +} + +void CSurfaceMovement::Surface_Plunging(CGeometry *geometry, CConfig *config, + unsigned long iter, unsigned short iZone) { + + su2double deltaT, time_new, time_old, Lref; + su2double Center[3], VarCoord[3], Omega[3], Ampl[3]; + su2double DEG2RAD = PI_NUMBER/180.0; + unsigned short iMarker, jMarker, Moving; + unsigned long iVertex; + string Marker_Tag, Moving_Tag; + int rank; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#else + rank = MASTER_NODE; +#endif + + /*--- Initialize the delta variation in coordinates ---*/ + VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; + + /*--- Retrieve values from the config file ---*/ + + deltaT = config->GetDelta_UnstTimeND(); + Lref = config->GetLength_Ref(); + + /*--- Compute delta time based on physical time step ---*/ + time_new = static_cast(iter)*deltaT; + if (iter == 0) { + time_old = time_new; + } else { + time_old = static_cast(iter-1)*deltaT; + } + + /*--- Store displacement of each node on the plunging surface ---*/ + /*--- Loop over markers and find the particular marker(s) (surface) to plunge ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + Moving = config->GetMarker_All_Moving(iMarker); + if (Moving == YES) { + for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { + + Moving_Tag = config->GetMarker_Moving(jMarker); + Marker_Tag = config->GetMarker_All_TagBound(iMarker); + + if (Marker_Tag == Moving_Tag) { + + /*--- Plunging frequency and amplitude from config. ---*/ + + Omega[0] = config->GetPlunging_Omega_X(jMarker)/config->GetOmega_Ref(); + Omega[1] = config->GetPlunging_Omega_Y(jMarker)/config->GetOmega_Ref(); + Omega[2] = config->GetPlunging_Omega_Z(jMarker)/config->GetOmega_Ref(); + Ampl[0] = config->GetPlunging_Ampl_X(jMarker)/Lref; + Ampl[1] = config->GetPlunging_Ampl_Y(jMarker)/Lref; + Ampl[2] = config->GetPlunging_Ampl_Z(jMarker)/Lref; + + /*--- Print some information to the console. Be verbose at the first + iteration only (mostly for debugging purposes). ---*/ + // Note that the MASTER_NODE might not contain all the markers being moved. + + if (rank == MASTER_NODE) { + cout << " Storing plunging displacement for marker: "; + cout << Marker_Tag << "." << endl; + if (iter == 0) { + cout << " Plunging frequency: (" << Omega[0] << ", " << Omega[1]; + cout << ", " << Omega[2] << ") rad/s." << endl; + cout << " Plunging amplitude: (" << Ampl[0]/DEG2RAD; + cout << ", " << Ampl[1]/DEG2RAD << ", " << Ampl[2]/DEG2RAD; + cout << ") degrees."<< endl; + } + } + + /*--- Compute delta change in the position in the x, y, & z directions. ---*/ + + VarCoord[0] = -Ampl[0]*(sin(Omega[0]*time_new) - sin(Omega[0]*time_old)); + VarCoord[1] = -Ampl[1]*(sin(Omega[1]*time_new) - sin(Omega[1]*time_old)); + VarCoord[2] = -Ampl[2]*(sin(Omega[2]*time_new) - sin(Omega[2]*time_old)); + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + /*--- Set node displacement for volume deformation ---*/ + geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + + } + } + } + } + } + + /*--- When updating the origins it is assumed that all markers have the + same plunging movement, because we use the last VarCoord set ---*/ + + /*--- Set the mesh motion center to the new location after + incrementing the position with the translation. This new + location will be used for subsequent mesh motion for the given marker.---*/ + + for (jMarker=0; jMarkerGetnMarker_Moving(); jMarker++) { + + /*-- Check if we want to update the motion origin for the given marker ---*/ + + if (config->GetMoveMotion_Origin(jMarker) == YES) { + Center[0] = config->GetMotion_Origin_X(jMarker) + VarCoord[0]; + Center[1] = config->GetMotion_Origin_Y(jMarker) + VarCoord[1]; + Center[2] = config->GetMotion_Origin_Z(jMarker) + VarCoord[2]; + config->SetMotion_Origin_X(jMarker, Center[0]); + config->SetMotion_Origin_Y(jMarker, Center[1]); + config->SetMotion_Origin_Z(jMarker, Center[2]); + } + } + + /*--- Set the moment computation center to the new location after + incrementing the position with the plunging. ---*/ + + for (jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { + Center[0] = config->GetRefOriginMoment_X(jMarker) + VarCoord[0]; + Center[1] = config->GetRefOriginMoment_Y(jMarker) + VarCoord[1]; + Center[2] = config->GetRefOriginMoment_Z(jMarker) + VarCoord[2]; + config->SetRefOriginMoment_X(jMarker, Center[0]); + config->SetRefOriginMoment_Y(jMarker, Center[1]); + config->SetRefOriginMoment_Z(jMarker, Center[2]); + } +} + +void CSurfaceMovement::Surface_Pitching(CGeometry *geometry, CConfig *config, + unsigned long iter, unsigned short iZone) { + + su2double deltaT, time_new, time_old, Lref, *Coord; + su2double Center[3], VarCoord[3], Omega[3], Ampl[3], Phase[3]; + su2double rotCoord[3], r[3] = {0.0,0.0,0.0}; + su2double rotMatrix[3][3] = {{0.0,0.0,0.0}, {0.0,0.0,0.0}, {0.0,0.0,0.0}}; + su2double dtheta, dphi, dpsi, cosTheta, sinTheta; + su2double cosPhi, sinPhi, cosPsi, sinPsi; + su2double DEG2RAD = PI_NUMBER/180.0; + unsigned short iMarker, jMarker, Moving, iDim, nDim = geometry->GetnDim(); + unsigned long iPoint, iVertex; + string Marker_Tag, Moving_Tag; + int rank; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#else + rank = MASTER_NODE; +#endif + + /*--- Initialize the delta variation in coordinates ---*/ + VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; + + /*--- Retrieve values from the config file ---*/ + + deltaT = config->GetDelta_UnstTimeND(); + Lref = config->GetLength_Ref(); + + /*--- Compute delta time based on physical time step ---*/ + time_new = static_cast(iter)*deltaT; + if (iter == 0) { + time_old = time_new; + } else { + time_old = static_cast(iter-1)*deltaT; + } + + /*--- Store displacement of each node on the pitching surface ---*/ + /*--- Loop over markers and find the particular marker(s) (surface) to pitch ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + Moving = config->GetMarker_All_Moving(iMarker); + if (Moving == YES) { + for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { + + Moving_Tag = config->GetMarker_Moving(jMarker); + Marker_Tag = config->GetMarker_All_TagBound(iMarker); + + if (Marker_Tag == Moving_Tag) { + + /*--- Pitching origin, frequency, and amplitude from config. ---*/ + + Center[0] = config->GetMotion_Origin_X(jMarker); + Center[1] = config->GetMotion_Origin_Y(jMarker); + Center[2] = config->GetMotion_Origin_Z(jMarker); + Omega[0] = config->GetPitching_Omega_X(jMarker)/config->GetOmega_Ref(); + Omega[1] = config->GetPitching_Omega_Y(jMarker)/config->GetOmega_Ref(); + Omega[2] = config->GetPitching_Omega_Z(jMarker)/config->GetOmega_Ref(); + Ampl[0] = config->GetPitching_Ampl_X(jMarker)*DEG2RAD; + Ampl[1] = config->GetPitching_Ampl_Y(jMarker)*DEG2RAD; + Ampl[2] = config->GetPitching_Ampl_Z(jMarker)*DEG2RAD; + Phase[0] = config->GetPitching_Phase_X(jMarker)*DEG2RAD; + Phase[1] = config->GetPitching_Phase_Y(jMarker)*DEG2RAD; + Phase[2] = config->GetPitching_Phase_Z(jMarker)*DEG2RAD; + + /*--- Print some information to the console. Be verbose at the first + iteration only (mostly for debugging purposes). ---*/ + // Note that the MASTER_NODE might not contain all the markers being moved. + + if (rank == MASTER_NODE) { + cout << " Storing pitching displacement for marker: "; + cout << Marker_Tag << "." << endl; + if (iter == 0) { + cout << " Pitching frequency: (" << Omega[0] << ", " << Omega[1]; + cout << ", " << Omega[2] << ") rad/s about origin: (" << Center[0]; + cout << ", " << Center[1] << ", " << Center[2] << ")." << endl; + cout << " Pitching amplitude about origin: (" << Ampl[0]/DEG2RAD; + cout << ", " << Ampl[1]/DEG2RAD << ", " << Ampl[2]/DEG2RAD; + cout << ") degrees."<< endl; + cout << " Pitching phase lag about origin: (" << Phase[0]/DEG2RAD; + cout << ", " << Phase[1]/DEG2RAD <<", "<< Phase[2]/DEG2RAD; + cout << ") degrees."<< endl; + } + } + + /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ + + dtheta = -Ampl[0]*(sin(Omega[0]*time_new + Phase[0]) + - sin(Omega[0]*time_old + Phase[0])); + dphi = -Ampl[1]*(sin(Omega[1]*time_new + Phase[1]) + - sin(Omega[1]*time_old + Phase[1])); + dpsi = -Ampl[2]*(sin(Omega[2]*time_new + Phase[2]) + - sin(Omega[2]*time_old + Phase[2])); + + /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ + + cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); + sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ + + rotMatrix[0][0] = cosPhi*cosPsi; + rotMatrix[1][0] = cosPhi*sinPsi; + rotMatrix[2][0] = -sinPhi; + + rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; + rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; + rotMatrix[2][1] = sinTheta*cosPhi; + + rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[2][2] = cosTheta*cosPhi; + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + /*--- Index and coordinates of the current point ---*/ + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Coord = geometry->node[iPoint]->GetCoord(); + + /*--- Calculate non-dim. position from rotation center ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + r[iDim] = (Coord[iDim]-Center[iDim])/Lref; + if (nDim == 2) r[nDim] = 0.0; + + /*--- Compute transformed point coordinates ---*/ + + rotCoord[0] = rotMatrix[0][0]*r[0] + + rotMatrix[0][1]*r[1] + + rotMatrix[0][2]*r[2] + Center[0]; + + rotCoord[1] = rotMatrix[1][0]*r[0] + + rotMatrix[1][1]*r[1] + + rotMatrix[1][2]*r[2] + Center[1]; + + rotCoord[2] = rotMatrix[2][0]*r[0] + + rotMatrix[2][1]*r[1] + + rotMatrix[2][2]*r[2] + Center[2]; + + /*--- Calculate delta change in the x, y, & z directions ---*/ + for (iDim = 0; iDim < nDim; iDim++) + VarCoord[iDim] = (rotCoord[iDim]-Coord[iDim])/Lref; + if (nDim == 2) VarCoord[nDim] = 0.0; + + /*--- Set node displacement for volume deformation ---*/ + geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + + } + } + } + } + } + /*--- For pitching we don't update the motion origin and moment reference origin. ---*/ +} + +void CSurfaceMovement::Surface_Rotating(CGeometry *geometry, CConfig *config, + unsigned long iter, unsigned short iZone) { + + su2double deltaT, time_new, time_old, Lref, *Coord; + su2double Center[3] = {0.0,0.0,0.0}, VarCoord[3] = {0.0,0.0,0.0}, Omega[3] = {0.0,0.0,0.0}, + rotCoord[3] = {0.0,0.0,0.0}, r[3] = {0.0,0.0,0.0}, Center_Aux[3] = {0.0,0.0,0.0}; + su2double rotMatrix[3][3] = {{0.0,0.0,0.0}, {0.0,0.0,0.0}, {0.0,0.0,0.0}}; + su2double dtheta, dphi, dpsi, cosTheta, sinTheta; + su2double cosPhi, sinPhi, cosPsi, sinPsi; + unsigned short iMarker, jMarker, Moving, iDim, nDim = geometry->GetnDim(); + unsigned long iPoint, iVertex; + string Marker_Tag, Moving_Tag; + int rank; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#else + rank = MASTER_NODE; +#endif + + /*--- Initialize the delta variation in coordinates ---*/ + VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; + + /*--- Retrieve values from the config file ---*/ + + deltaT = config->GetDelta_UnstTimeND(); + Lref = config->GetLength_Ref(); + + /*--- Compute delta time based on physical time step ---*/ + time_new = static_cast(iter)*deltaT; + if (iter == 0) { + time_old = time_new; + } else { + time_old = static_cast(iter-1)*deltaT; + } + + /*--- Store displacement of each node on the rotating surface ---*/ + /*--- Loop over markers and find the particular marker(s) (surface) to rotate ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + Moving = config->GetMarker_All_Moving(iMarker); + if (Moving == YES) { + for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { + + Moving_Tag = config->GetMarker_Moving(jMarker); + Marker_Tag = config->GetMarker_All_TagBound(iMarker); + + if (Marker_Tag == Moving_Tag) { + + /*--- Rotation origin and angular velocity from config. ---*/ + + Center[0] = config->GetMotion_Origin_X(jMarker); + Center[1] = config->GetMotion_Origin_Y(jMarker); + Center[2] = config->GetMotion_Origin_Z(jMarker); + Omega[0] = config->GetRotation_Rate_X(jMarker)/config->GetOmega_Ref(); + Omega[1] = config->GetRotation_Rate_Y(jMarker)/config->GetOmega_Ref(); + Omega[2] = config->GetRotation_Rate_Z(jMarker)/config->GetOmega_Ref(); + + /*--- Print some information to the console. Be verbose at the first + iteration only (mostly for debugging purposes). ---*/ + // Note that the MASTER_NODE might not contain all the markers being moved. + + if (rank == MASTER_NODE) { + cout << " Storing rotating displacement for marker: "; + cout << Marker_Tag << "." << endl; + if (iter == 0) { + cout << " Angular velocity: (" << Omega[0] << ", " << Omega[1]; + cout << ", " << Omega[2] << ") rad/s about origin: (" << Center[0]; + cout << ", " << Center[1] << ", " << Center[2] << ")." << endl; + } + } + + /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ + + dtheta = Omega[0]*(time_new-time_old); + dphi = Omega[1]*(time_new-time_old); + dpsi = Omega[2]*(time_new-time_old); + + /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ + + cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); + sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ + + rotMatrix[0][0] = cosPhi*cosPsi; + rotMatrix[1][0] = cosPhi*sinPsi; + rotMatrix[2][0] = -sinPhi; + + rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; + rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; + rotMatrix[2][1] = sinTheta*cosPhi; + + rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[2][2] = cosTheta*cosPhi; + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + /*--- Index and coordinates of the current point ---*/ + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Coord = geometry->node[iPoint]->GetCoord(); + + /*--- Calculate non-dim. position from rotation center ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + r[iDim] = (Coord[iDim]-Center[iDim])/Lref; + if (nDim == 2) r[nDim] = 0.0; + + /*--- Compute transformed point coordinates ---*/ + + rotCoord[0] = rotMatrix[0][0]*r[0] + + rotMatrix[0][1]*r[1] + + rotMatrix[0][2]*r[2] + Center[0]; + + rotCoord[1] = rotMatrix[1][0]*r[0] + + rotMatrix[1][1]*r[1] + + rotMatrix[1][2]*r[2] + Center[1]; + + rotCoord[2] = rotMatrix[2][0]*r[0] + + rotMatrix[2][1]*r[1] + + rotMatrix[2][2]*r[2] + Center[2]; + + /*--- Calculate delta change in the x, y, & z directions ---*/ + for (iDim = 0; iDim < nDim; iDim++) + VarCoord[iDim] = (rotCoord[iDim]-Coord[iDim])/Lref; + if (nDim == 2) VarCoord[nDim] = 0.0; + + /*--- Set node displacement for volume deformation ---*/ + geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + + } + } + } + } + } + + /*--- When updating the origins it is assumed that all markers have the + same rotation movement, because we use the last markers rotation matrix and center ---*/ + + /*--- Set the mesh motion center to the new location after + incrementing the position with the rotation. This new + location will be used for subsequent mesh motion for the given marker.---*/ + + for (jMarker=0; jMarkerGetnMarker_Moving(); jMarker++) { + + /*-- Check if we want to update the motion origin for the given marker ---*/ + + if (config->GetMoveMotion_Origin(jMarker) == YES) { + + Center_Aux[0] = config->GetMotion_Origin_X(jMarker); + Center_Aux[1] = config->GetMotion_Origin_Y(jMarker); + Center_Aux[2] = config->GetMotion_Origin_Z(jMarker); + + /*--- Calculate non-dim. position from rotation center ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + r[iDim] = (Center_Aux[iDim]-Center[iDim])/Lref; + if (nDim == 2) r[nDim] = 0.0; + + /*--- Compute transformed point coordinates ---*/ + + rotCoord[0] = rotMatrix[0][0]*r[0] + + rotMatrix[0][1]*r[1] + + rotMatrix[0][2]*r[2] + Center[0]; + + rotCoord[1] = rotMatrix[1][0]*r[0] + + rotMatrix[1][1]*r[1] + + rotMatrix[1][2]*r[2] + Center[1]; + + rotCoord[2] = rotMatrix[2][0]*r[0] + + rotMatrix[2][1]*r[1] + + rotMatrix[2][2]*r[2] + Center[2]; + + /*--- Calculate delta change in the x, y, & z directions ---*/ + for (iDim = 0; iDim < nDim; iDim++) + VarCoord[iDim] = (rotCoord[iDim]-Center_Aux[iDim])/Lref; + if (nDim == 2) VarCoord[nDim] = 0.0; + config->SetMotion_Origin_X(jMarker, Center_Aux[0]+VarCoord[0]); + config->SetMotion_Origin_Y(jMarker, Center_Aux[1]+VarCoord[1]); + config->SetMotion_Origin_Z(jMarker, Center_Aux[2]+VarCoord[2]); + } + } + + /*--- Set the moment computation center to the new location after + incrementing the position with the rotation. ---*/ + + for (jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { + + Center_Aux[0] = config->GetRefOriginMoment_X(jMarker); + Center_Aux[1] = config->GetRefOriginMoment_Y(jMarker); + Center_Aux[2] = config->GetRefOriginMoment_Z(jMarker); + + /*--- Calculate non-dim. position from rotation center ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + r[iDim] = (Center_Aux[iDim]-Center[iDim])/Lref; + if (nDim == 2) r[nDim] = 0.0; + + /*--- Compute transformed point coordinates ---*/ + + rotCoord[0] = rotMatrix[0][0]*r[0] + + rotMatrix[0][1]*r[1] + + rotMatrix[0][2]*r[2] + Center[0]; + + rotCoord[1] = rotMatrix[1][0]*r[0] + + rotMatrix[1][1]*r[1] + + rotMatrix[1][2]*r[2] + Center[1]; + + rotCoord[2] = rotMatrix[2][0]*r[0] + + rotMatrix[2][1]*r[1] + + rotMatrix[2][2]*r[2] + Center[2]; + + /*--- Calculate delta change in the x, y, & z directions ---*/ + for (iDim = 0; iDim < nDim; iDim++) + VarCoord[iDim] = (rotCoord[iDim]-Center_Aux[iDim])/Lref; + if (nDim == 2) VarCoord[nDim] = 0.0; + + config->SetRefOriginMoment_X(jMarker, Center_Aux[0]+VarCoord[0]); + config->SetRefOriginMoment_Y(jMarker, Center_Aux[1]+VarCoord[1]); + config->SetRefOriginMoment_Z(jMarker, Center_Aux[2]+VarCoord[2]); + } +} + +void CSurfaceMovement::AeroelasticDeform(CGeometry *geometry, CConfig *config, unsigned long ExtIter, unsigned short iMarker, unsigned short iMarker_Monitoring, vector& displacements) { + + /* The sign conventions of these are those of the Typical Section Wing Model, below the signs are corrected */ + su2double dh = -displacements[0]; // relative plunge + su2double dalpha = -displacements[1]; // relative pitch + su2double dh_x, dh_y; + su2double Center[2]; + unsigned short iDim; + su2double Lref = config->GetLength_Ref(); + su2double *Coord; + unsigned long iPoint, iVertex; + su2double x_new, y_new; + su2double VarCoord[3]; + string Monitoring_Tag = config->GetMarker_Monitoring(iMarker_Monitoring); + + /*--- Calculate the plunge displacement for the Typical Section Wing Model taking into account rotation ---*/ + if (config->GetKind_GridMovement(ZONE_0) == AEROELASTIC_RIGID_MOTION) { + su2double Omega, dt, psi; + dt = config->GetDelta_UnstTimeND(); + Omega = (config->GetRotation_Rate_Z(ZONE_0)/config->GetOmega_Ref()); + psi = Omega*(dt*ExtIter); + + /*--- Correct for the airfoil starting position (This is hardcoded in here) ---*/ + if (Monitoring_Tag == "Airfoil1") { + psi = psi + 0.0; + } + else if (Monitoring_Tag == "Airfoil2") { + psi = psi + 2.0/3.0*PI_NUMBER; + } + else if (Monitoring_Tag == "Airfoil3") { + psi = psi + 4.0/3.0*PI_NUMBER; + } + else + cout << "WARNING: There is a marker that we are monitoring that doesn't match the values hardcoded above!" << endl; + + dh_x = -dh*sin(psi); + dh_y = dh*cos(psi); + + } else { + dh_x = 0; + dh_y = dh; + } + + /*--- Pitching origin from config. ---*/ + + Center[0] = config->GetRefOriginMoment_X(iMarker_Monitoring); + Center[1] = config->GetRefOriginMoment_Y(iMarker_Monitoring); + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + /*--- Coordinates of the current point ---*/ + Coord = geometry->node[iPoint]->GetCoord(); + + /*--- Calculate non-dim. position from rotation center ---*/ + su2double r[2] = {0,0}; + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) + r[iDim] = (Coord[iDim]-Center[iDim])/Lref; + + /*--- Compute delta of transformed point coordinates ---*/ + // The deltas are needed for the FEA grid deformation Method. + // rotation contribution - previous position + plunging contribution + x_new = cos(dalpha)*r[0] - sin(dalpha)*r[1] -r[0] + dh_x; + y_new = sin(dalpha)*r[0] + cos(dalpha)*r[1] -r[1] + dh_y; + + VarCoord[0] = x_new; + VarCoord[1] = y_new; + VarCoord[2] = 0.0; + + /*--- Store new delta node locations for the surface ---*/ + geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + } + /*--- Set the elastic axis to the new location after incrementing the position with the plunge ---*/ + config->SetRefOriginMoment_X(iMarker_Monitoring, Center[0]+dh_x); + config->SetRefOriginMoment_Y(iMarker_Monitoring, Center[1]+dh_y); + + +} + +void CSurfaceMovement::SetBoundary_Flutter3D(CGeometry *geometry, CConfig *config, + CFreeFormDefBox **FFDBox, unsigned long iter, unsigned short iZone) { + + su2double omega, deltaT; + su2double alpha, alpha_new, alpha_old; + su2double time_new, time_old; + su2double Omega[3], Ampl[3]; + su2double DEG2RAD = PI_NUMBER/180.0; + int rank; + bool adjoint = config->GetAdjoint(); + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#else + rank = MASTER_NODE; +#endif + + /*--- Retrieve values from the config file ---*/ + + deltaT = config->GetDelta_UnstTimeND(); + + /*--- Pitching origin, frequency, and amplitude from config. ---*/ + + Omega[0] = (config->GetPitching_Omega_X(iZone)/config->GetOmega_Ref()); + Omega[1] = (config->GetPitching_Omega_Y(iZone)/config->GetOmega_Ref()); + Omega[2] = (config->GetPitching_Omega_Z(iZone)/config->GetOmega_Ref()); + Ampl[0] = config->GetPitching_Ampl_X(iZone)*DEG2RAD; + Ampl[1] = config->GetPitching_Ampl_Y(iZone)*DEG2RAD; + Ampl[2] = config->GetPitching_Ampl_Z(iZone)*DEG2RAD; + + /*--- Compute delta time based on physical time step ---*/ + + if (adjoint) { + + /*--- For the unsteady adjoint, we integrate backwards through + physical time, so perform mesh motion in reverse. ---*/ + + unsigned long nFlowIter = config->GetnExtIter(); + unsigned long directIter = nFlowIter - iter - 1; + time_new = static_cast(directIter)*deltaT; + time_old = time_new; + if (iter != 0) time_old = (static_cast(directIter)+1.0)*deltaT; + } else { + + /*--- Forward time for the direct problem ---*/ + + time_new = static_cast(iter)*deltaT; + time_old = time_new; + if (iter != 0) time_old = (static_cast(iter)-1.0)*deltaT; + } + + /*--- Update the pitching angle at this time step. Flip sign for + nose-up positive convention. ---*/ + + omega = Omega[2]; + alpha_new = Ampl[2]*sin(omega*time_new); + alpha_old = Ampl[2]*sin(omega*time_old); + alpha = (1E-10 + (alpha_new - alpha_old))*(-PI_NUMBER/180.0); + + if (rank == MASTER_NODE) + cout << "New dihedral angle (alpha): " << alpha_new/DEG2RAD << " degrees." << endl; + + unsigned short iOrder, jOrder, kOrder; + short iFFDBox; + su2double movement[3] = {0.0,0.0,0.0}; + bool *move = new bool [nFFDBox]; + unsigned short *index = new unsigned short[3]; + + move[0] = true; move[1] = true; move[2] = true; + + /*--- Change the value of the control point if move is true ---*/ + + for (iFFDBox = 0; iFFDBox < nFFDBox; iFFDBox++) + if (move[iFFDBox]) + for (iOrder = 0; iOrder < FFDBox[iFFDBox]->GetlOrder(); iOrder++) + for (jOrder = 0; jOrder < FFDBox[iFFDBox]->GetmOrder(); jOrder++) + for (kOrder = 0; kOrder < FFDBox[iFFDBox]->GetnOrder(); kOrder++) { + index[0] = iOrder; index[1] = jOrder; index[2] = kOrder; + su2double *coord = FFDBox[iFFDBox]->GetCoordControlPoints(iOrder, jOrder, kOrder); + movement[0] = 0.0; movement[1] = 0.0; movement[2] = coord[1]*tan(alpha); + FFDBox[iFFDBox]->SetControlPoints(index, movement); + } + + /*--- Recompute cartesian coordinates using the new control points position ---*/ + + for (iFFDBox = 0; iFFDBox < nFFDBox; iFFDBox++) + SetCartesianCoord(geometry, config, FFDBox[iFFDBox], iFFDBox); + +} + +void CSurfaceMovement::SetExternal_Deformation(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter) { + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Local variables ---*/ + + unsigned short iDim, nDim; + unsigned long iPoint = 0, flowIter = 0; + unsigned long jPoint, GlobalIndex; + su2double VarCoord[3], *Coord_Old = NULL, *Coord_New = NULL, Center[3] = {0.0,0.0,0.0}; + su2double Lref = config->GetLength_Ref(); + su2double NewCoord[3] = {0.0,0.0,0.0}, rotMatrix[3][3] = {{0.0,0.0,0.0}, {0.0,0.0,0.0}, {0.0,0.0,0.0}}; + su2double r[3] = {0.0,0.0,0.0}, rotCoord[3] = {0.0,0.0,0.0}; + unsigned long iVertex; + unsigned short iMarker; + char buffer[50]; + string motion_filename, UnstExt, text_line; + ifstream motion_file; + bool unsteady = config->GetUnsteady_Simulation(); + bool adjoint = config->GetAdjoint(); + + /*--- Load stuff from config ---*/ + + nDim = geometry->GetnDim(); + motion_filename = config->GetMotion_FileName(); + + /*--- Set the extension for the correct unsteady mesh motion file ---*/ + + if (unsteady) { + if (adjoint) { + /*--- For the unsteady adjoint, we integrate backwards through + physical time, so perform mesh motion in reverse. ---*/ + unsigned long nFlowIter = config->GetnExtIter() - 1; + flowIter = nFlowIter - iter; + unsigned short lastindex = motion_filename.find_last_of("."); + motion_filename = motion_filename.substr(0, lastindex); + if ((SU2_TYPE::Int(flowIter) >= 0) && (SU2_TYPE::Int(flowIter) < 10)) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(flowIter)); + if ((SU2_TYPE::Int(flowIter) >= 10) && (SU2_TYPE::Int(flowIter) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(flowIter)); + if ((SU2_TYPE::Int(flowIter) >= 100) && (SU2_TYPE::Int(flowIter) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(flowIter)); + if ((SU2_TYPE::Int(flowIter) >= 1000) && (SU2_TYPE::Int(flowIter) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(flowIter)); + if (SU2_TYPE::Int(flowIter) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(flowIter)); + UnstExt = string(buffer); + motion_filename.append(UnstExt); + } else { + /*--- Forward time for the direct problem ---*/ + flowIter = iter; + unsigned short lastindex = motion_filename.find_last_of("."); + motion_filename = motion_filename.substr(0, lastindex); + if ((SU2_TYPE::Int(flowIter) >= 0) && (SU2_TYPE::Int(flowIter) < 10)) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(flowIter)); + if ((SU2_TYPE::Int(flowIter) >= 10) && (SU2_TYPE::Int(flowIter) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(flowIter)); + if ((SU2_TYPE::Int(flowIter) >= 100) && (SU2_TYPE::Int(flowIter) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(flowIter)); + if ((SU2_TYPE::Int(flowIter) >= 1000) && (SU2_TYPE::Int(flowIter) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(flowIter)); + if (SU2_TYPE::Int(flowIter) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(flowIter)); + UnstExt = string(buffer); + motion_filename.append(UnstExt); + } + + if (rank == MASTER_NODE) + cout << "Reading in the arbitrary mesh motion from direct iteration " << flowIter << "." << endl; + } + + /*--- Open the motion file ---*/ + + motion_file.open(motion_filename.data(), ios::in); + /*--- Throw error if there is no file ---*/ + if (motion_file.fail()) { + cout << "There is no mesh motion file!" << endl; + exit(EXIT_FAILURE); + } + + /*--- Read in and store the new mesh node locations ---*/ + + while (getline(motion_file, text_line)) { + istringstream point_line(text_line); + if (nDim == 2) point_line >> iPoint >> NewCoord[0] >> NewCoord[1]; + if (nDim == 3) point_line >> iPoint >> NewCoord[0] >> NewCoord[1] >> NewCoord[2]; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_Moving(iMarker) == YES) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + jPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + GlobalIndex = geometry->node[jPoint]->GetGlobalIndex(); + if (GlobalIndex == iPoint) { + geometry->vertex[iMarker][iVertex]->SetVarCoord(NewCoord); + break; + } + } + } + } + } + /*--- Close the restart file ---*/ + motion_file.close(); + + /*--- If rotating as well, prepare the rotation matrix ---*/ + + if (config->GetGrid_Movement() && + config->GetKind_GridMovement(iZone) == EXTERNAL_ROTATION) { + + /*--- Variables needed only for rotation ---*/ + + su2double Omega[3], dt; + su2double dtheta, dphi, dpsi, cosTheta, sinTheta; + su2double cosPhi, sinPhi, cosPsi, sinPsi; + + /*--- Center of rotation & angular velocity vector from config ---*/ + Center[0] = config->GetMotion_Origin_X(iZone); + Center[1] = config->GetMotion_Origin_Y(iZone); + Center[2] = config->GetMotion_Origin_Z(iZone); + + /*--- Angular velocity vector from config ---*/ + + dt = static_cast(iter)*config->GetDelta_UnstTimeND(); + Omega[0] = config->GetRotation_Rate_X(iZone); + Omega[1] = config->GetRotation_Rate_Y(iZone); + Omega[2] = config->GetRotation_Rate_Z(iZone); + + /*--- For the unsteady adjoint, use reverse time ---*/ + if (adjoint) { + /*--- Set the first adjoint mesh position to the final direct one ---*/ + if (iter == 0) dt = ((su2double)config->GetnExtIter()-1) * dt; + /*--- Reverse the rotation direction for the adjoint ---*/ + else dt = -1.0*dt; + } else { + /*--- No rotation at all for the first direct solution ---*/ + if (iter == 0) dt = 0; + } + + /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ + + dtheta = Omega[0]*dt; + dphi = Omega[1]*dt; + dpsi = Omega[2]*dt; + + /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ + + cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); + sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ + + rotMatrix[0][0] = cosPhi*cosPsi; + rotMatrix[1][0] = cosPhi*sinPsi; + rotMatrix[2][0] = -sinPhi; + + rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; + rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; + rotMatrix[2][1] = sinTheta*cosPhi; + + rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[2][2] = cosTheta*cosPhi; + + } + + /*--- Loop through to find only moving surface markers ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_Moving(iMarker) == YES) { + + /*--- Loop over all surface points for this marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + /*--- Get current and new coordinates from file ---*/ + + Coord_Old = geometry->node[iPoint]->GetCoord(); + Coord_New = geometry->vertex[iMarker][iVertex]->GetVarCoord(); + + /*--- If we're also rotating, multiply each point by the + rotation matrix. It is assumed that the coordinates in + Coord_Old have already been rotated using SetRigid_Rotation(). ---*/ + + if (config->GetGrid_Movement() && + config->GetKind_GridMovement(iZone) == EXTERNAL_ROTATION) { + + /*--- Calculate non-dim. position from rotation center ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + r[iDim] = (Coord_New[iDim]-Center[iDim])/Lref; + if (nDim == 2) r[nDim] = 0.0; + + /*--- Compute transformed point coordinates ---*/ + + rotCoord[0] = rotMatrix[0][0]*r[0] + + rotMatrix[0][1]*r[1] + + rotMatrix[0][2]*r[2] + Center[0]; + + rotCoord[1] = rotMatrix[1][0]*r[0] + + rotMatrix[1][1]*r[1] + + rotMatrix[1][2]*r[2] + Center[1]; + + rotCoord[2] = rotMatrix[2][0]*r[0] + + rotMatrix[2][1]*r[1] + + rotMatrix[2][2]*r[2] + Center[2]; + + /*--- Copy rotated coords back to original array for consistency ---*/ + for (iDim = 0; iDim < nDim; iDim++) + Coord_New[iDim] = rotCoord[iDim]; + } + + /*--- Calculate delta change in the x, y, & z directions ---*/ + for (iDim = 0; iDim < nDim; iDim++) + VarCoord[iDim] = (Coord_New[iDim]-Coord_Old[iDim])/Lref; + if (nDim == 2) VarCoord[nDim] = 0.0; + + /*--- Set position changes to be applied by the spring analogy ---*/ + geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + + } + } + } +} + +void CSurfaceMovement::SetNACA_4Digits(CGeometry *boundary, CConfig *config) { + unsigned long iVertex; + unsigned short iMarker; + su2double VarCoord[3], *Coord, *Normal, Ycurv, Yesp; + + if (config->GetnDV() != 1) { cout << "This kind of design variable is not prepared for multiple deformations."; cin.get(); } + + su2double Ya = config->GetParamDV(0,0) / 100.0; /*--- Maximum camber as a fraction of the chord + (100 m is the first of the four digits) ---*/ + su2double Xa = config->GetParamDV(0,1) / 10.0; /*--- Location of maximum camber as a fraction of + the chord (10 p is the second digit in the NACA xxxx description) ---*/ + su2double t = config->GetParamDV(0,2) / 100.0; /*--- Maximum thickness as a fraction of the + chord (so 100 t gives the last two digits in + the NACA 4-digit denomination) ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { + VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; + if (config->GetMarker_All_DV(iMarker) == YES) { + Coord = boundary->vertex[iMarker][iVertex]->GetCoord(); + Normal = boundary->vertex[iMarker][iVertex]->GetNormal(); + + if (Coord[0] < Xa) Ycurv = (2.0*Xa*Coord[0]-pow(Coord[0],2.0))*(Ya/pow(Xa,2.0)); + else Ycurv = ((1.0-2.0*Xa)+2.0*Xa*Coord[0]-pow(Coord[0],2.0))*(Ya/pow((1.0-Xa), 2.0)); + + Yesp = t*(1.4845*sqrt(Coord[0])-0.6300*Coord[0]-1.7580*pow(Coord[0],2.0)+ + 1.4215*pow(Coord[0],3.0)-0.518*pow(Coord[0],4.0)); + + if (Normal[1] > 0) VarCoord[1] = (Ycurv + Yesp) - Coord[1]; + if (Normal[1] < 0) VarCoord[1] = (Ycurv - Yesp) - Coord[1]; + + } + boundary->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + } +} + +void CSurfaceMovement::SetParabolic(CGeometry *boundary, CConfig *config) { + unsigned long iVertex; + unsigned short iMarker; + su2double VarCoord[3], *Coord, *Normal; + + if (config->GetnDV() != 1) { cout << "This kind of design variable is not prepared for multiple deformations."; cin.get(); } + + su2double c = config->GetParamDV(0,0); /*--- Center of the parabola ---*/ + su2double t = config->GetParamDV(0,1) / 100.0; /*--- Thickness of the parabola ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { + VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; + if (config->GetMarker_All_DV(iMarker) == YES) { + Coord = boundary->vertex[iMarker][iVertex]->GetCoord(); + Normal = boundary->vertex[iMarker][iVertex]->GetNormal(); + + if (Normal[1] > 0) { + VarCoord[1] = t*(Coord[0]*Coord[0]-Coord[0])/(2.0*(c*c-c)) - Coord[1]; + } + if (Normal[1] < 0) { + VarCoord[1] = t*(Coord[0]-Coord[0]*Coord[0])/(2.0*(c*c-c)) - Coord[1]; + } + } + boundary->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + } +} + +void CSurfaceMovement::SetAirfoil(CGeometry *boundary, CConfig *config) { + unsigned long iVertex, n_Airfoil = 0; + unsigned short iMarker, nUpper, nLower, iUpper, iLower, iVar, iDim; + su2double *VarCoord, *Coord, NewYCoord, NewXCoord, *Coord_i, *Coord_ip1, yp1, ypn, + Airfoil_Coord[2]= {0.0,0.0}, factor, coeff = 10000, Upper, Lower, Arch = 0.0, TotalArch = 0.0, + x_i, x_ip1, y_i, y_ip1; + passivedouble AirfoilScale; + vector Svalue, Xcoord, Ycoord, Xcoord2, Ycoord2, Xcoord_Aux, Ycoord_Aux; + bool AddBegin = true, AddEnd = true; + char AirfoilFile[256], AirfoilFormat[15], MeshOrientation[15], AirfoilClose[15]; + ifstream airfoil_file; + string text_line; + int ierr = 0; + + unsigned short nDim = boundary->GetnDim(); + + VarCoord = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim++) + VarCoord[iDim] = 0.0; + + /*--- Get the SU2 module. SU2_CFD will use this routine for dynamically + deforming meshes (MARKER_MOVING), while SU2_DEF will use it for deforming + meshes after imposing design variable surface deformations (DV_MARKER). ---*/ + + unsigned short Kind_SU2 = config->GetKind_SU2(); + + /*--- Read the coordinates. Two main formats: + - Selig are in an x, y format starting from trailing edge, along the upper surface to the leading + edge and back around the lower surface to trailing edge. + - Lednicer are upper surface points leading edge to trailing edge and then lower surface leading + edge to trailing edge. + ---*/ + + /*--- Open the restart file, throw an error if this fails. ---*/ + + cout << "Enter the name of file with the airfoil information: "; + ierr = scanf("%s", AirfoilFile); + if (ierr == 0) { cout << "No input read!! "<< endl; exit(EXIT_FAILURE); } + airfoil_file.open(AirfoilFile, ios::in); + if (airfoil_file.fail()) { + cout << "There is no airfoil file!! "<< endl; + exit(EXIT_FAILURE); + } + cout << "Enter the format of the airfoil (Selig or Lednicer): "; + ierr = scanf("%s", AirfoilFormat); + if (ierr == 0) { cout << "No input read!! "<< endl; exit(EXIT_FAILURE); } + + cout << "Thickness scaling (1.0 means no scaling)?: "; + ierr = scanf("%lf", &AirfoilScale); + if (ierr == 0) { cout << "No input read!! "<< endl; exit(EXIT_FAILURE); } + + cout << "Close the airfoil (Yes or No)?: "; + ierr = scanf("%s", AirfoilClose); + if (ierr == 0) { cout << "No input read!! "<< endl; exit(EXIT_FAILURE); } + + cout << "Surface mesh orientation (clockwise, or anticlockwise): "; + ierr = scanf("%s", MeshOrientation); + if (ierr == 0) { cout << "No input read!! "<< endl; exit(EXIT_FAILURE); } + + /*--- The first line is the header ---*/ + + getline (airfoil_file, text_line); + cout << "File info: " << text_line << endl; + + if (strcmp (AirfoilFormat,"Selig") == 0) { + + while (getline (airfoil_file, text_line)) { + istringstream point_line(text_line); + + /*--- Read the x & y coordinates from this line of the file (anticlockwise) ---*/ + + point_line >> Airfoil_Coord[0] >> Airfoil_Coord[1]; + + /*--- Close the arifoil ---*/ + + if (strcmp (AirfoilClose,"Yes") == 0) + factor = -atan(coeff*(Airfoil_Coord[0]-1.0))*2.0/PI_NUMBER; + else factor = 1.0; + + /*--- Store the coordinates in vectors ---*/ + + Xcoord.push_back(Airfoil_Coord[0]); + Ycoord.push_back(Airfoil_Coord[1]*factor*AirfoilScale); + } + + } + if (strcmp (AirfoilFormat,"Lednicer") == 0) { + + /*--- The second line is the number of points ---*/ + + getline(airfoil_file, text_line); + istringstream point_line(text_line); + point_line >> Upper >> Lower; + + nUpper = SU2_TYPE::Int(Upper); + nLower = SU2_TYPE::Int(Lower); + + Xcoord.resize(nUpper+nLower-1); + Ycoord.resize(nUpper+nLower-1); + + /*--- White line ---*/ + + getline (airfoil_file, text_line); + + for (iUpper = 0; iUpper < nUpper; iUpper++) { + getline (airfoil_file, text_line); + istringstream point_line(text_line); + point_line >> Airfoil_Coord[0] >> Airfoil_Coord[1]; + Xcoord[nUpper-iUpper-1] = Airfoil_Coord[0]; + + if (strcmp (AirfoilClose,"Yes") == 0) + factor = -atan(coeff*(Airfoil_Coord[0]-1.0))*2.0/PI_NUMBER; + else factor = 1.0; + + Ycoord[nUpper-iUpper-1] = Airfoil_Coord[1]*AirfoilScale*factor; + } + + getline (airfoil_file, text_line); + + for (iLower = 0; iLower < nLower; iLower++) { + getline (airfoil_file, text_line); + istringstream point_line(text_line); + point_line >> Airfoil_Coord[0] >> Airfoil_Coord[1]; + + if (strcmp (AirfoilClose,"Yes") == 0) + factor = -atan(coeff*(Airfoil_Coord[0]-1.0))*2.0/PI_NUMBER; + else factor = 1.0; + + Xcoord[nUpper+iLower-1] = Airfoil_Coord[0]; + Ycoord[nUpper+iLower-1] = Airfoil_Coord[1]*AirfoilScale*factor; + } + + } + + /*--- Check the coordinate (1,0) at the beginning and end of the file ---*/ + + if (Xcoord[0] == 1.0) AddBegin = false; + if (Xcoord[Xcoord.size()-1] == 1.0) AddEnd = false; + + if (AddBegin) { Xcoord.insert(Xcoord.begin(), 1.0); Ycoord.insert(Ycoord.begin(), 0.0);} + if (AddEnd) { Xcoord.push_back(1.0); Ycoord.push_back(0.0);} + + /*--- Change the orientation (depend on the input file, and the mesh file) ---*/ + + if (strcmp (MeshOrientation,"clockwise") == 0) { + for (iVar = 0; iVar < Xcoord.size(); iVar++) { + Xcoord_Aux.push_back(Xcoord[iVar]); + Ycoord_Aux.push_back(Ycoord[iVar]); + } + + for (iVar = 0; iVar < Xcoord.size(); iVar++) { + Xcoord[iVar] = Xcoord_Aux[Xcoord.size()-iVar-1]; + Ycoord[iVar] = Ycoord_Aux[Xcoord.size()-iVar-1]; + } + } + + /*--- Compute the total arch length ---*/ + + Arch = 0.0; Svalue.push_back(Arch); + + for (iVar = 0; iVar < Xcoord.size()-1; iVar++) { + x_i = Xcoord[iVar]; x_ip1 = Xcoord[iVar+1]; + y_i = Ycoord[iVar]; y_ip1 = Ycoord[iVar+1]; + Arch += sqrt((x_ip1-x_i)*(x_ip1-x_i)+(y_ip1-y_i)*(y_ip1-y_i)); + Svalue.push_back(Arch); + } + x_i = Xcoord[Xcoord.size()-1]; x_ip1 = Xcoord[0]; + y_i = Ycoord[Xcoord.size()-1]; y_ip1 = Ycoord[0]; + Arch += sqrt((x_ip1-x_i)*(x_ip1-x_i)+(y_ip1-y_i)*(y_ip1-y_i)); + + /*--- Non dimensionalization ---*/ + + for (iVar = 0; iVar < Svalue.size(); iVar++) { Svalue[iVar] /= Arch; } + + /*--- Close the restart file ---*/ + + airfoil_file.close(); + + /*--- Create a spline for X and Y coordiantes using the arch length ---*/ + + n_Airfoil = Svalue.size(); + yp1 = (Xcoord[1]-Xcoord[0])/(Svalue[1]-Svalue[0]); + ypn = (Xcoord[n_Airfoil-1]-Xcoord[n_Airfoil-2])/(Svalue[n_Airfoil-1]-Svalue[n_Airfoil-2]); + + Xcoord2.resize(n_Airfoil+1); + boundary->SetSpline(Svalue, Xcoord, n_Airfoil, yp1, ypn, Xcoord2); + + n_Airfoil = Svalue.size(); + yp1 = (Ycoord[1]-Ycoord[0])/(Svalue[1]-Svalue[0]); + ypn = (Ycoord[n_Airfoil-1]-Ycoord[n_Airfoil-2])/(Svalue[n_Airfoil-1]-Svalue[n_Airfoil-2]); + + Ycoord2.resize(n_Airfoil+1); + boundary->SetSpline(Svalue, Ycoord, n_Airfoil, yp1, ypn, Ycoord2); + + TotalArch = 0.0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_CFD)) || + ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DEF))) { + for (iVertex = 0; iVertex < boundary->nVertex[iMarker]-1; iVertex++) { + Coord_i = boundary->vertex[iMarker][iVertex]->GetCoord(); + Coord_ip1 = boundary->vertex[iMarker][iVertex+1]->GetCoord(); + + x_i = Coord_i[0]; x_ip1 = Coord_ip1[0]; + y_i = Coord_i[1]; y_ip1 = Coord_ip1[1]; + + TotalArch += sqrt((x_ip1-x_i)*(x_ip1-x_i)+(y_ip1-y_i)*(y_ip1-y_i)); + } + Coord_i = boundary->vertex[iMarker][boundary->nVertex[iMarker]-1]->GetCoord(); + Coord_ip1 = boundary->vertex[iMarker][0]->GetCoord(); + x_i = Coord_i[0]; x_ip1 = Coord_ip1[0]; + y_i = Coord_i[1]; y_ip1 = Coord_ip1[1]; + TotalArch += sqrt((x_ip1-x_i)*(x_ip1-x_i)+(y_ip1-y_i)*(y_ip1-y_i)); + } + } + + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + Arch = 0.0; + for (iVertex = 0; iVertex < boundary->nVertex[iMarker]; iVertex++) { + VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; + if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_CFD)) || + ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_DEF))) { + Coord = boundary->vertex[iMarker][iVertex]->GetCoord(); + + if (iVertex == 0) Arch = 0.0; + else { + Coord_i = boundary->vertex[iMarker][iVertex-1]->GetCoord(); + Coord_ip1 = boundary->vertex[iMarker][iVertex]->GetCoord(); + x_i = Coord_i[0]; x_ip1 = Coord_ip1[0]; + y_i = Coord_i[1]; y_ip1 = Coord_ip1[1]; + Arch += sqrt((x_ip1-x_i)*(x_ip1-x_i)+(y_ip1-y_i)*(y_ip1-y_i))/TotalArch; + } + + NewXCoord = boundary->GetSpline(Svalue, Xcoord, Xcoord2, n_Airfoil, Arch); + NewYCoord = boundary->GetSpline(Svalue, Ycoord, Ycoord2, n_Airfoil, Arch); + + /*--- Store the delta change in the x & y coordinates ---*/ + + VarCoord[0] = NewXCoord - Coord[0]; + VarCoord[1] = NewYCoord - Coord[1]; + } + + boundary->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + + } + } + + delete [] VarCoord; + +} + +void CSurfaceMovement::ReadFFDInfo(CGeometry *geometry, CConfig *config, CFreeFormDefBox **FFDBox, string val_mesh_filename) { + + string text_line, iTag; + ifstream mesh_file; + su2double coord[3]; + unsigned short degree[3], iFFDBox, iCornerPoints, iControlPoints, iMarker, iDegree, jDegree, kDegree, + iChar, LevelFFDBox, nParentFFDBox, iParentFFDBox, nChildFFDBox, iChildFFDBox, nMarker, *nCornerPoints, + *nControlPoints; + unsigned long iSurfacePoints, iPoint, jPoint, iVertex, nVertex, nPoint, iElem = 0, + nElem, my_nSurfPoints, nSurfPoints, *nSurfacePoints; + + unsigned short nDim = geometry->GetnDim(); + int rank = MASTER_NODE; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + char *cstr = new char [val_mesh_filename.size()+1]; + strcpy (cstr, val_mesh_filename.c_str()); + + mesh_file.open(cstr, ios::in); + if (mesh_file.fail()) { + cout << "There is no geometry file (ReadFFDInfo)!!" << endl; + exit(EXIT_FAILURE); + } + + while (getline (mesh_file, text_line)) { + + /*--- Read the inner elements ---*/ + + string::size_type position = text_line.find ("NELEM=",0); + if (position != string::npos) { + text_line.erase (0,6); nElem = atoi(text_line.c_str()); + for (iElem = 0; iElem < nElem; iElem++) { + getline(mesh_file, text_line); + } + } + + /*--- Read the inner points ---*/ + + position = text_line.find ("NPOIN=",0); + if (position != string::npos) { + text_line.erase (0,6); nPoint = atoi(text_line.c_str()); + for (iPoint = 0; iPoint < nPoint; iPoint++) { + getline(mesh_file, text_line); + } + } + + /*--- Read the boundaries ---*/ + + position = text_line.find ("NMARK=",0); + if (position != string::npos) { + text_line.erase (0,6); nMarker = atoi(text_line.c_str()); + for (iMarker = 0; iMarker < nMarker; iMarker++) { + getline(mesh_file, text_line); + getline(mesh_file, text_line); + text_line.erase (0,13); nVertex = atoi(text_line.c_str()); + for (iVertex = 0; iVertex < nVertex; iVertex++) { + getline(mesh_file, text_line); + } + } + } + + /*--- Read the FFDBox information ---*/ + + position = text_line.find ("FFD_NBOX=",0); + if (position != string::npos) { + text_line.erase (0,9); + nFFDBox = atoi(text_line.c_str()); + + if (rank == MASTER_NODE) cout << nFFDBox << " Free Form Deformation boxes." << endl; + + nCornerPoints = new unsigned short[nFFDBox]; + nControlPoints = new unsigned short[nFFDBox]; + nSurfacePoints = new unsigned long[nFFDBox]; + + getline (mesh_file, text_line); + text_line.erase (0,11); + nLevel = atoi(text_line.c_str()); + + if (rank == MASTER_NODE) cout << nLevel << " Free Form Deformation nested levels." << endl; + + for (iFFDBox = 0 ; iFFDBox < nFFDBox; iFFDBox++) { + + /*--- Read the name of the FFD box ---*/ + + getline (mesh_file, text_line); + text_line.erase (0,8); + + /*--- Remove extra data from the FFDBox name ---*/ + + string::size_type position; + for (iChar = 0; iChar < 20; iChar++) { + position = text_line.find( " ", 0 ); + if (position != string::npos) text_line.erase (position,1); + position = text_line.find( "\r", 0 ); + if (position != string::npos) text_line.erase (position,1); + position = text_line.find( "\n", 0 ); + if (position != string::npos) text_line.erase (position,1); + } + + string TagFFDBox = text_line.c_str(); + + if (rank == MASTER_NODE) cout << "FFD box tag: " << TagFFDBox <<". "; + + /*--- Read the level of the FFD box ---*/ + + getline (mesh_file, text_line); + text_line.erase (0,10); + LevelFFDBox = atoi(text_line.c_str()); + + if (rank == MASTER_NODE) cout << "FFD box level: " << LevelFFDBox <<". "; + + /*--- Read the degree of the FFD box ---*/ + + getline (mesh_file, text_line); + text_line.erase (0,13); degree[0] = atoi(text_line.c_str()); + getline (mesh_file, text_line); + text_line.erase (0,13); degree[1] = atoi(text_line.c_str()); + + if (nDim == 2) { + degree[2] = 1; + } + else { + getline (mesh_file, text_line); + text_line.erase (0,13); degree[2] = atoi(text_line.c_str()); + } + + if (rank == MASTER_NODE) { + cout << "Degrees: " << degree[0] << ", " << degree[1]; + if (nDim == 3) cout << ", " << degree[2]; + cout << ". " << endl; + } + + FFDBox[iFFDBox] = new CFreeFormDefBox(SU2_TYPE::Int(degree[0]), SU2_TYPE::Int(degree[1]), SU2_TYPE::Int(degree[2])); + FFDBox[iFFDBox]->SetTag(TagFFDBox); FFDBox[iFFDBox]->SetLevel(LevelFFDBox); + + /*--- Read the number of parents boxes ---*/ + + getline (mesh_file, text_line); + text_line.erase (0,12); + nParentFFDBox = atoi(text_line.c_str()); + if (rank == MASTER_NODE) cout << "Number of parent boxes: " << nParentFFDBox <<". "; + for (iParentFFDBox = 0; iParentFFDBox < nParentFFDBox; iParentFFDBox++) { + getline(mesh_file, text_line); + + /*--- Remove extra data from the FFDBox name ---*/ + + string::size_type position; + for (iChar = 0; iChar < 20; iChar++) { + position = text_line.find( " ", 0 ); + if (position != string::npos) text_line.erase (position,1); + position = text_line.find( "\r", 0 ); + if (position != string::npos) text_line.erase (position,1); + position = text_line.find( "\n", 0 ); + if (position != string::npos) text_line.erase (position,1); + } + + string ParentFFDBox = text_line.c_str(); + FFDBox[iFFDBox]->SetParentFFDBox(ParentFFDBox); + } + + /*--- Read the number of children boxes ---*/ + + getline (mesh_file, text_line); + text_line.erase (0,13); + nChildFFDBox = atoi(text_line.c_str()); + if (rank == MASTER_NODE) cout << "Number of child boxes: " << nChildFFDBox <<"." << endl; + + for (iChildFFDBox = 0; iChildFFDBox < nChildFFDBox; iChildFFDBox++) { + getline(mesh_file, text_line); + + /*--- Remove extra data from the FFDBox name ---*/ + + string::size_type position; + for (iChar = 0; iChar < 20; iChar++) { + position = text_line.find( " ", 0 ); + if (position != string::npos) text_line.erase (position,1); + position = text_line.find( "\r", 0 ); + if (position != string::npos) text_line.erase (position,1); + position = text_line.find( "\n", 0 ); + if (position != string::npos) text_line.erase (position,1); + } + + string ChildFFDBox = text_line.c_str(); + FFDBox[iFFDBox]->SetChildFFDBox(ChildFFDBox); + } + + /*--- Read the number of the corner points ---*/ + + getline (mesh_file, text_line); + text_line.erase (0,18); nCornerPoints[iFFDBox] = atoi(text_line.c_str()); + if (rank == MASTER_NODE) cout << "Corner points: " << nCornerPoints[iFFDBox] <<". "; + if (nDim == 2) nCornerPoints[iFFDBox] = nCornerPoints[iFFDBox]*SU2_TYPE::Int(2); + + /*--- Read the coordinates of the corner points ---*/ + + for (iCornerPoints = 0; iCornerPoints < nCornerPoints[iFFDBox]; iCornerPoints++) { + + if (nDim == 2) { + if (iCornerPoints < nCornerPoints[iFFDBox]/SU2_TYPE::Int(2)) { + getline(mesh_file, text_line); istringstream FFDBox_line(text_line); + FFDBox_line >> coord[0]; FFDBox_line >> coord[1]; coord[2] = -0.5; + } + else { + coord[0] = FFDBox[iFFDBox]->GetCoordCornerPoints(0, iCornerPoints-nCornerPoints[iFFDBox]/SU2_TYPE::Int(2)); + coord[1] = FFDBox[iFFDBox]->GetCoordCornerPoints(1, iCornerPoints-nCornerPoints[iFFDBox]/SU2_TYPE::Int(2)); + coord[2] = 0.5; + } + } + else { + getline(mesh_file, text_line); istringstream FFDBox_line(text_line); + FFDBox_line >> coord[0]; FFDBox_line >> coord[1]; FFDBox_line >> coord[2]; + } + + FFDBox[iFFDBox]->SetCoordCornerPoints(coord, iCornerPoints); + + } + + /*--- Read the number of the control points ---*/ + + getline (mesh_file, text_line); + text_line.erase (0,19); nControlPoints[iFFDBox] = atoi(text_line.c_str()); + + if (rank == MASTER_NODE) cout << "Control points: " << nControlPoints[iFFDBox] <<". "; + + /*--- Method to identify if there is a FFDBox definition ---*/ + + if (nControlPoints[iFFDBox] != 0) FFDBoxDefinition = true; + + /*--- Read the coordinates of the control points ---*/ + + for (iControlPoints = 0; iControlPoints < nControlPoints[iFFDBox]; iControlPoints++) { + getline(mesh_file, text_line); istringstream FFDBox_line(text_line); + FFDBox_line >> iDegree; FFDBox_line >> jDegree; FFDBox_line >> kDegree; + FFDBox_line >> coord[0]; FFDBox_line >> coord[1]; FFDBox_line >> coord[2]; + FFDBox[iFFDBox]->SetCoordControlPoints(coord, iDegree, jDegree, kDegree); + FFDBox[iFFDBox]->SetCoordControlPoints_Copy(coord, iDegree, jDegree, kDegree); + } + + getline (mesh_file, text_line); + text_line.erase (0,19); nSurfacePoints[iFFDBox] = atoi(text_line.c_str()); + + /*--- The surface points parametric coordinates, all the nodes read the FFD + information but they only store their part ---*/ + + my_nSurfPoints = 0; + for (iSurfacePoints = 0; iSurfacePoints < nSurfacePoints[iFFDBox]; iSurfacePoints++) { + getline(mesh_file, text_line); istringstream FFDBox_line(text_line); + FFDBox_line >> iTag; FFDBox_line >> iPoint; + + if (config->GetMarker_All_TagBound(iTag) != -1) { + + iMarker = config->GetMarker_All_TagBound(iTag); + FFDBox_line >> coord[0]; FFDBox_line >> coord[1]; FFDBox_line >> coord[2]; + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + jPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if (iPoint == geometry->node[jPoint]->GetGlobalIndex()) { + FFDBox[iFFDBox]->Set_MarkerIndex(iMarker); + FFDBox[iFFDBox]->Set_VertexIndex(iVertex); + FFDBox[iFFDBox]->Set_PointIndex(jPoint); + FFDBox[iFFDBox]->Set_ParametricCoord(coord); + FFDBox[iFFDBox]->Set_CartesianCoord(geometry->node[jPoint]->GetCoord()); + my_nSurfPoints++; + } + } + + } + + } + + nSurfacePoints[iFFDBox] = my_nSurfPoints; + +#ifdef HAVE_MPI + nSurfPoints = 0; + SU2_MPI::Allreduce(&my_nSurfPoints, &nSurfPoints, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + if (rank == MASTER_NODE) cout << "Surface points: " << nSurfPoints <<"."<< endl; +#else + nSurfPoints = my_nSurfPoints; + if (rank == MASTER_NODE) cout << "Surface points: " << nSurfPoints <<"."<< endl; +#endif + + } + + delete [] nCornerPoints; + delete [] nControlPoints; + delete [] nSurfacePoints; + } + } + mesh_file.close(); + + if (nFFDBox == 0) { + if (rank == MASTER_NODE) cout <<"There is no FFD box definition. Just in case, check the .su2 file" << endl; + } + +} + +void CSurfaceMovement::ReadFFDInfo(CGeometry *geometry, CConfig *config, CFreeFormDefBox **FFDBox) { + + string text_line, iTag; + ifstream mesh_file; + su2double coord[3]; + unsigned short degree[3], iFFDBox, iCornerPoints, LevelFFDBox, nParentFFDBox, + iParentFFDBox, nChildFFDBox, iChildFFDBox, *nCornerPoints; + + unsigned short nDim = geometry->GetnDim(); + int rank = MASTER_NODE; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + + /*--- Read the FFDBox information from the config file ---*/ + + nFFDBox = config->GetnFFDBox(); + + if (rank == MASTER_NODE) cout << nFFDBox << " Free Form Deformation boxes." << endl; + + nCornerPoints = new unsigned short[nFFDBox]; + + nLevel = 1; // Nested FFD is not active + + if (rank == MASTER_NODE) cout << nLevel << " Free Form Deformation nested levels." << endl; + + for (iFFDBox = 0 ; iFFDBox < nFFDBox; iFFDBox++) { + + /*--- Read the name of the FFD box ---*/ + + string TagFFDBox = config->GetTagFFDBox(iFFDBox); + + if (rank == MASTER_NODE) cout << "FFD box tag: " << TagFFDBox <<". "; + + /*--- Read the level of the FFD box ---*/ + + LevelFFDBox = 0; // Nested FFD is not active + + if (rank == MASTER_NODE) cout << "FFD box level: " << LevelFFDBox <<". "; + + /*--- Read the degree of the FFD box ---*/ + + degree[0] = config->GetDegreeFFDBox(iFFDBox, 0); + degree[1] = config->GetDegreeFFDBox(iFFDBox, 1); + + if (nDim == 2) { degree[2] = 1; } + else { degree[2] = config->GetDegreeFFDBox(iFFDBox, 2); } + + if (rank == MASTER_NODE) { + cout << "Degrees: " << degree[0] << ", " << degree[1]; + if (nDim == 3) cout << ", " << degree[2]; + cout << ". " << endl; + } + + FFDBox[iFFDBox] = new CFreeFormDefBox(SU2_TYPE::Int(degree[0]), SU2_TYPE::Int(degree[1]), SU2_TYPE::Int(degree[2])); + FFDBox[iFFDBox]->SetTag(TagFFDBox); FFDBox[iFFDBox]->SetLevel(LevelFFDBox); + + /*--- Read the number of parents boxes ---*/ + + nParentFFDBox = 0; // Nested FFD is not active + if (rank == MASTER_NODE) cout << "Number of parent boxes: " << nParentFFDBox <<". "; + + for (iParentFFDBox = 0; iParentFFDBox < nParentFFDBox; iParentFFDBox++) { + string ParentFFDBox = "NONE"; // Nested FFD is not active + FFDBox[iFFDBox]->SetParentFFDBox(ParentFFDBox); + } + + /*--- Read the number of children boxes ---*/ + + nChildFFDBox = 0; // Nested FFD is not active + if (rank == MASTER_NODE) cout << "Number of child boxes: " << nChildFFDBox <<"." << endl; + + for (iChildFFDBox = 0; iChildFFDBox < nChildFFDBox; iChildFFDBox++) { + string ChildFFDBox = "NONE"; // Nested FFD is not active + FFDBox[iFFDBox]->SetChildFFDBox(ChildFFDBox); + } + + /*--- Read the number of the corner points ---*/ + + nCornerPoints[iFFDBox] = 8; + + /*--- Read the coordinates of the corner points ---*/ + + for (iCornerPoints = 0; iCornerPoints < nCornerPoints[iFFDBox]; iCornerPoints++) { + + if (nDim == 2) { + if (iCornerPoints < nCornerPoints[iFFDBox]/SU2_TYPE::Int(2)) { + coord[0] = config->GetCoordFFDBox(iFFDBox, iCornerPoints*3); + coord[1] = config->GetCoordFFDBox(iFFDBox, iCornerPoints*3+1); + coord[2] = -0.5; + } + else { + coord[0] = FFDBox[iFFDBox]->GetCoordCornerPoints(0, iCornerPoints-nCornerPoints[iFFDBox]/SU2_TYPE::Int(2)); + coord[1] = FFDBox[iFFDBox]->GetCoordCornerPoints(1, iCornerPoints-nCornerPoints[iFFDBox]/SU2_TYPE::Int(2)); + coord[2] = 0.5; + } + } + else { + coord[0] = config->GetCoordFFDBox(iFFDBox, iCornerPoints*3); + coord[1] = config->GetCoordFFDBox(iFFDBox, iCornerPoints*3+1); + coord[2] = config->GetCoordFFDBox(iFFDBox, iCornerPoints*3+2); + } + + FFDBox[iFFDBox]->SetCoordCornerPoints(coord, iCornerPoints); + + } + + /*--- Method to identify if there is a FFDBox definition ---*/ + + FFDBoxDefinition = false; + + } + + delete [] nCornerPoints; + + if (nFFDBox == 0) { + if (rank == MASTER_NODE) cout <<"There is no FFD box definition. Check the config file." << endl; +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + } + +} + +void CSurfaceMovement::MergeFFDInfo(CGeometry *geometry, CConfig *config) { + + /*--- Local variables needed on all processors ---*/ + + unsigned long iPoint; + unsigned short iFFDBox; + +#ifndef HAVE_MPI + + /*--- In serial, the single process has access to all geometry, so simply + load the coordinates into the data structure. ---*/ + + /*--- Total number of points in each FFD box. ---*/ + + for (iFFDBox = 0 ; iFFDBox < nFFDBox; iFFDBox++) { + + /*--- Loop over the mesh to collect the coords of the local points. ---*/ + + for (iPoint = 0; iPoint < FFDBox[iFFDBox]->GetnSurfacePoint(); iPoint++) { + + /*--- Retrieve the current parametric coordinates at this node. ---*/ + + GlobalCoordX[iFFDBox].push_back(FFDBox[iFFDBox]->Get_ParametricCoord(iPoint)[0]); + GlobalCoordY[iFFDBox].push_back(FFDBox[iFFDBox]->Get_ParametricCoord(iPoint)[1]); + GlobalCoordZ[iFFDBox].push_back(FFDBox[iFFDBox]->Get_ParametricCoord(iPoint)[2]); + GlobalPoint[iFFDBox].push_back(FFDBox[iFFDBox]->Get_PointIndex(iPoint)); + + /*--- Marker of the boundary in the local domain. ---*/ + + unsigned short MarkerIndex = FFDBox[iFFDBox]->Get_MarkerIndex(iPoint); + string TagBound = config->GetMarker_All_TagBound(MarkerIndex); + + /*--- Find the Marker of the boundary in the config file. ---*/ + + unsigned short MarkerIndex_CfgFile = config->GetMarker_CfgFile_TagBound(TagBound); + string TagBound_CfgFile = config->GetMarker_CfgFile_TagBound(MarkerIndex_CfgFile); + + /*--- Set the value of the tag at this node. ---*/ + + GlobalTag[iFFDBox].push_back(TagBound_CfgFile); + + } + + } + +#else + + /*--- MPI preprocessing ---*/ + + int iProcessor, nProcessor, rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); + + /*--- Local variables needed for merging the geometry with MPI. ---*/ + + unsigned long jPoint, iPointLocal; + unsigned long Buffer_Send_nPoint[1], *Buffer_Recv_nPoint = NULL; + unsigned long nLocalPoint = 0, MaxLocalPoint = 0; + unsigned long nBuffer_Scalar = 0; + + if (rank == MASTER_NODE) Buffer_Recv_nPoint = new unsigned long[nProcessor]; + + for (iFFDBox = 0 ; iFFDBox < nFFDBox; iFFDBox++) { + + nLocalPoint = 0; + for (iPoint = 0; iPoint < FFDBox[iFFDBox]->GetnSurfacePoint(); iPoint++) { + + iPointLocal = FFDBox[iFFDBox]->Get_PointIndex(iPoint); + + if (iPointLocal < geometry->GetnPointDomain()) { + nLocalPoint++; + } + + } + Buffer_Send_nPoint[0] = nLocalPoint; + + /*--- Communicate the total number of nodes on this domain. ---*/ + + SU2_MPI::Gather(&Buffer_Send_nPoint, 1, MPI_UNSIGNED_LONG, + Buffer_Recv_nPoint, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&nLocalPoint, &MaxLocalPoint, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + + nBuffer_Scalar = MaxLocalPoint; + + /*--- Send and Recv buffers. ---*/ + + su2double *Buffer_Send_X = new su2double[MaxLocalPoint]; + su2double *Buffer_Recv_X = NULL; + + su2double *Buffer_Send_Y = new su2double[MaxLocalPoint]; + su2double *Buffer_Recv_Y = NULL; + + su2double *Buffer_Send_Z = new su2double[MaxLocalPoint]; + su2double *Buffer_Recv_Z = NULL; + + unsigned long *Buffer_Send_Point = new unsigned long[MaxLocalPoint]; + unsigned long *Buffer_Recv_Point = NULL; + + unsigned short *Buffer_Send_MarkerIndex_CfgFile = new unsigned short[MaxLocalPoint]; + unsigned short *Buffer_Recv_MarkerIndex_CfgFile = NULL; + + /*--- Prepare the receive buffers in the master node only. ---*/ + + if (rank == MASTER_NODE) { + + Buffer_Recv_X = new su2double[nProcessor*MaxLocalPoint]; + Buffer_Recv_Y = new su2double[nProcessor*MaxLocalPoint]; + Buffer_Recv_Z = new su2double[nProcessor*MaxLocalPoint]; + Buffer_Recv_Point = new unsigned long[nProcessor*MaxLocalPoint]; + Buffer_Recv_MarkerIndex_CfgFile = new unsigned short[nProcessor*MaxLocalPoint]; + + } + + /*--- Main communication routine. Loop over each coordinate and perform + the MPI comm. Temporary 1-D buffers are used to send the coordinates at + all nodes on each partition to the master node. These are then unpacked + by the master and sorted by global index in one large n-dim. array. ---*/ + + /*--- Loop over this partition to collect the coords of the local points. ---*/ + + jPoint = 0; + for (iPoint = 0; iPoint < FFDBox[iFFDBox]->GetnSurfacePoint(); iPoint++) { + + iPointLocal = FFDBox[iFFDBox]->Get_PointIndex(iPoint); + + if (iPointLocal < geometry->GetnPointDomain()) { + + /*--- Load local coords into the temporary send buffer. ---*/ + + Buffer_Send_X[jPoint] = FFDBox[iFFDBox]->Get_ParametricCoord(iPoint)[0]; + Buffer_Send_Y[jPoint] = FFDBox[iFFDBox]->Get_ParametricCoord(iPoint)[1]; + Buffer_Send_Z[jPoint] = FFDBox[iFFDBox]->Get_ParametricCoord(iPoint)[2]; + + /*--- Store the global index for this local node. ---*/ + + Buffer_Send_Point[jPoint] = geometry->node[FFDBox[iFFDBox]->Get_PointIndex(iPoint)]->GetGlobalIndex(); + + /*--- Marker of the boundary in the local domain. ---*/ + + unsigned short MarkerIndex = FFDBox[iFFDBox]->Get_MarkerIndex(iPoint); + string TagBound = config->GetMarker_All_TagBound(MarkerIndex); + + /*--- Find the Marker of the boundary in the config file.---*/ + + unsigned short MarkerIndex_CfgFile = config->GetMarker_CfgFile_TagBound(TagBound); + Buffer_Send_MarkerIndex_CfgFile[jPoint] = MarkerIndex_CfgFile; + + jPoint++; + + } + + } + + /*--- Gather the coordinate data on the master node using MPI. ---*/ + + SU2_MPI::Gather(Buffer_Send_X, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_X, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Y, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Y, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Z, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Z, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Point, nBuffer_Scalar, MPI_UNSIGNED_LONG, Buffer_Recv_Point, nBuffer_Scalar, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_MarkerIndex_CfgFile, nBuffer_Scalar, MPI_UNSIGNED_SHORT, Buffer_Recv_MarkerIndex_CfgFile, nBuffer_Scalar, MPI_UNSIGNED_SHORT, MASTER_NODE, MPI_COMM_WORLD); + + /*--- The master node unpacks and sorts this variable by global index ---*/ + + if (rank == MASTER_NODE) { + + jPoint = 0; + + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { + + /*--- Get global index, then loop over each variable and store ---*/ + + GlobalCoordX[iFFDBox].push_back(Buffer_Recv_X[jPoint]); + GlobalCoordY[iFFDBox].push_back(Buffer_Recv_Y[jPoint]); + GlobalCoordZ[iFFDBox].push_back(Buffer_Recv_Z[jPoint]); + GlobalPoint[iFFDBox].push_back(Buffer_Recv_Point[jPoint]); + + string TagBound_CfgFile = config->GetMarker_CfgFile_TagBound(Buffer_Recv_MarkerIndex_CfgFile[jPoint]); + GlobalTag[iFFDBox].push_back(TagBound_CfgFile); + jPoint++; + + } + + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + + jPoint = (iProcessor+1)*nBuffer_Scalar; + + } + } + + /*--- Immediately release the temporary data buffers. ---*/ + + delete [] Buffer_Send_X; + delete [] Buffer_Send_Y; + delete [] Buffer_Send_Z; + delete [] Buffer_Send_Point; + delete [] Buffer_Send_MarkerIndex_CfgFile; + + if (rank == MASTER_NODE) { + delete [] Buffer_Recv_X; + delete [] Buffer_Recv_Y; + delete [] Buffer_Recv_Z; + delete [] Buffer_Recv_Point; + delete [] Buffer_Recv_MarkerIndex_CfgFile; + } + + } + + if (rank == MASTER_NODE) { + delete [] Buffer_Recv_nPoint; + } + +#endif + +} + +void CSurfaceMovement::WriteFFDInfo(CGeometry *geometry, CConfig *config) { + + + unsigned short iOrder, jOrder, kOrder, iFFDBox, iCornerPoints, iParentFFDBox, iChildFFDBox; + unsigned long iSurfacePoints; + char cstr[MAX_STRING_SIZE], mesh_file[MAX_STRING_SIZE]; + string str; + ofstream output_file; + su2double *coord; + string text_line; + + int rank = MASTER_NODE; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + unsigned short nDim = geometry->GetnDim(); + + /*--- Merge the FFD info ---*/ + + MergeFFDInfo(geometry, config); + + /*--- Attach to the mesh file the FFD information ---*/ + + if (rank == MASTER_NODE) { + + /*--- Read the name of the output file ---*/ + + str = config->GetMesh_Out_FileName(); + strcpy (mesh_file, str.c_str()); + strcpy (cstr, mesh_file); + + output_file.precision(15); + output_file.open(cstr, ios::out | ios::app); + + if (nFFDBox != 0) { + output_file << "FFD_NBOX= " << nFFDBox << endl; + output_file << "FFD_NLEVEL= " << nLevel << endl; + } + + for (iFFDBox = 0 ; iFFDBox < nFFDBox; iFFDBox++) { + + output_file << "FFD_TAG= " << FFDBox[iFFDBox]->GetTag() << endl; + output_file << "FFD_LEVEL= " << FFDBox[iFFDBox]->GetLevel() << endl; + + output_file << "FFD_DEGREE_I= " << FFDBox[iFFDBox]->GetlOrder()-1 << endl; + output_file << "FFD_DEGREE_J= " << FFDBox[iFFDBox]->GetmOrder()-1 << endl; + if (nDim == 3) output_file << "FFD_DEGREE_K= " << FFDBox[iFFDBox]->GetnOrder()-1 << endl; + + output_file << "FFD_PARENTS= " << FFDBox[iFFDBox]->GetnParentFFDBox() << endl; + for (iParentFFDBox = 0; iParentFFDBox < FFDBox[iFFDBox]->GetnParentFFDBox(); iParentFFDBox++) + output_file << FFDBox[iFFDBox]->GetParentFFDBoxTag(iParentFFDBox) << endl; + output_file << "FFD_CHILDREN= " << FFDBox[iFFDBox]->GetnChildFFDBox() << endl; + for (iChildFFDBox = 0; iChildFFDBox < FFDBox[iFFDBox]->GetnChildFFDBox(); iChildFFDBox++) + output_file << FFDBox[iFFDBox]->GetChildFFDBoxTag(iChildFFDBox) << endl; + + if (nDim == 2) { + output_file << "FFD_CORNER_POINTS= " << FFDBox[iFFDBox]->GetnCornerPoints()/SU2_TYPE::Int(2) << endl; + for (iCornerPoints = 0; iCornerPoints < FFDBox[iFFDBox]->GetnCornerPoints()/SU2_TYPE::Int(2); iCornerPoints++) { + coord = FFDBox[iFFDBox]->GetCoordCornerPoints(iCornerPoints); + output_file << coord[0] << "\t" << coord[1] << endl; + } + } + else { + output_file << "FFD_CORNER_POINTS= " << FFDBox[iFFDBox]->GetnCornerPoints() << endl; + for (iCornerPoints = 0; iCornerPoints < FFDBox[iFFDBox]->GetnCornerPoints(); iCornerPoints++) { + coord = FFDBox[iFFDBox]->GetCoordCornerPoints(iCornerPoints); + output_file << coord[0] << "\t" << coord[1] << "\t" << coord[2] << endl; + } + } + + /*--- Writing control points ---*/ + + if (FFDBox[iFFDBox]->GetnControlPoints() == 0) { + output_file << "FFD_CONTROL_POINTS= 0" << endl; + } + else { + output_file << "FFD_CONTROL_POINTS= " << FFDBox[iFFDBox]->GetnControlPoints() << endl; + for (iOrder = 0; iOrder < FFDBox[iFFDBox]->GetlOrder(); iOrder++) + for (jOrder = 0; jOrder < FFDBox[iFFDBox]->GetmOrder(); jOrder++) + for (kOrder = 0; kOrder < FFDBox[iFFDBox]->GetnOrder(); kOrder++) { + coord = FFDBox[iFFDBox]->GetCoordControlPoints(iOrder, jOrder, kOrder); + output_file << iOrder << "\t" << jOrder << "\t" << kOrder << "\t" << coord[0] << "\t" << coord[1] << "\t" << coord[2] << endl; + } + } + + /*--- Writing surface points ---*/ + + if (FFDBox[iFFDBox]->GetnControlPoints() == 0) { + output_file << "FFD_SURFACE_POINTS= 0" << endl; + } + else { + output_file << "FFD_SURFACE_POINTS= " << GlobalTag[iFFDBox].size() << endl; + + for (iSurfacePoints = 0; iSurfacePoints < GlobalTag[iFFDBox].size(); iSurfacePoints++) { + output_file << scientific << GlobalTag[iFFDBox][iSurfacePoints] << "\t" << GlobalPoint[iFFDBox][iSurfacePoints] + << "\t" << GlobalCoordX[iFFDBox][iSurfacePoints] << "\t" << GlobalCoordY[iFFDBox][iSurfacePoints] + << "\t" << GlobalCoordZ[iFFDBox][iSurfacePoints] << endl; + } + + } + + } + + output_file.close(); + + } + +} + +CFreeFormDefBox::CFreeFormDefBox(void) : CGridMovement() { } + +CFreeFormDefBox::CFreeFormDefBox(unsigned short val_lDegree, unsigned short val_mDegree, unsigned short val_nDegree) : CGridMovement() { + + unsigned short iCornerPoints, iOrder, jOrder, kOrder, iDim; + + /*--- FFD is always 3D (even in 2D problems) ---*/ + + nDim = 3; + nCornerPoints = 8; + + /*--- Allocate Corners points ---*/ + + Coord_Corner_Points = new su2double* [nCornerPoints]; + for (iCornerPoints = 0; iCornerPoints < nCornerPoints; iCornerPoints++) + Coord_Corner_Points[iCornerPoints] = new su2double [nDim]; + + ParamCoord = new su2double[nDim]; ParamCoord_ = new su2double[nDim]; + cart_coord = new su2double[nDim]; cart_coord_ = new su2double[nDim]; + Gradient = new su2double[nDim]; + + lDegree = val_lDegree; lOrder = lDegree+1; + mDegree = val_mDegree; mOrder = mDegree+1; + nDegree = val_nDegree; nOrder = nDegree+1; + nControlPoints = lOrder*mOrder*nOrder; + + lDegree_Copy = val_lDegree; lOrder_Copy = lDegree+1; + mDegree_Copy = val_mDegree; mOrder_Copy = mDegree+1; + nDegree_Copy = val_nDegree; nOrder_Copy = nDegree+1; + nControlPoints_Copy = lOrder_Copy*mOrder_Copy*nOrder_Copy; + + Coord_Control_Points = new su2double*** [lOrder]; + ParCoord_Control_Points = new su2double*** [lOrder]; + Coord_Control_Points_Copy = new su2double*** [lOrder]; + for (iOrder = 0; iOrder < lOrder; iOrder++) { + Coord_Control_Points[iOrder] = new su2double** [mOrder]; + ParCoord_Control_Points[iOrder] = new su2double** [mOrder]; + Coord_Control_Points_Copy[iOrder] = new su2double** [mOrder]; + for (jOrder = 0; jOrder < mOrder; jOrder++) { + Coord_Control_Points[iOrder][jOrder] = new su2double* [nOrder]; + ParCoord_Control_Points[iOrder][jOrder] = new su2double* [nOrder]; + Coord_Control_Points_Copy[iOrder][jOrder] = new su2double* [nOrder]; + for (kOrder = 0; kOrder < nOrder; kOrder++) { + Coord_Control_Points[iOrder][jOrder][kOrder] = new su2double [nDim]; + ParCoord_Control_Points[iOrder][jOrder][kOrder] = new su2double [nDim]; + Coord_Control_Points_Copy[iOrder][jOrder][kOrder] = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) { + Coord_Control_Points[iOrder][jOrder][kOrder][iDim] = 0.0; + ParCoord_Control_Points[iOrder][jOrder][kOrder][iDim] = 0.0; + Coord_Control_Points_Copy[iOrder][jOrder][kOrder][iDim] = 0.0; + } + } + } + } + +} + +CFreeFormDefBox::~CFreeFormDefBox(void) { + unsigned short iOrder, jOrder, kOrder, iCornerPoints; + + for (iOrder = 0; iOrder < lOrder; iOrder++) + for (jOrder = 0; jOrder < mOrder; jOrder++) + for (kOrder = 0; kOrder < nOrder; kOrder++) { + delete [] Coord_Control_Points[iOrder][jOrder][kOrder]; + delete [] ParCoord_Control_Points[iOrder][jOrder][kOrder]; + delete [] Coord_Control_Points_Copy[iOrder][jOrder][kOrder]; + } + delete [] Coord_Control_Points; + delete [] ParCoord_Control_Points; + delete [] Coord_Control_Points_Copy; + + delete [] ParamCoord; + delete [] cart_coord; + delete [] Gradient; + + for (iCornerPoints = 0; iCornerPoints < nCornerPoints; iCornerPoints++) + delete [] Coord_Corner_Points[iCornerPoints]; + delete [] Coord_Corner_Points; +} + +void CFreeFormDefBox::SetUnitCornerPoints(void) { + + unsigned short iDim; + su2double *coord = new su2double [nDim]; + + for (iDim = 0; iDim < nDim; iDim++) coord[iDim] = 0.0; + + coord [0] = 0.0; coord [1] = 0.0; coord [2] = 0.0; this->SetCoordCornerPoints(coord, 0); + coord [0] = 1.0; coord [1] = 0.0; coord [2] = 0.0; this->SetCoordCornerPoints(coord, 1); + coord [0] = 1.0; coord [1] = 1.0; coord [2] = 0.0; this->SetCoordCornerPoints(coord, 2); + coord [0] = 0.0; coord [1] = 1.0; coord [2] = 0.0; this->SetCoordCornerPoints(coord, 3); + coord [0] = 0.0; coord [1] = 0.0; coord [2] = 1.0; this->SetCoordCornerPoints(coord, 4); + coord [0] = 1.0; coord [1] = 0.0; coord [2] = 1.0; this->SetCoordCornerPoints(coord, 5); + coord [0] = 1.0; coord [1] = 1.0; coord [2] = 1.0; this->SetCoordCornerPoints(coord, 6); + coord [0] = 0.0; coord [1] = 1.0; coord [2] = 1.0; this->SetCoordCornerPoints(coord, 7); + + delete [] coord; + +} + +void CFreeFormDefBox::SetControlPoints_Parallelepiped (void) { + unsigned short iDim, iDegree, jDegree, kDegree; + + /*--- Set base control points according to the notation of Vtk for hexahedrons ---*/ + for (iDim = 0; iDim < nDim; iDim++) { + Coord_Control_Points [0] [0] [0] [iDim] = Coord_Corner_Points[0][iDim]; + Coord_Control_Points [lOrder-1] [0] [0] [iDim] = Coord_Corner_Points[1][iDim]; + Coord_Control_Points [lOrder-1] [mOrder-1] [0] [iDim] = Coord_Corner_Points[2][iDim]; + Coord_Control_Points [0] [mOrder-1] [0] [iDim] = Coord_Corner_Points[3][iDim]; + Coord_Control_Points [0] [0] [nOrder-1] [iDim] = Coord_Corner_Points[4][iDim]; + Coord_Control_Points [lOrder-1] [0] [nOrder-1] [iDim] = Coord_Corner_Points[5][iDim]; + Coord_Control_Points [lOrder-1] [mOrder-1] [nOrder-1] [iDim] = Coord_Corner_Points[6][iDim]; + Coord_Control_Points [0] [mOrder-1] [nOrder-1] [iDim] = Coord_Corner_Points[7][iDim]; + } + + /*--- Fill the rest of the cubic matrix of control points with uniform spacing (parallelepiped) ---*/ + for (iDegree = 0; iDegree <= lDegree; iDegree++) + for (jDegree = 0; jDegree <= mDegree; jDegree++) + for (kDegree = 0; kDegree <= nDegree; kDegree++) { + Coord_Control_Points[iDegree][jDegree][kDegree][0] = Coord_Corner_Points[0][0] + + su2double(iDegree)/su2double(lDegree)*(Coord_Corner_Points[1][0]-Coord_Corner_Points[0][0]); + Coord_Control_Points[iDegree][jDegree][kDegree][1] = Coord_Corner_Points[0][1] + + su2double(jDegree)/su2double(mDegree)*(Coord_Corner_Points[3][1]-Coord_Corner_Points[0][1]); + Coord_Control_Points[iDegree][jDegree][kDegree][2] = Coord_Corner_Points[0][2] + + su2double(kDegree)/su2double(nDegree)*(Coord_Corner_Points[4][2]-Coord_Corner_Points[0][2]); + } +} + +void CFreeFormDefBox::SetSupportCP(CFreeFormDefBox *FFDBox) { + unsigned short iDim, iOrder, jOrder, kOrder; + unsigned short lOrder = FFDBox->GetlOrder(); + unsigned short mOrder = FFDBox->GetmOrder(); + unsigned short nOrder = FFDBox->GetnOrder(); + + Coord_SupportCP = new su2double*** [lOrder]; + for (iOrder = 0; iOrder < lOrder; iOrder++) { + Coord_SupportCP[iOrder] = new su2double** [mOrder]; + for (jOrder = 0; jOrder < mOrder; jOrder++) { + Coord_SupportCP[iOrder][jOrder] = new su2double* [nOrder]; + for (kOrder = 0; kOrder < nOrder; kOrder++) + Coord_SupportCP[iOrder][jOrder][kOrder] = new su2double [nDim]; + } + } + + /*--- Set base support control points according to the notation of Vtk for hexahedrons ---*/ + for (iDim = 0; iDim < nDim; iDim++) { + Coord_SupportCP [0] [0] [0] [iDim] = Coord_Corner_Points[0][iDim]; + Coord_SupportCP [lOrder-1] [0] [0] [iDim] = Coord_Corner_Points[1][iDim]; + Coord_SupportCP [lOrder-1] [mOrder-1] [0] [iDim] = Coord_Corner_Points[2][iDim]; + Coord_SupportCP [0] [mOrder-1] [0] [iDim] = Coord_Corner_Points[3][iDim]; + Coord_SupportCP [0] [0] [nOrder-1] [iDim] = Coord_Corner_Points[4][iDim]; + Coord_SupportCP [lOrder-1] [0] [nOrder-1] [iDim] = Coord_Corner_Points[5][iDim]; + Coord_SupportCP [lOrder-1] [mOrder-1] [nOrder-1] [iDim] = Coord_Corner_Points[6][iDim]; + Coord_SupportCP [0] [mOrder-1] [nOrder-1] [iDim] = Coord_Corner_Points[7][iDim]; + } + + /*--- Fill the rest of the cubic matrix of support control points with uniform spacing ---*/ + for (iOrder = 0; iOrder < lOrder; iOrder++) + for (jOrder = 0; jOrder < mOrder; jOrder++) + for (kOrder = 0; kOrder < nOrder; kOrder++) { + Coord_SupportCP[iOrder][jOrder][kOrder][0] = Coord_Corner_Points[0][0] + + su2double(iOrder)/su2double(lOrder-1)*(Coord_Corner_Points[1][0]-Coord_Corner_Points[0][0]); + Coord_SupportCP[iOrder][jOrder][kOrder][1] = Coord_Corner_Points[0][1] + + su2double(jOrder)/su2double(mOrder-1)*(Coord_Corner_Points[3][1]-Coord_Corner_Points[0][1]); + Coord_SupportCP[iOrder][jOrder][kOrder][2] = Coord_Corner_Points[0][2] + + su2double(kOrder)/su2double(nOrder-1)*(Coord_Corner_Points[4][2]-Coord_Corner_Points[0][2]); + } +} + +void CFreeFormDefBox::SetSupportCPChange(CFreeFormDefBox *FFDBox) { + unsigned short iDim, iOrder, jOrder, kOrder; + su2double *CartCoordNew, *ParamCoord; + unsigned short lOrder = FFDBox->GetlOrder(); + unsigned short mOrder = FFDBox->GetmOrder(); + unsigned short nOrder = FFDBox->GetnOrder(); + + su2double ****ParamCoord_SupportCP = new su2double*** [lOrder]; + for (iOrder = 0; iOrder < lOrder; iOrder++) { + ParamCoord_SupportCP[iOrder] = new su2double** [mOrder]; + for (jOrder = 0; jOrder < mOrder; jOrder++) { + ParamCoord_SupportCP[iOrder][jOrder] = new su2double* [nOrder]; + for (kOrder = 0; kOrder < nOrder; kOrder++) + ParamCoord_SupportCP[iOrder][jOrder][kOrder] = new su2double [nDim]; + } + } + + for (iOrder = 0; iOrder < lOrder; iOrder++) + for (jOrder = 0; jOrder < mOrder; jOrder++) + for (kOrder = 0; kOrder < nOrder; kOrder++) + for (iDim = 0; iDim < nDim; iDim++) + ParamCoord_SupportCP[iOrder][jOrder][kOrder][iDim] = + Coord_SupportCP[iOrder][jOrder][kOrder][iDim]; + + for (iDim = 0; iDim < nDim; iDim++) { + Coord_Control_Points[0][0][0][iDim] = FFDBox->GetCoordCornerPoints(iDim, 0); + Coord_Control_Points[1][0][0][iDim] = FFDBox->GetCoordCornerPoints(iDim, 1); + Coord_Control_Points[1][1][0][iDim] = FFDBox->GetCoordCornerPoints(iDim, 2); + Coord_Control_Points[0][1][0][iDim] = FFDBox->GetCoordCornerPoints(iDim, 3); + Coord_Control_Points[0][0][1][iDim] = FFDBox->GetCoordCornerPoints(iDim, 4); + Coord_Control_Points[1][0][1][iDim] = FFDBox->GetCoordCornerPoints(iDim, 5); + Coord_Control_Points[1][1][1][iDim] = FFDBox->GetCoordCornerPoints(iDim, 6); + Coord_Control_Points[0][1][1][iDim] = FFDBox->GetCoordCornerPoints(iDim, 7); + } + + for (iOrder = 0; iOrder < FFDBox->GetlOrder(); iOrder++) { + for (jOrder = 0; jOrder < FFDBox->GetmOrder(); jOrder++) { + for (kOrder = 0; kOrder < FFDBox->GetnOrder(); kOrder++) { + ParamCoord = ParamCoord_SupportCP[iOrder][jOrder][kOrder]; + CartCoordNew = EvalCartesianCoord(ParamCoord); + FFDBox->SetCoordControlPoints(CartCoordNew, iOrder, jOrder, kOrder); + FFDBox->SetCoordControlPoints_Copy(CartCoordNew, iOrder, jOrder, kOrder); + } + } + } + +} + +void CFreeFormDefBox::SetTecplot(CGeometry *geometry, unsigned short iFFDBox, bool original) { + + ofstream FFDBox_file; + char FFDBox_filename[MAX_STRING_SIZE]; + bool new_file; + unsigned short iDim, iDegree, jDegree, kDegree; + + nDim = geometry->GetnDim(); + + SPRINTF (FFDBox_filename, "ffd_boxes.dat"); + + if ((original) && (iFFDBox == 0)) new_file = true; + else new_file = false; + + if (new_file) { + FFDBox_file.open(FFDBox_filename, ios::out); + FFDBox_file << "TITLE = \"Visualization of the FFD boxes generated by SU2_DEF.\"" << endl; + if (nDim == 2) FFDBox_file << "VARIABLES = \"x\", \"y\"" << endl; + else FFDBox_file << "VARIABLES = \"x\", \"y\", \"z\"" << endl; + } + else FFDBox_file.open(FFDBox_filename, ios::out | ios::app); + + FFDBox_file << "ZONE T= \"" << Tag; + if (original) FFDBox_file << " (Original FFD)\""; + else FFDBox_file << " (Deformed FFD)\""; + if (nDim == 2) FFDBox_file << ", I="< val_n) { value = 0; return value; } + if (val_i == 0) { + if (val_t == 0) value = 1; + else if (val_t == 1) value = 0; + else value = Binomial(val_n, val_i)*(pow(val_t, val_i)) * pow(1.0 - val_t, val_n - val_i); + } + else if (val_i == val_n) { + if (val_t == 0) value = 0; + else if (val_t == 1) value = 1; + else value = pow(val_t, val_n); + } + else value = Binomial(val_n, val_i)*(pow(val_t, val_i)) * pow(1.0-val_t, val_n - val_i); + + return value; +} + +su2double CFreeFormDefBox::GetBernsteinDerivative(short val_n, short val_i, + su2double val_t, short val_order) { + su2double value = 0.0; + + /*--- Verify this subroutine, it provides negative val_n, + which is a wrong value for GetBernstein ---*/ + + if (val_order == 0) { + value = GetBernstein(val_n, val_i, val_t); return value; + } + + if (val_i == 0) { + value = val_n*(-GetBernsteinDerivative(val_n-1, val_i, val_t, val_order-1)); return value; + } + else { + if (val_n == 0) { + value = val_t; return value; + } + else { + value = val_n*(GetBernsteinDerivative(val_n-1, val_i-1, val_t, val_order-1) - GetBernsteinDerivative(val_n-1, val_i, val_t, val_order-1)); + return value; + } + } + + return value; +} + +su2double *CFreeFormDefBox::GetFFDGradient(su2double *val_coord, su2double *xyz) { + + unsigned short iDim, jDim, lmn[3]; + + /*--- Set the Degree of the Berstein polynomials ---*/ + + lmn[0] = lDegree; lmn[1] = mDegree; lmn[2] = nDegree; + + for (iDim = 0; iDim < nDim; iDim++) Gradient[iDim] = 0.0; + + for (iDim = 0; iDim < nDim; iDim++) + for (jDim = 0; jDim < nDim; jDim++) + Gradient[jDim] += GetDerivative2(val_coord, iDim, xyz, lmn) * + GetDerivative3(val_coord, iDim, jDim, lmn); + + return Gradient; + +} + +void CFreeFormDefBox::GetFFDHessian(su2double *uvw, su2double *xyz, su2double **val_Hessian) { + + unsigned short iDim, jDim, lmn[3]; + + /*--- Set the Degree of the Berstein polynomials ---*/ + + lmn[0] = lDegree; lmn[1] = mDegree; lmn[2] = nDegree; + + for (iDim = 0; iDim < nDim; iDim++) + for (jDim = 0; jDim < nDim; jDim++) + val_Hessian[iDim][jDim] = 0.0; + + /*--- Note that being all the functions linear combinations of polynomials, they are C^\infty, + and the Hessian will be symmetric; no need to compute the under-diagonal part, for example ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + val_Hessian[0][0] += 2.0 * GetDerivative3(uvw, iDim,0, lmn) * GetDerivative3(uvw, iDim,0, lmn) + + GetDerivative2(uvw, iDim,xyz, lmn) * GetDerivative5(uvw, iDim,0,0, lmn); + + val_Hessian[1][1] += 2.0 * GetDerivative3(uvw, iDim,1, lmn) * GetDerivative3(uvw, iDim,1, lmn) + + GetDerivative2(uvw, iDim,xyz, lmn) * GetDerivative5(uvw, iDim,1,1, lmn); + + val_Hessian[2][2] += 2.0 * GetDerivative3(uvw, iDim,2, lmn) * GetDerivative3(uvw, iDim,2, lmn) + + GetDerivative2(uvw, iDim,xyz, lmn) * GetDerivative5(uvw, iDim,2,2, lmn); + + val_Hessian[0][1] += 2.0 * GetDerivative3(uvw, iDim,0, lmn) * GetDerivative3(uvw, iDim,1, lmn) + + GetDerivative2(uvw, iDim,xyz, lmn) * GetDerivative5(uvw, iDim,0,1, lmn); + + val_Hessian[0][2] += 2.0 * GetDerivative3(uvw, iDim,0, lmn) * GetDerivative3(uvw, iDim,2, lmn) + + GetDerivative2(uvw, iDim,xyz, lmn) * GetDerivative5(uvw, iDim,0,2, lmn); + + val_Hessian[1][2] += 2.0 * GetDerivative3(uvw, iDim,1, lmn) * GetDerivative3(uvw, iDim,2, lmn) + + GetDerivative2(uvw, iDim,xyz, lmn) * GetDerivative5(uvw, iDim,1,2, lmn); + } + + val_Hessian[1][0] = val_Hessian[0][1]; + val_Hessian[2][0] = val_Hessian[0][2]; + val_Hessian[2][1] = val_Hessian[1][2]; + +} + +su2double *CFreeFormDefBox::GetParametricCoord_Iterative(unsigned long iPoint, su2double *xyz, su2double *ParamCoordGuess, CConfig *config) { + + su2double *IndepTerm, SOR_Factor = 1.0, MinNormError, NormError, Determinant, AdjHessian[3][3], Temp[3] = {0.0,0.0,0.0}; + unsigned short iDim, jDim, RandonCounter; + unsigned long iter; + + su2double tol = config->GetFFD_Tol(); + unsigned short it_max = config->GetnFFD_Iter(); + unsigned short Random_Trials = 500; + + /*--- Allocate the Hessian ---*/ + + Hessian = new su2double* [nDim]; + IndepTerm = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) { + Hessian[iDim] = new su2double[nDim]; + ParamCoord[iDim] = ParamCoordGuess[iDim]; + IndepTerm [iDim] = 0.0; + } + + RandonCounter = 0; MinNormError = 1E6; + + /*--- External iteration ---*/ + + for (iter = 0; iter < (unsigned long)it_max*Random_Trials; iter++) { + + /*--- The independent term of the solution of our system is -Gradient(sol_old) ---*/ + + Gradient = GetFFDGradient(ParamCoord, xyz); + + for (iDim = 0; iDim < nDim; iDim++) IndepTerm[iDim] = - Gradient[iDim]; + + /*--- Hessian = The Matrix of our system, getHessian(sol_old,xyz,...) ---*/ + + GetFFDHessian(ParamCoord, xyz, Hessian); + + /*--- Adjoint to Hessian ---*/ + + AdjHessian[0][0] = Hessian[1][1]*Hessian[2][2]-Hessian[1][2]*Hessian[2][1]; + AdjHessian[0][1] = Hessian[0][2]*Hessian[2][1]-Hessian[0][1]*Hessian[2][2]; + AdjHessian[0][2] = Hessian[0][1]*Hessian[1][2]-Hessian[0][2]*Hessian[1][1]; + AdjHessian[1][0] = Hessian[1][2]*Hessian[2][0]-Hessian[1][0]*Hessian[2][2]; + AdjHessian[1][1] = Hessian[0][0]*Hessian[2][2]-Hessian[0][2]*Hessian[2][0]; + AdjHessian[1][2] = Hessian[0][2]*Hessian[1][0]-Hessian[0][0]*Hessian[1][2]; + AdjHessian[2][0] = Hessian[1][0]*Hessian[2][1]-Hessian[1][1]*Hessian[2][0]; + AdjHessian[2][1] = Hessian[0][1]*Hessian[2][0]-Hessian[0][0]*Hessian[2][1]; + AdjHessian[2][2] = Hessian[0][0]*Hessian[1][1]-Hessian[0][1]*Hessian[1][0]; + + /*--- Determinant of Hessian ---*/ + + Determinant = Hessian[0][0]*AdjHessian[0][0]+Hessian[0][1]*AdjHessian[1][0]+Hessian[0][2]*AdjHessian[2][0]; + + /*--- Hessian inverse ---*/ + + if (Determinant != 0) { + for (iDim = 0; iDim < nDim; iDim++) { + Temp[iDim] = 0.0; + for (jDim = 0; jDim < nDim; jDim++) { + Temp[iDim] += AdjHessian[iDim][jDim]*IndepTerm[jDim]/Determinant; + } + } + for (iDim = 0; iDim < nDim; iDim++) { + IndepTerm[iDim] = Temp[iDim]; + } + } + + /*--- Update with Successive over-relaxation ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + ParamCoord[iDim] = (1.0-SOR_Factor)*ParamCoord[iDim] + SOR_Factor*(ParamCoord[iDim] + IndepTerm[iDim]); + } + + /*--- If the gradient is small, we have converged ---*/ + + if ((fabs(IndepTerm[0]) < tol) && (fabs(IndepTerm[1]) < tol) && (fabs(IndepTerm[2]) < tol)) break; + + /*--- Compute the norm of the error ---*/ + + NormError = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + NormError += IndepTerm[iDim]*IndepTerm[iDim]; + NormError = sqrt(NormError); + + MinNormError = min(NormError, MinNormError); + + /*--- If we have no convergence with Random_Trials iterations probably we are in a local minima. ---*/ + + if (((iter % it_max) == 0) && (iter != 0)) { + + RandonCounter++; + if (RandonCounter == Random_Trials) { + cout << endl << "Unknown point: "<< iPoint <<" (" << xyz[0] <<", "<< xyz[1] <<", "<< xyz[2] <<"). Min Error: "<< MinNormError <<". Iter: "<< iter <<"."<< endl; + } + else { + SOR_Factor = 0.1; + for (iDim = 0; iDim < nDim; iDim++) + ParamCoord[iDim] = su2double(rand())/su2double(RAND_MAX); + } + + } + + } + + for (iDim = 0; iDim < nDim; iDim++) + delete [] Hessian[iDim]; + delete [] Hessian; + delete [] IndepTerm; + + /*--- The code has hit the max number of iterations ---*/ + + if (iter == (unsigned long)it_max*Random_Trials) { + cout << "Unknown point: (" << xyz[0] <<", "<< xyz[1] <<", "<< xyz[2] <<"). Increase the value of FFD_ITERATIONS." << endl; + } + + /*--- Real Solution is now ParamCoord; Return it ---*/ + + return ParamCoord; + +} + +unsigned long CFreeFormDefBox::Binomial(unsigned short n, unsigned short m) { + + unsigned short i, j; + unsigned long binomial[1000]; + + binomial[0] = 1; + for (i = 1; i <= n; ++i) { + binomial[i] = 1; + for (j = i-1U; j > 0; --j) { + binomial[j] += binomial[j-1U]; + } + } + + return binomial[m]; + +} + +bool CFreeFormDefBox::GetPointFFD(CGeometry *geometry, CConfig *config, unsigned long iPoint) { + su2double Coord[3] = {0.0, 0.0, 0.0}; + unsigned short iVar, jVar, iDim; + bool Inside = false; + + unsigned short Index[5][7] = { + {0, 1, 2, 5, 0, 1, 2}, + {0, 2, 7, 5, 0, 2, 7}, + {0, 2, 3, 7, 0, 2, 3}, + {0, 5, 7, 4, 0, 5, 7}, + {2, 7, 5, 6, 2, 7, 5}}; + unsigned short nDim = geometry->GetnDim(); + + for (iDim = 0; iDim < nDim; iDim++) + Coord[iDim] = geometry->node[iPoint]->GetCoord(iDim); + + /*--- 1st tetrahedron {V0, V1, V2, V5} + 2nd tetrahedron {V0, V2, V7, V5} + 3th tetrahedron {V0, V2, V3, V7} + 4th tetrahedron {V0, V5, V7, V4} + 5th tetrahedron {V2, V7, V5, V6} ---*/ + + for (iVar = 0; iVar < 5; iVar++) { + Inside = true; + for (jVar = 0; jVar < 4; jVar++) { + su2double Distance_Point = geometry->Point2Plane_Distance(Coord, + Coord_Corner_Points[Index[iVar][jVar+1]], + Coord_Corner_Points[Index[iVar][jVar+2]], + Coord_Corner_Points[Index[iVar][jVar+3]]); + + su2double Distance_Vertex = geometry->Point2Plane_Distance(Coord_Corner_Points[Index[iVar][jVar]], + Coord_Corner_Points[Index[iVar][jVar+1]], + Coord_Corner_Points[Index[iVar][jVar+2]], + Coord_Corner_Points[Index[iVar][jVar+3]]); + if (Distance_Point*Distance_Vertex < 0.0) Inside = false; + } + if (Inside) break; + } + + return Inside; + +} + +void CFreeFormDefBox::SetDeformationZone(CGeometry *geometry, CConfig *config, unsigned short iFFDBox) { + su2double *Coord; + unsigned short iMarker, iVar, jVar; + unsigned long iVertex, iPoint; + bool Inside = false; + + unsigned short Index[5][7] = { + {0, 1, 2, 5, 0, 1, 2}, + {0, 2, 7, 5, 0, 2, 7}, + {0, 2, 3, 7, 0, 2, 3}, + {0, 5, 7, 4, 0, 5, 7}, + {2, 7, 5, 6, 2, 7, 5}}; + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_DV(iMarker) == YES) + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + geometry->node[iPoint]->SetMove(false); + + Coord = geometry->node[iPoint]->GetCoord(); + + /*--- 1st tetrahedron {V0, V1, V2, V5} + 2nd tetrahedron {V0, V2, V7, V5} + 3th tetrahedron {V0, V2, V3, V7} + 4th tetrahedron {V0, V5, V7, V4} + 5th tetrahedron {V2, V7, V5, V6} ---*/ + + for (iVar = 0; iVar < 5; iVar++) { + Inside = true; + for (jVar = 0; jVar < 4; jVar++) { + su2double Distance_Point = geometry->Point2Plane_Distance(Coord, + Coord_Corner_Points[Index[iVar][jVar+1]], + Coord_Corner_Points[Index[iVar][jVar+2]], + Coord_Corner_Points[Index[iVar][jVar+3]]); + su2double Distance_Vertex = geometry->Point2Plane_Distance(Coord_Corner_Points[Index[iVar][jVar]], + Coord_Corner_Points[Index[iVar][jVar+1]], + Coord_Corner_Points[Index[iVar][jVar+2]], + Coord_Corner_Points[Index[iVar][jVar+3]]); + if (Distance_Point*Distance_Vertex < 0.0) Inside = false; + } + if (Inside) break; + } + + if (Inside) { + geometry->node[iPoint]->SetMove(true); + } + + } +} + +su2double CFreeFormDefBox::GetDerivative1(su2double *uvw, unsigned short val_diff, unsigned short *ijk, unsigned short *lmn) { + + unsigned short iDim; + su2double value = 0.0; + + value = GetBernsteinDerivative(lmn[val_diff], ijk[val_diff], uvw[val_diff], 1); + for (iDim = 0; iDim < nDim; iDim++) + if (iDim != val_diff) + value *= GetBernstein(lmn[iDim], ijk[iDim], uvw[iDim]); + + return value; + +} + +su2double CFreeFormDefBox::GetDerivative2 (su2double *uvw, unsigned short dim, su2double *xyz, unsigned short *lmn) { + + unsigned short iDegree, jDegree, kDegree; + su2double value = 0.0; + + for (iDegree = 0; iDegree <= lmn[0]; iDegree++) + for (jDegree = 0; jDegree <= lmn[1]; jDegree++) + for (kDegree = 0; kDegree <= lmn[2]; kDegree++) { + value += Coord_Control_Points[iDegree][jDegree][kDegree][dim] + * GetBernstein(lmn[0], iDegree, uvw[0]) + * GetBernstein(lmn[1], jDegree, uvw[1]) + * GetBernstein(lmn[2], kDegree, uvw[2]); + } + + return 2.0*(value - xyz[dim]); +} + +su2double CFreeFormDefBox::GetDerivative3(su2double *uvw, unsigned short dim, unsigned short diff_this, unsigned short *lmn) { + + unsigned short iDegree, jDegree, kDegree, iDim; + su2double value = 0; + + unsigned short *ijk = new unsigned short[nDim]; + + for (iDim = 0; iDim < nDim; iDim++) ijk[iDim] = 0; + + for (iDegree = 0; iDegree <= lmn[0]; iDegree++) + for (jDegree = 0; jDegree <= lmn[1]; jDegree++) + for (kDegree = 0; kDegree <= lmn[2]; kDegree++) { + ijk[0] = iDegree; ijk[1] = jDegree; ijk[2] = kDegree; + value += Coord_Control_Points[iDegree][jDegree][kDegree][dim] * + GetDerivative1(uvw, diff_this, ijk, lmn); + } + + delete [] ijk; + + return value; +} + +su2double CFreeFormDefBox::GetDerivative4(su2double *uvw, unsigned short val_diff, unsigned short val_diff2, + unsigned short *ijk, unsigned short *lmn) { + unsigned short iDim; + su2double value = 0.0; + + if (val_diff == val_diff2) { + value = GetBernsteinDerivative(lmn[val_diff], ijk[val_diff], uvw[val_diff], 2); + for (iDim = 0; iDim < nDim; iDim++) + if (iDim != val_diff) + value *= GetBernstein(lmn[iDim], ijk[iDim], uvw[iDim]); + } + else { + value = GetBernsteinDerivative(lmn[val_diff], ijk[val_diff], uvw[val_diff], 1) * + GetBernsteinDerivative(lmn[val_diff2], ijk[val_diff2], uvw[val_diff2], 1); + for (iDim = 0; iDim < nDim; iDim++) + if ((iDim != val_diff) && (iDim != val_diff2)) + value *= GetBernstein(lmn[iDim], ijk[iDim], uvw[iDim]); + } + + return value; +} + +su2double CFreeFormDefBox::GetDerivative5(su2double *uvw, unsigned short dim, unsigned short diff_this, unsigned short diff_this_also, + unsigned short *lmn) { + + unsigned short iDegree, jDegree, kDegree, iDim; + su2double value = 0.0; + + unsigned short *ijk = new unsigned short[nDim]; + + for (iDim = 0; iDim < nDim; iDim++) ijk[iDim] = 0; + + for (iDegree = 0; iDegree <= lmn[0]; iDegree++) + for (jDegree = 0; jDegree <= lmn[1]; jDegree++) + for (kDegree = 0; kDegree <= lmn[2]; kDegree++) { + ijk[0] = iDegree; ijk[1] = jDegree; ijk[2] = kDegree; + value += Coord_Control_Points[iDegree][jDegree][kDegree][dim] * + GetDerivative4(uvw, diff_this, diff_this_also, ijk, lmn); + } + + delete [] ijk; + + return value; +} diff --git a/Common/src/matrix_structure.cpp b/Common/src/matrix_structure.cpp index 18ad032eb2f..df53ff6bee4 100644 --- a/Common/src/matrix_structure.cpp +++ b/Common/src/matrix_structure.cpp @@ -1,1986 +1,1986 @@ -/*! - * \file matrix_structure.cpp - * \brief Main subroutines for doing the sparse structures - * \author F. Palacios, A. Bueno, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/matrix_structure.hpp" - -CSysMatrix::CSysMatrix(void) { - - /*--- Array initialization ---*/ - - matrix = NULL; - row_ptr = NULL; - col_ind = NULL; - block = NULL; - prod_block_vector = NULL; - prod_row_vector = NULL; - aux_vector = NULL; - sum_vector = NULL; - invM = NULL; - - /*--- Linelet preconditioner ---*/ - - LineletBool = NULL; - LineletPoint = NULL; - UBlock = NULL; - invUBlock = NULL; - LBlock = NULL; - yVector = NULL; - zVector = NULL; - rVector = NULL; - LFBlock = NULL; - LyVector = NULL; - FzVector = NULL; - max_nElem = 0; - -} - -CSysMatrix::~CSysMatrix(void) { - - unsigned long iElem; - - /*--- Memory deallocation ---*/ - - if (matrix != NULL) delete [] matrix; - if (row_ptr != NULL) delete [] row_ptr; - if (col_ind != NULL) delete [] col_ind; - if (block != NULL) delete [] block; - if (block_weight != NULL) delete [] block_weight; - if (block_inverse != NULL) delete [] block_inverse; - - if (prod_block_vector != NULL) delete [] prod_block_vector; - if (prod_row_vector != NULL) delete [] prod_row_vector; - if (aux_vector != NULL) delete [] aux_vector; - if (sum_vector != NULL) delete [] sum_vector; - if (invM != NULL) delete [] invM; - if (LineletBool != NULL) delete [] LineletBool; - if (LineletPoint != NULL) delete [] LineletPoint; - - for (iElem = 0; iElem < max_nElem; iElem++) { - if (UBlock[iElem] != NULL) delete [] UBlock[iElem]; - if (invUBlock[iElem] != NULL) delete [] invUBlock[iElem]; - if (LBlock[iElem] != NULL) delete [] LBlock[iElem]; - if (yVector[iElem] != NULL) delete [] yVector[iElem]; - if (zVector[iElem] != NULL) delete [] zVector[iElem]; - if (rVector[iElem] != NULL) delete [] rVector[iElem]; - } - if (UBlock != NULL) delete [] UBlock; - if (invUBlock != NULL) delete [] invUBlock; - if (LBlock != NULL) delete [] LBlock; - if (yVector != NULL) delete [] yVector; - if (zVector != NULL) delete [] zVector; - if (rVector != NULL) delete [] rVector; - - if (LFBlock != NULL) delete [] LFBlock; - if (LyVector != NULL) delete [] LyVector; - if (FzVector != NULL) delete [] FzVector; - -} - -void CSysMatrix::Initialize(unsigned long nPoint, unsigned long nPointDomain, - unsigned short nVar, unsigned short nEqn, - bool EdgeConnect, CGeometry *geometry, CConfig *config) { - - unsigned long iPoint, *row_ptr, *col_ind, index, nnz, Elem; - unsigned short iNeigh, iElem, iNode, *nNeigh; - vector::iterator it; - vector vneighs; - - /*--- Don't delete *row_ptr, *col_ind because they are - asigned to the Jacobian structure. ---*/ - - /*--- Compute the number of neighbors ---*/ - - nNeigh = new unsigned short [nPoint]; - for (iPoint = 0; iPoint < nPoint; iPoint++) { - - if (EdgeConnect) { - nNeigh[iPoint] = (geometry->node[iPoint]->GetnPoint()+1); // +1 -> to include diagonal element - } - else { - vneighs.clear(); - for (iElem = 0; iElem < geometry->node[iPoint]->GetnElem(); iElem++) { - Elem = geometry->node[iPoint]->GetElem(iElem); - for (iNode = 0; iNode < geometry->elem[Elem]->GetnNodes(); iNode++) - vneighs.push_back(geometry->elem[Elem]->GetNode(iNode)); - } - vneighs.push_back(iPoint); - - sort(vneighs.begin(), vneighs.end()); - it = unique(vneighs.begin(), vneighs.end()); - vneighs.resize(it - vneighs.begin()); - nNeigh[iPoint] = vneighs.size(); - } - - } - - /*--- Create row_ptr structure, using the number of neighbors ---*/ - - row_ptr = new unsigned long [nPoint+1]; - row_ptr[0] = 0; - for (iPoint = 0; iPoint < nPoint; iPoint++) - row_ptr[iPoint+1] = row_ptr[iPoint] + nNeigh[iPoint]; - nnz = row_ptr[nPoint]; - - /*--- Create col_ind structure ---*/ - - col_ind = new unsigned long [nnz]; - for (iPoint = 0; iPoint < nPoint; iPoint++) { - - vneighs.clear(); - - if (EdgeConnect) { - for (iNeigh = 0; iNeigh < geometry->node[iPoint]->GetnPoint(); iNeigh++) - vneighs.push_back(geometry->node[iPoint]->GetPoint(iNeigh)); - vneighs.push_back(iPoint); - } - else { - for (iElem = 0; iElem < geometry->node[iPoint]->GetnElem(); iElem++) { - Elem = geometry->node[iPoint]->GetElem(iElem); - for (iNode = 0; iNode < geometry->elem[Elem]->GetnNodes(); iNode++) - vneighs.push_back(geometry->elem[Elem]->GetNode(iNode)); - } - vneighs.push_back(iPoint); - } - - sort(vneighs.begin(), vneighs.end()); - it = unique(vneighs.begin(), vneighs.end()); - vneighs.resize( it - vneighs.begin() ); - - index = row_ptr[iPoint]; - for (iNeigh = 0; iNeigh < vneighs.size(); iNeigh++) { - col_ind[index] = vneighs[iNeigh]; - index++; - } - - } - - /*--- Set the indices in the in the sparce matrix structure, and memory allocation ---*/ - - SetIndexes(nPoint, nPointDomain, nVar, nEqn, row_ptr, col_ind, nnz, config); - - /*--- Initialization matrix to zero ---*/ - - SetValZero(); - - delete [] nNeigh; - -} - -void CSysMatrix::SetIndexes(unsigned long val_nPoint, unsigned long val_nPointDomain, unsigned short val_nVar, unsigned short val_nEq, unsigned long* val_row_ptr, unsigned long* val_col_ind, unsigned long val_nnz, CConfig *config) { - - unsigned long iVar; - - nPoint = val_nPoint; // Assign number of points in the mesh - nPointDomain = val_nPointDomain; // Assign number of points in the mesh - nVar = val_nVar; // Assign number of vars in each block system - nEqn = val_nEq; // Assign number of eqns in each block system - nnz = val_nnz; // Assign number of possible non zero blocks - row_ptr = val_row_ptr; - col_ind = val_col_ind; - - matrix = new su2double [nnz*nVar*nEqn]; // Reserve memory for the values of the matrix - block = new su2double [nVar*nEqn]; - block_weight = new su2double [nVar*nEqn]; - block_inverse = new su2double [nVar*nEqn]; - - prod_block_vector = new su2double [nEqn]; - prod_row_vector = new su2double [nVar]; - aux_vector = new su2double [nVar]; - sum_vector = new su2double [nVar]; - - /*--- Memory initialization ---*/ - - for (iVar = 0; iVar < nnz*nVar*nEqn; iVar++) matrix[iVar] = 0.0; - for (iVar = 0; iVar < nVar*nEqn; iVar++) block[iVar] = 0.0; - for (iVar = 0; iVar < nVar*nEqn; iVar++) block_weight[iVar] = 0.0; - for (iVar = 0; iVar < nVar*nEqn; iVar++) block_inverse[iVar] = 0.0; - - for (iVar = 0; iVar < nEqn; iVar++) prod_block_vector[iVar] = 0.0; - for (iVar = 0; iVar < nVar; iVar++) prod_row_vector[iVar] = 0.0; - for (iVar = 0; iVar < nVar; iVar++) aux_vector[iVar] = 0.0; - for (iVar = 0; iVar < nVar; iVar++) sum_vector[iVar] = 0.0; - - - /*--- Set specific preconditioner matrices (ILU) ---*/ - - if ((config->GetKind_Linear_Solver_Prec() == ILU) || - (config->GetKind_Linear_Solver() == SMOOTHER_ILU) || - (config->GetKind_DiscAdj_Linear_Prec() == ILU)) { - - /*--- Reserve memory for the ILU matrix. ---*/ - - ILU_matrix = new su2double [nnz*nVar*nEqn]; - for (iVar = 0; iVar < nnz*nVar*nEqn; iVar++) ILU_matrix[iVar] = 0.0; - } - - /*--- Set specific preconditioner matrices (Jacobi and Linelet) ---*/ - - if ((config->GetKind_Linear_Solver_Prec() == JACOBI) || - (config->GetKind_Linear_Solver_Prec() == LINELET) || - (config->GetKind_Linear_Solver() == SMOOTHER_JACOBI) || - (config->GetKind_Linear_Solver() == SMOOTHER_LINELET) || - (config->GetKind_DiscAdj_Linear_Solver() == JACOBI)) { - - /*--- Reserve memory for the values of the inverse of the preconditioner. ---*/ - - invM = new su2double [nPoint*nVar*nEqn]; - for (iVar = 0; iVar < nPoint*nVar*nEqn; iVar++) invM[iVar] = 0.0; - } - -} - -su2double *CSysMatrix::GetBlock(unsigned long block_i, unsigned long block_j) { - - unsigned long step = 0, index; - - for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { - step++; - if (col_ind[index] == block_j) { return &(matrix[(row_ptr[block_i]+step-1)*nVar*nEqn]); } - } - return NULL; - -} - -su2double CSysMatrix::GetBlock(unsigned long block_i, unsigned long block_j, unsigned short iVar, unsigned short jVar) { - - unsigned long step = 0, index; - - for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { - step++; - if (col_ind[index] == block_j) { return matrix[(row_ptr[block_i]+step-1)*nVar*nEqn+iVar*nEqn+jVar]; } - } - return 0; - -} - -void CSysMatrix::SetBlock(unsigned long block_i, unsigned long block_j, su2double **val_block) { - - unsigned long iVar, jVar, index, step = 0; - - for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { - step++; - if (col_ind[index] == block_j) { - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nEqn; jVar++) - matrix[(row_ptr[block_i]+step-1)*nVar*nEqn+iVar*nEqn+jVar] = SU2_TYPE::GetValue(val_block[iVar][jVar]); - break; - } - } - -} - -void CSysMatrix::SetBlock(unsigned long block_i, unsigned long block_j, su2double *val_block) { - - unsigned long iVar, jVar, index, step = 0; - - for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { - step++; - if (col_ind[index] == block_j) { - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nEqn; jVar++) - matrix[(row_ptr[block_i]+step-1)*nVar*nEqn+iVar*nEqn+jVar] = SU2_TYPE::GetValue(val_block[iVar*nVar+jVar]); - break; - } - } - -} - -void CSysMatrix::AddBlock(unsigned long block_i, unsigned long block_j, su2double **val_block) { - - unsigned long iVar, jVar, index, step = 0; - - for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { - step++; - if (col_ind[index] == block_j) { - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nEqn; jVar++) - matrix[(row_ptr[block_i]+step-1)*nVar*nEqn+iVar*nEqn+jVar] += SU2_TYPE::GetValue(val_block[iVar][jVar]); - break; - } - } - -} - -void CSysMatrix::SubtractBlock(unsigned long block_i, unsigned long block_j, su2double **val_block) { - - unsigned long iVar, jVar, index, step = 0; - - for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { - step++; - if (col_ind[index] == block_j) { - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nEqn; jVar++) - matrix[(row_ptr[block_i]+step-1)*nVar*nEqn+iVar*nEqn+jVar] -= SU2_TYPE::GetValue(val_block[iVar][jVar]); - break; - } - } - -} - -su2double *CSysMatrix::GetBlock_ILUMatrix(unsigned long block_i, unsigned long block_j) { - - unsigned long step = 0, index; - - for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { - step++; - if (col_ind[index] == block_j) { return &(ILU_matrix[(row_ptr[block_i]+step-1)*nVar*nEqn]); } - } - return NULL; - -} - -void CSysMatrix::SetBlock_ILUMatrix(unsigned long block_i, unsigned long block_j, su2double *val_block) { - - unsigned long iVar, jVar, index, step = 0; - - for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { - step++; - if (col_ind[index] == block_j) { - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nEqn; jVar++) - ILU_matrix[(row_ptr[block_i]+step-1)*nVar*nEqn+iVar*nEqn+jVar] = val_block[iVar*nVar+jVar]; - break; - } - } - -} - -void CSysMatrix::SetBlockTransposed_ILUMatrix(unsigned long block_i, unsigned long block_j, su2double *val_block) { - - unsigned long iVar, jVar, index, step = 0; - - for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { - step++; - if (col_ind[index] == block_j) { - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nEqn; jVar++) - ILU_matrix[(row_ptr[block_i]+step-1)*nVar*nEqn+iVar*nEqn+jVar] = val_block[jVar*nVar+iVar]; - break; - } - } - -} - -void CSysMatrix::SubtractBlock_ILUMatrix(unsigned long block_i, unsigned long block_j, su2double *val_block) { - - unsigned long iVar, jVar, index, step = 0; - - for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { - step++; - if (col_ind[index] == block_j) { - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nEqn; jVar++) - ILU_matrix[(row_ptr[block_i]+step-1)*nVar*nEqn+iVar*nEqn+jVar] -= val_block[iVar*nVar+jVar]; - break; - } - } - -} - -void CSysMatrix::MatrixVectorProduct(su2double *matrix, su2double *vector, su2double *product) { - - unsigned short iVar, jVar; - - for (iVar = 0; iVar < nVar; iVar++) { - product[iVar] = 0.0; - for (jVar = 0; jVar < nVar; jVar++) { - product[iVar] += matrix[iVar*nVar+jVar] * vector[jVar]; - } - } - -} - -void CSysMatrix::MatrixMatrixProduct(su2double *matrix_a, su2double *matrix_b, su2double *product) { - - unsigned short iVar, jVar, kVar; - - for (iVar = 0; iVar < nVar; iVar++) { - for (jVar = 0; jVar < nVar; jVar++) { - product[iVar*nVar+jVar] = 0.0; - for (kVar = 0; kVar < nVar; kVar++) { - product[iVar*nVar+jVar] += matrix_a[iVar*nVar+kVar]*matrix_b[kVar*nVar+jVar]; - } - } - } - -} - -void CSysMatrix::AddVal2Diag(unsigned long block_i, su2double val_matrix) { - - unsigned long step = 0, iVar, index; - - for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { - step++; - if (col_ind[index] == block_i) { // Only elements on the diagonal - for (iVar = 0; iVar < nVar; iVar++) - matrix[(row_ptr[block_i]+step-1)*nVar*nVar+iVar*nVar+iVar] += SU2_TYPE::GetValue(val_matrix); - break; - } - } - -} - -void CSysMatrix::SetVal2Diag(unsigned long block_i, su2double val_matrix) { - - unsigned long step = 0, iVar, jVar, index; - - for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { - step++; - if (col_ind[index] == block_i) { // Only elements on the diagonal - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - matrix[(row_ptr[block_i]+step-1)*nVar*nVar+iVar*nVar+jVar] = 0.0; - - for (iVar = 0; iVar < nVar; iVar++) - matrix[(row_ptr[block_i]+step-1)*nVar*nVar+iVar*nVar+iVar] = SU2_TYPE::GetValue(val_matrix); - - break; - } - } - -} - -void CSysMatrix::DeleteValsRowi(unsigned long i) { - - unsigned long block_i = i/nVar; - unsigned long row = i - block_i*nVar; - unsigned long index, iVar; - - for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { - for (iVar = 0; iVar < nVar; iVar++) - matrix[index*nVar*nVar+row*nVar+iVar] = 0.0; // Delete row values in the block - if (col_ind[index] == block_i) - matrix[index*nVar*nVar+row*nVar+row] = 1.0; // Set 1 to the diagonal element - } - -} - -void CSysMatrix::Gauss_Elimination(unsigned long block_i, su2double* rhs, bool transposed) { - - short iVar, jVar, kVar; // This is important, otherwise some compilers optimizations will fail - su2double weight, aux; - - su2double *Block = GetBlock(block_i, block_i); - - /*--- Copy block matrix, note that the original matrix - is modified by the algorithm---*/ - - if (!transposed){ - for (iVar = 0; iVar < (short)nVar; iVar++) - for (jVar = 0; jVar < (short)nVar; jVar++) - block[iVar*nVar+jVar] = Block[iVar*nVar+jVar]; - } else { - for (iVar = 0; iVar < (short)nVar; iVar++) - for (jVar = 0; jVar < (short)nVar; jVar++) - block[iVar*nVar+jVar] = Block[jVar*nVar+iVar]; - } - /*--- Gauss elimination ---*/ - - if (nVar == 1) { - rhs[0] /= block[0]; - } - else { - - /*--- Transform system in Upper Matrix ---*/ - - for (iVar = 1; iVar < (short)nVar; iVar++) { - for (jVar = 0; jVar < iVar; jVar++) { - weight = block[iVar*nVar+jVar] / block[jVar*nVar+jVar]; - for (kVar = jVar; kVar < (short)nVar; kVar++) - block[iVar*nVar+kVar] -= weight*block[jVar*nVar+kVar]; - rhs[iVar] -= weight*rhs[jVar]; - } - } - - /*--- Backwards substitution ---*/ - - rhs[nVar-1] = rhs[nVar-1] / block[nVar*nVar-1]; - for (iVar = (short)nVar-2; iVar >= 0; iVar--) { - aux = 0.0; - for (jVar = iVar+1; jVar < (short)nVar; jVar++) - aux += block[iVar*nVar+jVar]*rhs[jVar]; - rhs[iVar] = (rhs[iVar]-aux) / block[iVar*nVar+iVar]; - if (iVar == 0) break; - } - } - -} - -void CSysMatrix::Gauss_Elimination_ILUMatrix(unsigned long block_i, su2double* rhs) { - - short iVar, jVar, kVar; // This is important, otherwise some compilers optimizations will fail - su2double weight, aux; - - su2double *Block = GetBlock_ILUMatrix(block_i, block_i); - - /*--- Copy block matrix, note that the original matrix - is modified by the algorithm---*/ - - for (iVar = 0; iVar < (short)nVar; iVar++) - for (jVar = 0; jVar < (short)nVar; jVar++) - block[iVar*nVar+jVar] = Block[iVar*nVar+jVar]; - - /*--- Gauss elimination ---*/ - if (nVar == 1) { - rhs[0] /= block[0]; - } - else { - - /*--- Transform system in Upper Matrix ---*/ - for (iVar = 1; iVar < (short)nVar; iVar++) { - for (jVar = 0; jVar < iVar; jVar++) { - weight = block[iVar*nVar+jVar] / block[jVar*nVar+jVar]; - for (kVar = jVar; kVar < (short)nVar; kVar++) - block[iVar*nVar+kVar] -= weight*block[jVar*nVar+kVar]; - rhs[iVar] -= weight*rhs[jVar]; - } - } - - /*--- Backwards substitution ---*/ - rhs[nVar-1] = rhs[nVar-1] / block[nVar*nVar-1]; - for (iVar = (short)nVar-2; iVar >= 0; iVar--) { - aux = 0.0; - for (jVar = iVar+1; jVar < (short)nVar; jVar++) - aux += block[iVar*nVar+jVar]*rhs[jVar]; - rhs[iVar] = (rhs[iVar]-aux) / block[iVar*nVar+iVar]; - if (iVar == 0) break; - } - } - -} - -void CSysMatrix::Gauss_Elimination(su2double* Block, su2double* rhs) { - - short iVar, jVar, kVar; // This is important, otherwise some compilers optimizations will fail - su2double weight, aux; - - /*--- Copy block matrix, note that the original matrix - is modified by the algorithm---*/ - - for (iVar = 0; iVar < (short)nVar; iVar++) - for (jVar = 0; jVar < (short)nVar; jVar++) - block[iVar*nVar+jVar] = Block[iVar*nVar+jVar]; - - - if (nVar == 1) { - rhs[0] /= block[0]; - } - else { - /*--- Transform system in Upper Matrix ---*/ - for (iVar = 1; iVar < (short)nVar; iVar++) { - for (jVar = 0; jVar < iVar; jVar++) { - weight = block[iVar*nVar+jVar] / block[jVar*nVar+jVar]; - for (kVar = jVar; kVar < (short)nVar; kVar++) - block[iVar*nVar+kVar] -= weight*block[jVar*nVar+kVar]; - rhs[iVar] -= weight*rhs[jVar]; - } - } - - /*--- Backwards substitution ---*/ - rhs[nVar-1] = rhs[nVar-1] / block[nVar*nVar-1]; - for (iVar = (short)nVar-2; iVar >= 0; iVar--) { - aux = 0.0; - for (jVar = iVar+1; jVar < (short)nVar; jVar++) - aux += block[iVar*nVar+jVar]*rhs[jVar]; - rhs[iVar] = (rhs[iVar]-aux) / block[iVar*nVar+iVar]; - if (iVar == 0) break; - } - } - -} - -void CSysMatrix::ProdBlockVector(unsigned long block_i, unsigned long block_j, const CSysVector & vec) { - - unsigned long j = block_j*nVar; - unsigned short iVar, jVar; - - su2double *block = GetBlock(block_i, block_j); - - for (iVar = 0; iVar < nVar; iVar++) { - prod_block_vector[iVar] = 0; - for (jVar = 0; jVar < nVar; jVar++) - prod_block_vector[iVar] += block[iVar*nVar+jVar]*vec[j+jVar]; - } - -} - -void CSysMatrix::UpperProduct(CSysVector & vec, unsigned long row_i) { - - unsigned long iVar, index; - - for (iVar = 0; iVar < nVar; iVar++) - prod_row_vector[iVar] = 0; - - for (index = row_ptr[row_i]; index < row_ptr[row_i+1]; index++) { - if (col_ind[index] > row_i) { - ProdBlockVector(row_i, col_ind[index], vec); - for (iVar = 0; iVar < nVar; iVar++) - prod_row_vector[iVar] += prod_block_vector[iVar]; - } - } - -} - -void CSysMatrix::LowerProduct(CSysVector & vec, unsigned long row_i) { - - unsigned long iVar, index; - - for (iVar = 0; iVar < nVar; iVar++) - prod_row_vector[iVar] = 0; - - for (index = row_ptr[row_i]; index < row_ptr[row_i+1]; index++) { - if (col_ind[index] < row_i) { - ProdBlockVector(row_i, col_ind[index], vec); - for (iVar = 0; iVar < nVar; iVar++) - prod_row_vector[iVar] += prod_block_vector[iVar]; - } - } - -} - -void CSysMatrix::DiagonalProduct(CSysVector & vec, unsigned long row_i) { - - unsigned long iVar, index; - - for (iVar = 0; iVar < nVar; iVar++) - prod_row_vector[iVar] = 0; - - for (index = row_ptr[row_i]; index < row_ptr[row_i+1]; index++) { - if (col_ind[index] == row_i) { - ProdBlockVector(row_i, col_ind[index], vec); - for (iVar = 0; iVar < nVar; iVar++) - prod_row_vector[iVar] += prod_block_vector[iVar]; - } - } - -} - -void CSysMatrix::SendReceive_Solution(CSysVector & x, CGeometry *geometry, CConfig *config) { - - unsigned short iVar, iMarker, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double *Buffer_Receive = NULL, *Buffer_Send = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; - -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - - /*--- Allocate Receive and send buffers ---*/ - - Buffer_Receive = new su2double [nBufferR_Vector]; - Buffer_Send = new su2double[nBufferS_Vector]; - - /*--- Copy the solution that should be sended ---*/ - - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send[iVertex*nVar+iVar] = x[iPoint*nVar+iVar]; - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - - SU2_MPI::Sendrecv(Buffer_Send, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); - -#else - - /*--- Receive information without MPI ---*/ - - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive[iVar*nVertexR+iVertex] = Buffer_Send[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - - delete [] Buffer_Send; - - /*--- Do the coordinate transformation ---*/ - - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - - /*--- Copy transformed conserved variables back into buffer. ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - x[iPoint*nVar+iVar] = Buffer_Receive[iVertex*nVar+iVar]; - - } - - /*--- Deallocate receive buffer ---*/ - - delete [] Buffer_Receive; - - } - - } - -} - -void CSysMatrix::SendReceive_SolutionTransposed(CSysVector & x, CGeometry *geometry, CConfig *config) { - - unsigned short iVar, iMarker, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double *Buffer_Receive = NULL, *Buffer_Send = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker + 1; MarkerR = iMarker; - -#ifdef HAVE_MPI - - receive_from = config->GetMarker_All_SendRecv(MarkerR)-1; - send_to = abs(config->GetMarker_All_SendRecv(MarkerS))-1; - -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - - /*--- Allocate Receive and send buffers ---*/ - - Buffer_Receive = new su2double [nBufferR_Vector]; - Buffer_Send = new su2double[nBufferS_Vector]; - - /*--- Copy the solution that should be sended ---*/ - - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send[iVertex*nVar+iVar] = x[iPoint*nVar+iVar]; - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - - SU2_MPI::Sendrecv(Buffer_Send, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); - -#else - - /*--- Receive information without MPI ---*/ - - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive[iVar*nVertexR+iVertex] = Buffer_Send[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - - delete [] Buffer_Send; - - /*--- Do the coordinate transformation ---*/ - - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - - /*--- Copy transformed conserved variables back into buffer. ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - x[iPoint*nVar+iVar] += Buffer_Receive[iVertex*nVar+iVar]; - - } - - /*--- Deallocate receive buffer ---*/ - - delete [] Buffer_Receive; - - } - - } - -} - -void CSysMatrix::RowProduct(const CSysVector & vec, unsigned long row_i) { - - unsigned long iVar, index; - - for (iVar = 0; iVar < nVar; iVar++) - prod_row_vector[iVar] = 0; - - for (index = row_ptr[row_i]; index < row_ptr[row_i+1]; index++) { - ProdBlockVector(row_i, col_ind[index], vec); - for (iVar = 0; iVar < nVar; iVar++) - prod_row_vector[iVar] += prod_block_vector[iVar]; - } - -} - -void CSysMatrix::MatrixVectorProduct(const CSysVector & vec, CSysVector & prod) { - - unsigned long iPoint, iVar; - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - RowProduct(vec, iPoint); - for (iVar = 0; iVar < nVar; iVar++) - prod[iPoint*nVar+iVar] = prod_row_vector[iVar]; - } - -} - -void CSysMatrix::MatrixVectorProduct(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config) { - - unsigned long prod_begin, vec_begin, mat_begin, index, iVar, jVar, row_i; - - /*--- Some checks for consistency between CSysMatrix and the CSysVectors ---*/ - if ( (nVar != vec.GetNVar()) || (nVar != prod.GetNVar()) ) { - cerr << "CSysMatrix::MatrixVectorProduct(const CSysVector&, CSysVector): " - << "nVar values incompatible." << endl; - throw(-1); - } - if ( (nPoint != vec.GetNBlk()) || (nPoint != prod.GetNBlk()) ) { - cerr << "CSysMatrix::MatrixVectorProduct(const CSysVector&, CSysVector): " - << "nPoint and nBlk values incompatible." << endl; - throw(-1); - } - - prod = su2double(0.0); // set all entries of prod to zero - for (row_i = 0; row_i < nPointDomain; row_i++) { - prod_begin = row_i*nVar; // offset to beginning of block row_i - for (index = row_ptr[row_i]; index < row_ptr[row_i+1]; index++) { - vec_begin = col_ind[index]*nVar; // offset to beginning of block col_ind[index] - mat_begin = (index*nVar*nVar); // offset to beginning of matrix block[row_i][col_ind[indx]] - for (iVar = 0; iVar < nVar; iVar++) { - for (jVar = 0; jVar < nVar; jVar++) { - prod[(unsigned long)(prod_begin+iVar)] += matrix[(unsigned long)(mat_begin+iVar*nVar+jVar)]*vec[(unsigned long)(vec_begin+jVar)]; - } - } - } - } - - /*--- MPI Parallelization ---*/ - SendReceive_Solution(prod, geometry, config); - -} - -void CSysMatrix::MatrixVectorProductTransposed(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config) { - - unsigned long prod_begin, vec_begin, mat_begin, index, iVar, jVar , row_i; - - /*--- Some checks for consistency between CSysMatrix and the CSysVectors ---*/ - if ( (nVar != vec.GetNVar()) || (nVar != prod.GetNVar()) ) { - cerr << "CSysMatrix::MatrixVectorProductTransposed(const CSysVector&, CSysVector): " - << "nVar values incompatible." << endl; - throw(-1); - } - if ( (nPoint != vec.GetNBlk()) || (nPoint != prod.GetNBlk()) ) { - cerr << "CSysMatrix::MatrixVectorProductTransposed(const CSysVector&, CSysVector): " - << "nPoint and nBlk values incompatible." << endl; - throw(-1); - } - - prod = su2double(0.0); // set all entries of prod to zero - for (row_i = 0; row_i < nPointDomain; row_i++) { - vec_begin = row_i*nVar; // offset to beginning of block col_ind[index] - for (index = row_ptr[row_i]; index < row_ptr[row_i+1]; index++) { - prod_begin = col_ind[index]*nVar; // offset to beginning of block row_i - mat_begin = (index*nVar*nVar); // offset to beginning of matrix block[row_i][col_ind[indx]] - for (iVar = 0; iVar < nVar; iVar++) { - for (jVar = 0; jVar < nVar; jVar++) { - prod[(unsigned long)(prod_begin+jVar)] += matrix[(unsigned long)(mat_begin+iVar*nVar+jVar)]*vec[(unsigned long)(vec_begin+iVar)]; - } - } - } - } - - /*--- MPI Parallelization ---*/ - SendReceive_SolutionTransposed(prod, geometry, config); - -} - -void CSysMatrix::GetMultBlockBlock(su2double *c, su2double *a, su2double *b) { - - unsigned long iVar, jVar, kVar; - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) { - c[iVar*nVar+jVar] = 0.0; - for (kVar = 0; kVar < nVar; kVar++) - c[iVar*nVar+jVar] += a[iVar*nVar+kVar] * b[kVar*nVar+jVar]; - } - -} - -void CSysMatrix::GetMultBlockVector(su2double *c, su2double *a, su2double *b) { - - unsigned long iVar, jVar; - - for (iVar = 0; iVar < nVar; iVar++) { - c[iVar] = 0.0; - for (jVar = 0; jVar < nVar; jVar++) - c[iVar] += a[iVar*nVar+jVar] * b[jVar]; - } - -} - -void CSysMatrix::GetSubsBlock(su2double *c, su2double *a, su2double *b) { - - unsigned long iVar, jVar; - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - c[iVar*nVar+jVar] = a[iVar*nVar+jVar] - b[iVar*nVar+jVar]; - -} - -void CSysMatrix::GetSubsVector(su2double *c, su2double *a, su2double *b) { - - unsigned long iVar; - - for (iVar = 0; iVar < nVar; iVar++) - c[iVar] = a[iVar] - b[iVar]; - -} - -void CSysMatrix::InverseBlock(su2double *Block, su2double *invBlock) { - - unsigned long iVar, jVar; - - for (iVar = 0; iVar < nVar; iVar++) { - for (jVar = 0; jVar < nVar; jVar++) - aux_vector[jVar] = 0.0; - aux_vector[iVar] = 1.0; - - /*--- Compute the i-th column of the inverse matrix ---*/ - Gauss_Elimination(Block, aux_vector); - - for (jVar = 0; jVar < nVar; jVar++) - invBlock[jVar*nVar+iVar] = aux_vector[jVar]; - } - -} - -void CSysMatrix::InverseDiagonalBlock(unsigned long block_i, su2double *invBlock, bool transpose) { - - unsigned long iVar, jVar; - - for (iVar = 0; iVar < nVar; iVar++) { - for (jVar = 0; jVar < nVar; jVar++) - aux_vector[jVar] = 0.0; - aux_vector[iVar] = 1.0; - - /*--- Compute the i-th column of the inverse matrix ---*/ - - Gauss_Elimination(block_i, aux_vector, transpose); - for (jVar = 0; jVar < nVar; jVar++) - invBlock[jVar*nVar+iVar] = aux_vector[jVar]; - } - -} - - -void CSysMatrix::InverseDiagonalBlock_ILUMatrix(unsigned long block_i, su2double *invBlock) { - - unsigned long iVar, jVar; - - for (iVar = 0; iVar < nVar; iVar++) { - for (jVar = 0; jVar < nVar; jVar++) - aux_vector[jVar] = 0.0; - aux_vector[iVar] = 1.0; - - /*--- Compute the i-th column of the inverse matrix ---*/ - - Gauss_Elimination_ILUMatrix(block_i, aux_vector); - for (jVar = 0; jVar < nVar; jVar++) - invBlock[jVar*nVar+iVar] = aux_vector[jVar]; - } - -} - -void CSysMatrix::BuildJacobiPreconditioner(bool transpose) { - - unsigned long iPoint, iVar, jVar; - - /*--- Compute Jacobi Preconditioner ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint++) { - - /*--- Compute the inverse of the diagonal block ---*/ - InverseDiagonalBlock(iPoint, block_inverse, transpose); - - /*--- Set the inverse of the matrix to the invM structure (which is a vector) ---*/ - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - invM[iPoint*nVar*nVar+iVar*nVar+jVar] = block_inverse[iVar*nVar+jVar]; - } - -} - - -void CSysMatrix::ComputeJacobiPreconditioner(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config) { - - unsigned long iPoint, iVar, jVar; - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - prod[(unsigned long)(iPoint*nVar+iVar)] = 0.0; - for (jVar = 0; jVar < nVar; jVar++) - prod[(unsigned long)(iPoint*nVar+iVar)] += - invM[(unsigned long)(iPoint*nVar*nVar+iVar*nVar+jVar)]*vec[(unsigned long)(iPoint*nVar+jVar)]; - } - } - - /*--- MPI Parallelization ---*/ - - SendReceive_Solution(prod, geometry, config); - -} - -unsigned long CSysMatrix::Jacobi_Smoother(const CSysVector & b, CSysVector & x, CMatrixVectorProduct & mat_vec, su2double tol, unsigned long m, su2double *residual, bool monitoring, CGeometry *geometry, CConfig *config) { - - unsigned long iPoint, iVar, jVar; - int rank = MASTER_NODE; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Check the number of iterations requested ---*/ - - if (m < 1) { - if (rank == MASTER_NODE) cerr << "CSysMatrix::Jacobi_Smoother(): illegal value for smoothing iterations, m = " << m << endl; -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - } - - /*--- Create vectors to hold the residual and the Matrix-Vector product - of the Jacobian matrix with the current solution (x^k). These must be - stored in order to perform multiple iterations of the smoother. ---*/ - - CSysVector r(b); - CSysVector A_x(b); - - /*--- Calculate the initial residual, compute norm, and check - if system is already solved. Recall, r holds b initially. ---*/ - - mat_vec(x, A_x); - r -= A_x; - su2double norm_r = r.norm(); - su2double norm0 = b.norm(); - if ( (norm_r < tol*norm0) || (norm_r < eps) ) { - if (rank == MASTER_NODE) cout << "CSysMatrix::Jacobi_Smoother(): system solved by initial guess." << endl; - return 0; - } - - /*--- Set the norm to the initial initial residual value ---*/ - - norm0 = norm_r; - - /*--- Output header information including initial residual ---*/ - - int i = 0; - if ((monitoring) && (rank == MASTER_NODE)) { - cout << "\n# " << "Jacobi Smoother" << " residual history" << endl; - cout << "# Residual tolerance target = " << tol << endl; - cout << "# Initial residual norm = " << norm_r << endl; - cout << " " << i << " " << norm_r/norm0 << endl; - } - - /*--- Loop over all smoothing iterations ---*/ - - for (i = 0; i < (int)m; i++) { - - /*--- Apply the Jacobi smoother, i.e., multiply by the inverse of the - diagonal matrix of A, which was built in the preprocessing phase. Note - that we are directly updating the solution (x^k+1) during the loop. ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - for (jVar = 0; jVar < nVar; jVar++) - x[(unsigned long)(iPoint*nVar+iVar)] += - invM[(unsigned long)(iPoint*nVar*nVar+iVar*nVar+jVar)]*r[(unsigned long)(iPoint*nVar+jVar)]; - } - } - - /*--- MPI Parallelization ---*/ - - SendReceive_Solution(x, geometry, config); - - /*--- Update the residual (r^k+1 = b - A*x^k+1) with the new solution ---*/ - - r = b; - mat_vec(x, A_x); - r -= A_x; - - /*--- Check if solution has converged, else output the relative - residual if necessary. ---*/ - - norm_r = r.norm(); - if (norm_r < tol*norm0) break; - if (((monitoring) && (rank == MASTER_NODE)) && ((i+1) % 5 == 0)) - cout << " " << i << " " << norm_r/norm0 << endl; - - } - - if ((monitoring) && (rank == MASTER_NODE)) { - cout << "# Jacobi smoother final (true) residual:" << endl; - cout << "# Iteration = " << i << ": |res|/|res0| = " << norm_r/norm0 << ".\n" << endl; - } - - return i; - -} - -void CSysMatrix::BuildILUPreconditioner(bool transposed) { - - unsigned long index, index_; - su2double *Block_ij, *Block_jk; - long iPoint, jPoint, kPoint; - - /*--- Copy block matrix, note that the original matrix - is modified by the algorithm, so that we have the factorization stored - in the ILUMatrix at the end of this preprocessing. ---*/ - - for (iPoint = 0; iPoint < (long)nPointDomain; iPoint++) { - for (index = row_ptr[iPoint]; index < row_ptr[iPoint+1]; index++) { - jPoint = col_ind[index]; - if (transposed){ - Block_ij = GetBlock(jPoint, iPoint); - SetBlockTransposed_ILUMatrix(iPoint, jPoint, Block_ij); - } else { - Block_ij = GetBlock(iPoint, jPoint); - SetBlock_ILUMatrix(iPoint, jPoint, Block_ij); - } - } - } - - /*--- Transform system in Upper Matrix ---*/ - - for (iPoint = 1; iPoint < (long)nPointDomain; iPoint++) { - - /*--- For each row (unknown), loop over all entries in A on this row - row_ptr[iPoint+1] will have the index for the first entry on the next - row. ---*/ - - for (index = row_ptr[iPoint]; index < row_ptr[iPoint+1]; index++) { - - /*--- jPoint here is the column for each entry on this row ---*/ - - jPoint = col_ind[index]; - - /*--- Check that this column is in the lower triangular portion ---*/ - - if ((jPoint < iPoint) && (jPoint < (long)nPointDomain)) { - - /*--- If we're in the lower triangle, get the pointer to this block, - invert it, and then right multiply against the original block ---*/ - - Block_ij = GetBlock_ILUMatrix(iPoint, jPoint); - InverseDiagonalBlock_ILUMatrix(jPoint, block_inverse); - MatrixMatrixProduct(Block_ij, block_inverse, block_weight); - - /*--- block_weight holds Aij*inv(Ajj). Jump to the row for jPoint ---*/ - - for (index_ = row_ptr[jPoint]; index_ < row_ptr[jPoint+1]; index_++) { - - /*--- Get the column of the entry ---*/ - - kPoint = col_ind[index_]; - - /*--- If the column is greater than or equal to jPoint, i.e., the - upper triangular part, then multiply and modify the matrix. - Here, Aik' = Aik - Aij*inv(Ajj)*Ajk. ---*/ - - if (kPoint < (long)nPointDomain) { - Block_jk = GetBlock_ILUMatrix(jPoint, kPoint); - if (kPoint >= jPoint) { - - // WARNING: here we have a left multiply by Block_jk, should it - // be a right multiply to give Aik' = Aik - Aij*inv(Ajj)*Ajk? - - MatrixMatrixProduct(Block_jk, block_weight, block); - SubtractBlock_ILUMatrix(iPoint, kPoint, block); - - } - } - } - - /*--- Lastly, store block_weight in the lower triangular part, which - will be reused during the forward solve in the precon/smoother. ---*/ - - SetBlock_ILUMatrix(iPoint, jPoint, block_weight); - - } - } - } - -} - -void CSysMatrix::ComputeILUPreconditioner(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config) { - - unsigned long index; - su2double *Block_ij; - long iPoint, jPoint; - unsigned short iVar; - - /*--- Copy block matrix, note that the original matrix - is modified by the algorithm---*/ - - for (iPoint = 0; iPoint < (long)nPointDomain; iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - prod[iPoint*nVar+iVar] = vec[iPoint*nVar+iVar]; - } - } - - /*--- Transform system in Upper Matrix ---*/ - - for (iPoint = 1; iPoint < (long)nPointDomain; iPoint++) { - for (index = row_ptr[iPoint]; index < row_ptr[iPoint+1]; index++) { - jPoint = col_ind[index]; - if ((jPoint < iPoint) && (jPoint < (long)nPointDomain)) { - Block_ij = GetBlock_ILUMatrix(iPoint, jPoint); - MatrixVectorProduct(Block_ij, &prod[jPoint*nVar], aux_vector); - for (iVar = 0; iVar < nVar; iVar++) - prod[iPoint*nVar+iVar] -= aux_vector[iVar]; - - } - } - } - - /*--- Backwards substitution ---*/ - - InverseDiagonalBlock_ILUMatrix((nPointDomain-1), block_inverse); - MatrixVectorProduct(block_inverse, &prod[(nPointDomain-1)*nVar], aux_vector); - - for (iVar = 0; iVar < nVar; iVar++) - prod[ (nPointDomain-1)*nVar + iVar] = aux_vector[iVar]; - - for (iPoint = nPointDomain-2; iPoint >= 0; iPoint--) { - for (iVar = 0; iVar < nVar; iVar++) sum_vector[iVar] = 0.0; - for (index = row_ptr[iPoint]; index < row_ptr[iPoint+1]; index++) { - jPoint = col_ind[index]; - if (jPoint < (long)nPointDomain) { - Block_ij = GetBlock_ILUMatrix(iPoint, jPoint); - if ((jPoint >= iPoint+1) && (jPoint < (long)nPointDomain)) { - MatrixVectorProduct(Block_ij, &prod[jPoint*nVar], aux_vector); - for (iVar = 0; iVar < nVar; iVar++) sum_vector[iVar] += aux_vector[iVar]; - } - } - } - for (iVar = 0; iVar < nVar; iVar++) prod[iPoint*nVar+iVar] = (prod[iPoint*nVar+iVar]-sum_vector[iVar]); - InverseDiagonalBlock_ILUMatrix(iPoint, block_inverse); - MatrixVectorProduct(block_inverse, &prod[iPoint*nVar], aux_vector); - for (iVar = 0; iVar < nVar; iVar++) prod[iPoint*nVar+iVar] = aux_vector[iVar]; - if (iPoint == 0) break; - } - - /*--- MPI Parallelization ---*/ - - SendReceive_Solution(prod, geometry, config); - -} - -unsigned long CSysMatrix::ILU0_Smoother(const CSysVector & b, CSysVector & x, CMatrixVectorProduct & mat_vec, su2double tol, unsigned long m, su2double *residual, bool monitoring, CGeometry *geometry, CConfig *config) { - - unsigned long index; - su2double *Block_ij, omega = 1.0; - long iPoint, jPoint; - unsigned short iVar; - int rank = MASTER_NODE; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Check the number of iterations requested ---*/ - - if (m < 1) { - if (rank == MASTER_NODE) cerr << "CSysMatrix::ILU0_Smoother(): illegal value for smoothing iterations, m = " << m << endl; -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - } - - /*--- Create vectors to hold the residual and the Matrix-Vector product - of the Jacobian matrix with the current solution (x^k). These must be - stored in order to perform multiple iterations of the smoother. ---*/ - - CSysVector r(b); - CSysVector A_x(b); - - /*--- Calculate the initial residual, compute norm, and check - if system is already solved. Recall, r holds b initially. ---*/ - - mat_vec(x, A_x); - r -= A_x; - su2double norm_r = r.norm(); - su2double norm0 = b.norm(); - if ( (norm_r < tol*norm0) || (norm_r < eps) ) { - if (rank == MASTER_NODE) cout << "CSysMatrix::ILU0_Smoother(): system solved by initial guess." << endl; - return 0; - } - - /*--- Set the norm to the initial initial residual value ---*/ - - norm0 = norm_r; - - /*--- Output header information including initial residual ---*/ - - int i = 0; - if ((monitoring) && (rank == MASTER_NODE)) { - cout << "\n# " << "ILU0 Smoother" << " residual history" << endl; - cout << "# Residual tolerance target = " << tol << endl; - cout << "# Initial residual norm = " << norm_r << endl; - cout << " " << i << " " << norm_r/norm0 << endl; - } - - /*--- Loop over all smoothing iterations ---*/ - - for (i = 0; i < (int)m; i++) { - - /*--- Forward solve the system using the lower matrix entries that - were computed and stored during the ILU0 preprocessing. Note - that we are overwriting the residual vector as we go. ---*/ - - for (iPoint = 1; iPoint < (long)nPointDomain; iPoint++) { - - /*--- For each row (unknown), loop over all entries in A on this row - row_ptr[iPoint+1] will have the index for the first entry on the next - row. ---*/ - - for (index = row_ptr[iPoint]; index < row_ptr[iPoint+1]; index++) { - - /*--- jPoint here is the column for each entry on this row ---*/ - - jPoint = col_ind[index]; - - /*--- Check that this column is in the lower triangular portion ---*/ - - if ((jPoint < iPoint) && (jPoint < (long)nPointDomain)) { - - /*--- Lastly, get Aij*inv(Ajj) from the lower triangular part, which - was calculated in the preprocessing, and apply to r. ---*/ - - Block_ij = GetBlock_ILUMatrix(iPoint, jPoint); - MatrixVectorProduct(Block_ij, &r[jPoint*nVar], aux_vector); - for (iVar = 0; iVar < nVar; iVar++) - r[iPoint*nVar+iVar] -= aux_vector[iVar]; - - } - } - } - - /*--- Backwards substitution (starts at the last row) ---*/ - - InverseDiagonalBlock_ILUMatrix((nPointDomain-1), block_inverse); - MatrixVectorProduct(block_inverse, &r[(nPointDomain-1)*nVar], aux_vector); - - for (iVar = 0; iVar < nVar; iVar++) - r[(nPointDomain-1)*nVar + iVar] = aux_vector[iVar]; - - for (iPoint = nPointDomain-2; iPoint >= 0; iPoint--) { - for (iVar = 0; iVar < nVar; iVar++) sum_vector[iVar] = 0.0; - for (index = row_ptr[iPoint]; index < row_ptr[iPoint+1]; index++) { - jPoint = col_ind[index]; - if (jPoint < (long)nPointDomain) { - Block_ij = GetBlock_ILUMatrix(iPoint, jPoint); - if ((jPoint >= iPoint+1) && (jPoint < (long)nPointDomain)) { - MatrixVectorProduct(Block_ij, &r[jPoint*nVar], aux_vector); - for (iVar = 0; iVar < nVar; iVar++) sum_vector[iVar] += aux_vector[iVar]; - } - } - } - for (iVar = 0; iVar < nVar; iVar++) r[iPoint*nVar+iVar] = (r[iPoint*nVar+iVar]-sum_vector[iVar]); - InverseDiagonalBlock_ILUMatrix(iPoint, block_inverse); - MatrixVectorProduct(block_inverse, &r[iPoint*nVar], aux_vector); - for (iVar = 0; iVar < nVar; iVar++) r[iPoint*nVar+iVar] = aux_vector[iVar]; - if (iPoint == 0) break; - } - - /*--- Update solution (x^k+1 = x^k + w*M^-1*r^k) using the residual vector, - which holds the update after applying the ILU0 smoother, i.e., M^-1*r^k. - Omega is a relaxation factor that we have currently set to 1.0. ---*/ - - x.Plus_AX(omega, r); - - /*--- MPI Parallelization ---*/ - - SendReceive_Solution(x, geometry, config); - - /*--- Update the residual (r^k+1 = b - A*x^k+1) with the new solution ---*/ - - r = b; - mat_vec(x, A_x); - r -= A_x; - - /*--- Check if solution has converged, else output the relative - residual if necessary. ---*/ - - norm_r = r.norm(); - if (norm_r < tol*norm0) break; - if (((monitoring) && (rank == MASTER_NODE)) && ((i+1) % 5 == 0)) - cout << " " << i << " " << norm_r/norm0 << endl; - - } - - if ((monitoring) && (rank == MASTER_NODE)) { - cout << "# ILU0 smoother final (true) residual:" << endl; - cout << "# Iteration = " << i << ": |res|/|res0| = " << norm_r/norm0 << ".\n" << endl; - } - - return i; - -} - -void CSysMatrix::ComputeLU_SGSPreconditioner(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config) { - unsigned long iPoint, iVar; - - /*--- First part of the symmetric iteration: (D+L).x* = b ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - LowerProduct(prod, iPoint); // Compute L.x* - for (iVar = 0; iVar < nVar; iVar++) - aux_vector[iVar] = vec[iPoint*nVar+iVar] - prod_row_vector[iVar]; // Compute aux_vector = b - L.x* - Gauss_Elimination(iPoint, aux_vector); // Solve D.x* = aux_vector - for (iVar = 0; iVar < nVar; iVar++) - prod[iPoint*nVar+iVar] = aux_vector[iVar]; // Assesing x* = solution - } - - /*--- MPI Parallelization ---*/ - - SendReceive_Solution(prod, geometry, config); - - /*--- Second part of the symmetric iteration: (D+U).x_(1) = D.x* ---*/ - - for (iPoint = nPointDomain-1; (int)iPoint >= 0; iPoint--) { - DiagonalProduct(prod, iPoint); // Compute D.x* - for (iVar = 0; iVar < nVar; iVar++) - aux_vector[iVar] = prod_row_vector[iVar]; // Compute aux_vector = D.x* - UpperProduct(prod, iPoint); // Compute U.x_(n+1) - for (iVar = 0; iVar < nVar; iVar++) - aux_vector[iVar] -= prod_row_vector[iVar]; // Compute aux_vector = D.x*-U.x_(n+1) - Gauss_Elimination(iPoint, aux_vector); // Solve D.x* = aux_vector - for (iVar = 0; iVar < nVar; iVar++) - prod[iPoint*nVar + iVar] = aux_vector[iVar]; // Assesing x_(1) = solution - } - - /*--- MPI Parallelization ---*/ - - SendReceive_Solution(prod, geometry, config); - -} - -unsigned long CSysMatrix::LU_SGS_Smoother(const CSysVector & b, CSysVector & x, CMatrixVectorProduct & mat_vec, su2double tol, unsigned long m, su2double *residual, bool monitoring, CGeometry *geometry, CConfig *config) { - - unsigned long iPoint, iVar; - su2double omega = 1.0; - int rank = MASTER_NODE; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Check the number of iterations requested ---*/ - - if (m < 1) { - if (rank == MASTER_NODE) cerr << "CSysMatrix::LU_SGS_Smoother(): illegal value for smoothing iterations, m = " << m << endl; -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - } - - /*--- Create vectors to hold the residual and the Matrix-Vector product - of the Jacobian matrix with the current solution (x^k). These must be - stored in order to perform multiple iterations of the smoother. ---*/ - - CSysVector r(b); - CSysVector A_x(b); - CSysVector xStar(x); - - /*--- Calculate the initial residual, compute norm, and check - if system is already solved. Recall, r holds b initially. ---*/ - - mat_vec(x, A_x); - r -= A_x; - su2double norm_r = r.norm(); - su2double norm0 = b.norm(); - if ( (norm_r < tol*norm0) || (norm_r < eps) ) { - if (rank == MASTER_NODE) cout << "CSysMatrix::LU_SGS_Smoother(): system solved by initial guess." << endl; - return 0; - } - - /*--- Set the norm to the initial initial residual value ---*/ - - norm0 = norm_r; - - /*--- Output header information including initial residual ---*/ - - int i = 0; - if ((monitoring) && (rank == MASTER_NODE)) { - cout << "\n# " << "LU_SGS Smoother" << " residual history" << endl; - cout << "# Residual tolerance target = " << tol << endl; - cout << "# Initial residual norm = " << norm_r << endl; - cout << " " << i << " " << norm_r/norm0 << endl; - } - - /*--- Loop over all smoothing iterations ---*/ - - for (i = 0; i < (int)m; i++) { - - /*--- First part of the symmetric iteration: (D+L).x* = b ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - LowerProduct(xStar, iPoint); // Compute L.x* - for (iVar = 0; iVar < nVar; iVar++) - aux_vector[iVar] = r[iPoint*nVar+iVar] - prod_row_vector[iVar]; // Compute aux_vector = b - L.x* - Gauss_Elimination(iPoint, aux_vector); // Solve D.x* = aux_vector - for (iVar = 0; iVar < nVar; iVar++) - xStar[iPoint*nVar+iVar] = aux_vector[iVar]; // Assesing x* = solution, stored in r - } - - /*--- MPI Parallelization ---*/ - - SendReceive_Solution(xStar, geometry, config); - - /*--- Second part of the symmetric iteration: (D+U).x_(1) = D.x* ---*/ - - for (iPoint = nPointDomain-1; (int)iPoint >= 0; iPoint--) { - DiagonalProduct(xStar, iPoint); // Compute D.x* - for (iVar = 0; iVar < nVar; iVar++) - aux_vector[iVar] = prod_row_vector[iVar]; // Compute aux_vector = D.x* - UpperProduct(xStar, iPoint); // Compute U.x_(n+1) - for (iVar = 0; iVar < nVar; iVar++) - aux_vector[iVar] -= prod_row_vector[iVar]; // Compute aux_vector = D.x*-U.x_(n+1) - Gauss_Elimination(iPoint, aux_vector); // Solve D.x* = aux_vector - for (iVar = 0; iVar < nVar; iVar++) - xStar[iPoint*nVar+iVar] = aux_vector[iVar]; // Assesing x_(1) = solution - } - - /*--- Update solution (x^k+1 = x^k + w*M^-1*r^k) using the xStar vector, - which holds the update after applying the LU_SGS smoother, i.e., M^-1*r^k. - Omega is a relaxation factor that we have currently set to 1.0. ---*/ - - x.Plus_AX(omega, xStar); - - /*--- MPI Parallelization ---*/ - - SendReceive_Solution(x, geometry, config); - - /*--- Update the residual (r^k+1 = b - A*x^k+1) with the new solution ---*/ - - r = b; - mat_vec(x, A_x); - r -= A_x; - xStar = x; - - /*--- Check if solution has converged, else output the relative - residual if necessary. ---*/ - - norm_r = r.norm(); - if (norm_r < tol*norm0) break; - if (((monitoring) && (rank == MASTER_NODE)) && ((i+1) % 5 == 0)) - cout << " " << i << " " << norm_r/norm0 << endl; - - } - - if ((monitoring) && (rank == MASTER_NODE)) { - cout << "# LU_SGS smoother final (true) residual:" << endl; - cout << "# Iteration = " << i << ": |res|/|res0| = " << norm_r/norm0 << ".\n" << endl; - } - - return i; - -} - -unsigned short CSysMatrix::BuildLineletPreconditioner(CGeometry *geometry, CConfig *config) { - - bool *check_Point, add_point; - unsigned long iEdge, iPoint, jPoint, index_Point, iLinelet, iVertex, next_Point, counter, iElem; - unsigned short iMarker, iNode, ExtraLines = 100, MeanPoints; - su2double alpha = 0.9, weight, max_weight, *normal, area, volume_iPoint, volume_jPoint; - unsigned long Local_nPoints, Local_nLineLets, Global_nPoints, Global_nLineLets; - - /*--- Memory allocation --*/ - - check_Point = new bool [geometry->GetnPoint()]; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - check_Point[iPoint] = true; - - LineletBool = new bool[geometry->GetnPoint()]; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) - LineletBool[iPoint] = false; - - nLinelet = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX ) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL ) || - (config->GetMarker_All_KindBC(iMarker) == EULER_WALL ) || - (config->GetMarker_All_KindBC(iMarker) == DISPLACEMENT_BOUNDARY)) { - nLinelet += geometry->nVertex[iMarker]; - } - } - - /*--- If the domain contains well defined Linelets ---*/ - - if (nLinelet != 0) { - - /*--- Basic initial allocation ---*/ - - LineletPoint = new vector[nLinelet + ExtraLines]; - - /*--- Define the basic linelets, starting from each vertex ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX ) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL ) || - (config->GetMarker_All_KindBC(iMarker) == EULER_WALL ) || - (config->GetMarker_All_KindBC(iMarker) == DISPLACEMENT_BOUNDARY)) { - iLinelet = 0; - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - LineletPoint[iLinelet].push_back(iPoint); - check_Point[iPoint] = false; - iLinelet++; - } - } - } - - /*--- Create the linelet structure ---*/ - - iLinelet = 0; - - do { - - index_Point = 0; - - do { - - /*--- Compute the value of the max weight ---*/ - - iPoint = LineletPoint[iLinelet][index_Point]; - max_weight = 0.0; - for (iNode = 0; iNode < geometry->node[iPoint]->GetnPoint(); iNode++) { - jPoint = geometry->node[iPoint]->GetPoint(iNode); - if ((check_Point[jPoint]) && geometry->node[jPoint]->GetDomain()) { - iEdge = geometry->FindEdge(iPoint, jPoint); - normal = geometry->edge[iEdge]->GetNormal(); - if (geometry->GetnDim() == 3) area = sqrt(normal[0]*normal[0]+normal[1]*normal[1]+normal[2]*normal[2]); - else area = sqrt(normal[0]*normal[0]+normal[1]*normal[1]); - volume_iPoint = geometry->node[iPoint]->GetVolume(); - volume_jPoint = geometry->node[jPoint]->GetVolume(); - weight = 0.5*area*((1.0/volume_iPoint)+(1.0/volume_jPoint)); - max_weight = max(max_weight, weight); - } - } - - /*--- Verify if any face of the control volume must be added ---*/ - - add_point = false; - counter = 0; - next_Point = geometry->node[iPoint]->GetPoint(0); - for (iNode = 0; iNode < geometry->node[iPoint]->GetnPoint(); iNode++) { - jPoint = geometry->node[iPoint]->GetPoint(iNode); - iEdge = geometry->FindEdge(iPoint, jPoint); - normal = geometry->edge[iEdge]->GetNormal(); - if (geometry->GetnDim() == 3) area = sqrt(normal[0]*normal[0]+normal[1]*normal[1]+normal[2]*normal[2]); - else area = sqrt(normal[0]*normal[0]+normal[1]*normal[1]); - volume_iPoint = geometry->node[iPoint]->GetVolume(); - volume_jPoint = geometry->node[jPoint]->GetVolume(); - weight = 0.5*area*((1.0/volume_iPoint)+(1.0/volume_jPoint)); - if (((check_Point[jPoint]) && (weight/max_weight > alpha) && (geometry->node[jPoint]->GetDomain())) && - ((index_Point == 0) || ((index_Point > 0) && (jPoint != LineletPoint[iLinelet][index_Point-1])))) { - add_point = true; - next_Point = jPoint; - counter++; - } - } - - /*--- We have arrived to an isotropic zone ---*/ - - if (counter > 1) add_point = false; - - /*--- Add a typical point to the linelet, no leading edge ---*/ - - if (add_point) { - LineletPoint[iLinelet].push_back(next_Point); - check_Point[next_Point] = false; - index_Point++; - } - - } while (add_point); - iLinelet++; - } while (iLinelet < nLinelet); - - /*--- Identify the points that belong to a Linelet ---*/ - - for (iLinelet = 0; iLinelet < nLinelet; iLinelet++) { - for (iElem = 0; iElem < LineletPoint[iLinelet].size(); iElem++) { - iPoint = LineletPoint[iLinelet][iElem]; - LineletBool[iPoint] = true; - } - } - - /*--- Identify the maximum number of elements in a Linelet ---*/ - - max_nElem = LineletPoint[0].size(); - for (iLinelet = 1; iLinelet < nLinelet; iLinelet++) - if (LineletPoint[iLinelet].size() > max_nElem) - max_nElem = LineletPoint[iLinelet].size(); - - } - - /*--- The domain doesn't have well defined linelets ---*/ - - else { - - max_nElem = 0; - - } - - /*--- Screen output ---*/ - - Local_nPoints = 0; - for (iLinelet = 0; iLinelet < nLinelet; iLinelet++) { - Local_nPoints += LineletPoint[iLinelet].size(); - } - Local_nLineLets = nLinelet; - -#ifndef HAVE_MPI - Global_nPoints = Local_nPoints; - Global_nLineLets = Local_nLineLets; -#else - SU2_MPI::Allreduce(&Local_nPoints, &Global_nPoints, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&Local_nLineLets, &Global_nLineLets, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#endif - - MeanPoints = SU2_TYPE::Int(su2double(Global_nPoints)/su2double(Global_nLineLets)); - - /*--- Memory allocation --*/ - - UBlock = new su2double* [max_nElem]; - invUBlock = new su2double* [max_nElem]; - LBlock = new su2double* [max_nElem]; - yVector = new su2double* [max_nElem]; - zVector = new su2double* [max_nElem]; - rVector = new su2double* [max_nElem]; - for (iElem = 0; iElem < max_nElem; iElem++) { - UBlock[iElem] = new su2double [nVar*nVar]; - invUBlock[iElem] = new su2double [nVar*nVar]; - LBlock[iElem] = new su2double [nVar*nVar]; - yVector[iElem] = new su2double [nVar]; - zVector[iElem] = new su2double [nVar]; - rVector[iElem] = new su2double [nVar]; - } - - LFBlock = new su2double [nVar*nVar]; - LyVector = new su2double [nVar]; - FzVector = new su2double [nVar]; - - /*--- Memory deallocation --*/ - - delete [] check_Point; - - return MeanPoints; - -} - -void CSysMatrix::ComputeLineletPreconditioner(const CSysVector & vec, CSysVector & prod, - CGeometry *geometry, CConfig *config) { - - unsigned long iVar, jVar, nElem = 0, iLinelet, im1Point, iPoint, ip1Point, iElem; - long iElemLoop; - su2double *block; - - int rank = MASTER_NODE; - int size = SINGLE_NODE; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); -#endif - - if (size == SINGLE_NODE) { - - /*--- Jacobi preconditioning if there is no linelet ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - if (!LineletBool[iPoint]) { - for (iVar = 0; iVar < nVar; iVar++) { - prod[(unsigned long)(iPoint*nVar+iVar)] = 0.0; - for (jVar = 0; jVar < nVar; jVar++) - prod[(unsigned long)(iPoint*nVar+iVar)] += - invM[(unsigned long)(iPoint*nVar*nVar+iVar*nVar+jVar)]*vec[(unsigned long)(iPoint*nVar+jVar)]; - } - } - } - - /*--- MPI Parallelization ---*/ - - SendReceive_Solution(prod, geometry, config); - - /*--- Solve linelet using a Thomas' algorithm ---*/ - - for (iLinelet = 0; iLinelet < nLinelet; iLinelet++) { - - nElem = LineletPoint[iLinelet].size(); - - /*--- Copy vec vector to the new structure ---*/ - - for (iElem = 0; iElem < nElem; iElem++) { - iPoint = LineletPoint[iLinelet][iElem]; - for (iVar = 0; iVar < nVar; iVar++) - rVector[iElem][iVar] = vec[(unsigned long)(iPoint*nVar+iVar)]; - } - - /*--- Initialization (iElem = 0) ---*/ - - iPoint = LineletPoint[iLinelet][0]; - block = GetBlock(iPoint, iPoint); - for (iVar = 0; iVar < nVar; iVar++) { - yVector[0][iVar] = rVector[0][iVar]; - for (jVar = 0; jVar < nVar; jVar++) - UBlock[0][iVar*nVar+jVar] = block[iVar*nVar+jVar]; - } - - /*--- Main loop (without iElem = 0) ---*/ - - for (iElem = 1; iElem < nElem; iElem++) { - - im1Point = LineletPoint[iLinelet][iElem-1]; - iPoint = LineletPoint[iLinelet][iElem]; - - InverseBlock(UBlock[iElem-1], invUBlock[iElem-1]); - block = GetBlock(iPoint, im1Point); GetMultBlockBlock(LBlock[iElem], block, invUBlock[iElem-1]); - block = GetBlock(im1Point, iPoint); GetMultBlockBlock(LFBlock, LBlock[iElem], block); - block = GetBlock(iPoint, iPoint); GetSubsBlock(UBlock[iElem], block, LFBlock); - - /*--- Forward substituton ---*/ - - GetMultBlockVector(LyVector, LBlock[iElem], yVector[iElem-1]); - GetSubsVector(yVector[iElem], rVector[iElem], LyVector); - - } - - /*--- Backward substituton ---*/ - - InverseBlock(UBlock[nElem-1], invUBlock[nElem-1]); - GetMultBlockVector(zVector[nElem-1], invUBlock[nElem-1], yVector[nElem-1]); - - for (iElemLoop = nElem-2; iElemLoop >= 0; iElemLoop--) { - iPoint = LineletPoint[iLinelet][iElemLoop]; - ip1Point = LineletPoint[iLinelet][iElemLoop+1]; - block = GetBlock(iPoint, ip1Point); GetMultBlockVector(FzVector, block, zVector[iElemLoop+1]); - GetSubsVector(aux_vector, yVector[iElemLoop], FzVector); - GetMultBlockVector(zVector[iElemLoop], invUBlock[iElemLoop], aux_vector); - } - - /*--- Copy zVector to the prod vector ---*/ - - for (iElem = 0; iElem < nElem; iElem++) { - iPoint = LineletPoint[iLinelet][iElem]; - for (iVar = 0; iVar < nVar; iVar++) - prod[(unsigned long)(iPoint*nVar+iVar)] = zVector[iElem][iVar]; - } - - } - - /*--- MPI Parallelization ---*/ - - SendReceive_Solution(prod, geometry, config); - - } - else { - - if (rank == MASTER_NODE) cout << "ERROR: Linelet not implemented in parallel." << endl; - -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - - } - -} - -void CSysMatrix::ComputeResidual(const CSysVector & sol, const CSysVector & f, CSysVector & res) { - - unsigned long iPoint, iVar; - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - RowProduct(sol, iPoint); - for (iVar = 0; iVar < nVar; iVar++) { - res[iPoint*nVar+iVar] = prod_row_vector[iVar] - f[iPoint*nVar+iVar]; - } - } - -} +/*! + * \file matrix_structure.cpp + * \brief Main subroutines for doing the sparse structures + * \author F. Palacios, A. Bueno, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/matrix_structure.hpp" + +CSysMatrix::CSysMatrix(void) { + + /*--- Array initialization ---*/ + + matrix = NULL; + row_ptr = NULL; + col_ind = NULL; + block = NULL; + prod_block_vector = NULL; + prod_row_vector = NULL; + aux_vector = NULL; + sum_vector = NULL; + invM = NULL; + + /*--- Linelet preconditioner ---*/ + + LineletBool = NULL; + LineletPoint = NULL; + UBlock = NULL; + invUBlock = NULL; + LBlock = NULL; + yVector = NULL; + zVector = NULL; + rVector = NULL; + LFBlock = NULL; + LyVector = NULL; + FzVector = NULL; + max_nElem = 0; + +} + +CSysMatrix::~CSysMatrix(void) { + + unsigned long iElem; + + /*--- Memory deallocation ---*/ + + if (matrix != NULL) delete [] matrix; + if (row_ptr != NULL) delete [] row_ptr; + if (col_ind != NULL) delete [] col_ind; + if (block != NULL) delete [] block; + if (block_weight != NULL) delete [] block_weight; + if (block_inverse != NULL) delete [] block_inverse; + + if (prod_block_vector != NULL) delete [] prod_block_vector; + if (prod_row_vector != NULL) delete [] prod_row_vector; + if (aux_vector != NULL) delete [] aux_vector; + if (sum_vector != NULL) delete [] sum_vector; + if (invM != NULL) delete [] invM; + if (LineletBool != NULL) delete [] LineletBool; + if (LineletPoint != NULL) delete [] LineletPoint; + + for (iElem = 0; iElem < max_nElem; iElem++) { + if (UBlock[iElem] != NULL) delete [] UBlock[iElem]; + if (invUBlock[iElem] != NULL) delete [] invUBlock[iElem]; + if (LBlock[iElem] != NULL) delete [] LBlock[iElem]; + if (yVector[iElem] != NULL) delete [] yVector[iElem]; + if (zVector[iElem] != NULL) delete [] zVector[iElem]; + if (rVector[iElem] != NULL) delete [] rVector[iElem]; + } + if (UBlock != NULL) delete [] UBlock; + if (invUBlock != NULL) delete [] invUBlock; + if (LBlock != NULL) delete [] LBlock; + if (yVector != NULL) delete [] yVector; + if (zVector != NULL) delete [] zVector; + if (rVector != NULL) delete [] rVector; + + if (LFBlock != NULL) delete [] LFBlock; + if (LyVector != NULL) delete [] LyVector; + if (FzVector != NULL) delete [] FzVector; + +} + +void CSysMatrix::Initialize(unsigned long nPoint, unsigned long nPointDomain, + unsigned short nVar, unsigned short nEqn, + bool EdgeConnect, CGeometry *geometry, CConfig *config) { + + unsigned long iPoint, *row_ptr, *col_ind, index, nnz, Elem; + unsigned short iNeigh, iElem, iNode, *nNeigh; + vector::iterator it; + vector vneighs; + + /*--- Don't delete *row_ptr, *col_ind because they are + asigned to the Jacobian structure. ---*/ + + /*--- Compute the number of neighbors ---*/ + + nNeigh = new unsigned short [nPoint]; + for (iPoint = 0; iPoint < nPoint; iPoint++) { + + if (EdgeConnect) { + nNeigh[iPoint] = (geometry->node[iPoint]->GetnPoint()+1); // +1 -> to include diagonal element + } + else { + vneighs.clear(); + for (iElem = 0; iElem < geometry->node[iPoint]->GetnElem(); iElem++) { + Elem = geometry->node[iPoint]->GetElem(iElem); + for (iNode = 0; iNode < geometry->elem[Elem]->GetnNodes(); iNode++) + vneighs.push_back(geometry->elem[Elem]->GetNode(iNode)); + } + vneighs.push_back(iPoint); + + sort(vneighs.begin(), vneighs.end()); + it = unique(vneighs.begin(), vneighs.end()); + vneighs.resize(it - vneighs.begin()); + nNeigh[iPoint] = vneighs.size(); + } + + } + + /*--- Create row_ptr structure, using the number of neighbors ---*/ + + row_ptr = new unsigned long [nPoint+1]; + row_ptr[0] = 0; + for (iPoint = 0; iPoint < nPoint; iPoint++) + row_ptr[iPoint+1] = row_ptr[iPoint] + nNeigh[iPoint]; + nnz = row_ptr[nPoint]; + + /*--- Create col_ind structure ---*/ + + col_ind = new unsigned long [nnz]; + for (iPoint = 0; iPoint < nPoint; iPoint++) { + + vneighs.clear(); + + if (EdgeConnect) { + for (iNeigh = 0; iNeigh < geometry->node[iPoint]->GetnPoint(); iNeigh++) + vneighs.push_back(geometry->node[iPoint]->GetPoint(iNeigh)); + vneighs.push_back(iPoint); + } + else { + for (iElem = 0; iElem < geometry->node[iPoint]->GetnElem(); iElem++) { + Elem = geometry->node[iPoint]->GetElem(iElem); + for (iNode = 0; iNode < geometry->elem[Elem]->GetnNodes(); iNode++) + vneighs.push_back(geometry->elem[Elem]->GetNode(iNode)); + } + vneighs.push_back(iPoint); + } + + sort(vneighs.begin(), vneighs.end()); + it = unique(vneighs.begin(), vneighs.end()); + vneighs.resize( it - vneighs.begin() ); + + index = row_ptr[iPoint]; + for (iNeigh = 0; iNeigh < vneighs.size(); iNeigh++) { + col_ind[index] = vneighs[iNeigh]; + index++; + } + + } + + /*--- Set the indices in the in the sparce matrix structure, and memory allocation ---*/ + + SetIndexes(nPoint, nPointDomain, nVar, nEqn, row_ptr, col_ind, nnz, config); + + /*--- Initialization matrix to zero ---*/ + + SetValZero(); + + delete [] nNeigh; + +} + +void CSysMatrix::SetIndexes(unsigned long val_nPoint, unsigned long val_nPointDomain, unsigned short val_nVar, unsigned short val_nEq, unsigned long* val_row_ptr, unsigned long* val_col_ind, unsigned long val_nnz, CConfig *config) { + + unsigned long iVar; + + nPoint = val_nPoint; // Assign number of points in the mesh + nPointDomain = val_nPointDomain; // Assign number of points in the mesh + nVar = val_nVar; // Assign number of vars in each block system + nEqn = val_nEq; // Assign number of eqns in each block system + nnz = val_nnz; // Assign number of possible non zero blocks + row_ptr = val_row_ptr; + col_ind = val_col_ind; + + matrix = new su2double [nnz*nVar*nEqn]; // Reserve memory for the values of the matrix + block = new su2double [nVar*nEqn]; + block_weight = new su2double [nVar*nEqn]; + block_inverse = new su2double [nVar*nEqn]; + + prod_block_vector = new su2double [nEqn]; + prod_row_vector = new su2double [nVar]; + aux_vector = new su2double [nVar]; + sum_vector = new su2double [nVar]; + + /*--- Memory initialization ---*/ + + for (iVar = 0; iVar < nnz*nVar*nEqn; iVar++) matrix[iVar] = 0.0; + for (iVar = 0; iVar < nVar*nEqn; iVar++) block[iVar] = 0.0; + for (iVar = 0; iVar < nVar*nEqn; iVar++) block_weight[iVar] = 0.0; + for (iVar = 0; iVar < nVar*nEqn; iVar++) block_inverse[iVar] = 0.0; + + for (iVar = 0; iVar < nEqn; iVar++) prod_block_vector[iVar] = 0.0; + for (iVar = 0; iVar < nVar; iVar++) prod_row_vector[iVar] = 0.0; + for (iVar = 0; iVar < nVar; iVar++) aux_vector[iVar] = 0.0; + for (iVar = 0; iVar < nVar; iVar++) sum_vector[iVar] = 0.0; + + + /*--- Set specific preconditioner matrices (ILU) ---*/ + + if ((config->GetKind_Linear_Solver_Prec() == ILU) || + (config->GetKind_Linear_Solver() == SMOOTHER_ILU) || + (config->GetKind_DiscAdj_Linear_Prec() == ILU)) { + + /*--- Reserve memory for the ILU matrix. ---*/ + + ILU_matrix = new su2double [nnz*nVar*nEqn]; + for (iVar = 0; iVar < nnz*nVar*nEqn; iVar++) ILU_matrix[iVar] = 0.0; + } + + /*--- Set specific preconditioner matrices (Jacobi and Linelet) ---*/ + + if ((config->GetKind_Linear_Solver_Prec() == JACOBI) || + (config->GetKind_Linear_Solver_Prec() == LINELET) || + (config->GetKind_Linear_Solver() == SMOOTHER_JACOBI) || + (config->GetKind_Linear_Solver() == SMOOTHER_LINELET) || + (config->GetKind_DiscAdj_Linear_Solver() == JACOBI)) { + + /*--- Reserve memory for the values of the inverse of the preconditioner. ---*/ + + invM = new su2double [nPoint*nVar*nEqn]; + for (iVar = 0; iVar < nPoint*nVar*nEqn; iVar++) invM[iVar] = 0.0; + } + +} + +su2double *CSysMatrix::GetBlock(unsigned long block_i, unsigned long block_j) { + + unsigned long step = 0, index; + + for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { + step++; + if (col_ind[index] == block_j) { return &(matrix[(row_ptr[block_i]+step-1)*nVar*nEqn]); } + } + return NULL; + +} + +su2double CSysMatrix::GetBlock(unsigned long block_i, unsigned long block_j, unsigned short iVar, unsigned short jVar) { + + unsigned long step = 0, index; + + for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { + step++; + if (col_ind[index] == block_j) { return matrix[(row_ptr[block_i]+step-1)*nVar*nEqn+iVar*nEqn+jVar]; } + } + return 0; + +} + +void CSysMatrix::SetBlock(unsigned long block_i, unsigned long block_j, su2double **val_block) { + + unsigned long iVar, jVar, index, step = 0; + + for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { + step++; + if (col_ind[index] == block_j) { + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nEqn; jVar++) + matrix[(row_ptr[block_i]+step-1)*nVar*nEqn+iVar*nEqn+jVar] = SU2_TYPE::GetValue(val_block[iVar][jVar]); + break; + } + } + +} + +void CSysMatrix::SetBlock(unsigned long block_i, unsigned long block_j, su2double *val_block) { + + unsigned long iVar, jVar, index, step = 0; + + for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { + step++; + if (col_ind[index] == block_j) { + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nEqn; jVar++) + matrix[(row_ptr[block_i]+step-1)*nVar*nEqn+iVar*nEqn+jVar] = SU2_TYPE::GetValue(val_block[iVar*nVar+jVar]); + break; + } + } + +} + +void CSysMatrix::AddBlock(unsigned long block_i, unsigned long block_j, su2double **val_block) { + + unsigned long iVar, jVar, index, step = 0; + + for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { + step++; + if (col_ind[index] == block_j) { + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nEqn; jVar++) + matrix[(row_ptr[block_i]+step-1)*nVar*nEqn+iVar*nEqn+jVar] += SU2_TYPE::GetValue(val_block[iVar][jVar]); + break; + } + } + +} + +void CSysMatrix::SubtractBlock(unsigned long block_i, unsigned long block_j, su2double **val_block) { + + unsigned long iVar, jVar, index, step = 0; + + for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { + step++; + if (col_ind[index] == block_j) { + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nEqn; jVar++) + matrix[(row_ptr[block_i]+step-1)*nVar*nEqn+iVar*nEqn+jVar] -= SU2_TYPE::GetValue(val_block[iVar][jVar]); + break; + } + } + +} + +su2double *CSysMatrix::GetBlock_ILUMatrix(unsigned long block_i, unsigned long block_j) { + + unsigned long step = 0, index; + + for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { + step++; + if (col_ind[index] == block_j) { return &(ILU_matrix[(row_ptr[block_i]+step-1)*nVar*nEqn]); } + } + return NULL; + +} + +void CSysMatrix::SetBlock_ILUMatrix(unsigned long block_i, unsigned long block_j, su2double *val_block) { + + unsigned long iVar, jVar, index, step = 0; + + for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { + step++; + if (col_ind[index] == block_j) { + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nEqn; jVar++) + ILU_matrix[(row_ptr[block_i]+step-1)*nVar*nEqn+iVar*nEqn+jVar] = val_block[iVar*nVar+jVar]; + break; + } + } + +} + +void CSysMatrix::SetBlockTransposed_ILUMatrix(unsigned long block_i, unsigned long block_j, su2double *val_block) { + + unsigned long iVar, jVar, index, step = 0; + + for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { + step++; + if (col_ind[index] == block_j) { + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nEqn; jVar++) + ILU_matrix[(row_ptr[block_i]+step-1)*nVar*nEqn+iVar*nEqn+jVar] = val_block[jVar*nVar+iVar]; + break; + } + } + +} + +void CSysMatrix::SubtractBlock_ILUMatrix(unsigned long block_i, unsigned long block_j, su2double *val_block) { + + unsigned long iVar, jVar, index, step = 0; + + for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { + step++; + if (col_ind[index] == block_j) { + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nEqn; jVar++) + ILU_matrix[(row_ptr[block_i]+step-1)*nVar*nEqn+iVar*nEqn+jVar] -= val_block[iVar*nVar+jVar]; + break; + } + } + +} + +void CSysMatrix::MatrixVectorProduct(su2double *matrix, su2double *vector, su2double *product) { + + unsigned short iVar, jVar; + + for (iVar = 0; iVar < nVar; iVar++) { + product[iVar] = 0.0; + for (jVar = 0; jVar < nVar; jVar++) { + product[iVar] += matrix[iVar*nVar+jVar] * vector[jVar]; + } + } + +} + +void CSysMatrix::MatrixMatrixProduct(su2double *matrix_a, su2double *matrix_b, su2double *product) { + + unsigned short iVar, jVar, kVar; + + for (iVar = 0; iVar < nVar; iVar++) { + for (jVar = 0; jVar < nVar; jVar++) { + product[iVar*nVar+jVar] = 0.0; + for (kVar = 0; kVar < nVar; kVar++) { + product[iVar*nVar+jVar] += matrix_a[iVar*nVar+kVar]*matrix_b[kVar*nVar+jVar]; + } + } + } + +} + +void CSysMatrix::AddVal2Diag(unsigned long block_i, su2double val_matrix) { + + unsigned long step = 0, iVar, index; + + for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { + step++; + if (col_ind[index] == block_i) { // Only elements on the diagonal + for (iVar = 0; iVar < nVar; iVar++) + matrix[(row_ptr[block_i]+step-1)*nVar*nVar+iVar*nVar+iVar] += SU2_TYPE::GetValue(val_matrix); + break; + } + } + +} + +void CSysMatrix::SetVal2Diag(unsigned long block_i, su2double val_matrix) { + + unsigned long step = 0, iVar, jVar, index; + + for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { + step++; + if (col_ind[index] == block_i) { // Only elements on the diagonal + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + matrix[(row_ptr[block_i]+step-1)*nVar*nVar+iVar*nVar+jVar] = 0.0; + + for (iVar = 0; iVar < nVar; iVar++) + matrix[(row_ptr[block_i]+step-1)*nVar*nVar+iVar*nVar+iVar] = SU2_TYPE::GetValue(val_matrix); + + break; + } + } + +} + +void CSysMatrix::DeleteValsRowi(unsigned long i) { + + unsigned long block_i = i/nVar; + unsigned long row = i - block_i*nVar; + unsigned long index, iVar; + + for (index = row_ptr[block_i]; index < row_ptr[block_i+1]; index++) { + for (iVar = 0; iVar < nVar; iVar++) + matrix[index*nVar*nVar+row*nVar+iVar] = 0.0; // Delete row values in the block + if (col_ind[index] == block_i) + matrix[index*nVar*nVar+row*nVar+row] = 1.0; // Set 1 to the diagonal element + } + +} + +void CSysMatrix::Gauss_Elimination(unsigned long block_i, su2double* rhs, bool transposed) { + + short iVar, jVar, kVar; // This is important, otherwise some compilers optimizations will fail + su2double weight, aux; + + su2double *Block = GetBlock(block_i, block_i); + + /*--- Copy block matrix, note that the original matrix + is modified by the algorithm---*/ + + if (!transposed){ + for (iVar = 0; iVar < (short)nVar; iVar++) + for (jVar = 0; jVar < (short)nVar; jVar++) + block[iVar*nVar+jVar] = Block[iVar*nVar+jVar]; + } else { + for (iVar = 0; iVar < (short)nVar; iVar++) + for (jVar = 0; jVar < (short)nVar; jVar++) + block[iVar*nVar+jVar] = Block[jVar*nVar+iVar]; + } + /*--- Gauss elimination ---*/ + + if (nVar == 1) { + rhs[0] /= block[0]; + } + else { + + /*--- Transform system in Upper Matrix ---*/ + + for (iVar = 1; iVar < (short)nVar; iVar++) { + for (jVar = 0; jVar < iVar; jVar++) { + weight = block[iVar*nVar+jVar] / block[jVar*nVar+jVar]; + for (kVar = jVar; kVar < (short)nVar; kVar++) + block[iVar*nVar+kVar] -= weight*block[jVar*nVar+kVar]; + rhs[iVar] -= weight*rhs[jVar]; + } + } + + /*--- Backwards substitution ---*/ + + rhs[nVar-1] = rhs[nVar-1] / block[nVar*nVar-1]; + for (iVar = (short)nVar-2; iVar >= 0; iVar--) { + aux = 0.0; + for (jVar = iVar+1; jVar < (short)nVar; jVar++) + aux += block[iVar*nVar+jVar]*rhs[jVar]; + rhs[iVar] = (rhs[iVar]-aux) / block[iVar*nVar+iVar]; + if (iVar == 0) break; + } + } + +} + +void CSysMatrix::Gauss_Elimination_ILUMatrix(unsigned long block_i, su2double* rhs) { + + short iVar, jVar, kVar; // This is important, otherwise some compilers optimizations will fail + su2double weight, aux; + + su2double *Block = GetBlock_ILUMatrix(block_i, block_i); + + /*--- Copy block matrix, note that the original matrix + is modified by the algorithm---*/ + + for (iVar = 0; iVar < (short)nVar; iVar++) + for (jVar = 0; jVar < (short)nVar; jVar++) + block[iVar*nVar+jVar] = Block[iVar*nVar+jVar]; + + /*--- Gauss elimination ---*/ + if (nVar == 1) { + rhs[0] /= block[0]; + } + else { + + /*--- Transform system in Upper Matrix ---*/ + for (iVar = 1; iVar < (short)nVar; iVar++) { + for (jVar = 0; jVar < iVar; jVar++) { + weight = block[iVar*nVar+jVar] / block[jVar*nVar+jVar]; + for (kVar = jVar; kVar < (short)nVar; kVar++) + block[iVar*nVar+kVar] -= weight*block[jVar*nVar+kVar]; + rhs[iVar] -= weight*rhs[jVar]; + } + } + + /*--- Backwards substitution ---*/ + rhs[nVar-1] = rhs[nVar-1] / block[nVar*nVar-1]; + for (iVar = (short)nVar-2; iVar >= 0; iVar--) { + aux = 0.0; + for (jVar = iVar+1; jVar < (short)nVar; jVar++) + aux += block[iVar*nVar+jVar]*rhs[jVar]; + rhs[iVar] = (rhs[iVar]-aux) / block[iVar*nVar+iVar]; + if (iVar == 0) break; + } + } + +} + +void CSysMatrix::Gauss_Elimination(su2double* Block, su2double* rhs) { + + short iVar, jVar, kVar; // This is important, otherwise some compilers optimizations will fail + su2double weight, aux; + + /*--- Copy block matrix, note that the original matrix + is modified by the algorithm---*/ + + for (iVar = 0; iVar < (short)nVar; iVar++) + for (jVar = 0; jVar < (short)nVar; jVar++) + block[iVar*nVar+jVar] = Block[iVar*nVar+jVar]; + + + if (nVar == 1) { + rhs[0] /= block[0]; + } + else { + /*--- Transform system in Upper Matrix ---*/ + for (iVar = 1; iVar < (short)nVar; iVar++) { + for (jVar = 0; jVar < iVar; jVar++) { + weight = block[iVar*nVar+jVar] / block[jVar*nVar+jVar]; + for (kVar = jVar; kVar < (short)nVar; kVar++) + block[iVar*nVar+kVar] -= weight*block[jVar*nVar+kVar]; + rhs[iVar] -= weight*rhs[jVar]; + } + } + + /*--- Backwards substitution ---*/ + rhs[nVar-1] = rhs[nVar-1] / block[nVar*nVar-1]; + for (iVar = (short)nVar-2; iVar >= 0; iVar--) { + aux = 0.0; + for (jVar = iVar+1; jVar < (short)nVar; jVar++) + aux += block[iVar*nVar+jVar]*rhs[jVar]; + rhs[iVar] = (rhs[iVar]-aux) / block[iVar*nVar+iVar]; + if (iVar == 0) break; + } + } + +} + +void CSysMatrix::ProdBlockVector(unsigned long block_i, unsigned long block_j, const CSysVector & vec) { + + unsigned long j = block_j*nVar; + unsigned short iVar, jVar; + + su2double *block = GetBlock(block_i, block_j); + + for (iVar = 0; iVar < nVar; iVar++) { + prod_block_vector[iVar] = 0; + for (jVar = 0; jVar < nVar; jVar++) + prod_block_vector[iVar] += block[iVar*nVar+jVar]*vec[j+jVar]; + } + +} + +void CSysMatrix::UpperProduct(CSysVector & vec, unsigned long row_i) { + + unsigned long iVar, index; + + for (iVar = 0; iVar < nVar; iVar++) + prod_row_vector[iVar] = 0; + + for (index = row_ptr[row_i]; index < row_ptr[row_i+1]; index++) { + if (col_ind[index] > row_i) { + ProdBlockVector(row_i, col_ind[index], vec); + for (iVar = 0; iVar < nVar; iVar++) + prod_row_vector[iVar] += prod_block_vector[iVar]; + } + } + +} + +void CSysMatrix::LowerProduct(CSysVector & vec, unsigned long row_i) { + + unsigned long iVar, index; + + for (iVar = 0; iVar < nVar; iVar++) + prod_row_vector[iVar] = 0; + + for (index = row_ptr[row_i]; index < row_ptr[row_i+1]; index++) { + if (col_ind[index] < row_i) { + ProdBlockVector(row_i, col_ind[index], vec); + for (iVar = 0; iVar < nVar; iVar++) + prod_row_vector[iVar] += prod_block_vector[iVar]; + } + } + +} + +void CSysMatrix::DiagonalProduct(CSysVector & vec, unsigned long row_i) { + + unsigned long iVar, index; + + for (iVar = 0; iVar < nVar; iVar++) + prod_row_vector[iVar] = 0; + + for (index = row_ptr[row_i]; index < row_ptr[row_i+1]; index++) { + if (col_ind[index] == row_i) { + ProdBlockVector(row_i, col_ind[index], vec); + for (iVar = 0; iVar < nVar; iVar++) + prod_row_vector[iVar] += prod_block_vector[iVar]; + } + } + +} + +void CSysMatrix::SendReceive_Solution(CSysVector & x, CGeometry *geometry, CConfig *config) { + + unsigned short iVar, iMarker, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double *Buffer_Receive = NULL, *Buffer_Send = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; + +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + + /*--- Allocate Receive and send buffers ---*/ + + Buffer_Receive = new su2double [nBufferR_Vector]; + Buffer_Send = new su2double[nBufferS_Vector]; + + /*--- Copy the solution that should be sended ---*/ + + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send[iVertex*nVar+iVar] = x[iPoint*nVar+iVar]; + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + + SU2_MPI::Sendrecv(Buffer_Send, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); + +#else + + /*--- Receive information without MPI ---*/ + + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive[iVar*nVertexR+iVertex] = Buffer_Send[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + + delete [] Buffer_Send; + + /*--- Do the coordinate transformation ---*/ + + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + + /*--- Copy transformed conserved variables back into buffer. ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + x[iPoint*nVar+iVar] = Buffer_Receive[iVertex*nVar+iVar]; + + } + + /*--- Deallocate receive buffer ---*/ + + delete [] Buffer_Receive; + + } + + } + +} + +void CSysMatrix::SendReceive_SolutionTransposed(CSysVector & x, CGeometry *geometry, CConfig *config) { + + unsigned short iVar, iMarker, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double *Buffer_Receive = NULL, *Buffer_Send = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker + 1; MarkerR = iMarker; + +#ifdef HAVE_MPI + + receive_from = config->GetMarker_All_SendRecv(MarkerR)-1; + send_to = abs(config->GetMarker_All_SendRecv(MarkerS))-1; + +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + + /*--- Allocate Receive and send buffers ---*/ + + Buffer_Receive = new su2double [nBufferR_Vector]; + Buffer_Send = new su2double[nBufferS_Vector]; + + /*--- Copy the solution that should be sended ---*/ + + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send[iVertex*nVar+iVar] = x[iPoint*nVar+iVar]; + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + + SU2_MPI::Sendrecv(Buffer_Send, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); + +#else + + /*--- Receive information without MPI ---*/ + + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive[iVar*nVertexR+iVertex] = Buffer_Send[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + + delete [] Buffer_Send; + + /*--- Do the coordinate transformation ---*/ + + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + + /*--- Copy transformed conserved variables back into buffer. ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + x[iPoint*nVar+iVar] += Buffer_Receive[iVertex*nVar+iVar]; + + } + + /*--- Deallocate receive buffer ---*/ + + delete [] Buffer_Receive; + + } + + } + +} + +void CSysMatrix::RowProduct(const CSysVector & vec, unsigned long row_i) { + + unsigned long iVar, index; + + for (iVar = 0; iVar < nVar; iVar++) + prod_row_vector[iVar] = 0; + + for (index = row_ptr[row_i]; index < row_ptr[row_i+1]; index++) { + ProdBlockVector(row_i, col_ind[index], vec); + for (iVar = 0; iVar < nVar; iVar++) + prod_row_vector[iVar] += prod_block_vector[iVar]; + } + +} + +void CSysMatrix::MatrixVectorProduct(const CSysVector & vec, CSysVector & prod) { + + unsigned long iPoint, iVar; + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + RowProduct(vec, iPoint); + for (iVar = 0; iVar < nVar; iVar++) + prod[iPoint*nVar+iVar] = prod_row_vector[iVar]; + } + +} + +void CSysMatrix::MatrixVectorProduct(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config) { + + unsigned long prod_begin, vec_begin, mat_begin, index, iVar, jVar, row_i; + + /*--- Some checks for consistency between CSysMatrix and the CSysVectors ---*/ + if ( (nVar != vec.GetNVar()) || (nVar != prod.GetNVar()) ) { + cerr << "CSysMatrix::MatrixVectorProduct(const CSysVector&, CSysVector): " + << "nVar values incompatible." << endl; + throw(-1); + } + if ( (nPoint != vec.GetNBlk()) || (nPoint != prod.GetNBlk()) ) { + cerr << "CSysMatrix::MatrixVectorProduct(const CSysVector&, CSysVector): " + << "nPoint and nBlk values incompatible." << endl; + throw(-1); + } + + prod = su2double(0.0); // set all entries of prod to zero + for (row_i = 0; row_i < nPointDomain; row_i++) { + prod_begin = row_i*nVar; // offset to beginning of block row_i + for (index = row_ptr[row_i]; index < row_ptr[row_i+1]; index++) { + vec_begin = col_ind[index]*nVar; // offset to beginning of block col_ind[index] + mat_begin = (index*nVar*nVar); // offset to beginning of matrix block[row_i][col_ind[indx]] + for (iVar = 0; iVar < nVar; iVar++) { + for (jVar = 0; jVar < nVar; jVar++) { + prod[(unsigned long)(prod_begin+iVar)] += matrix[(unsigned long)(mat_begin+iVar*nVar+jVar)]*vec[(unsigned long)(vec_begin+jVar)]; + } + } + } + } + + /*--- MPI Parallelization ---*/ + SendReceive_Solution(prod, geometry, config); + +} + +void CSysMatrix::MatrixVectorProductTransposed(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config) { + + unsigned long prod_begin, vec_begin, mat_begin, index, iVar, jVar , row_i; + + /*--- Some checks for consistency between CSysMatrix and the CSysVectors ---*/ + if ( (nVar != vec.GetNVar()) || (nVar != prod.GetNVar()) ) { + cerr << "CSysMatrix::MatrixVectorProductTransposed(const CSysVector&, CSysVector): " + << "nVar values incompatible." << endl; + throw(-1); + } + if ( (nPoint != vec.GetNBlk()) || (nPoint != prod.GetNBlk()) ) { + cerr << "CSysMatrix::MatrixVectorProductTransposed(const CSysVector&, CSysVector): " + << "nPoint and nBlk values incompatible." << endl; + throw(-1); + } + + prod = su2double(0.0); // set all entries of prod to zero + for (row_i = 0; row_i < nPointDomain; row_i++) { + vec_begin = row_i*nVar; // offset to beginning of block col_ind[index] + for (index = row_ptr[row_i]; index < row_ptr[row_i+1]; index++) { + prod_begin = col_ind[index]*nVar; // offset to beginning of block row_i + mat_begin = (index*nVar*nVar); // offset to beginning of matrix block[row_i][col_ind[indx]] + for (iVar = 0; iVar < nVar; iVar++) { + for (jVar = 0; jVar < nVar; jVar++) { + prod[(unsigned long)(prod_begin+jVar)] += matrix[(unsigned long)(mat_begin+iVar*nVar+jVar)]*vec[(unsigned long)(vec_begin+iVar)]; + } + } + } + } + + /*--- MPI Parallelization ---*/ + SendReceive_SolutionTransposed(prod, geometry, config); + +} + +void CSysMatrix::GetMultBlockBlock(su2double *c, su2double *a, su2double *b) { + + unsigned long iVar, jVar, kVar; + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) { + c[iVar*nVar+jVar] = 0.0; + for (kVar = 0; kVar < nVar; kVar++) + c[iVar*nVar+jVar] += a[iVar*nVar+kVar] * b[kVar*nVar+jVar]; + } + +} + +void CSysMatrix::GetMultBlockVector(su2double *c, su2double *a, su2double *b) { + + unsigned long iVar, jVar; + + for (iVar = 0; iVar < nVar; iVar++) { + c[iVar] = 0.0; + for (jVar = 0; jVar < nVar; jVar++) + c[iVar] += a[iVar*nVar+jVar] * b[jVar]; + } + +} + +void CSysMatrix::GetSubsBlock(su2double *c, su2double *a, su2double *b) { + + unsigned long iVar, jVar; + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + c[iVar*nVar+jVar] = a[iVar*nVar+jVar] - b[iVar*nVar+jVar]; + +} + +void CSysMatrix::GetSubsVector(su2double *c, su2double *a, su2double *b) { + + unsigned long iVar; + + for (iVar = 0; iVar < nVar; iVar++) + c[iVar] = a[iVar] - b[iVar]; + +} + +void CSysMatrix::InverseBlock(su2double *Block, su2double *invBlock) { + + unsigned long iVar, jVar; + + for (iVar = 0; iVar < nVar; iVar++) { + for (jVar = 0; jVar < nVar; jVar++) + aux_vector[jVar] = 0.0; + aux_vector[iVar] = 1.0; + + /*--- Compute the i-th column of the inverse matrix ---*/ + Gauss_Elimination(Block, aux_vector); + + for (jVar = 0; jVar < nVar; jVar++) + invBlock[jVar*nVar+iVar] = aux_vector[jVar]; + } + +} + +void CSysMatrix::InverseDiagonalBlock(unsigned long block_i, su2double *invBlock, bool transpose) { + + unsigned long iVar, jVar; + + for (iVar = 0; iVar < nVar; iVar++) { + for (jVar = 0; jVar < nVar; jVar++) + aux_vector[jVar] = 0.0; + aux_vector[iVar] = 1.0; + + /*--- Compute the i-th column of the inverse matrix ---*/ + + Gauss_Elimination(block_i, aux_vector, transpose); + for (jVar = 0; jVar < nVar; jVar++) + invBlock[jVar*nVar+iVar] = aux_vector[jVar]; + } + +} + + +void CSysMatrix::InverseDiagonalBlock_ILUMatrix(unsigned long block_i, su2double *invBlock) { + + unsigned long iVar, jVar; + + for (iVar = 0; iVar < nVar; iVar++) { + for (jVar = 0; jVar < nVar; jVar++) + aux_vector[jVar] = 0.0; + aux_vector[iVar] = 1.0; + + /*--- Compute the i-th column of the inverse matrix ---*/ + + Gauss_Elimination_ILUMatrix(block_i, aux_vector); + for (jVar = 0; jVar < nVar; jVar++) + invBlock[jVar*nVar+iVar] = aux_vector[jVar]; + } + +} + +void CSysMatrix::BuildJacobiPreconditioner(bool transpose) { + + unsigned long iPoint, iVar, jVar; + + /*--- Compute Jacobi Preconditioner ---*/ + for (iPoint = 0; iPoint < nPoint; iPoint++) { + + /*--- Compute the inverse of the diagonal block ---*/ + InverseDiagonalBlock(iPoint, block_inverse, transpose); + + /*--- Set the inverse of the matrix to the invM structure (which is a vector) ---*/ + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + invM[iPoint*nVar*nVar+iVar*nVar+jVar] = block_inverse[iVar*nVar+jVar]; + } + +} + + +void CSysMatrix::ComputeJacobiPreconditioner(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config) { + + unsigned long iPoint, iVar, jVar; + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + prod[(unsigned long)(iPoint*nVar+iVar)] = 0.0; + for (jVar = 0; jVar < nVar; jVar++) + prod[(unsigned long)(iPoint*nVar+iVar)] += + invM[(unsigned long)(iPoint*nVar*nVar+iVar*nVar+jVar)]*vec[(unsigned long)(iPoint*nVar+jVar)]; + } + } + + /*--- MPI Parallelization ---*/ + + SendReceive_Solution(prod, geometry, config); + +} + +unsigned long CSysMatrix::Jacobi_Smoother(const CSysVector & b, CSysVector & x, CMatrixVectorProduct & mat_vec, su2double tol, unsigned long m, su2double *residual, bool monitoring, CGeometry *geometry, CConfig *config) { + + unsigned long iPoint, iVar, jVar; + int rank = MASTER_NODE; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Check the number of iterations requested ---*/ + + if (m < 1) { + if (rank == MASTER_NODE) cerr << "CSysMatrix::Jacobi_Smoother(): illegal value for smoothing iterations, m = " << m << endl; +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + } + + /*--- Create vectors to hold the residual and the Matrix-Vector product + of the Jacobian matrix with the current solution (x^k). These must be + stored in order to perform multiple iterations of the smoother. ---*/ + + CSysVector r(b); + CSysVector A_x(b); + + /*--- Calculate the initial residual, compute norm, and check + if system is already solved. Recall, r holds b initially. ---*/ + + mat_vec(x, A_x); + r -= A_x; + su2double norm_r = r.norm(); + su2double norm0 = b.norm(); + if ( (norm_r < tol*norm0) || (norm_r < eps) ) { + if (rank == MASTER_NODE) cout << "CSysMatrix::Jacobi_Smoother(): system solved by initial guess." << endl; + return 0; + } + + /*--- Set the norm to the initial initial residual value ---*/ + + norm0 = norm_r; + + /*--- Output header information including initial residual ---*/ + + int i = 0; + if ((monitoring) && (rank == MASTER_NODE)) { + cout << "\n# " << "Jacobi Smoother" << " residual history" << endl; + cout << "# Residual tolerance target = " << tol << endl; + cout << "# Initial residual norm = " << norm_r << endl; + cout << " " << i << " " << norm_r/norm0 << endl; + } + + /*--- Loop over all smoothing iterations ---*/ + + for (i = 0; i < (int)m; i++) { + + /*--- Apply the Jacobi smoother, i.e., multiply by the inverse of the + diagonal matrix of A, which was built in the preprocessing phase. Note + that we are directly updating the solution (x^k+1) during the loop. ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + for (jVar = 0; jVar < nVar; jVar++) + x[(unsigned long)(iPoint*nVar+iVar)] += + invM[(unsigned long)(iPoint*nVar*nVar+iVar*nVar+jVar)]*r[(unsigned long)(iPoint*nVar+jVar)]; + } + } + + /*--- MPI Parallelization ---*/ + + SendReceive_Solution(x, geometry, config); + + /*--- Update the residual (r^k+1 = b - A*x^k+1) with the new solution ---*/ + + r = b; + mat_vec(x, A_x); + r -= A_x; + + /*--- Check if solution has converged, else output the relative + residual if necessary. ---*/ + + norm_r = r.norm(); + if (norm_r < tol*norm0) break; + if (((monitoring) && (rank == MASTER_NODE)) && ((i+1) % 5 == 0)) + cout << " " << i << " " << norm_r/norm0 << endl; + + } + + if ((monitoring) && (rank == MASTER_NODE)) { + cout << "# Jacobi smoother final (true) residual:" << endl; + cout << "# Iteration = " << i << ": |res|/|res0| = " << norm_r/norm0 << ".\n" << endl; + } + + return i; + +} + +void CSysMatrix::BuildILUPreconditioner(bool transposed) { + + unsigned long index, index_; + su2double *Block_ij, *Block_jk; + long iPoint, jPoint, kPoint; + + /*--- Copy block matrix, note that the original matrix + is modified by the algorithm, so that we have the factorization stored + in the ILUMatrix at the end of this preprocessing. ---*/ + + for (iPoint = 0; iPoint < (long)nPointDomain; iPoint++) { + for (index = row_ptr[iPoint]; index < row_ptr[iPoint+1]; index++) { + jPoint = col_ind[index]; + if (transposed){ + Block_ij = GetBlock(jPoint, iPoint); + SetBlockTransposed_ILUMatrix(iPoint, jPoint, Block_ij); + } else { + Block_ij = GetBlock(iPoint, jPoint); + SetBlock_ILUMatrix(iPoint, jPoint, Block_ij); + } + } + } + + /*--- Transform system in Upper Matrix ---*/ + + for (iPoint = 1; iPoint < (long)nPointDomain; iPoint++) { + + /*--- For each row (unknown), loop over all entries in A on this row + row_ptr[iPoint+1] will have the index for the first entry on the next + row. ---*/ + + for (index = row_ptr[iPoint]; index < row_ptr[iPoint+1]; index++) { + + /*--- jPoint here is the column for each entry on this row ---*/ + + jPoint = col_ind[index]; + + /*--- Check that this column is in the lower triangular portion ---*/ + + if ((jPoint < iPoint) && (jPoint < (long)nPointDomain)) { + + /*--- If we're in the lower triangle, get the pointer to this block, + invert it, and then right multiply against the original block ---*/ + + Block_ij = GetBlock_ILUMatrix(iPoint, jPoint); + InverseDiagonalBlock_ILUMatrix(jPoint, block_inverse); + MatrixMatrixProduct(Block_ij, block_inverse, block_weight); + + /*--- block_weight holds Aij*inv(Ajj). Jump to the row for jPoint ---*/ + + for (index_ = row_ptr[jPoint]; index_ < row_ptr[jPoint+1]; index_++) { + + /*--- Get the column of the entry ---*/ + + kPoint = col_ind[index_]; + + /*--- If the column is greater than or equal to jPoint, i.e., the + upper triangular part, then multiply and modify the matrix. + Here, Aik' = Aik - Aij*inv(Ajj)*Ajk. ---*/ + + if (kPoint < (long)nPointDomain) { + Block_jk = GetBlock_ILUMatrix(jPoint, kPoint); + if (kPoint >= jPoint) { + + // WARNING: here we have a left multiply by Block_jk, should it + // be a right multiply to give Aik' = Aik - Aij*inv(Ajj)*Ajk? + + MatrixMatrixProduct(Block_jk, block_weight, block); + SubtractBlock_ILUMatrix(iPoint, kPoint, block); + + } + } + } + + /*--- Lastly, store block_weight in the lower triangular part, which + will be reused during the forward solve in the precon/smoother. ---*/ + + SetBlock_ILUMatrix(iPoint, jPoint, block_weight); + + } + } + } + +} + +void CSysMatrix::ComputeILUPreconditioner(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config) { + + unsigned long index; + su2double *Block_ij; + long iPoint, jPoint; + unsigned short iVar; + + /*--- Copy block matrix, note that the original matrix + is modified by the algorithm---*/ + + for (iPoint = 0; iPoint < (long)nPointDomain; iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + prod[iPoint*nVar+iVar] = vec[iPoint*nVar+iVar]; + } + } + + /*--- Transform system in Upper Matrix ---*/ + + for (iPoint = 1; iPoint < (long)nPointDomain; iPoint++) { + for (index = row_ptr[iPoint]; index < row_ptr[iPoint+1]; index++) { + jPoint = col_ind[index]; + if ((jPoint < iPoint) && (jPoint < (long)nPointDomain)) { + Block_ij = GetBlock_ILUMatrix(iPoint, jPoint); + MatrixVectorProduct(Block_ij, &prod[jPoint*nVar], aux_vector); + for (iVar = 0; iVar < nVar; iVar++) + prod[iPoint*nVar+iVar] -= aux_vector[iVar]; + + } + } + } + + /*--- Backwards substitution ---*/ + + InverseDiagonalBlock_ILUMatrix((nPointDomain-1), block_inverse); + MatrixVectorProduct(block_inverse, &prod[(nPointDomain-1)*nVar], aux_vector); + + for (iVar = 0; iVar < nVar; iVar++) + prod[ (nPointDomain-1)*nVar + iVar] = aux_vector[iVar]; + + for (iPoint = nPointDomain-2; iPoint >= 0; iPoint--) { + for (iVar = 0; iVar < nVar; iVar++) sum_vector[iVar] = 0.0; + for (index = row_ptr[iPoint]; index < row_ptr[iPoint+1]; index++) { + jPoint = col_ind[index]; + if (jPoint < (long)nPointDomain) { + Block_ij = GetBlock_ILUMatrix(iPoint, jPoint); + if ((jPoint >= iPoint+1) && (jPoint < (long)nPointDomain)) { + MatrixVectorProduct(Block_ij, &prod[jPoint*nVar], aux_vector); + for (iVar = 0; iVar < nVar; iVar++) sum_vector[iVar] += aux_vector[iVar]; + } + } + } + for (iVar = 0; iVar < nVar; iVar++) prod[iPoint*nVar+iVar] = (prod[iPoint*nVar+iVar]-sum_vector[iVar]); + InverseDiagonalBlock_ILUMatrix(iPoint, block_inverse); + MatrixVectorProduct(block_inverse, &prod[iPoint*nVar], aux_vector); + for (iVar = 0; iVar < nVar; iVar++) prod[iPoint*nVar+iVar] = aux_vector[iVar]; + if (iPoint == 0) break; + } + + /*--- MPI Parallelization ---*/ + + SendReceive_Solution(prod, geometry, config); + +} + +unsigned long CSysMatrix::ILU0_Smoother(const CSysVector & b, CSysVector & x, CMatrixVectorProduct & mat_vec, su2double tol, unsigned long m, su2double *residual, bool monitoring, CGeometry *geometry, CConfig *config) { + + unsigned long index; + su2double *Block_ij, omega = 1.0; + long iPoint, jPoint; + unsigned short iVar; + int rank = MASTER_NODE; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Check the number of iterations requested ---*/ + + if (m < 1) { + if (rank == MASTER_NODE) cerr << "CSysMatrix::ILU0_Smoother(): illegal value for smoothing iterations, m = " << m << endl; +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + } + + /*--- Create vectors to hold the residual and the Matrix-Vector product + of the Jacobian matrix with the current solution (x^k). These must be + stored in order to perform multiple iterations of the smoother. ---*/ + + CSysVector r(b); + CSysVector A_x(b); + + /*--- Calculate the initial residual, compute norm, and check + if system is already solved. Recall, r holds b initially. ---*/ + + mat_vec(x, A_x); + r -= A_x; + su2double norm_r = r.norm(); + su2double norm0 = b.norm(); + if ( (norm_r < tol*norm0) || (norm_r < eps) ) { + if (rank == MASTER_NODE) cout << "CSysMatrix::ILU0_Smoother(): system solved by initial guess." << endl; + return 0; + } + + /*--- Set the norm to the initial initial residual value ---*/ + + norm0 = norm_r; + + /*--- Output header information including initial residual ---*/ + + int i = 0; + if ((monitoring) && (rank == MASTER_NODE)) { + cout << "\n# " << "ILU0 Smoother" << " residual history" << endl; + cout << "# Residual tolerance target = " << tol << endl; + cout << "# Initial residual norm = " << norm_r << endl; + cout << " " << i << " " << norm_r/norm0 << endl; + } + + /*--- Loop over all smoothing iterations ---*/ + + for (i = 0; i < (int)m; i++) { + + /*--- Forward solve the system using the lower matrix entries that + were computed and stored during the ILU0 preprocessing. Note + that we are overwriting the residual vector as we go. ---*/ + + for (iPoint = 1; iPoint < (long)nPointDomain; iPoint++) { + + /*--- For each row (unknown), loop over all entries in A on this row + row_ptr[iPoint+1] will have the index for the first entry on the next + row. ---*/ + + for (index = row_ptr[iPoint]; index < row_ptr[iPoint+1]; index++) { + + /*--- jPoint here is the column for each entry on this row ---*/ + + jPoint = col_ind[index]; + + /*--- Check that this column is in the lower triangular portion ---*/ + + if ((jPoint < iPoint) && (jPoint < (long)nPointDomain)) { + + /*--- Lastly, get Aij*inv(Ajj) from the lower triangular part, which + was calculated in the preprocessing, and apply to r. ---*/ + + Block_ij = GetBlock_ILUMatrix(iPoint, jPoint); + MatrixVectorProduct(Block_ij, &r[jPoint*nVar], aux_vector); + for (iVar = 0; iVar < nVar; iVar++) + r[iPoint*nVar+iVar] -= aux_vector[iVar]; + + } + } + } + + /*--- Backwards substitution (starts at the last row) ---*/ + + InverseDiagonalBlock_ILUMatrix((nPointDomain-1), block_inverse); + MatrixVectorProduct(block_inverse, &r[(nPointDomain-1)*nVar], aux_vector); + + for (iVar = 0; iVar < nVar; iVar++) + r[(nPointDomain-1)*nVar + iVar] = aux_vector[iVar]; + + for (iPoint = nPointDomain-2; iPoint >= 0; iPoint--) { + for (iVar = 0; iVar < nVar; iVar++) sum_vector[iVar] = 0.0; + for (index = row_ptr[iPoint]; index < row_ptr[iPoint+1]; index++) { + jPoint = col_ind[index]; + if (jPoint < (long)nPointDomain) { + Block_ij = GetBlock_ILUMatrix(iPoint, jPoint); + if ((jPoint >= iPoint+1) && (jPoint < (long)nPointDomain)) { + MatrixVectorProduct(Block_ij, &r[jPoint*nVar], aux_vector); + for (iVar = 0; iVar < nVar; iVar++) sum_vector[iVar] += aux_vector[iVar]; + } + } + } + for (iVar = 0; iVar < nVar; iVar++) r[iPoint*nVar+iVar] = (r[iPoint*nVar+iVar]-sum_vector[iVar]); + InverseDiagonalBlock_ILUMatrix(iPoint, block_inverse); + MatrixVectorProduct(block_inverse, &r[iPoint*nVar], aux_vector); + for (iVar = 0; iVar < nVar; iVar++) r[iPoint*nVar+iVar] = aux_vector[iVar]; + if (iPoint == 0) break; + } + + /*--- Update solution (x^k+1 = x^k + w*M^-1*r^k) using the residual vector, + which holds the update after applying the ILU0 smoother, i.e., M^-1*r^k. + Omega is a relaxation factor that we have currently set to 1.0. ---*/ + + x.Plus_AX(omega, r); + + /*--- MPI Parallelization ---*/ + + SendReceive_Solution(x, geometry, config); + + /*--- Update the residual (r^k+1 = b - A*x^k+1) with the new solution ---*/ + + r = b; + mat_vec(x, A_x); + r -= A_x; + + /*--- Check if solution has converged, else output the relative + residual if necessary. ---*/ + + norm_r = r.norm(); + if (norm_r < tol*norm0) break; + if (((monitoring) && (rank == MASTER_NODE)) && ((i+1) % 5 == 0)) + cout << " " << i << " " << norm_r/norm0 << endl; + + } + + if ((monitoring) && (rank == MASTER_NODE)) { + cout << "# ILU0 smoother final (true) residual:" << endl; + cout << "# Iteration = " << i << ": |res|/|res0| = " << norm_r/norm0 << ".\n" << endl; + } + + return i; + +} + +void CSysMatrix::ComputeLU_SGSPreconditioner(const CSysVector & vec, CSysVector & prod, CGeometry *geometry, CConfig *config) { + unsigned long iPoint, iVar; + + /*--- First part of the symmetric iteration: (D+L).x* = b ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + LowerProduct(prod, iPoint); // Compute L.x* + for (iVar = 0; iVar < nVar; iVar++) + aux_vector[iVar] = vec[iPoint*nVar+iVar] - prod_row_vector[iVar]; // Compute aux_vector = b - L.x* + Gauss_Elimination(iPoint, aux_vector); // Solve D.x* = aux_vector + for (iVar = 0; iVar < nVar; iVar++) + prod[iPoint*nVar+iVar] = aux_vector[iVar]; // Assesing x* = solution + } + + /*--- MPI Parallelization ---*/ + + SendReceive_Solution(prod, geometry, config); + + /*--- Second part of the symmetric iteration: (D+U).x_(1) = D.x* ---*/ + + for (iPoint = nPointDomain-1; (int)iPoint >= 0; iPoint--) { + DiagonalProduct(prod, iPoint); // Compute D.x* + for (iVar = 0; iVar < nVar; iVar++) + aux_vector[iVar] = prod_row_vector[iVar]; // Compute aux_vector = D.x* + UpperProduct(prod, iPoint); // Compute U.x_(n+1) + for (iVar = 0; iVar < nVar; iVar++) + aux_vector[iVar] -= prod_row_vector[iVar]; // Compute aux_vector = D.x*-U.x_(n+1) + Gauss_Elimination(iPoint, aux_vector); // Solve D.x* = aux_vector + for (iVar = 0; iVar < nVar; iVar++) + prod[iPoint*nVar + iVar] = aux_vector[iVar]; // Assesing x_(1) = solution + } + + /*--- MPI Parallelization ---*/ + + SendReceive_Solution(prod, geometry, config); + +} + +unsigned long CSysMatrix::LU_SGS_Smoother(const CSysVector & b, CSysVector & x, CMatrixVectorProduct & mat_vec, su2double tol, unsigned long m, su2double *residual, bool monitoring, CGeometry *geometry, CConfig *config) { + + unsigned long iPoint, iVar; + su2double omega = 1.0; + int rank = MASTER_NODE; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Check the number of iterations requested ---*/ + + if (m < 1) { + if (rank == MASTER_NODE) cerr << "CSysMatrix::LU_SGS_Smoother(): illegal value for smoothing iterations, m = " << m << endl; +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + } + + /*--- Create vectors to hold the residual and the Matrix-Vector product + of the Jacobian matrix with the current solution (x^k). These must be + stored in order to perform multiple iterations of the smoother. ---*/ + + CSysVector r(b); + CSysVector A_x(b); + CSysVector xStar(x); + + /*--- Calculate the initial residual, compute norm, and check + if system is already solved. Recall, r holds b initially. ---*/ + + mat_vec(x, A_x); + r -= A_x; + su2double norm_r = r.norm(); + su2double norm0 = b.norm(); + if ( (norm_r < tol*norm0) || (norm_r < eps) ) { + if (rank == MASTER_NODE) cout << "CSysMatrix::LU_SGS_Smoother(): system solved by initial guess." << endl; + return 0; + } + + /*--- Set the norm to the initial initial residual value ---*/ + + norm0 = norm_r; + + /*--- Output header information including initial residual ---*/ + + int i = 0; + if ((monitoring) && (rank == MASTER_NODE)) { + cout << "\n# " << "LU_SGS Smoother" << " residual history" << endl; + cout << "# Residual tolerance target = " << tol << endl; + cout << "# Initial residual norm = " << norm_r << endl; + cout << " " << i << " " << norm_r/norm0 << endl; + } + + /*--- Loop over all smoothing iterations ---*/ + + for (i = 0; i < (int)m; i++) { + + /*--- First part of the symmetric iteration: (D+L).x* = b ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + LowerProduct(xStar, iPoint); // Compute L.x* + for (iVar = 0; iVar < nVar; iVar++) + aux_vector[iVar] = r[iPoint*nVar+iVar] - prod_row_vector[iVar]; // Compute aux_vector = b - L.x* + Gauss_Elimination(iPoint, aux_vector); // Solve D.x* = aux_vector + for (iVar = 0; iVar < nVar; iVar++) + xStar[iPoint*nVar+iVar] = aux_vector[iVar]; // Assesing x* = solution, stored in r + } + + /*--- MPI Parallelization ---*/ + + SendReceive_Solution(xStar, geometry, config); + + /*--- Second part of the symmetric iteration: (D+U).x_(1) = D.x* ---*/ + + for (iPoint = nPointDomain-1; (int)iPoint >= 0; iPoint--) { + DiagonalProduct(xStar, iPoint); // Compute D.x* + for (iVar = 0; iVar < nVar; iVar++) + aux_vector[iVar] = prod_row_vector[iVar]; // Compute aux_vector = D.x* + UpperProduct(xStar, iPoint); // Compute U.x_(n+1) + for (iVar = 0; iVar < nVar; iVar++) + aux_vector[iVar] -= prod_row_vector[iVar]; // Compute aux_vector = D.x*-U.x_(n+1) + Gauss_Elimination(iPoint, aux_vector); // Solve D.x* = aux_vector + for (iVar = 0; iVar < nVar; iVar++) + xStar[iPoint*nVar+iVar] = aux_vector[iVar]; // Assesing x_(1) = solution + } + + /*--- Update solution (x^k+1 = x^k + w*M^-1*r^k) using the xStar vector, + which holds the update after applying the LU_SGS smoother, i.e., M^-1*r^k. + Omega is a relaxation factor that we have currently set to 1.0. ---*/ + + x.Plus_AX(omega, xStar); + + /*--- MPI Parallelization ---*/ + + SendReceive_Solution(x, geometry, config); + + /*--- Update the residual (r^k+1 = b - A*x^k+1) with the new solution ---*/ + + r = b; + mat_vec(x, A_x); + r -= A_x; + xStar = x; + + /*--- Check if solution has converged, else output the relative + residual if necessary. ---*/ + + norm_r = r.norm(); + if (norm_r < tol*norm0) break; + if (((monitoring) && (rank == MASTER_NODE)) && ((i+1) % 5 == 0)) + cout << " " << i << " " << norm_r/norm0 << endl; + + } + + if ((monitoring) && (rank == MASTER_NODE)) { + cout << "# LU_SGS smoother final (true) residual:" << endl; + cout << "# Iteration = " << i << ": |res|/|res0| = " << norm_r/norm0 << ".\n" << endl; + } + + return i; + +} + +unsigned short CSysMatrix::BuildLineletPreconditioner(CGeometry *geometry, CConfig *config) { + + bool *check_Point, add_point; + unsigned long iEdge, iPoint, jPoint, index_Point, iLinelet, iVertex, next_Point, counter, iElem; + unsigned short iMarker, iNode, ExtraLines = 100, MeanPoints; + su2double alpha = 0.9, weight, max_weight, *normal, area, volume_iPoint, volume_jPoint; + unsigned long Local_nPoints, Local_nLineLets, Global_nPoints, Global_nLineLets; + + /*--- Memory allocation --*/ + + check_Point = new bool [geometry->GetnPoint()]; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + check_Point[iPoint] = true; + + LineletBool = new bool[geometry->GetnPoint()]; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) + LineletBool[iPoint] = false; + + nLinelet = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX ) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL ) || + (config->GetMarker_All_KindBC(iMarker) == EULER_WALL ) || + (config->GetMarker_All_KindBC(iMarker) == DISPLACEMENT_BOUNDARY)) { + nLinelet += geometry->nVertex[iMarker]; + } + } + + /*--- If the domain contains well defined Linelets ---*/ + + if (nLinelet != 0) { + + /*--- Basic initial allocation ---*/ + + LineletPoint = new vector[nLinelet + ExtraLines]; + + /*--- Define the basic linelets, starting from each vertex ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX ) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL ) || + (config->GetMarker_All_KindBC(iMarker) == EULER_WALL ) || + (config->GetMarker_All_KindBC(iMarker) == DISPLACEMENT_BOUNDARY)) { + iLinelet = 0; + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + LineletPoint[iLinelet].push_back(iPoint); + check_Point[iPoint] = false; + iLinelet++; + } + } + } + + /*--- Create the linelet structure ---*/ + + iLinelet = 0; + + do { + + index_Point = 0; + + do { + + /*--- Compute the value of the max weight ---*/ + + iPoint = LineletPoint[iLinelet][index_Point]; + max_weight = 0.0; + for (iNode = 0; iNode < geometry->node[iPoint]->GetnPoint(); iNode++) { + jPoint = geometry->node[iPoint]->GetPoint(iNode); + if ((check_Point[jPoint]) && geometry->node[jPoint]->GetDomain()) { + iEdge = geometry->FindEdge(iPoint, jPoint); + normal = geometry->edge[iEdge]->GetNormal(); + if (geometry->GetnDim() == 3) area = sqrt(normal[0]*normal[0]+normal[1]*normal[1]+normal[2]*normal[2]); + else area = sqrt(normal[0]*normal[0]+normal[1]*normal[1]); + volume_iPoint = geometry->node[iPoint]->GetVolume(); + volume_jPoint = geometry->node[jPoint]->GetVolume(); + weight = 0.5*area*((1.0/volume_iPoint)+(1.0/volume_jPoint)); + max_weight = max(max_weight, weight); + } + } + + /*--- Verify if any face of the control volume must be added ---*/ + + add_point = false; + counter = 0; + next_Point = geometry->node[iPoint]->GetPoint(0); + for (iNode = 0; iNode < geometry->node[iPoint]->GetnPoint(); iNode++) { + jPoint = geometry->node[iPoint]->GetPoint(iNode); + iEdge = geometry->FindEdge(iPoint, jPoint); + normal = geometry->edge[iEdge]->GetNormal(); + if (geometry->GetnDim() == 3) area = sqrt(normal[0]*normal[0]+normal[1]*normal[1]+normal[2]*normal[2]); + else area = sqrt(normal[0]*normal[0]+normal[1]*normal[1]); + volume_iPoint = geometry->node[iPoint]->GetVolume(); + volume_jPoint = geometry->node[jPoint]->GetVolume(); + weight = 0.5*area*((1.0/volume_iPoint)+(1.0/volume_jPoint)); + if (((check_Point[jPoint]) && (weight/max_weight > alpha) && (geometry->node[jPoint]->GetDomain())) && + ((index_Point == 0) || ((index_Point > 0) && (jPoint != LineletPoint[iLinelet][index_Point-1])))) { + add_point = true; + next_Point = jPoint; + counter++; + } + } + + /*--- We have arrived to an isotropic zone ---*/ + + if (counter > 1) add_point = false; + + /*--- Add a typical point to the linelet, no leading edge ---*/ + + if (add_point) { + LineletPoint[iLinelet].push_back(next_Point); + check_Point[next_Point] = false; + index_Point++; + } + + } while (add_point); + iLinelet++; + } while (iLinelet < nLinelet); + + /*--- Identify the points that belong to a Linelet ---*/ + + for (iLinelet = 0; iLinelet < nLinelet; iLinelet++) { + for (iElem = 0; iElem < LineletPoint[iLinelet].size(); iElem++) { + iPoint = LineletPoint[iLinelet][iElem]; + LineletBool[iPoint] = true; + } + } + + /*--- Identify the maximum number of elements in a Linelet ---*/ + + max_nElem = LineletPoint[0].size(); + for (iLinelet = 1; iLinelet < nLinelet; iLinelet++) + if (LineletPoint[iLinelet].size() > max_nElem) + max_nElem = LineletPoint[iLinelet].size(); + + } + + /*--- The domain doesn't have well defined linelets ---*/ + + else { + + max_nElem = 0; + + } + + /*--- Screen output ---*/ + + Local_nPoints = 0; + for (iLinelet = 0; iLinelet < nLinelet; iLinelet++) { + Local_nPoints += LineletPoint[iLinelet].size(); + } + Local_nLineLets = nLinelet; + +#ifndef HAVE_MPI + Global_nPoints = Local_nPoints; + Global_nLineLets = Local_nLineLets; +#else + SU2_MPI::Allreduce(&Local_nPoints, &Global_nPoints, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&Local_nLineLets, &Global_nLineLets, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); +#endif + + MeanPoints = SU2_TYPE::Int(su2double(Global_nPoints)/su2double(Global_nLineLets)); + + /*--- Memory allocation --*/ + + UBlock = new su2double* [max_nElem]; + invUBlock = new su2double* [max_nElem]; + LBlock = new su2double* [max_nElem]; + yVector = new su2double* [max_nElem]; + zVector = new su2double* [max_nElem]; + rVector = new su2double* [max_nElem]; + for (iElem = 0; iElem < max_nElem; iElem++) { + UBlock[iElem] = new su2double [nVar*nVar]; + invUBlock[iElem] = new su2double [nVar*nVar]; + LBlock[iElem] = new su2double [nVar*nVar]; + yVector[iElem] = new su2double [nVar]; + zVector[iElem] = new su2double [nVar]; + rVector[iElem] = new su2double [nVar]; + } + + LFBlock = new su2double [nVar*nVar]; + LyVector = new su2double [nVar]; + FzVector = new su2double [nVar]; + + /*--- Memory deallocation --*/ + + delete [] check_Point; + + return MeanPoints; + +} + +void CSysMatrix::ComputeLineletPreconditioner(const CSysVector & vec, CSysVector & prod, + CGeometry *geometry, CConfig *config) { + + unsigned long iVar, jVar, nElem = 0, iLinelet, im1Point, iPoint, ip1Point, iElem; + long iElemLoop; + su2double *block; + + int rank = MASTER_NODE; + int size = SINGLE_NODE; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); +#endif + + if (size == SINGLE_NODE) { + + /*--- Jacobi preconditioning if there is no linelet ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + if (!LineletBool[iPoint]) { + for (iVar = 0; iVar < nVar; iVar++) { + prod[(unsigned long)(iPoint*nVar+iVar)] = 0.0; + for (jVar = 0; jVar < nVar; jVar++) + prod[(unsigned long)(iPoint*nVar+iVar)] += + invM[(unsigned long)(iPoint*nVar*nVar+iVar*nVar+jVar)]*vec[(unsigned long)(iPoint*nVar+jVar)]; + } + } + } + + /*--- MPI Parallelization ---*/ + + SendReceive_Solution(prod, geometry, config); + + /*--- Solve linelet using a Thomas' algorithm ---*/ + + for (iLinelet = 0; iLinelet < nLinelet; iLinelet++) { + + nElem = LineletPoint[iLinelet].size(); + + /*--- Copy vec vector to the new structure ---*/ + + for (iElem = 0; iElem < nElem; iElem++) { + iPoint = LineletPoint[iLinelet][iElem]; + for (iVar = 0; iVar < nVar; iVar++) + rVector[iElem][iVar] = vec[(unsigned long)(iPoint*nVar+iVar)]; + } + + /*--- Initialization (iElem = 0) ---*/ + + iPoint = LineletPoint[iLinelet][0]; + block = GetBlock(iPoint, iPoint); + for (iVar = 0; iVar < nVar; iVar++) { + yVector[0][iVar] = rVector[0][iVar]; + for (jVar = 0; jVar < nVar; jVar++) + UBlock[0][iVar*nVar+jVar] = block[iVar*nVar+jVar]; + } + + /*--- Main loop (without iElem = 0) ---*/ + + for (iElem = 1; iElem < nElem; iElem++) { + + im1Point = LineletPoint[iLinelet][iElem-1]; + iPoint = LineletPoint[iLinelet][iElem]; + + InverseBlock(UBlock[iElem-1], invUBlock[iElem-1]); + block = GetBlock(iPoint, im1Point); GetMultBlockBlock(LBlock[iElem], block, invUBlock[iElem-1]); + block = GetBlock(im1Point, iPoint); GetMultBlockBlock(LFBlock, LBlock[iElem], block); + block = GetBlock(iPoint, iPoint); GetSubsBlock(UBlock[iElem], block, LFBlock); + + /*--- Forward substituton ---*/ + + GetMultBlockVector(LyVector, LBlock[iElem], yVector[iElem-1]); + GetSubsVector(yVector[iElem], rVector[iElem], LyVector); + + } + + /*--- Backward substituton ---*/ + + InverseBlock(UBlock[nElem-1], invUBlock[nElem-1]); + GetMultBlockVector(zVector[nElem-1], invUBlock[nElem-1], yVector[nElem-1]); + + for (iElemLoop = nElem-2; iElemLoop >= 0; iElemLoop--) { + iPoint = LineletPoint[iLinelet][iElemLoop]; + ip1Point = LineletPoint[iLinelet][iElemLoop+1]; + block = GetBlock(iPoint, ip1Point); GetMultBlockVector(FzVector, block, zVector[iElemLoop+1]); + GetSubsVector(aux_vector, yVector[iElemLoop], FzVector); + GetMultBlockVector(zVector[iElemLoop], invUBlock[iElemLoop], aux_vector); + } + + /*--- Copy zVector to the prod vector ---*/ + + for (iElem = 0; iElem < nElem; iElem++) { + iPoint = LineletPoint[iLinelet][iElem]; + for (iVar = 0; iVar < nVar; iVar++) + prod[(unsigned long)(iPoint*nVar+iVar)] = zVector[iElem][iVar]; + } + + } + + /*--- MPI Parallelization ---*/ + + SendReceive_Solution(prod, geometry, config); + + } + else { + + if (rank == MASTER_NODE) cout << "ERROR: Linelet not implemented in parallel." << endl; + +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + + } + +} + +void CSysMatrix::ComputeResidual(const CSysVector & sol, const CSysVector & f, CSysVector & res) { + + unsigned long iPoint, iVar; + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + RowProduct(sol, iPoint); + for (iVar = 0; iVar < nVar; iVar++) { + res[iPoint*nVar+iVar] = prod_row_vector[iVar] - f[iPoint*nVar+iVar]; + } + } + +} diff --git a/Common/src/primal_grid_structure.cpp b/Common/src/primal_grid_structure.cpp index ab4993915e3..1783445f341 100644 --- a/Common/src/primal_grid_structure.cpp +++ b/Common/src/primal_grid_structure.cpp @@ -1,604 +1,604 @@ -/*! - * \file primal_grid_structure.cpp - * \brief Main classes for defining the primal grid elements - * \author F. Palacios - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/primal_grid_structure.hpp" - -unsigned short CPrimalGrid::nDim; - -CPrimalGrid::CPrimalGrid(void) { - - /*--- Set the default values for the pointers ---*/ - Nodes = NULL; - Neighbor_Elements = NULL; - Coord_CG = NULL; - Coord_FaceElems_CG = NULL; - -} - -CPrimalGrid::~CPrimalGrid() { - - if (Nodes != NULL) delete[] Nodes; - if (Coord_CG != NULL) delete[] Coord_CG; - if (Neighbor_Elements != NULL) delete[] Neighbor_Elements; - -} - -void CPrimalGrid::SetCoord_CG(su2double **val_coord) { - unsigned short iDim, iNode, NodeFace, iFace; - - for (iDim = 0; iDim < nDim; iDim++) { - Coord_CG[iDim] = 0.0; - for (iNode = 0; iNode < GetnNodes(); iNode++) - Coord_CG[iDim] += val_coord[iNode][iDim]/su2double(GetnNodes()); - } - - for (iFace = 0; iFace < GetnFaces(); iFace++) - for (iDim = 0; iDim < nDim; iDim++) { - Coord_FaceElems_CG[iFace][iDim] = 0.0; - for (iNode = 0; iNode < GetnNodesFace(iFace); iNode++) { - NodeFace = GetFaces(iFace, iNode); - Coord_FaceElems_CG[iFace][iDim] += val_coord[NodeFace][iDim]/su2double(GetnNodesFace(iFace)); - } - } -} - -void CPrimalGrid::GetAllNeighbor_Elements() { - cout << "( "; - for (unsigned short iFace = 0; iFace < GetnFaces(); iFace++) - { - cout << GetNeighbor_Elements(iFace) << ", "; - } - cout << ")" << endl; -} - -unsigned short CVertexMPI::nFaces = 0; - -unsigned short CVertexMPI::nNodes = 1; - -unsigned short CVertexMPI::nNeighbor_Elements = 0; - -unsigned short CVertexMPI::VTK_Type = 1; - -unsigned short CVertexMPI::maxNodesFace = 0; - -CVertexMPI::CVertexMPI(unsigned long val_point, unsigned short val_nDim) : CPrimalGrid() { - unsigned short iDim; - - /*--- Allocate CG coordinates ---*/ - nDim = val_nDim; - Coord_CG = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim++) Coord_CG[iDim] = 0.0; - - /*--- Allocate and define face structure of the element ---*/ - Nodes = new unsigned long[nNodes]; - Nodes[0] = val_point; - - /*--- By default, no rotation in the solution ---*/ - Rotation_Type = 0; - -} - -CVertexMPI::~CVertexMPI() { - unsigned short iFaces; - - for (iFaces = 0; iFaces < nFaces; iFaces++) - if (Coord_FaceElems_CG[iFaces] != NULL) delete[] Coord_FaceElems_CG[iFaces]; - if (Coord_FaceElems_CG != NULL) delete[] Coord_FaceElems_CG; - -} - -void CVertexMPI::Change_Orientation(void) { cout << "Not defined orientation change" << endl; } - -unsigned short CLine::Faces[1][2]={{0,1}}; - -unsigned short CLine::Neighbor_Nodes[2][1]={{1},{0}}; - -unsigned short CLine::nNodesFace[1]={2}; - -unsigned short CLine::nNeighbor_Nodes[2]={1,1}; - -unsigned short CLine::nFaces = 1; - -unsigned short CLine::nNodes = 2; - -unsigned short CLine::nNeighbor_Elements = 1; - -unsigned short CLine::VTK_Type = 3; - -unsigned short CLine::maxNodesFace = 2; - -CLine::CLine(unsigned long val_point_0, unsigned long val_point_1, - unsigned short val_nDim) : CPrimalGrid() { - unsigned short iDim, iFace; - - /*--- Allocate CG coordinates ---*/ - - nDim = val_nDim; - Coord_CG = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Coord_CG[iDim] = 0.0; - Coord_FaceElems_CG = new su2double* [nFaces]; - for (iFace = 0; iFace < nFaces; iFace++) { - Coord_FaceElems_CG[iFace] = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Coord_FaceElems_CG[iFace][iDim] = 0.0; - } - - /*--- Allocate and define face structure of the element ---*/ - - Nodes = new unsigned long[nNodes]; - Nodes[0] = val_point_0; - Nodes[1] = val_point_1; - -} - -CLine::~CLine() { - unsigned short iFaces; - - for (iFaces = 0; iFaces < nFaces; iFaces++) - if (Coord_FaceElems_CG[iFaces] != NULL) delete[] Coord_FaceElems_CG[iFaces]; - if (Coord_FaceElems_CG != NULL) delete[] Coord_FaceElems_CG; - -} - -void CLine::Change_Orientation(void) { - unsigned long iPoint, jPoint; - - iPoint = Nodes[0]; - jPoint = Nodes[1]; - Nodes[0] = jPoint; - Nodes[1] = iPoint; -} - -unsigned short CTriangle::Faces[3][2] = {{0,1},{1,2},{2,0}}; - -unsigned short CTriangle::Neighbor_Nodes[3][2] = {{1,2},{2,0},{0,1}}; - -unsigned short CTriangle::nNodesFace[3] = {2,2,2}; - -unsigned short CTriangle::nNeighbor_Nodes[3] = {2,2,2}; - -unsigned short CTriangle::nFaces = 3; - -unsigned short CTriangle::nNodes = 3; - -unsigned short CTriangle::nNeighbor_Elements = 3; - -unsigned short CTriangle::VTK_Type = 5; - -unsigned short CTriangle::maxNodesFace = 2; - -CTriangle::CTriangle(unsigned long val_point_0, unsigned long val_point_1, - unsigned long val_point_2, unsigned short val_nDim) : CPrimalGrid() { - unsigned short iDim, iFace, iNeighbor_Elements; - - /*--- Allocate CG coordinates ---*/ - nDim = val_nDim; - Coord_CG = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Coord_CG[iDim] = 0.0; - Coord_FaceElems_CG = new su2double* [nFaces]; - for (iFace = 0; iFace < nFaces; iFace++) { - Coord_FaceElems_CG[iFace] = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Coord_FaceElems_CG[iFace][iDim] = 0.0; - } - /*--- Allocate and define face structure of the element ---*/ - Nodes = new unsigned long[nNodes]; - Nodes[0] = val_point_0; - Nodes[1] = val_point_1; - Nodes[2] = val_point_2; - - /*--- Allocate and define neighbor elements to a element ---*/ - nNeighbor_Elements = nFaces; - Neighbor_Elements = new long[nNeighbor_Elements]; - for (iNeighbor_Elements = 0; iNeighbor_Elements. + */ + +#include "../include/primal_grid_structure.hpp" + +unsigned short CPrimalGrid::nDim; + +CPrimalGrid::CPrimalGrid(void) { + + /*--- Set the default values for the pointers ---*/ + Nodes = NULL; + Neighbor_Elements = NULL; + Coord_CG = NULL; + Coord_FaceElems_CG = NULL; + +} + +CPrimalGrid::~CPrimalGrid() { + + if (Nodes != NULL) delete[] Nodes; + if (Coord_CG != NULL) delete[] Coord_CG; + if (Neighbor_Elements != NULL) delete[] Neighbor_Elements; + +} + +void CPrimalGrid::SetCoord_CG(su2double **val_coord) { + unsigned short iDim, iNode, NodeFace, iFace; + + for (iDim = 0; iDim < nDim; iDim++) { + Coord_CG[iDim] = 0.0; + for (iNode = 0; iNode < GetnNodes(); iNode++) + Coord_CG[iDim] += val_coord[iNode][iDim]/su2double(GetnNodes()); + } + + for (iFace = 0; iFace < GetnFaces(); iFace++) + for (iDim = 0; iDim < nDim; iDim++) { + Coord_FaceElems_CG[iFace][iDim] = 0.0; + for (iNode = 0; iNode < GetnNodesFace(iFace); iNode++) { + NodeFace = GetFaces(iFace, iNode); + Coord_FaceElems_CG[iFace][iDim] += val_coord[NodeFace][iDim]/su2double(GetnNodesFace(iFace)); + } + } +} + +void CPrimalGrid::GetAllNeighbor_Elements() { + cout << "( "; + for (unsigned short iFace = 0; iFace < GetnFaces(); iFace++) + { + cout << GetNeighbor_Elements(iFace) << ", "; + } + cout << ")" << endl; +} + +unsigned short CVertexMPI::nFaces = 0; + +unsigned short CVertexMPI::nNodes = 1; + +unsigned short CVertexMPI::nNeighbor_Elements = 0; + +unsigned short CVertexMPI::VTK_Type = 1; + +unsigned short CVertexMPI::maxNodesFace = 0; + +CVertexMPI::CVertexMPI(unsigned long val_point, unsigned short val_nDim) : CPrimalGrid() { + unsigned short iDim; + + /*--- Allocate CG coordinates ---*/ + nDim = val_nDim; + Coord_CG = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim++) Coord_CG[iDim] = 0.0; + + /*--- Allocate and define face structure of the element ---*/ + Nodes = new unsigned long[nNodes]; + Nodes[0] = val_point; + + /*--- By default, no rotation in the solution ---*/ + Rotation_Type = 0; + +} + +CVertexMPI::~CVertexMPI() { + unsigned short iFaces; + + for (iFaces = 0; iFaces < nFaces; iFaces++) + if (Coord_FaceElems_CG[iFaces] != NULL) delete[] Coord_FaceElems_CG[iFaces]; + if (Coord_FaceElems_CG != NULL) delete[] Coord_FaceElems_CG; + +} + +void CVertexMPI::Change_Orientation(void) { cout << "Not defined orientation change" << endl; } + +unsigned short CLine::Faces[1][2]={{0,1}}; + +unsigned short CLine::Neighbor_Nodes[2][1]={{1},{0}}; + +unsigned short CLine::nNodesFace[1]={2}; + +unsigned short CLine::nNeighbor_Nodes[2]={1,1}; + +unsigned short CLine::nFaces = 1; + +unsigned short CLine::nNodes = 2; + +unsigned short CLine::nNeighbor_Elements = 1; + +unsigned short CLine::VTK_Type = 3; + +unsigned short CLine::maxNodesFace = 2; + +CLine::CLine(unsigned long val_point_0, unsigned long val_point_1, + unsigned short val_nDim) : CPrimalGrid() { + unsigned short iDim, iFace; + + /*--- Allocate CG coordinates ---*/ + + nDim = val_nDim; + Coord_CG = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Coord_CG[iDim] = 0.0; + Coord_FaceElems_CG = new su2double* [nFaces]; + for (iFace = 0; iFace < nFaces; iFace++) { + Coord_FaceElems_CG[iFace] = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Coord_FaceElems_CG[iFace][iDim] = 0.0; + } + + /*--- Allocate and define face structure of the element ---*/ + + Nodes = new unsigned long[nNodes]; + Nodes[0] = val_point_0; + Nodes[1] = val_point_1; + +} + +CLine::~CLine() { + unsigned short iFaces; + + for (iFaces = 0; iFaces < nFaces; iFaces++) + if (Coord_FaceElems_CG[iFaces] != NULL) delete[] Coord_FaceElems_CG[iFaces]; + if (Coord_FaceElems_CG != NULL) delete[] Coord_FaceElems_CG; + +} + +void CLine::Change_Orientation(void) { + unsigned long iPoint, jPoint; + + iPoint = Nodes[0]; + jPoint = Nodes[1]; + Nodes[0] = jPoint; + Nodes[1] = iPoint; +} + +unsigned short CTriangle::Faces[3][2] = {{0,1},{1,2},{2,0}}; + +unsigned short CTriangle::Neighbor_Nodes[3][2] = {{1,2},{2,0},{0,1}}; + +unsigned short CTriangle::nNodesFace[3] = {2,2,2}; + +unsigned short CTriangle::nNeighbor_Nodes[3] = {2,2,2}; + +unsigned short CTriangle::nFaces = 3; + +unsigned short CTriangle::nNodes = 3; + +unsigned short CTriangle::nNeighbor_Elements = 3; + +unsigned short CTriangle::VTK_Type = 5; + +unsigned short CTriangle::maxNodesFace = 2; + +CTriangle::CTriangle(unsigned long val_point_0, unsigned long val_point_1, + unsigned long val_point_2, unsigned short val_nDim) : CPrimalGrid() { + unsigned short iDim, iFace, iNeighbor_Elements; + + /*--- Allocate CG coordinates ---*/ + nDim = val_nDim; + Coord_CG = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Coord_CG[iDim] = 0.0; + Coord_FaceElems_CG = new su2double* [nFaces]; + for (iFace = 0; iFace < nFaces; iFace++) { + Coord_FaceElems_CG[iFace] = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Coord_FaceElems_CG[iFace][iDim] = 0.0; + } + /*--- Allocate and define face structure of the element ---*/ + Nodes = new unsigned long[nNodes]; + Nodes[0] = val_point_0; + Nodes[1] = val_point_1; + Nodes[2] = val_point_2; + + /*--- Allocate and define neighbor elements to a element ---*/ + nNeighbor_Elements = nFaces; + Neighbor_Elements = new long[nNeighbor_Elements]; + for (iNeighbor_Elements = 0; iNeighbor_Elementsdriver_structure.cpp file. - * \author T. Economon, H. Kline, R. Sanchez - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -#include "../../Common/include/mpi_structure.hpp" -#include "iteration_structure.hpp" -#include "solver_structure.hpp" -#include "integration_structure.hpp" -#include "output_structure.hpp" -#include "numerics_structure.hpp" -#include "../../Common/include/geometry_structure.hpp" -#include "../../Common/include/grid_movement_structure.hpp" -#include "../../Common/include/config_structure.hpp" - -using namespace std; - -/*! - * \class CDriver - * \brief Parent class for driving an iteration of a single or multi-zone problem. - * \author T. Economon - * \version 4.0.1 "Cardinal" - */ -class CDriver { -protected: - unsigned short nZone; /*!< \brief Total number of zones in the problem. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] iteration_container - Container vector with all the iteration methods. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] geometry_container - Geometrical definition of the problem. - * \param[in] integration_container - Container vector with all the integration methods. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config - Definition of the particular problem. - * \param[in] val_nZone - Total number of zones. - */ - CDriver(CIteration **iteration_container, - CSolver ****solver_container, - CGeometry ***geometry_container, - CIntegration ***integration_container, - CNumerics *****numerics_container, - CConfig **config, - unsigned short val_nZone); - - /*! - * \brief Destructor of the class. - */ - virtual ~CDriver(void); - - /*! - * \brief A virtual member. - * \param[in] iteration_container - Container vector with all the iteration methods. - * \param[in] output - Pointer to the COutput class. - * \param[in] integration_container - Container vector with all the integration methods. - * \param[in] geometry_container - Geometrical definition of the problem. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config_container - 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. - */ - - virtual void Run(CIteration **iteration_container, - COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox){}; - /*! - * \brief Definition of the physics iteration class or within a single zone. - * \param[in] iteration_container - Pointer to the iteration container to be instantiated. - * \param[in] config - Definition of the particular problem. - * \param[in] iZone - Index of the zone. - */ - void Iteration_Preprocessing(CIteration **iteration_container, CConfig **config, unsigned short iZone); - - /*! - * \brief Definition and allocation of all solution classes. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void Solver_Preprocessing(CSolver ***solver_container, CGeometry **geometry, CConfig *config); - - /*! - * \brief Definition and allocation of all integration classes. - * \param[in] integration_container - Container vector with all the integration methods. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void Integration_Preprocessing(CIntegration **integration_container, CGeometry **geometry, CConfig *config); - - /*! - * \brief Definition and allocation of all solver classes. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void Numerics_Preprocessing(CNumerics ****numerics_container, CSolver ***solver_container, CGeometry **geometry, CConfig *config); - -}; -/*! - * \class CSingleZoneDriver - * \brief Class for driving an iteration of the physics within a single zone. - * \author T. Economon - * \version 4.0.1 "Cardinal" - */ -class CSingleZoneDriver : public CDriver { -public: - - /*! - * \brief Constructor of the class. - * \param[in] iteration_container - Container vector with all the iteration methods. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] geometry_container - Geometrical definition of the problem. - * \param[in] integration_container - Container vector with all the integration methods. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config - Definition of the particular problem. - * \param[in] val_nZone - Total number of zones. - */ - CSingleZoneDriver(CIteration **iteration_container, - CSolver ****solver_container, - CGeometry ***geometry_container, - CIntegration ***integration_container, - CNumerics *****numerics_container, - CConfig **config, - unsigned short val_nZone); - - /*! - * \brief Destructor of the class. - */ - ~CSingleZoneDriver(void); - - /*! - * \brief Run a single iteration of the physics within a single zone. - * \param[in] iteration_container - Container vector with all the iteration methods. - * \param[in] output - Pointer to the COutput class. - * \param[in] integration_container - Container vector with all the integration methods. - * \param[in] geometry_container - Geometrical definition of the problem. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config_container - 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. - */ - - void Run(CIteration **iteration_container, - COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox); - - -}; - - -/*! - * \class CMultiZoneDriver - * \brief Class for driving an iteration of the physics within multiple zones. - * \author T. Economon - * \version 4.0.1 "Cardinal" - */ -class CMultiZoneDriver : public CDriver { -public: - - /*! - * \brief Constructor of the class. - * \param[in] iteration_container - Container vector with all the iteration methods. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] geometry_container - Geometrical definition of the problem. - * \param[in] integration_container - Container vector with all the integration methods. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config - Definition of the particular problem. - * \param[in] val_nZone - Total number of zones. - */ - CMultiZoneDriver(CIteration **iteration_container, - CSolver ****solver_container, - CGeometry ***geometry_container, - CIntegration ***integration_container, - CNumerics *****numerics_container, - CConfig **config, - unsigned short val_nZone); - - /*! - * \brief Destructor of the class. - */ - ~CMultiZoneDriver(void); - - /*! - * \brief Run a single iteration of the physics within multiple zones. - * \param[in] iteration_container - Container vector with all the iteration methods. - * \param[in] output - Pointer to the COutput class. - * \param[in] integration_container - Container vector with all the integration methods. - * \param[in] geometry_container - Geometrical definition of the problem. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config_container - 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. - */ - - void Run(CIteration **iteration_container, - COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox); - -}; - - -/*! - * \class CSpectralDriver - * \brief Class for driving an iteration of a spectral method problem using multiple zones. - * \author T. Economon - * \version 4.0.1 "Cardinal" - */ -class CSpectralDriver : public CDriver { -public: - - /*! - * \brief Constructor of the class. - * \param[in] iteration_container - Container vector with all the iteration methods. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] geometry_container - Geometrical definition of the problem. - * \param[in] integration_container - Container vector with all the integration methods. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config - Definition of the particular problem. - * \param[in] val_nZone - Total number of zones. - */ - CSpectralDriver(CIteration **iteration_container, - CSolver ****solver_container, - CGeometry ***geometry_container, - CIntegration ***integration_container, - CNumerics *****numerics_container, - CConfig **config, - unsigned short val_nZone); - - /*! - * \brief Destructor of the class. - */ - ~CSpectralDriver(void); - - /*! - * \brief Run a single iteration of a spectral method problem. - * \param[in] iteration_container - Container vector with all the iteration methods. - * \param[in] output - Pointer to the COutput class. - * \param[in] integration_container - Container vector with all the integration methods. - * \param[in] geometry_container - Geometrical definition of the problem. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config_container - 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. - */ - - void Run(CIteration **iteration_container, - COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox); - - /*! - * \brief Computation and storage of the time spectral source terms. - * \author T. Economon, K. Naik - * \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. - * \param[in] nZone - Total number of zones (periodic instances). - * \param[in] iZone - Current zone number. - */ - void SetTimeSpectral(CGeometry ***geometry_container, CSolver ****solver_container, - CConfig **config_container, unsigned short nZone, unsigned short iZone); - - /*! - * \brief Computation of the Time-Spectral operator matrix. - * \author K. Naik - * \param[in] D - su2double pointer to the operator matrix. - * \param[in] nZone - Total number of zones (periodic instances). - */ - void ComputeTimeSpectral_Operator(su2double **D, su2double period, unsigned short nZone); - - /*! - * \brief Computation and storage of the time-spectral mesh velocities. - * \author K. Naik, T. Economon - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] nZone - Total number of zones (periodic instances). - */ - void SetTimeSpectral_Velocities(CGeometry ***geometry_container, - CConfig **config_container, unsigned short nZone); - -}; - - -/*! - * \class CFSIDriver - * \brief Class for driving a BGS iteration for a fluid-structure interaction problem in multiple zones. - * \author R. Sanchez. - * \version 4.0.1 "Cardinal" - */ -class CFSIDriver : public CDriver { -public: - - /*! - * \brief Constructor of the class. - * \param[in] iteration_container - Container vector with all the iteration methods. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] geometry_container - Geometrical definition of the problem. - * \param[in] integration_container - Container vector with all the integration methods. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config - Definition of the particular problem. - * \param[in] val_nZone - Total number of zones. - */ - CFSIDriver(CIteration **iteration_container, - CSolver ****solver_container, - CGeometry ***geometry_container, - CIntegration ***integration_container, - CNumerics *****numerics_container, - CConfig **config, - unsigned short val_nZone); - - /*! - * \brief Destructor of the class. - */ - ~CFSIDriver(void); - - /*! - * \brief Run a Block Gauss-Seidel iteration of the FSI problem. - * \param[in] iteration_container - Container vector with all the iteration methods. - * \param[in] output - Pointer to the COutput class. - * \param[in] integration_container - Container vector with all the integration methods. - * \param[in] geometry_container - Geometrical definition of the problem. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config_container - 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. - */ - - void Run(CIteration **iteration_container, - COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox); - -}; - +/*! + * \file driver_structure.hpp + * \brief Headers of the main subroutines for driving single or multi-zone problems. + * The subroutines and functions are in the driver_structure.cpp file. + * \author T. Economon, H. Kline, R. Sanchez + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +#include "../../Common/include/mpi_structure.hpp" +#include "iteration_structure.hpp" +#include "solver_structure.hpp" +#include "integration_structure.hpp" +#include "output_structure.hpp" +#include "numerics_structure.hpp" +#include "../../Common/include/geometry_structure.hpp" +#include "../../Common/include/grid_movement_structure.hpp" +#include "../../Common/include/config_structure.hpp" + +using namespace std; + +/*! + * \class CDriver + * \brief Parent class for driving an iteration of a single or multi-zone problem. + * \author T. Economon + * \version 4.0.1 "Cardinal" + */ +class CDriver { +protected: + unsigned short nZone; /*!< \brief Total number of zones in the problem. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] iteration_container - Container vector with all the iteration methods. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] geometry_container - Geometrical definition of the problem. + * \param[in] integration_container - Container vector with all the integration methods. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] val_nZone - Total number of zones. + */ + CDriver(CIteration **iteration_container, + CSolver ****solver_container, + CGeometry ***geometry_container, + CIntegration ***integration_container, + CNumerics *****numerics_container, + CConfig **config, + unsigned short val_nZone); + + /*! + * \brief Destructor of the class. + */ + virtual ~CDriver(void); + + /*! + * \brief A virtual member. + * \param[in] iteration_container - Container vector with all the iteration methods. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration_container - Container vector with all the integration methods. + * \param[in] geometry_container - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config_container - 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. + */ + + virtual void Run(CIteration **iteration_container, + COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox){}; + /*! + * \brief Definition of the physics iteration class or within a single zone. + * \param[in] iteration_container - Pointer to the iteration container to be instantiated. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the zone. + */ + void Iteration_Preprocessing(CIteration **iteration_container, CConfig **config, unsigned short iZone); + + /*! + * \brief Definition and allocation of all solution classes. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void Solver_Preprocessing(CSolver ***solver_container, CGeometry **geometry, CConfig *config); + + /*! + * \brief Definition and allocation of all integration classes. + * \param[in] integration_container - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void Integration_Preprocessing(CIntegration **integration_container, CGeometry **geometry, CConfig *config); + + /*! + * \brief Definition and allocation of all solver classes. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void Numerics_Preprocessing(CNumerics ****numerics_container, CSolver ***solver_container, CGeometry **geometry, CConfig *config); + +}; +/*! + * \class CSingleZoneDriver + * \brief Class for driving an iteration of the physics within a single zone. + * \author T. Economon + * \version 4.0.1 "Cardinal" + */ +class CSingleZoneDriver : public CDriver { +public: + + /*! + * \brief Constructor of the class. + * \param[in] iteration_container - Container vector with all the iteration methods. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] geometry_container - Geometrical definition of the problem. + * \param[in] integration_container - Container vector with all the integration methods. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] val_nZone - Total number of zones. + */ + CSingleZoneDriver(CIteration **iteration_container, + CSolver ****solver_container, + CGeometry ***geometry_container, + CIntegration ***integration_container, + CNumerics *****numerics_container, + CConfig **config, + unsigned short val_nZone); + + /*! + * \brief Destructor of the class. + */ + ~CSingleZoneDriver(void); + + /*! + * \brief Run a single iteration of the physics within a single zone. + * \param[in] iteration_container - Container vector with all the iteration methods. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration_container - Container vector with all the integration methods. + * \param[in] geometry_container - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config_container - 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. + */ + + void Run(CIteration **iteration_container, + COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox); + + +}; + + +/*! + * \class CMultiZoneDriver + * \brief Class for driving an iteration of the physics within multiple zones. + * \author T. Economon + * \version 4.0.1 "Cardinal" + */ +class CMultiZoneDriver : public CDriver { +public: + + /*! + * \brief Constructor of the class. + * \param[in] iteration_container - Container vector with all the iteration methods. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] geometry_container - Geometrical definition of the problem. + * \param[in] integration_container - Container vector with all the integration methods. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] val_nZone - Total number of zones. + */ + CMultiZoneDriver(CIteration **iteration_container, + CSolver ****solver_container, + CGeometry ***geometry_container, + CIntegration ***integration_container, + CNumerics *****numerics_container, + CConfig **config, + unsigned short val_nZone); + + /*! + * \brief Destructor of the class. + */ + ~CMultiZoneDriver(void); + + /*! + * \brief Run a single iteration of the physics within multiple zones. + * \param[in] iteration_container - Container vector with all the iteration methods. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration_container - Container vector with all the integration methods. + * \param[in] geometry_container - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config_container - 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. + */ + + void Run(CIteration **iteration_container, + COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox); + +}; + + +/*! + * \class CSpectralDriver + * \brief Class for driving an iteration of a spectral method problem using multiple zones. + * \author T. Economon + * \version 4.0.1 "Cardinal" + */ +class CSpectralDriver : public CDriver { +public: + + /*! + * \brief Constructor of the class. + * \param[in] iteration_container - Container vector with all the iteration methods. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] geometry_container - Geometrical definition of the problem. + * \param[in] integration_container - Container vector with all the integration methods. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] val_nZone - Total number of zones. + */ + CSpectralDriver(CIteration **iteration_container, + CSolver ****solver_container, + CGeometry ***geometry_container, + CIntegration ***integration_container, + CNumerics *****numerics_container, + CConfig **config, + unsigned short val_nZone); + + /*! + * \brief Destructor of the class. + */ + ~CSpectralDriver(void); + + /*! + * \brief Run a single iteration of a spectral method problem. + * \param[in] iteration_container - Container vector with all the iteration methods. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration_container - Container vector with all the integration methods. + * \param[in] geometry_container - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config_container - 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. + */ + + void Run(CIteration **iteration_container, + COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox); + + /*! + * \brief Computation and storage of the time spectral source terms. + * \author T. Economon, K. Naik + * \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. + * \param[in] nZone - Total number of zones (periodic instances). + * \param[in] iZone - Current zone number. + */ + void SetTimeSpectral(CGeometry ***geometry_container, CSolver ****solver_container, + CConfig **config_container, unsigned short nZone, unsigned short iZone); + + /*! + * \brief Computation of the Time-Spectral operator matrix. + * \author K. Naik + * \param[in] D - su2double pointer to the operator matrix. + * \param[in] nZone - Total number of zones (periodic instances). + */ + void ComputeTimeSpectral_Operator(su2double **D, su2double period, unsigned short nZone); + + /*! + * \brief Computation and storage of the time-spectral mesh velocities. + * \author K. Naik, T. Economon + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] nZone - Total number of zones (periodic instances). + */ + void SetTimeSpectral_Velocities(CGeometry ***geometry_container, + CConfig **config_container, unsigned short nZone); + +}; + + +/*! + * \class CFSIDriver + * \brief Class for driving a BGS iteration for a fluid-structure interaction problem in multiple zones. + * \author R. Sanchez. + * \version 4.0.1 "Cardinal" + */ +class CFSIDriver : public CDriver { +public: + + /*! + * \brief Constructor of the class. + * \param[in] iteration_container - Container vector with all the iteration methods. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] geometry_container - Geometrical definition of the problem. + * \param[in] integration_container - Container vector with all the integration methods. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] val_nZone - Total number of zones. + */ + CFSIDriver(CIteration **iteration_container, + CSolver ****solver_container, + CGeometry ***geometry_container, + CIntegration ***integration_container, + CNumerics *****numerics_container, + CConfig **config, + unsigned short val_nZone); + + /*! + * \brief Destructor of the class. + */ + ~CFSIDriver(void); + + /*! + * \brief Run a Block Gauss-Seidel iteration of the FSI problem. + * \param[in] iteration_container - Container vector with all the iteration methods. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration_container - Container vector with all the integration methods. + * \param[in] geometry_container - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config_container - 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. + */ + + void Run(CIteration **iteration_container, + COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox); + +}; + diff --git a/SU2_CFD/include/integration_structure.hpp b/SU2_CFD/include/integration_structure.hpp index c84e2cfc9cf..54f8e5da812 100644 --- a/SU2_CFD/include/integration_structure.hpp +++ b/SU2_CFD/include/integration_structure.hpp @@ -1,640 +1,640 @@ -/*! - * \file integration_structure.hpp - * \brief Headers of the main subroutines for space and time integration. - * The subroutines and functions are in the integration_structure.cpp, - * integration_time.cpp, and integration_notime.cpp files. - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -#include "../../Common/include/mpi_structure.hpp" - -#include -#include -#include - -#include "solver_structure.hpp" -#include "../../Common/include/geometry_structure.hpp" -#include "../../Common/include/config_structure.hpp" - -using namespace std; - -/*! - * \class CIntegration - * \brief Main class for doing the space integration, time integration, and monitoring - * of a system of Partial Differential Equations (PDE). - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CIntegration { -protected: - su2double Cauchy_Value, /*!< \brief Summed value of the convergence indicator. */ - Cauchy_Func; /*!< \brief Current value of the convergence indicator at one iteration. */ - unsigned short Cauchy_Counter; /*!< \brief Number of elements of the Cauchy serial. */ - su2double *Cauchy_Serie; /*!< \brief Complete Cauchy serial. */ - su2double Old_Func, /*!< \brief Old value of the objective function (the function which is monitored). */ - New_Func; /*!< \brief Current value of the objective function (the function which is monitored). */ - bool Convergence, /*!< \brief To indicate if the flow solver (direct, adjoint, or linearized) has converged or not. */ - Convergence_FSI, /*!< \brief To indicate if the FSI problem has converged or not. */ - Convergence_FullMG; /*!< \brief To indicate if the Full Multigrid has converged and it is necessary to add a new level. */ - su2double InitResidual; /*!< \brief Initial value of the residual to evaluate the convergence level. */ - -public: - - /*! - * \brief Constructor of the class. - */ - CIntegration(CConfig *config); - - /*! - * \brief Destructor of the class. - */ - virtual ~CIntegration(void); - - /*! - * \brief Do the space integration of the numerical system. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] solver - Description of the numerical method. - * \param[in] config - Definition of the particular problem. - * \param[in] iMesh - Index of the mesh in multigrid computations. - * \param[in] iRKStep - Current step of the Runge-Kutta iteration. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - */ - void Space_Integration(CGeometry *geometry, CSolver **solver_container, CNumerics **numerics, CConfig *config, - unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem); - - /*! - * \brief Do the time integration (explicit or implicit) of the numerical system. - * \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. - * \param[in] iRKStep - Current step of the Runge-Kutta iteration. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] Iteration - Current iteration. - */ - void Time_Integration(CGeometry *geometry, CSolver **solver_container, CConfig *config, - unsigned short iRKStep, unsigned short RunTime_EqSystem, unsigned long Iteration); - - /*! - * \brief Initialize the adjoint solution using the primal problem. - * \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. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] Iteration - Current iteration. - */ - void Adjoint_Setup(CGeometry ***geometry, CSolver ****solver_container, CConfig **config, - unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone); - - /*! - * \brief Do the convergence analisys to determine if the code must stop the execution. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] Iteration - Current iteration. - * \param[in] monitor - Objective function that is use to study its convergence. - */ - void Convergence_Monitoring(CGeometry *geometry, CConfig *config, - unsigned long Iteration, su2double monitor, unsigned short iMesh); - - /*! - * \brief Do the convergence analysis to determine if the FSI problem has converged on the structural side. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] Iteration - Current iteration. - * \param[in] monitor - Objective function that is use to study its convergence. - */ - void Convergence_Monitoring_FSI(CGeometry *fea_geometry, CConfig *fea_config, CSolver *fea_solver, unsigned long iFSIIter); - - - /*! - * \brief Get the value of the convergence. - * \return Level of convergence of the solution. - */ - su2double GetCauchy_Value(void); - - /*! - * \brief Get the indicator of the convergence for the direct, adjoint and linearized problem. - * \return TRUE means that the convergence criteria is satisfied; - * otherwise FALSE. - */ - bool GetConvergence(void); - - /*! - * \brief Get the indicator of the convergence for the Fluid-Structure Interaction problem. - * \return TRUE means that the convergence criteria is satisfied; - * otherwise FALSE. - */ - bool GetConvergence_FSI(void); - - /*! - * \brief Set the indicator of the convergence. - * \param[in] value - TRUE means that the convergence criteria is satisfied; - * otherwise FALSE. - */ - void SetConvergence(bool value); - - - /*! - * \brief Set the indicator of the convergence for FSI. - * \param[in] valueFSI - TRUE means that the convergence criteria for FSI is satisfied; - * otherwise FALSE. - */ - void SetConvergence_FSI(bool valueFSI); - - - /*! - * \brief Get the indicator of the convergence for the full multigrid problem. - * \return TRUE means that the convergence criteria is satisfied; - * otherwise FALSE. - */ - bool GetConvergence_FullMG(void); - - /*! - * \brief Save the solution, and volume at different time steps. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] solution - Flow solution. - * \param[in] config - Definition of the particular problem. - */ - void SetDualTime_Solver(CGeometry *geometry, CSolver *solver, CConfig *config, unsigned short iMesh); - - /*! - * \brief Save the structural solution at different time steps. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] solution - Structural solution. - * \param[in] config - Definition of the particular problem. - */ - void SetStructural_Solver(CGeometry *geometry, CSolver *solver, CConfig *config, unsigned short iMesh); - - /*! - * \brief A virtual member. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config - Definition of the particular problem. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] Iteration - Current iteration. - */ - virtual void MultiGrid_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, - CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone); - - /*! - * \brief A virtual member. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config - Definition of the particular problem. - * \param[in] iMesh - Index of the mesh in multigrid computations. - * \param[in] mu - Variable for controlling the kind of multigrid algorithm. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] Iteration - Current iteration. - */ - virtual void MultiGrid_Cycle(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, - CConfig **config, unsigned short iMesh, unsigned short mu, unsigned short RunTime_EqSystem, - unsigned long Iteration, unsigned short iZone); - - /*! - * \brief A virtual member. - * \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. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] Iteration - Current iteration. - * \param[in] monitor - value of the non-dimensional parameters for monitoring the convergence. - */ - virtual void NonDimensional_Parameters(CGeometry **geometry, CSolver ***solver_container, CNumerics ****numerics_container, - CConfig *config, unsigned short FinestMesh, unsigned short RunTime_EqSystem, unsigned long Iteration, - su2double *monitor); - - /*! - * \brief A virtual member. - * \param[out] sol_fine - Pointer to the solution on the fine grid. - * \param[in] geo_fine - Geometrical definition of the fine grid. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetProlongated_Correction(CSolver *sol_fine, CGeometry *geo_fine, CConfig *config, unsigned short iMesh); - - /*! - * \brief A virtual member. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[out] sol_fine - Pointer to the solution on the fine grid. - * \param[in] sol_coarse - Pointer to the solution on the coarse grid. - * \param[in] geo_fine - Geometrical definition of the fine grid. - * \param[in] geo_coarse - Geometrical definition of the coarse grid. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetProlongated_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, - CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] sol_fine - Pointer to the solution on the fine grid. - * \param[out] sol_coarse - Pointer to the solution on the coarse grid. - * \param[in] geo_fine - Geometrical definition of the fine grid. - * \param[in] geo_coarse - Geometrical definition of the coarse grid. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetRestricted_Residual(CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, - CGeometry *geo_coarse, CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] sol_fine - Pointer to the solution on the fine grid. - * \param[out] sol_coarse - Pointer to the solution on the coarse grid. - * \param[in] geo_fine - Geometrical definition of the fine grid. - * \param[in] geo_coarse - Geometrical definition of the coarse grid. - * \param[in] config - Definition of the particular problem. - * \param[in] iMesh - Index of the mesh in multigrid computations. - * \param[in] InclSharedDomain - Include the shared domain in the interpolation. - */ - virtual void SetRestricted_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] sol_fine - Pointer to the solution on the fine grid. - * \param[out] sol_coarse - Pointer to the solution on the coarse grid. - * \param[in] geo_fine - Geometrical definition of the fine grid. - * \param[in] geo_coarse - Geometrical definition of the coarse grid. - * \param[in] config - Definition of the particular problem. - * \param[in] iMesh - Index of the mesh in multigrid computations. - * \param[in] InclSharedDomain - Include the shared domain in the interpolation. - */ - virtual void SetRestricted_EddyVisc(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] sol_fine - Pointer to the solution on the fine grid. - * \param[out] sol_coarse - Pointer to the solution on the coarse grid. - * \param[in] geo_fine - Geometrical definition of the fine grid. - * \param[in] geo_coarse - Geometrical definition of the coarse grid. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetRestricted_Gradient(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, - CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] flow - Flow solution. - */ - virtual void SetResidual_Term(CGeometry *geometry, CSolver *flow); - - /*! - * \brief A virtual member. - * \param[in] sol_fine - Pointer to the solution on the fine grid. - * \param[in] sol_coarse - Pointer to the solution on the coarse grid. - * \param[in] geo_fine - Geometrical definition of the fine grid. - * \param[in] geo_coarse - Geometrical definition of the coarse grid. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetForcing_Term(CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, - CConfig *config, unsigned short iMesh); - - /*! - * \brief A virtual member. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config - Definition of the particular problem. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] Iteration - Current iteration. - */ - virtual void SingleGrid_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, - CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone); - - /*! - * \brief A virtual member. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config - Definition of the particular problem. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] Iteration - Current iteration. - */ - virtual void Structural_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, - CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone); - - - /*! - * \brief A virtual member. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config - Definition of the particular problem. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] iMesh - Index of the mesh in multigrid computations. - */ - virtual void SetPotential_Solver(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, - CConfig **config, unsigned short RunTime_EqSystem, unsigned short iMesh, unsigned short iZone); - - /*! - * \brief A virtual member. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] solution - Container vector with all the solutions on the finest grid. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] val_nSmooth - Number of smoothing iterations. - * \param[in] val_smooth_coeff - Relaxation factor. - * \param[in] config - Definition of the particular problem. - */ - virtual void Smooth_Solution(unsigned short RunTime_EqSystem, CSolver *solver, CGeometry *geometry, - unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config); - -}; - -/*! - * \class CMultiGridIntegration - * \brief Class for doing the numerical integration using a multigrid method. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CMultiGridIntegration : public CIntegration { -protected: - -public: - - /*! - * \brief Constructor of the class. - * \param[in] config - Definition of the particular problem. - */ - CMultiGridIntegration(CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CMultiGridIntegration(void); - - /*! - * \brief This subroutine calls the MultiGrid_Cycle and also prepare the multigrid levels and the monitoring. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config - Definition of the particular problem. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] Iteration - Current iteration. - */ - void MultiGrid_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, - CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone); - - /*! - * \brief Perform a Full-Approximation Storage (FAS) Multigrid. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config - Definition of the particular problem. - * \param[in] iMesh - Index of the mesh in multigrid computations. - * \param[in] mu - Variable for controlling the kind of multigrid algorithm. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] Iteration - Current iteration. - */ - void MultiGrid_Cycle(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, - CConfig **config, unsigned short iMesh, unsigned short mu, unsigned short RunTime_EqSystem, - unsigned long Iteration, unsigned short iZone); - - /*! - * \brief Compute the non-dimensional parameters. - * \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. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] Iteration - Current iteration. - * \param[in] monitor - value of the non-dimensional parameters for monitoring the convergence. - */ - void NonDimensional_Parameters(CGeometry **geometry, CSolver ***solver_container, CNumerics ****numerics_container, - CConfig *config, unsigned short FinestMesh, unsigned short RunTime_EqSystem, unsigned long Iteration, - su2double *monitor); - - /*! - * \brief Compute the fine solution from a coarse solution. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[out] sol_fine - Pointer to the solution on the fine grid. - * \param[in] sol_coarse - Pointer to the solution on the coarse grid. - * \param[in] geo_fine - Geometrical definition of the fine grid. - * \param[in] geo_coarse - Geometrical definition of the coarse grid. - * \param[in] config - Definition of the particular problem. - */ - void SetProlongated_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, - CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); - - /*! - * \brief Compute the fine grid correction from the coarse solution. - * \param[out] sol_fine - Pointer to the solution on the fine grid. - * \param[in] sol_coarse - Pointer to the solution on the coarse grid. - * \param[in] geo_fine - Geometrical definition of the fine grid. - * \param[in] geo_coarse - Geometrical definition of the coarse grid. - * \param[in] config - Definition of the particular problem. - */ - void GetProlongated_Correction(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, - CGeometry *geo_coarse, CConfig *config); - - /*! - * \brief Do an implicit smoothing of the prolongated correction. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] solution - Container vector with all the solutions on the finest grid. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] val_nSmooth - Number of smoothing iterations. - * \param[in] val_smooth_coeff - Relaxation factor. - * \param[in] config - Definition of the particular problem. - */ - void SmoothProlongated_Correction(unsigned short RunTime_EqSystem, CSolver *solver, CGeometry *geometry, - unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config); - - /*! - * \brief Do an implicit smoothing of the solution. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] solution - Container vector with all the solutions on the finest grid. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] val_nSmooth - Number of smoothing iterations. - * \param[in] val_smooth_coeff - Relaxation factor. - * \param[in] config - Definition of the particular problem. - */ - void Smooth_Solution(unsigned short RunTime_EqSystem, CSolver *solver, CGeometry *geometry, - unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config); - - /*! - * \brief Set the value of the corrected fine grid solution. - * \param[out] sol_fine - Pointer to the solution on the fine grid. - * \param[in] geo_fine - Geometrical definition of the fine grid. - * \param[in] config - Definition of the particular problem. - */ - void SetProlongated_Correction(CSolver *sol_fine, CGeometry *geo_fine, CConfig *config, unsigned short iMesh); - - /*! - * \brief Compute truncation error in the coarse grid using the fine grid information. - * \param[in] sol_fine - Pointer to the solution on the fine grid. - * \param[out] sol_coarse - Pointer to the solution on the coarse grid. - * \param[in] geo_fine - Geometrical definition of the fine grid. - * \param[in] geo_coarse - Geometrical definition of the coarse grid. - * \param[in] config - Definition of the particular problem. - */ - void SetRestricted_Residual(CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, - CGeometry *geo_coarse, CConfig *config); - - /*! - * \brief Restrict solution from fine grid to a coarse grid. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] sol_fine - Pointer to the solution on the fine grid. - * \param[out] sol_coarse - Pointer to the solution on the coarse grid. - * \param[in] geo_fine - Geometrical definition of the fine grid. - * \param[in] geo_coarse - Geometrical definition of the coarse grid. - * \param[in] config - Definition of the particular problem. - * \param[in] iMesh - Index of the mesh in multigrid computations. - * \param[in] InclSharedDomain - Include the shared domain in the interpolation. - */ - void SetRestricted_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); - - /*! - * \brief Compute the gradient in coarse grid using the fine grid information. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] sol_fine - Pointer to the solution on the fine grid. - * \param[out] sol_coarse - Pointer to the solution on the coarse grid. - * \param[in] geo_fine - Geometrical definition of the fine grid. - * \param[in] geo_coarse - Geometrical definition of the coarse grid. - * \param[in] config - Definition of the particular problem. - */ - void SetRestricted_Gradient(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, - CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); - - /*! - * \brief Add the truncation error to the residual. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] flow - Flow solution. - */ - void SetResidual_Term(CGeometry *geometry, CSolver *flow); - - /*! - * \brief Compute the forcing term. - * \param[in] sol_fine - Pointer to the solution on the fine grid. - * \param[in] sol_coarse - Pointer to the solution on the coarse grid. - * \param[in] geo_fine - Geometrical definition of the fine grid. - * \param[in] geo_coarse - Geometrical definition of the coarse grid. - * \param[in] config - Definition of the particular problem. - */ - void SetForcing_Term(CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, - CConfig *config, unsigned short iMesh); -}; - -/*! - * \class CSingleGridIntegration - * \brief Class for doing the numerical integration of the turbulence model. - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CSingleGridIntegration : public CIntegration { -public: - - /*! - * \brief Constructor of the class. - * \param[in] config - Definition of the particular problem. - */ - CSingleGridIntegration(CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSingleGridIntegration(void); - - /*! - * \brief Do the numerical integration (implicit) of the turbulence solver. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config - Definition of the particular problem. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] Iteration - Current iteration. - */ - void SingleGrid_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, - CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone); - - /*! - * \brief Restrict solution from fine grid to a coarse grid. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] sol_fine - Pointer to the solution on the fine grid. - * \param[out] sol_coarse - Pointer to the solution on the coarse grid. - * \param[in] geo_fine - Geometrical definition of the fine grid. - * \param[in] geo_coarse - Geometrical definition of the coarse grid. - * \param[in] config - Definition of the particular problem. - * \param[in] iMesh - Index of the mesh in multigrid computations. - * \param[in] InclSharedDomain - Include the shared domain in the interpolation. - */ - void SetRestricted_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); - - /*! - * \brief Restrict solution from fine grid to a coarse grid. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] sol_fine - Pointer to the solution on the fine grid. - * \param[out] sol_coarse - Pointer to the solution on the coarse grid. - * \param[in] geo_fine - Geometrical definition of the fine grid. - * \param[in] geo_coarse - Geometrical definition of the coarse grid. - * \param[in] config - Definition of the particular problem. - * \param[in] iMesh - Index of the mesh in multigrid computations. - * \param[in] InclSharedDomain - Include the shared domain in the interpolation. - */ - void SetRestricted_EddyVisc(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); - -}; - - -/*! - * \class CStructuralIntegration - * \brief Class for doing the numerical integration of the structural model. - * \author R. Sanchez. - * \version 4.0.1 "Cardinal" - */ -class CStructuralIntegration : public CIntegration { -public: - - /*! - * \brief Constructor of the class. - * \param[in] config - Definition of the particular problem. - */ - CStructuralIntegration(CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CStructuralIntegration(void); - - /*! - * \brief Do the numerical integration (implicit) of the structural solver. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config - Definition of the particular problem. - * \param[in] RunTime_EqSystem - System of equations which is going to be solved. - * \param[in] Iteration - Current iteration. - */ - void Structural_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, - CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone); - -}; - -#include "integration_structure.inl" +/*! + * \file integration_structure.hpp + * \brief Headers of the main subroutines for space and time integration. + * The subroutines and functions are in the integration_structure.cpp, + * integration_time.cpp, and integration_notime.cpp files. + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +#include "../../Common/include/mpi_structure.hpp" + +#include +#include +#include + +#include "solver_structure.hpp" +#include "../../Common/include/geometry_structure.hpp" +#include "../../Common/include/config_structure.hpp" + +using namespace std; + +/*! + * \class CIntegration + * \brief Main class for doing the space integration, time integration, and monitoring + * of a system of Partial Differential Equations (PDE). + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CIntegration { +protected: + su2double Cauchy_Value, /*!< \brief Summed value of the convergence indicator. */ + Cauchy_Func; /*!< \brief Current value of the convergence indicator at one iteration. */ + unsigned short Cauchy_Counter; /*!< \brief Number of elements of the Cauchy serial. */ + su2double *Cauchy_Serie; /*!< \brief Complete Cauchy serial. */ + su2double Old_Func, /*!< \brief Old value of the objective function (the function which is monitored). */ + New_Func; /*!< \brief Current value of the objective function (the function which is monitored). */ + bool Convergence, /*!< \brief To indicate if the flow solver (direct, adjoint, or linearized) has converged or not. */ + Convergence_FSI, /*!< \brief To indicate if the FSI problem has converged or not. */ + Convergence_FullMG; /*!< \brief To indicate if the Full Multigrid has converged and it is necessary to add a new level. */ + su2double InitResidual; /*!< \brief Initial value of the residual to evaluate the convergence level. */ + +public: + + /*! + * \brief Constructor of the class. + */ + CIntegration(CConfig *config); + + /*! + * \brief Destructor of the class. + */ + virtual ~CIntegration(void); + + /*! + * \brief Do the space integration of the numerical system. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] solver - Description of the numerical method. + * \param[in] config - Definition of the particular problem. + * \param[in] iMesh - Index of the mesh in multigrid computations. + * \param[in] iRKStep - Current step of the Runge-Kutta iteration. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + */ + void Space_Integration(CGeometry *geometry, CSolver **solver_container, CNumerics **numerics, CConfig *config, + unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem); + + /*! + * \brief Do the time integration (explicit or implicit) of the numerical system. + * \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. + * \param[in] iRKStep - Current step of the Runge-Kutta iteration. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] Iteration - Current iteration. + */ + void Time_Integration(CGeometry *geometry, CSolver **solver_container, CConfig *config, + unsigned short iRKStep, unsigned short RunTime_EqSystem, unsigned long Iteration); + + /*! + * \brief Initialize the adjoint solution using the primal problem. + * \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. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] Iteration - Current iteration. + */ + void Adjoint_Setup(CGeometry ***geometry, CSolver ****solver_container, CConfig **config, + unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone); + + /*! + * \brief Do the convergence analisys to determine if the code must stop the execution. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] Iteration - Current iteration. + * \param[in] monitor - Objective function that is use to study its convergence. + */ + void Convergence_Monitoring(CGeometry *geometry, CConfig *config, + unsigned long Iteration, su2double monitor, unsigned short iMesh); + + /*! + * \brief Do the convergence analysis to determine if the FSI problem has converged on the structural side. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] Iteration - Current iteration. + * \param[in] monitor - Objective function that is use to study its convergence. + */ + void Convergence_Monitoring_FSI(CGeometry *fea_geometry, CConfig *fea_config, CSolver *fea_solver, unsigned long iFSIIter); + + + /*! + * \brief Get the value of the convergence. + * \return Level of convergence of the solution. + */ + su2double GetCauchy_Value(void); + + /*! + * \brief Get the indicator of the convergence for the direct, adjoint and linearized problem. + * \return TRUE means that the convergence criteria is satisfied; + * otherwise FALSE. + */ + bool GetConvergence(void); + + /*! + * \brief Get the indicator of the convergence for the Fluid-Structure Interaction problem. + * \return TRUE means that the convergence criteria is satisfied; + * otherwise FALSE. + */ + bool GetConvergence_FSI(void); + + /*! + * \brief Set the indicator of the convergence. + * \param[in] value - TRUE means that the convergence criteria is satisfied; + * otherwise FALSE. + */ + void SetConvergence(bool value); + + + /*! + * \brief Set the indicator of the convergence for FSI. + * \param[in] valueFSI - TRUE means that the convergence criteria for FSI is satisfied; + * otherwise FALSE. + */ + void SetConvergence_FSI(bool valueFSI); + + + /*! + * \brief Get the indicator of the convergence for the full multigrid problem. + * \return TRUE means that the convergence criteria is satisfied; + * otherwise FALSE. + */ + bool GetConvergence_FullMG(void); + + /*! + * \brief Save the solution, and volume at different time steps. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solution - Flow solution. + * \param[in] config - Definition of the particular problem. + */ + void SetDualTime_Solver(CGeometry *geometry, CSolver *solver, CConfig *config, unsigned short iMesh); + + /*! + * \brief Save the structural solution at different time steps. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solution - Structural solution. + * \param[in] config - Definition of the particular problem. + */ + void SetStructural_Solver(CGeometry *geometry, CSolver *solver, CConfig *config, unsigned short iMesh); + + /*! + * \brief A virtual member. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] Iteration - Current iteration. + */ + virtual void MultiGrid_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, + CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone); + + /*! + * \brief A virtual member. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] iMesh - Index of the mesh in multigrid computations. + * \param[in] mu - Variable for controlling the kind of multigrid algorithm. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] Iteration - Current iteration. + */ + virtual void MultiGrid_Cycle(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, + CConfig **config, unsigned short iMesh, unsigned short mu, unsigned short RunTime_EqSystem, + unsigned long Iteration, unsigned short iZone); + + /*! + * \brief A virtual member. + * \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. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] Iteration - Current iteration. + * \param[in] monitor - value of the non-dimensional parameters for monitoring the convergence. + */ + virtual void NonDimensional_Parameters(CGeometry **geometry, CSolver ***solver_container, CNumerics ****numerics_container, + CConfig *config, unsigned short FinestMesh, unsigned short RunTime_EqSystem, unsigned long Iteration, + su2double *monitor); + + /*! + * \brief A virtual member. + * \param[out] sol_fine - Pointer to the solution on the fine grid. + * \param[in] geo_fine - Geometrical definition of the fine grid. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetProlongated_Correction(CSolver *sol_fine, CGeometry *geo_fine, CConfig *config, unsigned short iMesh); + + /*! + * \brief A virtual member. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[out] sol_fine - Pointer to the solution on the fine grid. + * \param[in] sol_coarse - Pointer to the solution on the coarse grid. + * \param[in] geo_fine - Geometrical definition of the fine grid. + * \param[in] geo_coarse - Geometrical definition of the coarse grid. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetProlongated_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, + CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); + + /*! + * \brief A virtual member. + * \param[in] sol_fine - Pointer to the solution on the fine grid. + * \param[out] sol_coarse - Pointer to the solution on the coarse grid. + * \param[in] geo_fine - Geometrical definition of the fine grid. + * \param[in] geo_coarse - Geometrical definition of the coarse grid. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetRestricted_Residual(CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, + CGeometry *geo_coarse, CConfig *config); + + /*! + * \brief A virtual member. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] sol_fine - Pointer to the solution on the fine grid. + * \param[out] sol_coarse - Pointer to the solution on the coarse grid. + * \param[in] geo_fine - Geometrical definition of the fine grid. + * \param[in] geo_coarse - Geometrical definition of the coarse grid. + * \param[in] config - Definition of the particular problem. + * \param[in] iMesh - Index of the mesh in multigrid computations. + * \param[in] InclSharedDomain - Include the shared domain in the interpolation. + */ + virtual void SetRestricted_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); + + /*! + * \brief A virtual member. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] sol_fine - Pointer to the solution on the fine grid. + * \param[out] sol_coarse - Pointer to the solution on the coarse grid. + * \param[in] geo_fine - Geometrical definition of the fine grid. + * \param[in] geo_coarse - Geometrical definition of the coarse grid. + * \param[in] config - Definition of the particular problem. + * \param[in] iMesh - Index of the mesh in multigrid computations. + * \param[in] InclSharedDomain - Include the shared domain in the interpolation. + */ + virtual void SetRestricted_EddyVisc(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); + + /*! + * \brief A virtual member. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] sol_fine - Pointer to the solution on the fine grid. + * \param[out] sol_coarse - Pointer to the solution on the coarse grid. + * \param[in] geo_fine - Geometrical definition of the fine grid. + * \param[in] geo_coarse - Geometrical definition of the coarse grid. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetRestricted_Gradient(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, + CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); + + /*! + * \brief A virtual member. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] flow - Flow solution. + */ + virtual void SetResidual_Term(CGeometry *geometry, CSolver *flow); + + /*! + * \brief A virtual member. + * \param[in] sol_fine - Pointer to the solution on the fine grid. + * \param[in] sol_coarse - Pointer to the solution on the coarse grid. + * \param[in] geo_fine - Geometrical definition of the fine grid. + * \param[in] geo_coarse - Geometrical definition of the coarse grid. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetForcing_Term(CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, + CConfig *config, unsigned short iMesh); + + /*! + * \brief A virtual member. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] Iteration - Current iteration. + */ + virtual void SingleGrid_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, + CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone); + + /*! + * \brief A virtual member. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] Iteration - Current iteration. + */ + virtual void Structural_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, + CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone); + + + /*! + * \brief A virtual member. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] iMesh - Index of the mesh in multigrid computations. + */ + virtual void SetPotential_Solver(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, + CConfig **config, unsigned short RunTime_EqSystem, unsigned short iMesh, unsigned short iZone); + + /*! + * \brief A virtual member. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] solution - Container vector with all the solutions on the finest grid. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] val_nSmooth - Number of smoothing iterations. + * \param[in] val_smooth_coeff - Relaxation factor. + * \param[in] config - Definition of the particular problem. + */ + virtual void Smooth_Solution(unsigned short RunTime_EqSystem, CSolver *solver, CGeometry *geometry, + unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config); + +}; + +/*! + * \class CMultiGridIntegration + * \brief Class for doing the numerical integration using a multigrid method. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CMultiGridIntegration : public CIntegration { +protected: + +public: + + /*! + * \brief Constructor of the class. + * \param[in] config - Definition of the particular problem. + */ + CMultiGridIntegration(CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CMultiGridIntegration(void); + + /*! + * \brief This subroutine calls the MultiGrid_Cycle and also prepare the multigrid levels and the monitoring. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] Iteration - Current iteration. + */ + void MultiGrid_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, + CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone); + + /*! + * \brief Perform a Full-Approximation Storage (FAS) Multigrid. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] iMesh - Index of the mesh in multigrid computations. + * \param[in] mu - Variable for controlling the kind of multigrid algorithm. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] Iteration - Current iteration. + */ + void MultiGrid_Cycle(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, + CConfig **config, unsigned short iMesh, unsigned short mu, unsigned short RunTime_EqSystem, + unsigned long Iteration, unsigned short iZone); + + /*! + * \brief Compute the non-dimensional parameters. + * \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. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] Iteration - Current iteration. + * \param[in] monitor - value of the non-dimensional parameters for monitoring the convergence. + */ + void NonDimensional_Parameters(CGeometry **geometry, CSolver ***solver_container, CNumerics ****numerics_container, + CConfig *config, unsigned short FinestMesh, unsigned short RunTime_EqSystem, unsigned long Iteration, + su2double *monitor); + + /*! + * \brief Compute the fine solution from a coarse solution. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[out] sol_fine - Pointer to the solution on the fine grid. + * \param[in] sol_coarse - Pointer to the solution on the coarse grid. + * \param[in] geo_fine - Geometrical definition of the fine grid. + * \param[in] geo_coarse - Geometrical definition of the coarse grid. + * \param[in] config - Definition of the particular problem. + */ + void SetProlongated_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, + CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); + + /*! + * \brief Compute the fine grid correction from the coarse solution. + * \param[out] sol_fine - Pointer to the solution on the fine grid. + * \param[in] sol_coarse - Pointer to the solution on the coarse grid. + * \param[in] geo_fine - Geometrical definition of the fine grid. + * \param[in] geo_coarse - Geometrical definition of the coarse grid. + * \param[in] config - Definition of the particular problem. + */ + void GetProlongated_Correction(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, + CGeometry *geo_coarse, CConfig *config); + + /*! + * \brief Do an implicit smoothing of the prolongated correction. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] solution - Container vector with all the solutions on the finest grid. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] val_nSmooth - Number of smoothing iterations. + * \param[in] val_smooth_coeff - Relaxation factor. + * \param[in] config - Definition of the particular problem. + */ + void SmoothProlongated_Correction(unsigned short RunTime_EqSystem, CSolver *solver, CGeometry *geometry, + unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config); + + /*! + * \brief Do an implicit smoothing of the solution. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] solution - Container vector with all the solutions on the finest grid. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] val_nSmooth - Number of smoothing iterations. + * \param[in] val_smooth_coeff - Relaxation factor. + * \param[in] config - Definition of the particular problem. + */ + void Smooth_Solution(unsigned short RunTime_EqSystem, CSolver *solver, CGeometry *geometry, + unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config); + + /*! + * \brief Set the value of the corrected fine grid solution. + * \param[out] sol_fine - Pointer to the solution on the fine grid. + * \param[in] geo_fine - Geometrical definition of the fine grid. + * \param[in] config - Definition of the particular problem. + */ + void SetProlongated_Correction(CSolver *sol_fine, CGeometry *geo_fine, CConfig *config, unsigned short iMesh); + + /*! + * \brief Compute truncation error in the coarse grid using the fine grid information. + * \param[in] sol_fine - Pointer to the solution on the fine grid. + * \param[out] sol_coarse - Pointer to the solution on the coarse grid. + * \param[in] geo_fine - Geometrical definition of the fine grid. + * \param[in] geo_coarse - Geometrical definition of the coarse grid. + * \param[in] config - Definition of the particular problem. + */ + void SetRestricted_Residual(CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, + CGeometry *geo_coarse, CConfig *config); + + /*! + * \brief Restrict solution from fine grid to a coarse grid. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] sol_fine - Pointer to the solution on the fine grid. + * \param[out] sol_coarse - Pointer to the solution on the coarse grid. + * \param[in] geo_fine - Geometrical definition of the fine grid. + * \param[in] geo_coarse - Geometrical definition of the coarse grid. + * \param[in] config - Definition of the particular problem. + * \param[in] iMesh - Index of the mesh in multigrid computations. + * \param[in] InclSharedDomain - Include the shared domain in the interpolation. + */ + void SetRestricted_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); + + /*! + * \brief Compute the gradient in coarse grid using the fine grid information. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] sol_fine - Pointer to the solution on the fine grid. + * \param[out] sol_coarse - Pointer to the solution on the coarse grid. + * \param[in] geo_fine - Geometrical definition of the fine grid. + * \param[in] geo_coarse - Geometrical definition of the coarse grid. + * \param[in] config - Definition of the particular problem. + */ + void SetRestricted_Gradient(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, + CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); + + /*! + * \brief Add the truncation error to the residual. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] flow - Flow solution. + */ + void SetResidual_Term(CGeometry *geometry, CSolver *flow); + + /*! + * \brief Compute the forcing term. + * \param[in] sol_fine - Pointer to the solution on the fine grid. + * \param[in] sol_coarse - Pointer to the solution on the coarse grid. + * \param[in] geo_fine - Geometrical definition of the fine grid. + * \param[in] geo_coarse - Geometrical definition of the coarse grid. + * \param[in] config - Definition of the particular problem. + */ + void SetForcing_Term(CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, + CConfig *config, unsigned short iMesh); +}; + +/*! + * \class CSingleGridIntegration + * \brief Class for doing the numerical integration of the turbulence model. + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CSingleGridIntegration : public CIntegration { +public: + + /*! + * \brief Constructor of the class. + * \param[in] config - Definition of the particular problem. + */ + CSingleGridIntegration(CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSingleGridIntegration(void); + + /*! + * \brief Do the numerical integration (implicit) of the turbulence solver. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] Iteration - Current iteration. + */ + void SingleGrid_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, + CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone); + + /*! + * \brief Restrict solution from fine grid to a coarse grid. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] sol_fine - Pointer to the solution on the fine grid. + * \param[out] sol_coarse - Pointer to the solution on the coarse grid. + * \param[in] geo_fine - Geometrical definition of the fine grid. + * \param[in] geo_coarse - Geometrical definition of the coarse grid. + * \param[in] config - Definition of the particular problem. + * \param[in] iMesh - Index of the mesh in multigrid computations. + * \param[in] InclSharedDomain - Include the shared domain in the interpolation. + */ + void SetRestricted_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); + + /*! + * \brief Restrict solution from fine grid to a coarse grid. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] sol_fine - Pointer to the solution on the fine grid. + * \param[out] sol_coarse - Pointer to the solution on the coarse grid. + * \param[in] geo_fine - Geometrical definition of the fine grid. + * \param[in] geo_coarse - Geometrical definition of the coarse grid. + * \param[in] config - Definition of the particular problem. + * \param[in] iMesh - Index of the mesh in multigrid computations. + * \param[in] InclSharedDomain - Include the shared domain in the interpolation. + */ + void SetRestricted_EddyVisc(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config); + +}; + + +/*! + * \class CStructuralIntegration + * \brief Class for doing the numerical integration of the structural model. + * \author R. Sanchez. + * \version 4.0.1 "Cardinal" + */ +class CStructuralIntegration : public CIntegration { +public: + + /*! + * \brief Constructor of the class. + * \param[in] config - Definition of the particular problem. + */ + CStructuralIntegration(CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CStructuralIntegration(void); + + /*! + * \brief Do the numerical integration (implicit) of the structural solver. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] RunTime_EqSystem - System of equations which is going to be solved. + * \param[in] Iteration - Current iteration. + */ + void Structural_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, + CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone); + +}; + +#include "integration_structure.inl" diff --git a/SU2_CFD/include/integration_structure.inl b/SU2_CFD/include/integration_structure.inl index 1202e1e24fa..3f998c8c0ca 100644 --- a/SU2_CFD/include/integration_structure.inl +++ b/SU2_CFD/include/integration_structure.inl @@ -1,86 +1,86 @@ -/*! - * \file integration_structure.inl - * \brief In-Line subroutines of the integration_structure.hpp file. - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -inline su2double CIntegration::GetCauchy_Value(void) { return Cauchy_Value; } - -inline bool CIntegration::GetConvergence(void) { return Convergence; } - -inline bool CIntegration::GetConvergence_FSI(void) { return Convergence_FSI; } - -inline bool CIntegration::GetConvergence_FullMG(void) { return Convergence_FullMG; } - -inline void CIntegration::SetConvergence(bool value) { Convergence = value; } - -inline void CIntegration::SetConvergence_FSI(bool valueFSI) { Convergence_FSI = valueFSI; } - -inline void CIntegration::MultiGrid_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, - CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone) { } - -inline void CIntegration::MultiGrid_Cycle(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, - CConfig **config, unsigned short iMesh, unsigned short mu, unsigned short RunTime_EqSystem, - unsigned long Iteration, unsigned short iZone) { } - -inline void CIntegration::NonDimensional_Parameters(CGeometry **geometry, CSolver ***solver_container, CNumerics ****numerics_container, - CConfig *config, unsigned short FinestMesh, unsigned short RunTime_EqSystem, unsigned long Iteration, - su2double *monitor) { } - -inline void CIntegration::SetProlongated_Correction(CSolver *sol_fine, CGeometry *geo_fine, CConfig *config, unsigned short iMesh) { } - -inline void CIntegration::SetProlongated_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, - CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { } - -inline void CIntegration::SetRestricted_Residual(CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, - CGeometry *geo_coarse, CConfig *config) { } - -inline void CIntegration::SetRestricted_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { } - -inline void CIntegration::SetRestricted_EddyVisc(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { } - -inline void CIntegration::SetRestricted_Gradient(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, - CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { } - -inline void CIntegration::SetResidual_Term(CGeometry *geometry, CSolver *flow) { } - -inline void CIntegration::SetForcing_Term(CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, - CConfig *config, unsigned short iMesh) { } - -inline void CIntegration::SingleGrid_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, - CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone) { } - -inline void CIntegration::Structural_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, - CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone) { } - -inline void CIntegration::SetPotential_Solver(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, - CConfig **config, unsigned short RunTime_EqSystem, unsigned short iMesh, unsigned short iZone) { } - -inline void CIntegration::Smooth_Solution(unsigned short RunTime_EqSystem, CSolver *solver, CGeometry *geometry, unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config) { } +/*! + * \file integration_structure.inl + * \brief In-Line subroutines of the integration_structure.hpp file. + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +inline su2double CIntegration::GetCauchy_Value(void) { return Cauchy_Value; } + +inline bool CIntegration::GetConvergence(void) { return Convergence; } + +inline bool CIntegration::GetConvergence_FSI(void) { return Convergence_FSI; } + +inline bool CIntegration::GetConvergence_FullMG(void) { return Convergence_FullMG; } + +inline void CIntegration::SetConvergence(bool value) { Convergence = value; } + +inline void CIntegration::SetConvergence_FSI(bool valueFSI) { Convergence_FSI = valueFSI; } + +inline void CIntegration::MultiGrid_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, + CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone) { } + +inline void CIntegration::MultiGrid_Cycle(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, + CConfig **config, unsigned short iMesh, unsigned short mu, unsigned short RunTime_EqSystem, + unsigned long Iteration, unsigned short iZone) { } + +inline void CIntegration::NonDimensional_Parameters(CGeometry **geometry, CSolver ***solver_container, CNumerics ****numerics_container, + CConfig *config, unsigned short FinestMesh, unsigned short RunTime_EqSystem, unsigned long Iteration, + su2double *monitor) { } + +inline void CIntegration::SetProlongated_Correction(CSolver *sol_fine, CGeometry *geo_fine, CConfig *config, unsigned short iMesh) { } + +inline void CIntegration::SetProlongated_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, + CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { } + +inline void CIntegration::SetRestricted_Residual(CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, + CGeometry *geo_coarse, CConfig *config) { } + +inline void CIntegration::SetRestricted_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { } + +inline void CIntegration::SetRestricted_EddyVisc(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { } + +inline void CIntegration::SetRestricted_Gradient(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, + CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { } + +inline void CIntegration::SetResidual_Term(CGeometry *geometry, CSolver *flow) { } + +inline void CIntegration::SetForcing_Term(CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, + CConfig *config, unsigned short iMesh) { } + +inline void CIntegration::SingleGrid_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, + CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone) { } + +inline void CIntegration::Structural_Iteration(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, + CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone) { } + +inline void CIntegration::SetPotential_Solver(CGeometry ***geometry, CSolver ****solver_container, CNumerics *****numerics_container, + CConfig **config, unsigned short RunTime_EqSystem, unsigned short iMesh, unsigned short iZone) { } + +inline void CIntegration::Smooth_Solution(unsigned short RunTime_EqSystem, CSolver *solver, CGeometry *geometry, unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config) { } diff --git a/SU2_CFD/include/numerics_structure.hpp b/SU2_CFD/include/numerics_structure.hpp index b83cf351c32..221de294278 100644 --- a/SU2_CFD/include/numerics_structure.hpp +++ b/SU2_CFD/include/numerics_structure.hpp @@ -1,4948 +1,4948 @@ -/*! - * \file numerics_structure.hpp - * \brief Headers of the main subroutines for the dumerical definition of the problem. - * The subroutines and functions are in the numerics_structure.cpp, - * numerics_convective.cpp, numerics_viscous.cpp, and - * numerics_source.cpp files. - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -#include "../../Common/include/mpi_structure.hpp" - -#include -#include -#include -#include - -#include "../../Common/include/config_structure.hpp" -#include "../../Common/include/gauss_structure.hpp" -#include "../../Common/include/element_structure.hpp" -#include "variable_structure.hpp" - -using namespace std; - -/*! - * \class CNumerics - * \brief Class for defining the numerical methods. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CNumerics { -protected: - unsigned short nDim, nVar; /*!< \brief Number of dimensions and variables. */ - su2double Gamma; /*!< \brief Fluid's Gamma constant (ratio of specific heats). */ - su2double Gamma_Minus_One; /*!< \brief Fluids's Gamma - 1.0 . */ - su2double Gas_Constant; /*!< \brief Gas constant. */ - su2double *Vector; /*!< \brief Auxiliary vector. */ - su2double *Enthalpy_formation; - su2double Prandtl_Lam; /*!< \brief Laminar Prandtl's number. */ - su2double Prandtl_Turb; /*!< \brief Turbulent Prandtl's number. */ - -public: - - su2double - **Flux_Tensor, /*!< \brief Flux tensor (used for viscous and inviscid purposes. */ - *Proj_Flux_Tensor; /*!< \brief Flux tensor projected in a direction. */ - - su2double - **tau, /*!< \brief Viscous stress tensor. */ - **delta; /*!< \brief Identity matrix. */ - su2double **dVdU; /*!< \brief Transformation matrix from primitive variables, V, to conserved, U. */ - su2double - *Diffusion_Coeff_i, /*!< \brief Species diffusion coefficients at point i. */ - *Diffusion_Coeff_j; /*!< \brief Species diffusion coefficients at point j. */ - su2double Laminar_Viscosity_i, /*!< \brief Laminar viscosity at point i. */ - Laminar_Viscosity_j, /*!< \brief Laminar viscosity at point j. */ - Laminar_Viscosity_id, /*!< \brief Variation of laminar viscosity at point i. */ - Laminar_Viscosity_jd; /*!< \brief Variation of laminar viscosity at point j. */ - su2double Thermal_Conductivity_i, /*!< \brief Thermal conductivity at point i. */ - Thermal_Conductivity_j, /*!< \brief Thermal conductivity at point j. */ - Thermal_Conductivity_ve_i, /*!< \brief Thermal conductivity at point i. */ - Thermal_Conductivity_ve_j; /*!< \brief Thermal conductivity at point j. */ - su2double Cp_i, /*!< \brief Cp at point i. */ - Cp_j; /*!< \brief Cp at point j. */ - su2double *Theta_v; /*!< \brief Characteristic vibrational temperature */ - su2double Eddy_Viscosity_i, /*!< \brief Eddy viscosity at point i. */ - Eddy_Viscosity_j; /*!< \brief Eddy viscosity at point j. */ - su2double turb_ke_i, /*!< \brief Turbulent kinetic energy at point i. */ - turb_ke_j; /*!< \brief Turbulent kinetic energy at point j. */ - su2double Pressure_i, /*!< \brief Pressure at point i. */ - Pressure_j; /*!< \brief Pressure at point j. */ - su2double GravityForce_i, /*!< \brief Gravity force at point i. */ - GravityForce_j; /*!< \brief Gravity force at point j. */ - su2double Density_i, /*!< \brief Density at point i. */ - Density_j; /*!< \brief Density at point j. */ - su2double DensityInc_i, /*!< \brief Incompressible density at point i. */ - DensityInc_j; /*!< \brief Incompressible density at point j. */ - su2double BetaInc2_i, /*!< \brief Beta incompressible at point i. */ - BetaInc2_j; /*!< \brief Beta incompressible at point j. */ - su2double Lambda_i, /*!< \brief Spectral radius at point i. */ - Lambda_j; /*!< \brief Spectral radius at point j. */ - su2double LambdaComb_i, /*!< \brief Spectral radius at point i. */ - LambdaComb_j; /*!< \brief Spectral radius at point j. */ - su2double SoundSpeed_i, /*!< \brief Sound speed at point i. */ - SoundSpeed_j; /*!< \brief Sound speed at point j. */ - su2double Enthalpy_i, /*!< \brief Enthalpy at point i. */ - Enthalpy_j; /*!< \brief Enthalpy at point j. */ - su2double dist_i, /*!< \brief Distance of point i to the nearest wall. */ - dist_j; /*!< \brief Distance of point j to the nearest wall. */ - su2double Temp_i, /*!< \brief Temperature at point i. */ - Temp_j; /*!< \brief Temperature at point j. */ - su2double *Temp_tr_i, /*!< \brief Temperature transl-rot at point i. */ - *Temp_tr_j;/*!< \brief Temperature transl-rot at point j. */ - su2double *Temp_vib_i, /*!< \brief Temperature vibrational at point i. */ - *Temp_vib_j;/*!< \brief Temperature vibrational at point j. */ - su2double *Und_Lapl_i, /*!< \brief Undivided laplacians at point i. */ - *Und_Lapl_j; /*!< \brief Undivided laplacians at point j. */ - su2double Sensor_i, /*!< \brief Pressure sensor at point i. */ - Sensor_j; /*!< \brief Pressure sensor at point j. */ - su2double *GridVel_i, /*!< \brief Grid velocity at point i. */ - *GridVel_j; /*!< \brief Grid velocity at point j. */ - su2double *U_i, /*!< \brief Vector of conservative variables at point i. */ - *U_id, /*!< \brief Vector of derivative of conservative variables at point i. */ - *UZeroOrder_i, /*!< \brief Vector of conservative variables at point i without reconstruction. */ - *U_j, /*!< \brief Vector of conservative variables at point j. */ - *UZeroOrder_j, /*!< \brief Vector of conservative variables at point j without reconstruction. */ - *U_jd, /*!< \brief Vector of derivative of conservative variables at point j. */ - *U_0, /*!< \brief Vector of conservative variables at node 0. */ - *U_1, /*!< \brief Vector of conservative variables at node 1. */ - *U_2, /*!< \brief Vector of conservative variables at node 2. */ - *U_3; /*!< \brief Vector of conservative variables at node 3. */ - su2double *V_i, /*!< \brief Vector of primitive variables at point i. */ - *V_j; /*!< \brief Vector of primitive variables at point j. */ - su2double *S_i, /*!< \brief Vector of secondary variables at point i. */ - *S_j; /*!< \brief Vector of secondary variables at point j. */ - su2double *Psi_i, /*!< \brief Vector of adjoint variables at point i. */ - *Psi_j; /*!< \brief Vector of adjoint variables at point j. */ - su2double *DeltaU_i, /*!< \brief Vector of linearized variables at point i. */ - *DeltaU_j; /*!< \brief Vector of linearized variables at point j. */ - su2double *TurbVar_i, /*!< \brief Vector of turbulent variables at point i. */ - *TurbVar_id, /*!< \brief Vector of derivative of turbulent variables at point i. */ - *TurbVar_j, /*!< \brief Vector of turbulent variables at point j. */ - *TurbVar_jd; /*!< \brief Vector of derivative of turbulent variables at point j. */ - su2double *TransVar_i, /*!< \brief Vector of turbulent variables at point i. */ - *TransVar_j; /*!< \brief Vector of turbulent variables at point j. */ - su2double *LevelSetVar_i, /*!< \brief Vector of turbulent variables at point i. */ - *LevelSetVar_j; /*!< \brief Vector of turbulent variables at point j. */ - su2double *TurbPsi_i, /*!< \brief Vector of adjoint turbulent variables at point i. */ - *TurbPsi_j; /*!< \brief Vector of adjoint turbulent variables at point j. */ - su2double **ConsVar_Grad_i, /*!< \brief Gradient of conservative variables at point i. */ - **ConsVar_Grad_j, /*!< \brief Gradient of conservative variables at point j. */ - **ConsVar_Grad_0, /*!< \brief Gradient of conservative variables at point 0. */ - **ConsVar_Grad_1, /*!< \brief Gradient of conservative variables at point 1. */ - **ConsVar_Grad_2, /*!< \brief Gradient of conservative variables at point 2. */ - **ConsVar_Grad_3, /*!< \brief Gradient of conservative variables at point 3. */ - **ConsVar_Grad; /*!< \brief Gradient of conservative variables which is a scalar. */ - su2double **PrimVar_Grad_i, /*!< \brief Gradient of primitive variables at point i. */ - **PrimVar_Grad_j; /*!< \brief Gradient of primitive variables at point j. */ - su2double *PrimVar_Lim_i, /*!< \brief Limiter of primitive variables at point i. */ - *PrimVar_Lim_j; /*!< \brief Limiter of primitive variables at point j. */ - su2double *PsiVar_Lim_i, /*!< \brief Limiter of adjoint variables at point i. */ - *PsiVar_Lim_j; /*!< \brief Limiter of adjoint variables at point j. */ - su2double **PsiVar_Grad_i, /*!< \brief Gradient of adjoint variables at point i. */ - **PsiVar_Grad_j; /*!< \brief Gradient of adjoint variables at point j. */ - su2double **TurbVar_Grad_i, /*!< \brief Gradient of turbulent variables at point i. */ - **TurbVar_Grad_j; /*!< \brief Gradient of turbulent variables at point j. */ - su2double **TransVar_Grad_i, /*!< \brief Gradient of turbulent variables at point i. */ - **TransVar_Grad_j; /*!< \brief Gradient of turbulent variables at point j. */ - su2double **LevelSetVar_Grad_i, /*!< \brief Gradient of level set variables at point i. */ - **LevelSetVar_Grad_j; /*!< \brief Gradient of level set variables at point j. */ - su2double **TurbPsi_Grad_i, /*!< \brief Gradient of adjoint turbulent variables at point i. */ - **TurbPsi_Grad_j; /*!< \brief Gradient of adjoint turbulent variables at point j. */ - su2double *AuxVar_Grad_i, /*!< \brief Gradient of an auxiliary variable at point i. */ - *AuxVar_Grad_j; /*!< \brief Gradient of an auxiliary variable at point i. */ - su2double *Coord_i, /*!< \brief Cartesians coordinates of point i. */ - *Coord_j, /*!< \brief Cartesians coordinates of point j. */ - *Coord_0, /*!< \brief Cartesians coordinates of point 0 (Galerkin method, triangle). */ - *Coord_1, /*!< \brief Cartesians coordinates of point 1 (Galerkin method, tetrahedra). */ - *Coord_2, /*!< \brief Cartesians coordinates of point 2 (Galerkin method, triangle). */ - *Coord_3; /*!< \brief Cartesians coordinates of point 3 (Galerkin method, tetrahedra). */ - unsigned short Neighbor_i, /*!< \brief Number of neighbors of the point i. */ - Neighbor_j; /*!< \brief Number of neighbors of the point j. */ - su2double *Normal, /*!< \brief Normal vector, it norm is the area of the face. */ - *UnitNormal, /*!< \brief Unitary normal vector. */ - *UnitNormald; /*!< \brief derivatve of unitary normal vector. */ - su2double TimeStep, /*!< \brief Time step useful in dual time method. */ - Area, /*!< \brief Area of the face i-j. */ - Volume; /*!< \brief Volume of the control volume around point i. */ - su2double Volume_n, /*!< \brief Volume of the control volume at time n. */ - Volume_nM1, /*!< \brief Volume of the control volume at time n-1. */ - Volume_nP1; /*!< \brief Volume of the control volume at time n+1. */ - su2double *U_n, /*!< \brief Vector of conservative variables at time n. */ - *U_nM1, /*!< \brief Vector of conservative variables at time n-1. */ - *U_nP1; /*!< \brief Vector of conservative variables at time n+1. */ - su2double vel2_inf; /*!< \brief value of the square of freestream speed. */ - su2double *WindGust_i, /*!< \brief Wind gust at point i. */ - *WindGust_j; /*!< \brief Wind gust at point j. */ - su2double *WindGustDer_i, /*!< \brief Wind gust derivatives at point i. */ - *WindGustDer_j; /*!< \brief Wind gust derivatives at point j. */ - su2double *Vorticity_i, *Vorticity_j; /*!< \brief Vorticity. */ - su2double StrainMag_i, StrainMag_j; /*!< \brief Strain rate magnitude. */ - - su2double *l, *m; - su2double *dPdU_i, *dPdU_j; - su2double *dTdU_i, *dTdU_j; - su2double *dTvedU_i, *dTvedU_j; - su2double *Ys, **dFdYj, **dFdYi, *sumdFdYih, *sumdFdYjh, *sumdFdYieve, *sumdFdYjeve; - unsigned short RHOS_INDEX, T_INDEX, TVE_INDEX, VEL_INDEX, P_INDEX, - RHO_INDEX, H_INDEX, A_INDEX, RHOCVTR_INDEX, RHOCVVE_INDEX; - CVariable *var; - - /*! - * \brief Constructor of the class. - */ - CNumerics(void); - - /*! - * \overload - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CNumerics(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - virtual ~CNumerics(void); - - /*! - * \brief Compute the determinant of a 3 by 3 matrix. - * \param[in] val_matrix 3 by 3 matrix. - * \result Determinant of the matrix - */ - su2double Determinant_3x3(su2double A00, su2double A01, su2double A02, - su2double A10, su2double A11, su2double A12, - su2double A20, su2double A21, su2double A22); - - /*! - * \brief Set the solution at different times. - * \param[in] val_u_nM1 Conservative solution at time n-1. - * \param[in] val_u_n Conservative solution at time n. - * \param[in] val_u_nP1 Conservative solution at time n+1. - */ - void SetPastSol(su2double *val_u_nM1, su2double *val_u_n, su2double *val_u_nP1); - - /*! - * \brief Set the control volume at different times. - * \param[in] val_volume_nM1 - Control volume at time n-1. - * \param[in] val_volume_n - Control volume at time n. - * \param[in] val_volume_nP1 - Control volume at time n+1. - */ - void SetPastVolume(su2double val_volume_nM1, su2double val_volume_n, su2double val_volume_nP1); - - /*! - * \brief Set the time step. - * \param[in] val_timestep - Value of the time step. - */ - void SetTimeStep(su2double val_timestep); - - /*! - * \brief Get the Preconditioning Beta. - * \return val_Beta - Value of the low Mach Preconditioner. - */ - virtual su2double GetPrecond_Beta(); - - /*! - * \brief Set the freestream velocity square. - * \param[in] SetVelocity2_Inf - Value of the square of the freestream velocity. - */ - void SetVelocity2_Inf(su2double val_velocity2); - - /*! - * \brief Set the value of the vorticity - * \param[in] val_vorticity - Value of the vorticity. - */ - void SetVorticity(su2double *val_vorticity_i, su2double *val_vorticity_j); - - /*! - * \brief Set the value of the rate of strain magnitude. - * \param[in] val_StrainMag_i - Value of the magnitude of rate of strain at point i. - * \param[in] val_StrainMag_j - Value of the magnitude of rate of strain at point j. - */ - void SetStrainMag(su2double val_strainmag_i, su2double val_strainmag_j); - - /*! - * \brief Set the value of the conservative variables. - * \param[in] val_u_i - Value of the conservative variable at point i. - * \param[in] val_u_j - Value of the conservative variable at point j. - */ - void SetConservative(su2double *val_u_i, su2double *val_u_j); - - /*! - * \brief Set the value of the conservative variables withour reconstruction. - * \param[in] val_u_i - Value of the conservative variable at point i. - * \param[in] val_u_j - Value of the conservative variable at point j. - */ - void SetConservative_ZeroOrder(su2double *val_u_i, su2double *val_u_j); - - /*! - * \brief Set the value of the primitive variables. - * \param[in] val_v_i - Value of the primitive variable at point i. - * \param[in] val_v_j - Value of the primitive variable at point j. - */ - void SetPrimitive(su2double *val_v_i, su2double *val_v_j); - - /*! - * \brief Set the value of the primitive variables. - * \param[in] val_v_i - Value of the primitive variable at point i. - * \param[in] val_v_j - Value of the primitive variable at point j. - */ - void SetSecondary(su2double *val_s_i, su2double *val_s_j); - - /*! - * \brief Set the value of the conservative variables. - * \param[in] val_u_0 - Value of the conservative variable at point 0. - * \param[in] val_u_1 - Value of the conservative variable at point 1. - * \param[in] val_u_2 - Value of the conservative variable at point 2. - */ - void SetConservative(su2double *val_u_0, su2double *val_u_1, su2double *val_u_2); - - /*! - * \brief Set the value of the conservative variables. - * \param[in] val_u_0 - Value of the conservative variable at point 0. - * \param[in] val_u_1 - Value of the conservative variable at point 1. - * \param[in] val_u_2 - Value of the conservative variable at point 2. - * \param[in] val_u_3 - Value of the conservative variable at point 3. - */ - void SetConservative(su2double *val_u_0, su2double *val_u_1, su2double *val_u_2, su2double *val_u_3); - - /*! - * \brief Set the gradient of the conservative variables. - * \param[in] val_consvar_grad_i - Gradient of the conservative variable at point i. - * \param[in] val_consvar_grad_j - Gradient of the conservative variable at point j. - */ - void SetConsVarGradient(su2double **val_consvar_grad_i, su2double **val_consvar_grad_j); - - /*! - * \brief Set the gradient of the conservative variables. - * \param[in] val_consvar_grad_0 - Gradient of the conservative variable at point 0. - * \param[in] val_consvar_grad_1 - Gradient of the conservative variable at point 1. - * \param[in] val_consvar_grad_2 - Gradient of the conservative variable at point 2. - */ - void SetConsVarGradient(su2double **val_consvar_grad_0, - su2double **val_consvar_grad_1, - su2double **val_consvar_grad_2); - - /*! - * \brief Set the gradient of the conservative variables. - * \param[in] val_consvar_grad_0 - Gradient of the conservative variable at point 0. - * \param[in] val_consvar_grad_1 - Gradient of the conservative variable at point 1. - * \param[in] val_consvar_grad_2 - Gradient of the conservative variable at point 2. - * \param[in] val_consvar_grad_3 - Gradient of the conservative variable at point 3. - */ - void SetConsVarGradient(su2double **val_consvar_grad_0, - su2double **val_consvar_grad_1, - su2double **val_consvar_grad_2, - su2double **val_consvar_grad_3); - - /*! - * \brief Set the gradient of the conservative variables. - * \param[in] val_consvar_grad - Gradient of the conservative variable which is a scalar. - */ - void SetConsVarGradient(su2double **val_consvar_grad); - - /*! - * \brief Set the gradient of the primitive variables. - * \param[in] val_primvar_grad_i - Gradient of the primitive variable at point i. - * \param[in] val_primvar_grad_j - Gradient of the primitive variable at point j. - */ - void SetPrimVarGradient(su2double **val_primvar_grad_i, - su2double **val_primvar_grad_j); - - /*! - * \brief Set the Limiter of the primitive variables. - * \param[in] val_primvar_lim_i - Limiter of the primitive variable at point i. - * \param[in] val_primvar_lim_j - Limiter of the primitive variable at point j. - */ - void SetPrimVarLimiter(su2double *val_primvar_lim_i, - su2double *val_primvar_lim_j); - - /*! - * \brief Set the value of the adjoint variable. - * \param[in] val_psi_i - Value of the adjoint variable at point i. - * \param[in] val_psi_j - Value of the adjoint variable at point j. - */ - void SetAdjointVar(su2double *val_psi_i, su2double *val_psi_j); - - /*! - * \brief Set the gradient of the adjoint variables. - * \param[in] val_psivar_grad_i - Gradient of the adjoint variable at point i. - * \param[in] val_psivar_grad_j - Gradient of the adjoint variable at point j. - */ - void SetAdjointVarGradient(su2double **val_psivar_grad_i, su2double **val_psivar_grad_j); - - /*! - * \brief Set the limiter of the adjoint variables. - * \param[in] val_psivar_lim_i - Gradient of the adjoint variable at point i. - * \param[in] val_psivar_lim_j - Gradient of the adjoint variable at point j. - */ - void SetAdjointVarLimiter(su2double *val_psivar_lim_i, su2double *val_psivar_lim_j); - - /*! - * \brief Set the value of the turbulent variable. - * \param[in] val_turbvar_i - Value of the turbulent variable at point i. - * \param[in] val_turbvar_j - Value of the turbulent variable at point j. - */ - void SetTurbVar(su2double *val_turbvar_i, su2double *val_turbvar_j); - - /*! - * \brief Set the value of the turbulent variable. - * \param[in] val_transvar_i - Value of the turbulent variable at point i. - * \param[in] val_transvar_j - Value of the turbulent variable at point j. - */ - void SetTransVar(su2double *val_transvar_i, su2double *val_transvar_j); - - /*! - * \brief Set the gradient of the turbulent variables. - * \param[in] val_turbvar_grad_i - Gradient of the turbulent variable at point i. - * \param[in] val_turbvar_grad_j - Gradient of the turbulent variable at point j. - */ - void SetTurbVarGradient(su2double **val_turbvar_grad_i, su2double **val_turbvar_grad_j); - - /*! - * \brief Set the gradient of the turbulent variables. - * \param[in] val_turbvar_grad_i - Gradient of the turbulent variable at point i. - * \param[in] val_turbvar_grad_j - Gradient of the turbulent variable at point j. - */ - void SetTransVarGradient(su2double **val_transvar_grad_i, su2double **val_transvar_grad_j); - - /*! - * \brief Set the value of the level set variable. - * \param[in] val_levelsetvar_i - Value of the level set variable at point i. - * \param[in] val_levelsetvar_j - Value of the level set variable at point j. - */ - void SetLevelSetVar(su2double *val_levelsetvar_i, su2double *val_levelsetvar_j); - - /*! - * \brief Set the gradient of the level set variables. - * \param[in] val_levelsetvar_grad_i - Gradient of the level set variable at point i. - * \param[in] val_levelsetvar_grad_j - Gradient of the level set variable at point j. - */ - void SetLevelSetVarGradient(su2double **val_levelsetvar_grad_i, su2double **val_levelsetvar_grad_j); - - /*! - * \brief Set the value of the adjoint turbulent variable. - * \param[in] val_turbpsivar_i - Value of the adjoint turbulent variable at point i. - * \param[in] val_turbpsivar_j - Value of the adjoint turbulent variable at point j. - */ - void SetTurbAdjointVar(su2double *val_turbpsivar_i, su2double *val_turbpsivar_j); - - /*! - * \brief Set the gradient of the adjoint turbulent variables. - * \param[in] val_turbpsivar_grad_i - Gradient of the adjoint turbulent variable at point i. - * \param[in] val_turbpsivar_grad_j - Gradient of the adjoint turbulent variable at point j. - */ - void SetTurbAdjointGradient (su2double **val_turbpsivar_grad_i, su2double **val_turbpsivar_grad_j); - - /*! - * \brief Set the value of the first blending function. - * \param[in] val_F1_i - Value of the first Menter blending function at point i. - * \param[in] val_F1_j - Value of the first Menter blending function at point j. - */ - virtual void SetF1blending(su2double val_F1_i, su2double val_F1_j) {/* empty */}; - - /*! - * \brief Set the value of the second blending function. - * \param[in] val_F1_i - Value of the second Menter blending function at point i. - * \param[in] val_F1_j - Value of the second Menter blending function at point j. - */ - virtual void SetF2blending(su2double val_F1_i, su2double val_F1_j) {/* empty */}; - - /*! - * \brief Set the value of the cross diffusion for the SST model. - * \param[in] val_CDkw_i - Value of the cross diffusion at point i. - * \param[in] val_CDkw_j - Value of the cross diffusion at point j. - */ - virtual void SetCrossDiff(su2double val_CDkw_i, su2double val_CDkw_j) {/* empty */}; - - /*! - * \brief Set the gradient of the auxiliary variables. - * \param[in] val_auxvargrad_i - Gradient of the auxiliary variable at point i. - * \param[in] val_auxvargrad_j - Gradient of the auxiliary variable at point j. - */ - void SetAuxVarGrad(su2double *val_auxvargrad_i, su2double *val_auxvargrad_j); - - /*! - * \brief Set the diffusion coefficient - * \param[in] val_diffusioncoeff_i - Value of the diffusion coefficients at i. - * \param[in] val_diffusioncoeff_j - Value of the diffusion coefficients at j - */ - void SetDiffusionCoeff(su2double* val_diffusioncoeff_i, - su2double* val_diffusioncoeff_j); - - /*! - * \brief Set the laminar viscosity. - * \param[in] val_laminar_viscosity_i - Value of the laminar viscosity at point i. - * \param[in] val_laminar_viscosity_j - Value of the laminar viscosity at point j. - */ - void SetLaminarViscosity(su2double val_laminar_viscosity_i, - su2double val_laminar_viscosity_j); - - /*! - * \brief Set the thermal conductivity (translational/rotational) - * \param[in] val_thermal_conductivity_i - Value of the thermal conductivity at point i. - * \param[in] val_thermal_conductivity_j - Value of the thermal conductivity at point j. - * \param[in] iSpecies - Value of the species. - */ - void SetThermalConductivity(su2double val_thermal_conductivity_i, - su2double val_thermal_conductivity_j); - - /*! - * \brief Set the thermal conductivity (translational/rotational) - * \param[in] val_thermal_conductivity_i - Value of the thermal conductivity at point i. - * \param[in] val_thermal_conductivity_j - Value of the thermal conductivity at point j. - * \param[in] iSpecies - Value of the species. - */ - void SetThermalConductivity_ve(su2double val_thermal_conductivity_ve_i, - su2double val_thermal_conductivity_ve_j); - - /*! - * \brief Set the eddy viscosity. - * \param[in] val_eddy_viscosity_i - Value of the eddy viscosity at point i. - * \param[in] val_eddy_viscosity_j - Value of the eddy viscosity at point j. - */ - void SetEddyViscosity(su2double val_eddy_viscosity_i, - su2double val_eddy_viscosity_j); - - /*! - * \brief Set the turbulent kinetic energy. - * \param[in] val_turb_ke_i - Value of the turbulent kinetic energy at point i. - * \param[in] val_turb_ke_j - Value of the turbulent kinetic energy at point j. - */ - void SetTurbKineticEnergy(su2double val_turb_ke_i, su2double val_turb_ke_j); - - /*! - * \brief Set the value of the distance from the nearest wall. - * \param[in] val_dist_i - Value of of the distance from point i to the nearest wall. - * \param[in] val_dist_j - Value of of the distance from point j to the nearest wall. - */ - void SetDistance(su2double val_dist_i, su2double val_dist_j); - - /*! - * \brief Set coordinates of the points. - * \param[in] val_coord_i - Coordinates of the point i. - * \param[in] val_coord_j - Coordinates of the point j. - */ - void SetCoord(su2double *val_coord_i, su2double *val_coord_j); - - /*! - * \overload - * \param[in] val_coord_0 - Coordinates of the point 0. - * \param[in] val_coord_1 - Coordinates of the point 1. - * \param[in] val_coord_2 - Coordinates of the point 2. - */ - void SetCoord(su2double *val_coord_0, su2double *val_coord_1, su2double *val_coord_2); - - /*! - * \overload - * \param[in] val_coord_0 - Coordinates of the point 0. - * \param[in] val_coord_1 - Coordinates of the point 1. - * \param[in] val_coord_2 - Coordinates of the point 2. - * \param[in] val_coord_3 - Coordinates of the point 3. - */ - void SetCoord(su2double *val_coord_0, su2double *val_coord_1, su2double *val_coord_2, - su2double *val_coord_3); - - /*! - * \brief Set the velocity of the computational grid. - * \param[in] val_gridvel_i - Grid velocity of the point i. - * \param[in] val_gridvel_j - Grid velocity of the point j. - */ - void SetGridVel(su2double *val_gridvel_i, su2double *val_gridvel_j); - - /*! - * \brief Set the wind gust value. - * \param[in] val_windgust_i - Wind gust of the point i. - * \param[in] val_windgust_j - Wind gust of the point j. - */ - void SetWindGust(su2double *val_windgust_i, su2double *val_windgust_j); - - /*! - * \brief Set the wind gust derivatives values. - * \param[in] val_windgust_i - Wind gust derivatives of the point i. - * \param[in] val_windgust_j - Wind gust derivatives of the point j. - */ - void SetWindGustDer(su2double *val_windgustder_i, su2double *val_windgustder_j); - - /*! - * \brief Set the value of the pressure. - * \param[in] val_pressure_i - Value of the pressure at point i. - * \param[in] val_pressure_j - Value of the pressure at point j. - */ - void SetPressure(su2double val_pressure_i, su2double val_pressure_j); - - /*! - * \brief Set the value of the density for the incompressible solver. - * \param[in] val_densityinc_i - Value of the pressure at point i. - * \param[in] val_densityinc_j - Value of the pressure at point j. - */ - void SetDensityInc(su2double val_densityinc_i, su2double val_densityinc_j); - - /*! - * \brief Set the value of the beta for incompressible flows. - * \param[in] val_betainc2_i - Value of beta for incompressible flows at point i. - * \param[in] val_betainc2_j - Value of beta for incompressible flows at point j. - */ - void SetBetaInc2(su2double val_betainc2_i, su2double val_betainc2_j); - - /*! - * \brief Set the value of the sound speed. - * \param[in] val_soundspeed_i - Value of the sound speed at point i. - * \param[in] val_soundspeed_j - Value of the sound speed at point j. - */ - void SetSoundSpeed(su2double val_soundspeed_i, su2double val_soundspeed_j); - - /*! - * \brief Set the value of the temperature. - * \param[in] val_temp_i - Value of the temperature at point i. - * \param[in] val_temp_j - Value of the temperature at point j. - */ - void SetTemperature(su2double val_temp_i, su2double val_temp_j); - - /*! - * \brief Set the value of the enthalpy. - * \param[in] val_enthalpy_i - Value of the enthalpy at point i. - * \param[in] val_enthalpy_j - Value of the enthalpy at point j. - */ - void SetEnthalpy(su2double val_enthalpy_i, su2double val_enthalpy_j); - - /*! - * \brief Set the value of the spectral radius. - * \param[in] val_lambda_i - Value of the spectral radius at point i. - * \param[in] val_lambda_j - Value of the spectral radius at point j. - */ - void SetLambda(su2double val_lambda_i, su2double val_lambda_j); - - /*! - * \brief Set the value of undivided laplacian. - * \param[in] val_und_lapl_i Undivided laplacian at point i. - * \param[in] val_und_lapl_j Undivided laplacian at point j. - */ - void SetUndivided_Laplacian(su2double *val_und_lapl_i, su2double *val_und_lapl_j); - - /*! - * \brief Set the value of the pressure sensor. - * \param[in] val_sensor_i Pressure sensor at point i. - * \param[in] val_sensor_j Pressure sensor at point j. - */ - void SetSensor(su2double val_sensor_i, su2double val_sensor_j); - - /*! - * \brief Set the number of neighbor to a point. - * \param[in] val_neighbor_i - Number of neighbor to point i. - * \param[in] val_neighbor_j - Number of neighbor to point j. - */ - void SetNeighbor(unsigned short val_neighbor_i, unsigned short val_neighbor_j); - - /*! - * \brief Set the value of the normal vector to the face between two points. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - */ - void SetNormal(su2double *val_normal); - - /*! - * \brief Set the value of the volume of the control volume. - * \param[in] val_volume Volume of the control volume. - */ - void SetVolume(su2double val_volume); - - /*! - * \brief Retrieves the value of the species density in the primitive variable vector. - * \param[in] iRho_s - */ - void SetRhosIndex(unsigned short val_Index); - - /*! - * \brief Retrieves the value of the species density in the primitive variable vector. - * \param[in] iRho_s - */ - void SetRhoIndex(unsigned short val_Index); - - /*! - * \brief Retrieves the value of the species density in the primitive variable vector. - * \param[in] iRho_s - */ - void SetPIndex(unsigned short val_Index); - - /*! - * \brief Retrieves the value of the species density in the primitive variable vector. - * \param[in] iRho_s - */ - void SetTIndex(unsigned short val_Index); - - /*! - * \brief Retrieves the value of the species density in the primitive variable vector. - * \param[in] iRho_s - */ - void SetTveIndex(unsigned short val_Index); - - /*! - * \brief Retrieves the value of the velocity index in the primitive variable vector. - * \param[in] i(rho*u) - */ - void SetVelIndex(unsigned short val_Index); - - /*! - * \brief Retrieves the value of the species density in the primitive variable vector. - * \param[in] iRho_s - */ - void SetHIndex(unsigned short val_Index); - - /*! - * \brief Retrieves the value of the species density in the primitive variable vector. - * \param[in] iRho_s - */ - void SetAIndex(unsigned short val_Index); - - /*! - * \brief Retrieves the value of the species density in the primitive variable vector. - * \param[in] iRho_s - */ - void SetRhoCvtrIndex(unsigned short val_Index); - - /*! - * \brief Retrieves the value of the species density in the primitive variable vector. - * \param[in] iRho_s - */ - void SetRhoCvveIndex(unsigned short val_Index); - - /*! - * \brief Sets the value of the derivative of pressure w.r.t. species density. - * \param[in] iRho_s - */ - void SetdPdU(su2double *val_dPdU_i, su2double *val_dPdU_j); - - /*! - * \brief Sets the value of the derivative of temperature w.r.t. species density. - * \param[in] iRho_s - */ - void SetdTdU(su2double *val_dTdU_i, su2double *val_dTdU_j); - - /*! - * \brief Sets the value of the derivative of vib-el. temperature w.r.t. species density. - * \param[in] iRho_s - */ - void SetdTvedU(su2double *val_dTvedU_i, su2double *val_dTvedU_j); - - /*! - * \brief Get the inviscid fluxes. - * \param[in] val_density - Value of the density. - * \param[in] val_velocity - Value of the velocity. - * \param[in] val_pressure - Value of the pressure. - * \param[in] val_enthalpy - Value of the enthalpy. - */ - void GetInviscidFlux(su2double val_density, su2double *val_velocity, su2double val_pressure, su2double val_enthalpy); - - /*! - * \brief Get the viscous fluxes. - * \param[in] val_primvar - Value of the primitive variables. - * \param[in] val_gradprimvar - Gradient of the primitive variables. - * \param[in] val_laminar_viscosity - Value of the laminar viscosity. - * \param[in] val_eddy_viscosity - Value of the eddy viscosity. - * \param[in] val_mach_inf - Value of the Mach number at the infinity. - */ - void GetViscousFlux(su2double *val_primvar, su2double **val_gradprimvar, - su2double val_laminar_viscosity, su2double val_eddy_viscosity, - su2double val_mach_inf); - - /*! - * \brief Compute the projected inviscid flux vector. - * \param[in] val_density - Pointer to the density. - * \param[in] val_velocity - Pointer to the velocity. - * \param[in] val_pressure - Pointer to the pressure. - * \param[in] val_enthalpy - Pointer to the enthalpy. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[out] val_Proj_Flux - Pointer to the projected flux. - */ - void GetInviscidProjFlux(su2double *val_density, su2double *val_velocity, - su2double *val_pressure, su2double *val_enthalpy, - su2double *val_normal, su2double *val_Proj_Flux); - - /*! - * \brief Compute the projected inviscid flux vector for incompresible simulations - * \param[in] val_density - Pointer to the density. - * \param[in] val_velocity - Pointer to the velocity. - * \param[in] val_pressure - Pointer to the pressure. - * \param[in] val_betainc2 - Value of the artificial compresibility factor. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[out] val_Proj_Flux - Pointer to the projected flux. - */ - void GetInviscidArtCompProjFlux(su2double *val_density, su2double *val_velocity, - su2double *val_pressure, su2double *val_betainc2, - su2double *val_normal, su2double *val_Proj_Flux); - - /*! - * \brief Compute the projected inviscid flux vector for incompresible simulations - * \param[in] val_density - Pointer to the density. - * \param[in] val_velocity - Pointer to the velocity. - * \param[in] val_pressure - Pointer to the pressure. - * \param[in] val_betainc2 - Value of the artificial compresibility factor. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[out] val_Proj_Flux - Pointer to the projected flux. - */ - void GetInviscidArtComp_FreeSurf_ProjFlux(su2double *val_density, - su2double *val_velocity, - su2double *val_pressure, - su2double *val_betainc2, - su2double *val_levelset, - su2double *val_normal, - su2double *val_Proj_Flux); - - - /*! - * \brief Compute the projection of the viscous fluxes into a direction. - * \param[in] val_primvar - Primitive variables. - * \param[in] val_gradprimvar - Gradient of the primitive variables. - * \param[in] val_turb_ke - Turbulent kinetic energy - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[in] val_laminar_viscosity - Laminar viscosity. - * \param[in] val_eddy_viscosity - Eddy viscosity. - * \param[in] val_thermal_conductivity - Thermal Conductivity. - * \param[in] val_eddy_conductivity - Eddy Conductivity. - */ - - void GetViscousProjFlux(su2double *val_primvar, su2double **val_gradprimvar, - su2double val_turb_ke, su2double *val_normal, - su2double val_laminar_viscosity, - su2double val_eddy_viscosity); - /*! - * \brief Compute the projection of the viscous fluxes into a direction for general fluid model. - * \param[in] val_primvar - Primitive variables. - * \param[in] val_gradprimvar - Gradient of the primitive variables. - * \param[in] val_turb_ke - Turbulent kinetic energy - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[in] val_laminar_viscosity - Laminar viscosity. - * \param[in] val_eddy_viscosity - Eddy viscosity. - * \param[in] val_thermal_conductivity - Thermal Conductivity. - * \param[in] val_heat_capacity_cp - Heat Capacity at constant pressure. - */ - - void GetViscousProjFlux(su2double *val_primvar, su2double **val_gradprimvar, - su2double val_turb_ke, su2double *val_normal, - su2double val_laminar_viscosity, - su2double val_eddy_viscosity, - su2double val_thermal_conductivity, - su2double val_heat_capacity_cp); - - /* - * \brief Compute the projection of the viscous fluxes into a direction (artificial compresibility method). - * \param[in] val_primvar - Primitive variables. - * \param[in] val_gradprimvar - Gradient of the primitive variables. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[in] val_laminar_viscosity - Laminar viscosity. - * \param[in] val_eddy_viscosity - Eddy viscosity. - */ - - void GetViscousArtCompProjFlux(su2double **val_gradprimvar, - su2double *val_normal, - su2double val_laminar_viscosity, - su2double val_eddy_viscosity); - - /*! - * \brief Compute the projection of the inviscid Jacobian matrices. - * \param[in] val_velocity Pointer to the velocity. - * \param[in] val_energy Value of the energy. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[in] val_scale - Scale of the projection. - * \param[out] val_Proj_Jac_tensor - Pointer to the projected inviscid Jacobian. - */ - void GetInviscidProjJac(su2double *val_velocity, su2double *val_energy, - su2double *val_normal, su2double val_scale, - su2double **val_Proj_Jac_tensor); - - /*! - * \brief Compute the projection of the inviscid Jacobian matrices (artificial compresibility). - * \param[in] val_density - Value of the density. - * \param[in] val_velocity - Pointer to the velocity. - * \param[in] val_betainc2 - Value of the artificial compresibility factor. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[in] val_scale - Scale of the projection. - * \param[out] val_Proj_Jac_tensor - Pointer to the projected inviscid Jacobian. - */ - void GetInviscidArtCompProjJac(su2double *val_density, su2double *val_velocity, - su2double *val_betainc2, su2double *val_normal, - su2double val_scale, - su2double **val_Proj_Jac_tensor); - - /*! - * \brief Compute the projection of the inviscid Jacobian matrices (artificial compresibility). - * \param[in] val_density - Value of the density. - * \param[in] val_velocity - Pointer to the velocity. - * \param[in] val_betainc2 - Value of the artificial compresibility factor. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[in] val_scale - Scale of the projection. - * \param[out] val_Proj_Jac_tensor - Pointer to the projected inviscid Jacobian. - */ - void GetInviscidArtComp_FreeSurf_ProjJac(su2double *val_density, - su2double *val_ddensity, - su2double *val_velocity, - su2double *val_betainc2, - su2double *val_levelset, - su2double *val_normal, - su2double val_scale, - su2double **val_Proj_Jac_tensor); - - /*! - * \brief Compute the projection of the inviscid Jacobian matrices for general fluid model. - * \param[in] val_velocity Pointer to the velocity. - * \param[in] val_energy Value of the energy. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[in] val_scale - Scale of the projection. - * \param[out] val_Proj_Jac_tensor - Pointer to the projected inviscid Jacobian. - */ - void GetInviscidProjJac(su2double *val_velocity, su2double *val_enthalphy, - su2double *val_chi, su2double *val_kappa, - su2double *val_normal, su2double val_scale, - su2double **val_Proj_Jac_tensor); - - /*! - * \brief TSL-Approximation of Viscous NS Jacobians. - * \param[in] val_Mean_PrimVar - Mean value of the primitive variables. - * \param[in] val_laminar_viscosity - Value of the laminar viscosity. - * \param[in] val_eddy_viscosity - Value of the eddy viscosity. - * \param[in] val_dist_ij - Distance between the points. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[in] val_dS - Area of the face between two nodes. - * \param[in] val_Proj_Visc_Flux - Pointer to the projected viscous flux. - * \param[out] val_Proj_Jac_Tensor_i - Pointer to the projected viscous Jacobian at point i. - * \param[out] val_Proj_Jac_Tensor_j - Pointer to the projected viscous Jacobian at point j. - */ - void GetViscousProjJacs(su2double *val_Mean_PrimVar, - su2double val_laminar_viscosity, - su2double val_eddy_viscosity, - su2double val_dist_ij, - su2double *val_normal, su2double val_dS, - su2double *val_Proj_Visc_Flux, - su2double **val_Proj_Jac_Tensor_i, - su2double **val_Proj_Jac_Tensor_j); - - /*! - * \brief TSL-Approximation of Viscous NS Jacobians for arbitrary equations of state. - * \param[in] val_Mean_PrimVar - Mean value of the primitive variables. - * \param[in] val_gradprimvar - Mean value of the gradient of the primitive variables. - * \param[in] val_Mean_SecVar - Mean value of the secondary variables. - * \param[in] val_laminar_viscosity - Value of the laminar viscosity. - * \param[in] val_eddy_viscosity - Value of the eddy viscosity. - * \param[in] val_thermal_conductivity - Value of the thermal conductivity. - * \param[in] val_heat_capacity_cp - Value of the specific heat at constant pressure. - * \param[in] val_dist_ij - Distance between the points. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[in] val_dS - Area of the face between two nodes. - * \param[in] val_Proj_Visc_Flux - Pointer to the projected viscous flux. - * \param[out] val_Proj_Jac_Tensor_i - Pointer to the projected viscous Jacobian at point i. - * \param[out] val_Proj_Jac_Tensor_j - Pointer to the projected viscous Jacobian at point j. - */ - void GetViscousProjJacs(su2double *val_Mean_PrimVar, - su2double **val_gradprimvar, - su2double *val_Mean_SecVar, - su2double val_laminar_viscosity, - su2double val_eddy_viscosity, - su2double val_thermal_conductivity, - su2double val_heat_capacity_cp, - su2double val_dist_ij, - su2double *val_normal, su2double val_dS, - su2double *val_Proj_Visc_Flux, - su2double **val_Proj_Jac_Tensor_i, - su2double **val_Proj_Jac_Tensor_j); - - /*! - * \brief Mapping between primitives variables P and conservatives variables C. - * \param[in] val_Mean_PrimVar - Mean value of the primitive variables. - * \param[in] val_Mean_PrimVar - Mean Value of the secondary variables. - * \param[out] val_Jac_PC - Pointer to the Jacobian dPdC. - */ - void GetPrimitive2Conservative (su2double *val_Mean_PrimVar, - su2double *val_Mean_SecVar, - su2double **val_Jac_PC); - - /*! - * \brief Compute the projection of the viscous Jacobian matrices. - * \param[in] val_laminar_viscosity - Value of the laminar viscosity. - * \param[in] val_eddy_viscosity - Value of the eddy viscosity. - * \param[in] val_dist_ij - Distance between the points. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[in] val_dS - Area of the face between two nodes. - * \param[out] val_Proj_Jac_Tensor_i - Pointer to the projected viscous Jacobian at point i. - * \param[out] val_Proj_Jac_Tensor_j - Pointer to the projected viscous Jacobian at point j. - */ - void GetViscousArtCompProjJacs(su2double val_laminar_viscosity, - su2double val_eddy_viscosity, su2double val_dist_ij, - su2double *val_normal, su2double val_dS, - su2double **val_Proj_Jac_Tensor_i, - su2double **val_Proj_Jac_Tensor_j); - - /*! - * \overload - * \brief Computation of the matrix P for a generic fluid model - * \param[in] val_density - Value of the density. - * \param[in] val_velocity - Value of the velocity. - * \param[in] val_soundspeed - Value of the sound speed. - * \param[in] val_enthalpy - Value of the Enthalpy - * \param[in] val_chi - Value of the derivative of Pressure with respect to the Density. - * \param[in] val_kappa - Value of the derivative of Pressure with respect to the volume specific Static Energy. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[out] val_p_tensor - Pointer to the P matrix. - */ - void GetPMatrix(su2double *val_density, su2double *val_velocity, - su2double *val_soundspeed, su2double *val_enthalpy, su2double *val_chi, su2double *val_kappa, - su2double *val_normal, su2double **val_p_tensor); - - /*! - * \brief Computation of the matrix P, this matrix diagonalize the conservative Jacobians in - * the form $P^{-1}(A.Normal)P=Lambda$. - * \param[in] val_density - Value of the density. - * \param[in] val_velocity - Value of the velocity. - * \param[in] val_soundspeed - Value of the sound speed. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[out] val_p_tensor - Pointer to the P matrix. - */ - void GetPMatrix(su2double *val_density, su2double *val_velocity, - su2double *val_soundspeed, su2double *val_normal, - su2double **val_p_tensor); - - /*! - * \brief Computation of the matrix Rinv*Pe. - * \param[in] Beta2 - A variable in used to define Pe matrix. - * \param[in] val_enthalpy - value of the enthalpy. - * \param[in] val_soundspeed - value of the sound speed. - * \param[in] val_density - value of the density. - * \param[in] val_velocity - value of the velocity. - * \param[out] val_invR_invPe - Pointer to the matrix of conversion from entropic to conserved variables. - */ - void GetinvRinvPe(su2double Beta2, su2double val_enthalpy, su2double val_soundspeed, - su2double val_density, su2double* val_velocity, +/*! + * \file numerics_structure.hpp + * \brief Headers of the main subroutines for the dumerical definition of the problem. + * The subroutines and functions are in the numerics_structure.cpp, + * numerics_convective.cpp, numerics_viscous.cpp, and + * numerics_source.cpp files. + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +#include "../../Common/include/mpi_structure.hpp" + +#include +#include +#include +#include + +#include "../../Common/include/config_structure.hpp" +#include "../../Common/include/gauss_structure.hpp" +#include "../../Common/include/element_structure.hpp" +#include "variable_structure.hpp" + +using namespace std; + +/*! + * \class CNumerics + * \brief Class for defining the numerical methods. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CNumerics { +protected: + unsigned short nDim, nVar; /*!< \brief Number of dimensions and variables. */ + su2double Gamma; /*!< \brief Fluid's Gamma constant (ratio of specific heats). */ + su2double Gamma_Minus_One; /*!< \brief Fluids's Gamma - 1.0 . */ + su2double Gas_Constant; /*!< \brief Gas constant. */ + su2double *Vector; /*!< \brief Auxiliary vector. */ + su2double *Enthalpy_formation; + su2double Prandtl_Lam; /*!< \brief Laminar Prandtl's number. */ + su2double Prandtl_Turb; /*!< \brief Turbulent Prandtl's number. */ + +public: + + su2double + **Flux_Tensor, /*!< \brief Flux tensor (used for viscous and inviscid purposes. */ + *Proj_Flux_Tensor; /*!< \brief Flux tensor projected in a direction. */ + + su2double + **tau, /*!< \brief Viscous stress tensor. */ + **delta; /*!< \brief Identity matrix. */ + su2double **dVdU; /*!< \brief Transformation matrix from primitive variables, V, to conserved, U. */ + su2double + *Diffusion_Coeff_i, /*!< \brief Species diffusion coefficients at point i. */ + *Diffusion_Coeff_j; /*!< \brief Species diffusion coefficients at point j. */ + su2double Laminar_Viscosity_i, /*!< \brief Laminar viscosity at point i. */ + Laminar_Viscosity_j, /*!< \brief Laminar viscosity at point j. */ + Laminar_Viscosity_id, /*!< \brief Variation of laminar viscosity at point i. */ + Laminar_Viscosity_jd; /*!< \brief Variation of laminar viscosity at point j. */ + su2double Thermal_Conductivity_i, /*!< \brief Thermal conductivity at point i. */ + Thermal_Conductivity_j, /*!< \brief Thermal conductivity at point j. */ + Thermal_Conductivity_ve_i, /*!< \brief Thermal conductivity at point i. */ + Thermal_Conductivity_ve_j; /*!< \brief Thermal conductivity at point j. */ + su2double Cp_i, /*!< \brief Cp at point i. */ + Cp_j; /*!< \brief Cp at point j. */ + su2double *Theta_v; /*!< \brief Characteristic vibrational temperature */ + su2double Eddy_Viscosity_i, /*!< \brief Eddy viscosity at point i. */ + Eddy_Viscosity_j; /*!< \brief Eddy viscosity at point j. */ + su2double turb_ke_i, /*!< \brief Turbulent kinetic energy at point i. */ + turb_ke_j; /*!< \brief Turbulent kinetic energy at point j. */ + su2double Pressure_i, /*!< \brief Pressure at point i. */ + Pressure_j; /*!< \brief Pressure at point j. */ + su2double GravityForce_i, /*!< \brief Gravity force at point i. */ + GravityForce_j; /*!< \brief Gravity force at point j. */ + su2double Density_i, /*!< \brief Density at point i. */ + Density_j; /*!< \brief Density at point j. */ + su2double DensityInc_i, /*!< \brief Incompressible density at point i. */ + DensityInc_j; /*!< \brief Incompressible density at point j. */ + su2double BetaInc2_i, /*!< \brief Beta incompressible at point i. */ + BetaInc2_j; /*!< \brief Beta incompressible at point j. */ + su2double Lambda_i, /*!< \brief Spectral radius at point i. */ + Lambda_j; /*!< \brief Spectral radius at point j. */ + su2double LambdaComb_i, /*!< \brief Spectral radius at point i. */ + LambdaComb_j; /*!< \brief Spectral radius at point j. */ + su2double SoundSpeed_i, /*!< \brief Sound speed at point i. */ + SoundSpeed_j; /*!< \brief Sound speed at point j. */ + su2double Enthalpy_i, /*!< \brief Enthalpy at point i. */ + Enthalpy_j; /*!< \brief Enthalpy at point j. */ + su2double dist_i, /*!< \brief Distance of point i to the nearest wall. */ + dist_j; /*!< \brief Distance of point j to the nearest wall. */ + su2double Temp_i, /*!< \brief Temperature at point i. */ + Temp_j; /*!< \brief Temperature at point j. */ + su2double *Temp_tr_i, /*!< \brief Temperature transl-rot at point i. */ + *Temp_tr_j;/*!< \brief Temperature transl-rot at point j. */ + su2double *Temp_vib_i, /*!< \brief Temperature vibrational at point i. */ + *Temp_vib_j;/*!< \brief Temperature vibrational at point j. */ + su2double *Und_Lapl_i, /*!< \brief Undivided laplacians at point i. */ + *Und_Lapl_j; /*!< \brief Undivided laplacians at point j. */ + su2double Sensor_i, /*!< \brief Pressure sensor at point i. */ + Sensor_j; /*!< \brief Pressure sensor at point j. */ + su2double *GridVel_i, /*!< \brief Grid velocity at point i. */ + *GridVel_j; /*!< \brief Grid velocity at point j. */ + su2double *U_i, /*!< \brief Vector of conservative variables at point i. */ + *U_id, /*!< \brief Vector of derivative of conservative variables at point i. */ + *UZeroOrder_i, /*!< \brief Vector of conservative variables at point i without reconstruction. */ + *U_j, /*!< \brief Vector of conservative variables at point j. */ + *UZeroOrder_j, /*!< \brief Vector of conservative variables at point j without reconstruction. */ + *U_jd, /*!< \brief Vector of derivative of conservative variables at point j. */ + *U_0, /*!< \brief Vector of conservative variables at node 0. */ + *U_1, /*!< \brief Vector of conservative variables at node 1. */ + *U_2, /*!< \brief Vector of conservative variables at node 2. */ + *U_3; /*!< \brief Vector of conservative variables at node 3. */ + su2double *V_i, /*!< \brief Vector of primitive variables at point i. */ + *V_j; /*!< \brief Vector of primitive variables at point j. */ + su2double *S_i, /*!< \brief Vector of secondary variables at point i. */ + *S_j; /*!< \brief Vector of secondary variables at point j. */ + su2double *Psi_i, /*!< \brief Vector of adjoint variables at point i. */ + *Psi_j; /*!< \brief Vector of adjoint variables at point j. */ + su2double *DeltaU_i, /*!< \brief Vector of linearized variables at point i. */ + *DeltaU_j; /*!< \brief Vector of linearized variables at point j. */ + su2double *TurbVar_i, /*!< \brief Vector of turbulent variables at point i. */ + *TurbVar_id, /*!< \brief Vector of derivative of turbulent variables at point i. */ + *TurbVar_j, /*!< \brief Vector of turbulent variables at point j. */ + *TurbVar_jd; /*!< \brief Vector of derivative of turbulent variables at point j. */ + su2double *TransVar_i, /*!< \brief Vector of turbulent variables at point i. */ + *TransVar_j; /*!< \brief Vector of turbulent variables at point j. */ + su2double *LevelSetVar_i, /*!< \brief Vector of turbulent variables at point i. */ + *LevelSetVar_j; /*!< \brief Vector of turbulent variables at point j. */ + su2double *TurbPsi_i, /*!< \brief Vector of adjoint turbulent variables at point i. */ + *TurbPsi_j; /*!< \brief Vector of adjoint turbulent variables at point j. */ + su2double **ConsVar_Grad_i, /*!< \brief Gradient of conservative variables at point i. */ + **ConsVar_Grad_j, /*!< \brief Gradient of conservative variables at point j. */ + **ConsVar_Grad_0, /*!< \brief Gradient of conservative variables at point 0. */ + **ConsVar_Grad_1, /*!< \brief Gradient of conservative variables at point 1. */ + **ConsVar_Grad_2, /*!< \brief Gradient of conservative variables at point 2. */ + **ConsVar_Grad_3, /*!< \brief Gradient of conservative variables at point 3. */ + **ConsVar_Grad; /*!< \brief Gradient of conservative variables which is a scalar. */ + su2double **PrimVar_Grad_i, /*!< \brief Gradient of primitive variables at point i. */ + **PrimVar_Grad_j; /*!< \brief Gradient of primitive variables at point j. */ + su2double *PrimVar_Lim_i, /*!< \brief Limiter of primitive variables at point i. */ + *PrimVar_Lim_j; /*!< \brief Limiter of primitive variables at point j. */ + su2double *PsiVar_Lim_i, /*!< \brief Limiter of adjoint variables at point i. */ + *PsiVar_Lim_j; /*!< \brief Limiter of adjoint variables at point j. */ + su2double **PsiVar_Grad_i, /*!< \brief Gradient of adjoint variables at point i. */ + **PsiVar_Grad_j; /*!< \brief Gradient of adjoint variables at point j. */ + su2double **TurbVar_Grad_i, /*!< \brief Gradient of turbulent variables at point i. */ + **TurbVar_Grad_j; /*!< \brief Gradient of turbulent variables at point j. */ + su2double **TransVar_Grad_i, /*!< \brief Gradient of turbulent variables at point i. */ + **TransVar_Grad_j; /*!< \brief Gradient of turbulent variables at point j. */ + su2double **LevelSetVar_Grad_i, /*!< \brief Gradient of level set variables at point i. */ + **LevelSetVar_Grad_j; /*!< \brief Gradient of level set variables at point j. */ + su2double **TurbPsi_Grad_i, /*!< \brief Gradient of adjoint turbulent variables at point i. */ + **TurbPsi_Grad_j; /*!< \brief Gradient of adjoint turbulent variables at point j. */ + su2double *AuxVar_Grad_i, /*!< \brief Gradient of an auxiliary variable at point i. */ + *AuxVar_Grad_j; /*!< \brief Gradient of an auxiliary variable at point i. */ + su2double *Coord_i, /*!< \brief Cartesians coordinates of point i. */ + *Coord_j, /*!< \brief Cartesians coordinates of point j. */ + *Coord_0, /*!< \brief Cartesians coordinates of point 0 (Galerkin method, triangle). */ + *Coord_1, /*!< \brief Cartesians coordinates of point 1 (Galerkin method, tetrahedra). */ + *Coord_2, /*!< \brief Cartesians coordinates of point 2 (Galerkin method, triangle). */ + *Coord_3; /*!< \brief Cartesians coordinates of point 3 (Galerkin method, tetrahedra). */ + unsigned short Neighbor_i, /*!< \brief Number of neighbors of the point i. */ + Neighbor_j; /*!< \brief Number of neighbors of the point j. */ + su2double *Normal, /*!< \brief Normal vector, it norm is the area of the face. */ + *UnitNormal, /*!< \brief Unitary normal vector. */ + *UnitNormald; /*!< \brief derivatve of unitary normal vector. */ + su2double TimeStep, /*!< \brief Time step useful in dual time method. */ + Area, /*!< \brief Area of the face i-j. */ + Volume; /*!< \brief Volume of the control volume around point i. */ + su2double Volume_n, /*!< \brief Volume of the control volume at time n. */ + Volume_nM1, /*!< \brief Volume of the control volume at time n-1. */ + Volume_nP1; /*!< \brief Volume of the control volume at time n+1. */ + su2double *U_n, /*!< \brief Vector of conservative variables at time n. */ + *U_nM1, /*!< \brief Vector of conservative variables at time n-1. */ + *U_nP1; /*!< \brief Vector of conservative variables at time n+1. */ + su2double vel2_inf; /*!< \brief value of the square of freestream speed. */ + su2double *WindGust_i, /*!< \brief Wind gust at point i. */ + *WindGust_j; /*!< \brief Wind gust at point j. */ + su2double *WindGustDer_i, /*!< \brief Wind gust derivatives at point i. */ + *WindGustDer_j; /*!< \brief Wind gust derivatives at point j. */ + su2double *Vorticity_i, *Vorticity_j; /*!< \brief Vorticity. */ + su2double StrainMag_i, StrainMag_j; /*!< \brief Strain rate magnitude. */ + + su2double *l, *m; + su2double *dPdU_i, *dPdU_j; + su2double *dTdU_i, *dTdU_j; + su2double *dTvedU_i, *dTvedU_j; + su2double *Ys, **dFdYj, **dFdYi, *sumdFdYih, *sumdFdYjh, *sumdFdYieve, *sumdFdYjeve; + unsigned short RHOS_INDEX, T_INDEX, TVE_INDEX, VEL_INDEX, P_INDEX, + RHO_INDEX, H_INDEX, A_INDEX, RHOCVTR_INDEX, RHOCVVE_INDEX; + CVariable *var; + + /*! + * \brief Constructor of the class. + */ + CNumerics(void); + + /*! + * \overload + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CNumerics(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + virtual ~CNumerics(void); + + /*! + * \brief Compute the determinant of a 3 by 3 matrix. + * \param[in] val_matrix 3 by 3 matrix. + * \result Determinant of the matrix + */ + su2double Determinant_3x3(su2double A00, su2double A01, su2double A02, + su2double A10, su2double A11, su2double A12, + su2double A20, su2double A21, su2double A22); + + /*! + * \brief Set the solution at different times. + * \param[in] val_u_nM1 Conservative solution at time n-1. + * \param[in] val_u_n Conservative solution at time n. + * \param[in] val_u_nP1 Conservative solution at time n+1. + */ + void SetPastSol(su2double *val_u_nM1, su2double *val_u_n, su2double *val_u_nP1); + + /*! + * \brief Set the control volume at different times. + * \param[in] val_volume_nM1 - Control volume at time n-1. + * \param[in] val_volume_n - Control volume at time n. + * \param[in] val_volume_nP1 - Control volume at time n+1. + */ + void SetPastVolume(su2double val_volume_nM1, su2double val_volume_n, su2double val_volume_nP1); + + /*! + * \brief Set the time step. + * \param[in] val_timestep - Value of the time step. + */ + void SetTimeStep(su2double val_timestep); + + /*! + * \brief Get the Preconditioning Beta. + * \return val_Beta - Value of the low Mach Preconditioner. + */ + virtual su2double GetPrecond_Beta(); + + /*! + * \brief Set the freestream velocity square. + * \param[in] SetVelocity2_Inf - Value of the square of the freestream velocity. + */ + void SetVelocity2_Inf(su2double val_velocity2); + + /*! + * \brief Set the value of the vorticity + * \param[in] val_vorticity - Value of the vorticity. + */ + void SetVorticity(su2double *val_vorticity_i, su2double *val_vorticity_j); + + /*! + * \brief Set the value of the rate of strain magnitude. + * \param[in] val_StrainMag_i - Value of the magnitude of rate of strain at point i. + * \param[in] val_StrainMag_j - Value of the magnitude of rate of strain at point j. + */ + void SetStrainMag(su2double val_strainmag_i, su2double val_strainmag_j); + + /*! + * \brief Set the value of the conservative variables. + * \param[in] val_u_i - Value of the conservative variable at point i. + * \param[in] val_u_j - Value of the conservative variable at point j. + */ + void SetConservative(su2double *val_u_i, su2double *val_u_j); + + /*! + * \brief Set the value of the conservative variables withour reconstruction. + * \param[in] val_u_i - Value of the conservative variable at point i. + * \param[in] val_u_j - Value of the conservative variable at point j. + */ + void SetConservative_ZeroOrder(su2double *val_u_i, su2double *val_u_j); + + /*! + * \brief Set the value of the primitive variables. + * \param[in] val_v_i - Value of the primitive variable at point i. + * \param[in] val_v_j - Value of the primitive variable at point j. + */ + void SetPrimitive(su2double *val_v_i, su2double *val_v_j); + + /*! + * \brief Set the value of the primitive variables. + * \param[in] val_v_i - Value of the primitive variable at point i. + * \param[in] val_v_j - Value of the primitive variable at point j. + */ + void SetSecondary(su2double *val_s_i, su2double *val_s_j); + + /*! + * \brief Set the value of the conservative variables. + * \param[in] val_u_0 - Value of the conservative variable at point 0. + * \param[in] val_u_1 - Value of the conservative variable at point 1. + * \param[in] val_u_2 - Value of the conservative variable at point 2. + */ + void SetConservative(su2double *val_u_0, su2double *val_u_1, su2double *val_u_2); + + /*! + * \brief Set the value of the conservative variables. + * \param[in] val_u_0 - Value of the conservative variable at point 0. + * \param[in] val_u_1 - Value of the conservative variable at point 1. + * \param[in] val_u_2 - Value of the conservative variable at point 2. + * \param[in] val_u_3 - Value of the conservative variable at point 3. + */ + void SetConservative(su2double *val_u_0, su2double *val_u_1, su2double *val_u_2, su2double *val_u_3); + + /*! + * \brief Set the gradient of the conservative variables. + * \param[in] val_consvar_grad_i - Gradient of the conservative variable at point i. + * \param[in] val_consvar_grad_j - Gradient of the conservative variable at point j. + */ + void SetConsVarGradient(su2double **val_consvar_grad_i, su2double **val_consvar_grad_j); + + /*! + * \brief Set the gradient of the conservative variables. + * \param[in] val_consvar_grad_0 - Gradient of the conservative variable at point 0. + * \param[in] val_consvar_grad_1 - Gradient of the conservative variable at point 1. + * \param[in] val_consvar_grad_2 - Gradient of the conservative variable at point 2. + */ + void SetConsVarGradient(su2double **val_consvar_grad_0, + su2double **val_consvar_grad_1, + su2double **val_consvar_grad_2); + + /*! + * \brief Set the gradient of the conservative variables. + * \param[in] val_consvar_grad_0 - Gradient of the conservative variable at point 0. + * \param[in] val_consvar_grad_1 - Gradient of the conservative variable at point 1. + * \param[in] val_consvar_grad_2 - Gradient of the conservative variable at point 2. + * \param[in] val_consvar_grad_3 - Gradient of the conservative variable at point 3. + */ + void SetConsVarGradient(su2double **val_consvar_grad_0, + su2double **val_consvar_grad_1, + su2double **val_consvar_grad_2, + su2double **val_consvar_grad_3); + + /*! + * \brief Set the gradient of the conservative variables. + * \param[in] val_consvar_grad - Gradient of the conservative variable which is a scalar. + */ + void SetConsVarGradient(su2double **val_consvar_grad); + + /*! + * \brief Set the gradient of the primitive variables. + * \param[in] val_primvar_grad_i - Gradient of the primitive variable at point i. + * \param[in] val_primvar_grad_j - Gradient of the primitive variable at point j. + */ + void SetPrimVarGradient(su2double **val_primvar_grad_i, + su2double **val_primvar_grad_j); + + /*! + * \brief Set the Limiter of the primitive variables. + * \param[in] val_primvar_lim_i - Limiter of the primitive variable at point i. + * \param[in] val_primvar_lim_j - Limiter of the primitive variable at point j. + */ + void SetPrimVarLimiter(su2double *val_primvar_lim_i, + su2double *val_primvar_lim_j); + + /*! + * \brief Set the value of the adjoint variable. + * \param[in] val_psi_i - Value of the adjoint variable at point i. + * \param[in] val_psi_j - Value of the adjoint variable at point j. + */ + void SetAdjointVar(su2double *val_psi_i, su2double *val_psi_j); + + /*! + * \brief Set the gradient of the adjoint variables. + * \param[in] val_psivar_grad_i - Gradient of the adjoint variable at point i. + * \param[in] val_psivar_grad_j - Gradient of the adjoint variable at point j. + */ + void SetAdjointVarGradient(su2double **val_psivar_grad_i, su2double **val_psivar_grad_j); + + /*! + * \brief Set the limiter of the adjoint variables. + * \param[in] val_psivar_lim_i - Gradient of the adjoint variable at point i. + * \param[in] val_psivar_lim_j - Gradient of the adjoint variable at point j. + */ + void SetAdjointVarLimiter(su2double *val_psivar_lim_i, su2double *val_psivar_lim_j); + + /*! + * \brief Set the value of the turbulent variable. + * \param[in] val_turbvar_i - Value of the turbulent variable at point i. + * \param[in] val_turbvar_j - Value of the turbulent variable at point j. + */ + void SetTurbVar(su2double *val_turbvar_i, su2double *val_turbvar_j); + + /*! + * \brief Set the value of the turbulent variable. + * \param[in] val_transvar_i - Value of the turbulent variable at point i. + * \param[in] val_transvar_j - Value of the turbulent variable at point j. + */ + void SetTransVar(su2double *val_transvar_i, su2double *val_transvar_j); + + /*! + * \brief Set the gradient of the turbulent variables. + * \param[in] val_turbvar_grad_i - Gradient of the turbulent variable at point i. + * \param[in] val_turbvar_grad_j - Gradient of the turbulent variable at point j. + */ + void SetTurbVarGradient(su2double **val_turbvar_grad_i, su2double **val_turbvar_grad_j); + + /*! + * \brief Set the gradient of the turbulent variables. + * \param[in] val_turbvar_grad_i - Gradient of the turbulent variable at point i. + * \param[in] val_turbvar_grad_j - Gradient of the turbulent variable at point j. + */ + void SetTransVarGradient(su2double **val_transvar_grad_i, su2double **val_transvar_grad_j); + + /*! + * \brief Set the value of the level set variable. + * \param[in] val_levelsetvar_i - Value of the level set variable at point i. + * \param[in] val_levelsetvar_j - Value of the level set variable at point j. + */ + void SetLevelSetVar(su2double *val_levelsetvar_i, su2double *val_levelsetvar_j); + + /*! + * \brief Set the gradient of the level set variables. + * \param[in] val_levelsetvar_grad_i - Gradient of the level set variable at point i. + * \param[in] val_levelsetvar_grad_j - Gradient of the level set variable at point j. + */ + void SetLevelSetVarGradient(su2double **val_levelsetvar_grad_i, su2double **val_levelsetvar_grad_j); + + /*! + * \brief Set the value of the adjoint turbulent variable. + * \param[in] val_turbpsivar_i - Value of the adjoint turbulent variable at point i. + * \param[in] val_turbpsivar_j - Value of the adjoint turbulent variable at point j. + */ + void SetTurbAdjointVar(su2double *val_turbpsivar_i, su2double *val_turbpsivar_j); + + /*! + * \brief Set the gradient of the adjoint turbulent variables. + * \param[in] val_turbpsivar_grad_i - Gradient of the adjoint turbulent variable at point i. + * \param[in] val_turbpsivar_grad_j - Gradient of the adjoint turbulent variable at point j. + */ + void SetTurbAdjointGradient (su2double **val_turbpsivar_grad_i, su2double **val_turbpsivar_grad_j); + + /*! + * \brief Set the value of the first blending function. + * \param[in] val_F1_i - Value of the first Menter blending function at point i. + * \param[in] val_F1_j - Value of the first Menter blending function at point j. + */ + virtual void SetF1blending(su2double val_F1_i, su2double val_F1_j) {/* empty */}; + + /*! + * \brief Set the value of the second blending function. + * \param[in] val_F1_i - Value of the second Menter blending function at point i. + * \param[in] val_F1_j - Value of the second Menter blending function at point j. + */ + virtual void SetF2blending(su2double val_F1_i, su2double val_F1_j) {/* empty */}; + + /*! + * \brief Set the value of the cross diffusion for the SST model. + * \param[in] val_CDkw_i - Value of the cross diffusion at point i. + * \param[in] val_CDkw_j - Value of the cross diffusion at point j. + */ + virtual void SetCrossDiff(su2double val_CDkw_i, su2double val_CDkw_j) {/* empty */}; + + /*! + * \brief Set the gradient of the auxiliary variables. + * \param[in] val_auxvargrad_i - Gradient of the auxiliary variable at point i. + * \param[in] val_auxvargrad_j - Gradient of the auxiliary variable at point j. + */ + void SetAuxVarGrad(su2double *val_auxvargrad_i, su2double *val_auxvargrad_j); + + /*! + * \brief Set the diffusion coefficient + * \param[in] val_diffusioncoeff_i - Value of the diffusion coefficients at i. + * \param[in] val_diffusioncoeff_j - Value of the diffusion coefficients at j + */ + void SetDiffusionCoeff(su2double* val_diffusioncoeff_i, + su2double* val_diffusioncoeff_j); + + /*! + * \brief Set the laminar viscosity. + * \param[in] val_laminar_viscosity_i - Value of the laminar viscosity at point i. + * \param[in] val_laminar_viscosity_j - Value of the laminar viscosity at point j. + */ + void SetLaminarViscosity(su2double val_laminar_viscosity_i, + su2double val_laminar_viscosity_j); + + /*! + * \brief Set the thermal conductivity (translational/rotational) + * \param[in] val_thermal_conductivity_i - Value of the thermal conductivity at point i. + * \param[in] val_thermal_conductivity_j - Value of the thermal conductivity at point j. + * \param[in] iSpecies - Value of the species. + */ + void SetThermalConductivity(su2double val_thermal_conductivity_i, + su2double val_thermal_conductivity_j); + + /*! + * \brief Set the thermal conductivity (translational/rotational) + * \param[in] val_thermal_conductivity_i - Value of the thermal conductivity at point i. + * \param[in] val_thermal_conductivity_j - Value of the thermal conductivity at point j. + * \param[in] iSpecies - Value of the species. + */ + void SetThermalConductivity_ve(su2double val_thermal_conductivity_ve_i, + su2double val_thermal_conductivity_ve_j); + + /*! + * \brief Set the eddy viscosity. + * \param[in] val_eddy_viscosity_i - Value of the eddy viscosity at point i. + * \param[in] val_eddy_viscosity_j - Value of the eddy viscosity at point j. + */ + void SetEddyViscosity(su2double val_eddy_viscosity_i, + su2double val_eddy_viscosity_j); + + /*! + * \brief Set the turbulent kinetic energy. + * \param[in] val_turb_ke_i - Value of the turbulent kinetic energy at point i. + * \param[in] val_turb_ke_j - Value of the turbulent kinetic energy at point j. + */ + void SetTurbKineticEnergy(su2double val_turb_ke_i, su2double val_turb_ke_j); + + /*! + * \brief Set the value of the distance from the nearest wall. + * \param[in] val_dist_i - Value of of the distance from point i to the nearest wall. + * \param[in] val_dist_j - Value of of the distance from point j to the nearest wall. + */ + void SetDistance(su2double val_dist_i, su2double val_dist_j); + + /*! + * \brief Set coordinates of the points. + * \param[in] val_coord_i - Coordinates of the point i. + * \param[in] val_coord_j - Coordinates of the point j. + */ + void SetCoord(su2double *val_coord_i, su2double *val_coord_j); + + /*! + * \overload + * \param[in] val_coord_0 - Coordinates of the point 0. + * \param[in] val_coord_1 - Coordinates of the point 1. + * \param[in] val_coord_2 - Coordinates of the point 2. + */ + void SetCoord(su2double *val_coord_0, su2double *val_coord_1, su2double *val_coord_2); + + /*! + * \overload + * \param[in] val_coord_0 - Coordinates of the point 0. + * \param[in] val_coord_1 - Coordinates of the point 1. + * \param[in] val_coord_2 - Coordinates of the point 2. + * \param[in] val_coord_3 - Coordinates of the point 3. + */ + void SetCoord(su2double *val_coord_0, su2double *val_coord_1, su2double *val_coord_2, + su2double *val_coord_3); + + /*! + * \brief Set the velocity of the computational grid. + * \param[in] val_gridvel_i - Grid velocity of the point i. + * \param[in] val_gridvel_j - Grid velocity of the point j. + */ + void SetGridVel(su2double *val_gridvel_i, su2double *val_gridvel_j); + + /*! + * \brief Set the wind gust value. + * \param[in] val_windgust_i - Wind gust of the point i. + * \param[in] val_windgust_j - Wind gust of the point j. + */ + void SetWindGust(su2double *val_windgust_i, su2double *val_windgust_j); + + /*! + * \brief Set the wind gust derivatives values. + * \param[in] val_windgust_i - Wind gust derivatives of the point i. + * \param[in] val_windgust_j - Wind gust derivatives of the point j. + */ + void SetWindGustDer(su2double *val_windgustder_i, su2double *val_windgustder_j); + + /*! + * \brief Set the value of the pressure. + * \param[in] val_pressure_i - Value of the pressure at point i. + * \param[in] val_pressure_j - Value of the pressure at point j. + */ + void SetPressure(su2double val_pressure_i, su2double val_pressure_j); + + /*! + * \brief Set the value of the density for the incompressible solver. + * \param[in] val_densityinc_i - Value of the pressure at point i. + * \param[in] val_densityinc_j - Value of the pressure at point j. + */ + void SetDensityInc(su2double val_densityinc_i, su2double val_densityinc_j); + + /*! + * \brief Set the value of the beta for incompressible flows. + * \param[in] val_betainc2_i - Value of beta for incompressible flows at point i. + * \param[in] val_betainc2_j - Value of beta for incompressible flows at point j. + */ + void SetBetaInc2(su2double val_betainc2_i, su2double val_betainc2_j); + + /*! + * \brief Set the value of the sound speed. + * \param[in] val_soundspeed_i - Value of the sound speed at point i. + * \param[in] val_soundspeed_j - Value of the sound speed at point j. + */ + void SetSoundSpeed(su2double val_soundspeed_i, su2double val_soundspeed_j); + + /*! + * \brief Set the value of the temperature. + * \param[in] val_temp_i - Value of the temperature at point i. + * \param[in] val_temp_j - Value of the temperature at point j. + */ + void SetTemperature(su2double val_temp_i, su2double val_temp_j); + + /*! + * \brief Set the value of the enthalpy. + * \param[in] val_enthalpy_i - Value of the enthalpy at point i. + * \param[in] val_enthalpy_j - Value of the enthalpy at point j. + */ + void SetEnthalpy(su2double val_enthalpy_i, su2double val_enthalpy_j); + + /*! + * \brief Set the value of the spectral radius. + * \param[in] val_lambda_i - Value of the spectral radius at point i. + * \param[in] val_lambda_j - Value of the spectral radius at point j. + */ + void SetLambda(su2double val_lambda_i, su2double val_lambda_j); + + /*! + * \brief Set the value of undivided laplacian. + * \param[in] val_und_lapl_i Undivided laplacian at point i. + * \param[in] val_und_lapl_j Undivided laplacian at point j. + */ + void SetUndivided_Laplacian(su2double *val_und_lapl_i, su2double *val_und_lapl_j); + + /*! + * \brief Set the value of the pressure sensor. + * \param[in] val_sensor_i Pressure sensor at point i. + * \param[in] val_sensor_j Pressure sensor at point j. + */ + void SetSensor(su2double val_sensor_i, su2double val_sensor_j); + + /*! + * \brief Set the number of neighbor to a point. + * \param[in] val_neighbor_i - Number of neighbor to point i. + * \param[in] val_neighbor_j - Number of neighbor to point j. + */ + void SetNeighbor(unsigned short val_neighbor_i, unsigned short val_neighbor_j); + + /*! + * \brief Set the value of the normal vector to the face between two points. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + */ + void SetNormal(su2double *val_normal); + + /*! + * \brief Set the value of the volume of the control volume. + * \param[in] val_volume Volume of the control volume. + */ + void SetVolume(su2double val_volume); + + /*! + * \brief Retrieves the value of the species density in the primitive variable vector. + * \param[in] iRho_s + */ + void SetRhosIndex(unsigned short val_Index); + + /*! + * \brief Retrieves the value of the species density in the primitive variable vector. + * \param[in] iRho_s + */ + void SetRhoIndex(unsigned short val_Index); + + /*! + * \brief Retrieves the value of the species density in the primitive variable vector. + * \param[in] iRho_s + */ + void SetPIndex(unsigned short val_Index); + + /*! + * \brief Retrieves the value of the species density in the primitive variable vector. + * \param[in] iRho_s + */ + void SetTIndex(unsigned short val_Index); + + /*! + * \brief Retrieves the value of the species density in the primitive variable vector. + * \param[in] iRho_s + */ + void SetTveIndex(unsigned short val_Index); + + /*! + * \brief Retrieves the value of the velocity index in the primitive variable vector. + * \param[in] i(rho*u) + */ + void SetVelIndex(unsigned short val_Index); + + /*! + * \brief Retrieves the value of the species density in the primitive variable vector. + * \param[in] iRho_s + */ + void SetHIndex(unsigned short val_Index); + + /*! + * \brief Retrieves the value of the species density in the primitive variable vector. + * \param[in] iRho_s + */ + void SetAIndex(unsigned short val_Index); + + /*! + * \brief Retrieves the value of the species density in the primitive variable vector. + * \param[in] iRho_s + */ + void SetRhoCvtrIndex(unsigned short val_Index); + + /*! + * \brief Retrieves the value of the species density in the primitive variable vector. + * \param[in] iRho_s + */ + void SetRhoCvveIndex(unsigned short val_Index); + + /*! + * \brief Sets the value of the derivative of pressure w.r.t. species density. + * \param[in] iRho_s + */ + void SetdPdU(su2double *val_dPdU_i, su2double *val_dPdU_j); + + /*! + * \brief Sets the value of the derivative of temperature w.r.t. species density. + * \param[in] iRho_s + */ + void SetdTdU(su2double *val_dTdU_i, su2double *val_dTdU_j); + + /*! + * \brief Sets the value of the derivative of vib-el. temperature w.r.t. species density. + * \param[in] iRho_s + */ + void SetdTvedU(su2double *val_dTvedU_i, su2double *val_dTvedU_j); + + /*! + * \brief Get the inviscid fluxes. + * \param[in] val_density - Value of the density. + * \param[in] val_velocity - Value of the velocity. + * \param[in] val_pressure - Value of the pressure. + * \param[in] val_enthalpy - Value of the enthalpy. + */ + void GetInviscidFlux(su2double val_density, su2double *val_velocity, su2double val_pressure, su2double val_enthalpy); + + /*! + * \brief Get the viscous fluxes. + * \param[in] val_primvar - Value of the primitive variables. + * \param[in] val_gradprimvar - Gradient of the primitive variables. + * \param[in] val_laminar_viscosity - Value of the laminar viscosity. + * \param[in] val_eddy_viscosity - Value of the eddy viscosity. + * \param[in] val_mach_inf - Value of the Mach number at the infinity. + */ + void GetViscousFlux(su2double *val_primvar, su2double **val_gradprimvar, + su2double val_laminar_viscosity, su2double val_eddy_viscosity, + su2double val_mach_inf); + + /*! + * \brief Compute the projected inviscid flux vector. + * \param[in] val_density - Pointer to the density. + * \param[in] val_velocity - Pointer to the velocity. + * \param[in] val_pressure - Pointer to the pressure. + * \param[in] val_enthalpy - Pointer to the enthalpy. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[out] val_Proj_Flux - Pointer to the projected flux. + */ + void GetInviscidProjFlux(su2double *val_density, su2double *val_velocity, + su2double *val_pressure, su2double *val_enthalpy, + su2double *val_normal, su2double *val_Proj_Flux); + + /*! + * \brief Compute the projected inviscid flux vector for incompresible simulations + * \param[in] val_density - Pointer to the density. + * \param[in] val_velocity - Pointer to the velocity. + * \param[in] val_pressure - Pointer to the pressure. + * \param[in] val_betainc2 - Value of the artificial compresibility factor. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[out] val_Proj_Flux - Pointer to the projected flux. + */ + void GetInviscidArtCompProjFlux(su2double *val_density, su2double *val_velocity, + su2double *val_pressure, su2double *val_betainc2, + su2double *val_normal, su2double *val_Proj_Flux); + + /*! + * \brief Compute the projected inviscid flux vector for incompresible simulations + * \param[in] val_density - Pointer to the density. + * \param[in] val_velocity - Pointer to the velocity. + * \param[in] val_pressure - Pointer to the pressure. + * \param[in] val_betainc2 - Value of the artificial compresibility factor. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[out] val_Proj_Flux - Pointer to the projected flux. + */ + void GetInviscidArtComp_FreeSurf_ProjFlux(su2double *val_density, + su2double *val_velocity, + su2double *val_pressure, + su2double *val_betainc2, + su2double *val_levelset, + su2double *val_normal, + su2double *val_Proj_Flux); + + + /*! + * \brief Compute the projection of the viscous fluxes into a direction. + * \param[in] val_primvar - Primitive variables. + * \param[in] val_gradprimvar - Gradient of the primitive variables. + * \param[in] val_turb_ke - Turbulent kinetic energy + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[in] val_laminar_viscosity - Laminar viscosity. + * \param[in] val_eddy_viscosity - Eddy viscosity. + * \param[in] val_thermal_conductivity - Thermal Conductivity. + * \param[in] val_eddy_conductivity - Eddy Conductivity. + */ + + void GetViscousProjFlux(su2double *val_primvar, su2double **val_gradprimvar, + su2double val_turb_ke, su2double *val_normal, + su2double val_laminar_viscosity, + su2double val_eddy_viscosity); + /*! + * \brief Compute the projection of the viscous fluxes into a direction for general fluid model. + * \param[in] val_primvar - Primitive variables. + * \param[in] val_gradprimvar - Gradient of the primitive variables. + * \param[in] val_turb_ke - Turbulent kinetic energy + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[in] val_laminar_viscosity - Laminar viscosity. + * \param[in] val_eddy_viscosity - Eddy viscosity. + * \param[in] val_thermal_conductivity - Thermal Conductivity. + * \param[in] val_heat_capacity_cp - Heat Capacity at constant pressure. + */ + + void GetViscousProjFlux(su2double *val_primvar, su2double **val_gradprimvar, + su2double val_turb_ke, su2double *val_normal, + su2double val_laminar_viscosity, + su2double val_eddy_viscosity, + su2double val_thermal_conductivity, + su2double val_heat_capacity_cp); + + /* + * \brief Compute the projection of the viscous fluxes into a direction (artificial compresibility method). + * \param[in] val_primvar - Primitive variables. + * \param[in] val_gradprimvar - Gradient of the primitive variables. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[in] val_laminar_viscosity - Laminar viscosity. + * \param[in] val_eddy_viscosity - Eddy viscosity. + */ + + void GetViscousArtCompProjFlux(su2double **val_gradprimvar, + su2double *val_normal, + su2double val_laminar_viscosity, + su2double val_eddy_viscosity); + + /*! + * \brief Compute the projection of the inviscid Jacobian matrices. + * \param[in] val_velocity Pointer to the velocity. + * \param[in] val_energy Value of the energy. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[in] val_scale - Scale of the projection. + * \param[out] val_Proj_Jac_tensor - Pointer to the projected inviscid Jacobian. + */ + void GetInviscidProjJac(su2double *val_velocity, su2double *val_energy, + su2double *val_normal, su2double val_scale, + su2double **val_Proj_Jac_tensor); + + /*! + * \brief Compute the projection of the inviscid Jacobian matrices (artificial compresibility). + * \param[in] val_density - Value of the density. + * \param[in] val_velocity - Pointer to the velocity. + * \param[in] val_betainc2 - Value of the artificial compresibility factor. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[in] val_scale - Scale of the projection. + * \param[out] val_Proj_Jac_tensor - Pointer to the projected inviscid Jacobian. + */ + void GetInviscidArtCompProjJac(su2double *val_density, su2double *val_velocity, + su2double *val_betainc2, su2double *val_normal, + su2double val_scale, + su2double **val_Proj_Jac_tensor); + + /*! + * \brief Compute the projection of the inviscid Jacobian matrices (artificial compresibility). + * \param[in] val_density - Value of the density. + * \param[in] val_velocity - Pointer to the velocity. + * \param[in] val_betainc2 - Value of the artificial compresibility factor. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[in] val_scale - Scale of the projection. + * \param[out] val_Proj_Jac_tensor - Pointer to the projected inviscid Jacobian. + */ + void GetInviscidArtComp_FreeSurf_ProjJac(su2double *val_density, + su2double *val_ddensity, + su2double *val_velocity, + su2double *val_betainc2, + su2double *val_levelset, + su2double *val_normal, + su2double val_scale, + su2double **val_Proj_Jac_tensor); + + /*! + * \brief Compute the projection of the inviscid Jacobian matrices for general fluid model. + * \param[in] val_velocity Pointer to the velocity. + * \param[in] val_energy Value of the energy. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[in] val_scale - Scale of the projection. + * \param[out] val_Proj_Jac_tensor - Pointer to the projected inviscid Jacobian. + */ + void GetInviscidProjJac(su2double *val_velocity, su2double *val_enthalphy, + su2double *val_chi, su2double *val_kappa, + su2double *val_normal, su2double val_scale, + su2double **val_Proj_Jac_tensor); + + /*! + * \brief TSL-Approximation of Viscous NS Jacobians. + * \param[in] val_Mean_PrimVar - Mean value of the primitive variables. + * \param[in] val_laminar_viscosity - Value of the laminar viscosity. + * \param[in] val_eddy_viscosity - Value of the eddy viscosity. + * \param[in] val_dist_ij - Distance between the points. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[in] val_dS - Area of the face between two nodes. + * \param[in] val_Proj_Visc_Flux - Pointer to the projected viscous flux. + * \param[out] val_Proj_Jac_Tensor_i - Pointer to the projected viscous Jacobian at point i. + * \param[out] val_Proj_Jac_Tensor_j - Pointer to the projected viscous Jacobian at point j. + */ + void GetViscousProjJacs(su2double *val_Mean_PrimVar, + su2double val_laminar_viscosity, + su2double val_eddy_viscosity, + su2double val_dist_ij, + su2double *val_normal, su2double val_dS, + su2double *val_Proj_Visc_Flux, + su2double **val_Proj_Jac_Tensor_i, + su2double **val_Proj_Jac_Tensor_j); + + /*! + * \brief TSL-Approximation of Viscous NS Jacobians for arbitrary equations of state. + * \param[in] val_Mean_PrimVar - Mean value of the primitive variables. + * \param[in] val_gradprimvar - Mean value of the gradient of the primitive variables. + * \param[in] val_Mean_SecVar - Mean value of the secondary variables. + * \param[in] val_laminar_viscosity - Value of the laminar viscosity. + * \param[in] val_eddy_viscosity - Value of the eddy viscosity. + * \param[in] val_thermal_conductivity - Value of the thermal conductivity. + * \param[in] val_heat_capacity_cp - Value of the specific heat at constant pressure. + * \param[in] val_dist_ij - Distance between the points. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[in] val_dS - Area of the face between two nodes. + * \param[in] val_Proj_Visc_Flux - Pointer to the projected viscous flux. + * \param[out] val_Proj_Jac_Tensor_i - Pointer to the projected viscous Jacobian at point i. + * \param[out] val_Proj_Jac_Tensor_j - Pointer to the projected viscous Jacobian at point j. + */ + void GetViscousProjJacs(su2double *val_Mean_PrimVar, + su2double **val_gradprimvar, + su2double *val_Mean_SecVar, + su2double val_laminar_viscosity, + su2double val_eddy_viscosity, + su2double val_thermal_conductivity, + su2double val_heat_capacity_cp, + su2double val_dist_ij, + su2double *val_normal, su2double val_dS, + su2double *val_Proj_Visc_Flux, + su2double **val_Proj_Jac_Tensor_i, + su2double **val_Proj_Jac_Tensor_j); + + /*! + * \brief Mapping between primitives variables P and conservatives variables C. + * \param[in] val_Mean_PrimVar - Mean value of the primitive variables. + * \param[in] val_Mean_PrimVar - Mean Value of the secondary variables. + * \param[out] val_Jac_PC - Pointer to the Jacobian dPdC. + */ + void GetPrimitive2Conservative (su2double *val_Mean_PrimVar, + su2double *val_Mean_SecVar, + su2double **val_Jac_PC); + + /*! + * \brief Compute the projection of the viscous Jacobian matrices. + * \param[in] val_laminar_viscosity - Value of the laminar viscosity. + * \param[in] val_eddy_viscosity - Value of the eddy viscosity. + * \param[in] val_dist_ij - Distance between the points. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[in] val_dS - Area of the face between two nodes. + * \param[out] val_Proj_Jac_Tensor_i - Pointer to the projected viscous Jacobian at point i. + * \param[out] val_Proj_Jac_Tensor_j - Pointer to the projected viscous Jacobian at point j. + */ + void GetViscousArtCompProjJacs(su2double val_laminar_viscosity, + su2double val_eddy_viscosity, su2double val_dist_ij, + su2double *val_normal, su2double val_dS, + su2double **val_Proj_Jac_Tensor_i, + su2double **val_Proj_Jac_Tensor_j); + + /*! + * \overload + * \brief Computation of the matrix P for a generic fluid model + * \param[in] val_density - Value of the density. + * \param[in] val_velocity - Value of the velocity. + * \param[in] val_soundspeed - Value of the sound speed. + * \param[in] val_enthalpy - Value of the Enthalpy + * \param[in] val_chi - Value of the derivative of Pressure with respect to the Density. + * \param[in] val_kappa - Value of the derivative of Pressure with respect to the volume specific Static Energy. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[out] val_p_tensor - Pointer to the P matrix. + */ + void GetPMatrix(su2double *val_density, su2double *val_velocity, + su2double *val_soundspeed, su2double *val_enthalpy, su2double *val_chi, su2double *val_kappa, + su2double *val_normal, su2double **val_p_tensor); + + /*! + * \brief Computation of the matrix P, this matrix diagonalize the conservative Jacobians in + * the form $P^{-1}(A.Normal)P=Lambda$. + * \param[in] val_density - Value of the density. + * \param[in] val_velocity - Value of the velocity. + * \param[in] val_soundspeed - Value of the sound speed. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[out] val_p_tensor - Pointer to the P matrix. + */ + void GetPMatrix(su2double *val_density, su2double *val_velocity, + su2double *val_soundspeed, su2double *val_normal, + su2double **val_p_tensor); + + /*! + * \brief Computation of the matrix Rinv*Pe. + * \param[in] Beta2 - A variable in used to define Pe matrix. + * \param[in] val_enthalpy - value of the enthalpy. + * \param[in] val_soundspeed - value of the sound speed. + * \param[in] val_density - value of the density. + * \param[in] val_velocity - value of the velocity. + * \param[out] val_invR_invPe - Pointer to the matrix of conversion from entropic to conserved variables. + */ + void GetinvRinvPe(su2double Beta2, su2double val_enthalpy, su2double val_soundspeed, + su2double val_density, su2double* val_velocity, su2double** val_invR_invPe); - - /*! - * \brief Computation of the matrix R. - * \param[in] val_pressure - value of the pressure. - * \param[in] val_soundspeed - value of the sound speed. - * \param[in] val_density - value of the density. - * \param[in] val_velocity - value of the velocity. - * \param[out] val_invR_invPe - Pointer to the matrix of conversion from entropic to conserved variables. - */ + + /*! + * \brief Computation of the matrix R. + * \param[in] val_pressure - value of the pressure. + * \param[in] val_soundspeed - value of the sound speed. + * \param[in] val_density - value of the density. + * \param[in] val_velocity - value of the velocity. + * \param[out] val_invR_invPe - Pointer to the matrix of conversion from entropic to conserved variables. + */ + + void GetRMatrix(su2double val_pressure, su2double val_soundspeed, + su2double val_density, su2double* val_velocity, + su2double** val_invR_invPe); + /*! + * \brief Computation of the matrix R. + * \param[in] val_soundspeed - value of the sound speed. + * \param[in] val_density - value of the density. + * \param[in] val_normal - value of the unit normal. + * \param[out] R_Matrix - Pointer to the matrix of conversion from entropic to conserved variables. + */ + void GetRMatrix(su2double val_soundspeed, su2double val_density, su2double* val_normal, su2double **R_Matrix); - void GetRMatrix(su2double val_pressure, su2double val_soundspeed, - su2double val_density, su2double* val_velocity, - su2double** val_invR_invPe); - /*! - * \brief Computation of the matrix R. - * \param[in] val_soundspeed - value of the sound speed. - * \param[in] val_density - value of the density. - * \param[in] val_normal - value of the unit normal. - * \param[out] R_Matrix - Pointer to the matrix of conversion from entropic to conserved variables. - */ - void GetRMatrix(su2double val_soundspeed, su2double val_density, su2double* val_normal, su2double **R_Matrix); - - - - /*! - * \brief Computation of the matrix R. - * \param[in] val_soundspeed - value of the sound speed. - * \param[in] val_density - value of the density. - * \param[in] val_normal - value of the unit normal. - * \param[out] L_Matrix - Pointer to the matrix of conversion from conserved to entropic variables. - */ - void GetLMatrix(su2double val_soundspeed, su2double val_density, su2double* val_normal, su2double **L_Matrix); - - /*! - * \brief Computation of the matrix Td, this matrix diagonalize the preconditioned conservative Jacobians - * in the form $Tg |Lambda| Td = Pc{-1}|Pc (A.Normal)|$. - * \param[in] Beta2 - A variable in used to define absPeJacobian matrix. - * \param[in] r_hat - A variable in used to define absPeJacobian matrix. - * \param[in] s_hat - A variable in used to define absPeJacobian matrix. - * \param[in] t_hat - A variable in used to define absPeJacobian matrix. - * \param[in] rB2a2 - A variable in used to define absPeJacobian matrix. - * \param[in] val_Lambda - Eigenvalues of the Preconditioned Jacobian. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[out] val_absPeJac - Pointer to the Preconditioned Jacobian matrix. - */ - void GetPrecondJacobian(su2double Beta2, su2double r_hat, su2double s_hat, su2double t_hat, su2double rB2a2, su2double* val_Lambda, su2double* val_normal, su2double** val_absPeJac); - - /*! - * \brief Computation of the matrix P (artificial compresibility), this matrix diagonalize the conservative Jacobians in - * the form $P^{-1}(A.Normal)P=Lambda$. - * \param[in] val_density - Value of the density. - * \param[in] val_velocity - Value of the velocity. - * \param[in] val_betainv2 - Value of the compresibility factor. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[out] val_p_tensor - Pointer to the P matrix. - */ + + + /*! + * \brief Computation of the matrix R. + * \param[in] val_soundspeed - value of the sound speed. + * \param[in] val_density - value of the density. + * \param[in] val_normal - value of the unit normal. + * \param[out] L_Matrix - Pointer to the matrix of conversion from conserved to entropic variables. + */ + void GetLMatrix(su2double val_soundspeed, su2double val_density, su2double* val_normal, su2double **L_Matrix); + + /*! + * \brief Computation of the matrix Td, this matrix diagonalize the preconditioned conservative Jacobians + * in the form $Tg |Lambda| Td = Pc{-1}|Pc (A.Normal)|$. + * \param[in] Beta2 - A variable in used to define absPeJacobian matrix. + * \param[in] r_hat - A variable in used to define absPeJacobian matrix. + * \param[in] s_hat - A variable in used to define absPeJacobian matrix. + * \param[in] t_hat - A variable in used to define absPeJacobian matrix. + * \param[in] rB2a2 - A variable in used to define absPeJacobian matrix. + * \param[in] val_Lambda - Eigenvalues of the Preconditioned Jacobian. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[out] val_absPeJac - Pointer to the Preconditioned Jacobian matrix. + */ + void GetPrecondJacobian(su2double Beta2, su2double r_hat, su2double s_hat, su2double t_hat, su2double rB2a2, su2double* val_Lambda, su2double* val_normal, su2double** val_absPeJac); + + /*! + * \brief Computation of the matrix P (artificial compresibility), this matrix diagonalize the conservative Jacobians in + * the form $P^{-1}(A.Normal)P=Lambda$. + * \param[in] val_density - Value of the density. + * \param[in] val_velocity - Value of the velocity. + * \param[in] val_betainv2 - Value of the compresibility factor. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[out] val_p_tensor - Pointer to the P matrix. + */ void GetPArtCompMatrix(su2double *val_density, su2double *val_velocity, - su2double *val_betainv2, su2double *val_normal, - su2double **val_p_tensor); - - /*! - * \brief Computation of the matrix P (artificial compresibility), this matrix diagonalize the conservative Jacobians in - * the form $P^{-1}(A.Normal)P=Lambda$. - * \param[in] val_density - Value of the density. - * \param[in] val_velocity - Value of the velocity. - * \param[in] val_betainv2 - Value of the compresibility factor. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[out] val_p_tensor - Pointer to the P matrix. - */ - void GetPArtComp_FreeSurf_Matrix(su2double *val_density, su2double *val_ddensity, - su2double *val_velocity, su2double *val_betainv2, - su2double *val_levelset, su2double *val_normal, - su2double **val_p_tensor); - - /*! - * \brief Computation of the matrix P^{-1}, this matrix diagonalize the conservative Jacobians - * in the form $P^{-1}(A.Normal)P=Lambda$. - * \param[in] val_density - Value of the density. - * \param[in] val_velocity - Value of the velocity. - * \param[in] val_soundspeed - Value of the sound speed. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[out] val_invp_tensor - Pointer to inverse of the P matrix. - */ - void GetPMatrix_inv(su2double **val_invp_tensor, su2double *val_density, - su2double *val_velocity, su2double *val_soundspeed, - su2double *val_chi, su2double *val_kappa, - su2double *val_normal); - - /*! - * \brief Computation of the matrix P^{-1}, this matrix diagonalize the conservative Jacobians - * in the form $P^{-1}(A.Normal)P=Lambda$. - * \param[in] val_density - Value of the density. - * \param[in] val_velocity - Value of the velocity. - * \param[in] val_soundspeed - Value of the sound speed. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[out] val_invp_tensor - Pointer to inverse of the P matrix. - */ - void GetPMatrix_inv(su2double *val_density, su2double *val_velocity, - su2double *val_soundspeed, su2double *val_normal, - su2double **val_invp_tensor); - - /*! - * \brief Computation of the matrix P^{-1} (artificial compresibility), this matrix diagonalize the conservative Jacobians - * in the form $P^{-1}(A.Normal)P=Lambda$. - * \param[in] val_density - Value of the density. - * \param[in] val_velocity - Value of the velocity. - * \param[in] val_betainv2 - Value of the compresibility factor. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[out] val_invp_tensor - Pointer to inverse of the P matrix. - */ - void GetPArtCompMatrix_inv(su2double *val_density, su2double *val_velocity, - su2double *val_betainv2, su2double *val_normal, - su2double **val_invp_tensor); - - /*! - * \brief Computation of the matrix P^{-1} (artificial compresibility), this matrix diagonalize the conservative Jacobians - * in the form $P^{-1}(A.Normal)P=Lambda$. - * \param[in] val_density - Value of the density. - * \param[in] val_velocity - Value of the velocity. - * \param[in] val_betainv2 - Value of the compresibility factor. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[out] val_invp_tensor - Pointer to inverse of the P matrix. - */ - void GetPArtComp_FreeSurf_Matrix_inv(su2double *val_density, - su2double *val_ddensity, - su2double *val_velocity, - su2double *val_betainv2, - su2double *val_levelset, - su2double *val_normal, - su2double **val_invp_tensor); - - /*! - * \brief Compute viscous residual and jacobian. - */ - void GetAdjViscousFlux_Jac(su2double Pressure_i, su2double Pressure_j, su2double Density_i, su2double Density_j, - su2double ViscDens_i, su2double ViscDens_j, su2double *Velocity_i, su2double *Velocity_j, - su2double sq_vel_i, su2double sq_vel_j, - su2double XiDens_i, su2double XiDens_j, su2double **Mean_GradPhi, su2double *Mean_GradPsiE, - su2double dPhiE_dn, su2double *Normal, su2double *Edge_Vector, su2double dist_ij_2, su2double *val_residual_i, - su2double *val_residual_j, - su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, - su2double **val_Jacobian_jj, bool implicit); - - /*! - * \brief Computation of the projected inviscid lambda (eingenvalues). - * \param[in] val_velocity - Value of the velocity. - * \param[in] val_soundspeed - Value of the sound speed. - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[in] val_Lambda_Vector - Pointer to Lambda matrix. - */ - void GetJacInviscidLambda_fabs(su2double *val_velocity, su2double val_soundspeed, - su2double *val_normal, su2double *val_Lambda_Vector); - - /*! - * \brief Compute the numerical residual. - * \param[out] val_residual - Pointer to the total residual. - * \param[in] config - Definition of the particular problem. - */ - virtual void ComputeResidual(su2double *val_residual, CConfig *config); - - /*! - * \overload - * \param[out] val_residual_i - Pointer to the total residual at point i. - * \param[out] val_residual_j - Pointer to the total residual at point j. - */ - virtual void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j); - - virtual void ComputeResidual_TransLM(su2double *val_residual, - su2double **val_Jacobian_i, - su2double **val_Jacobian_j, CConfig *config, - su2double &gamma_sep) ; - - /*! - * \overload - * \param[out] val_residual_i - Pointer to the total residual at point i. - * \param[out] val_residual_j - Pointer to the total residual at point j. - * \param[in] config - Definition of the particular problem. - */ - virtual void ComputeResidual(su2double *val_residual_i, - su2double *val_residual_j, CConfig *config); - - /*! - * \overload - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - virtual void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, - su2double **val_Jacobian_j, CConfig *config); - - /*! - * \overload - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[out] val_JacobianMeanFlow_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_JacobianMeanFlow_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - virtual void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, - su2double **val_Jacobian_j, - su2double **val_JacobianMeanFlow_i, - su2double **val_JacobianMeanFlow_j, - CConfig *config); - - /*! - * \overload - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - virtual void ComputeResidual(su2double **val_Jacobian_i, su2double **val_Jacobian_j, - CConfig *config); - - /*! - * \overload - * \param[out] val_resconv - Pointer to the convective residual. - * \param[out] val_resvisc - Pointer to the artificial viscosity residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - virtual void ComputeResidual(su2double *val_resconv, su2double *val_resvisc, - su2double **val_Jacobian_i, su2double **val_Jacobian_j, - CConfig *config); - - /*! - * \overload - * \param[out] val_residual_i - Pointer to the total residual at point i. - * \param[out] val_residual_j - Pointer to the total viscosity residual at point j. - * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. - * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. - * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. - * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. - * \param[in] config - Definition of the particular problem. - */ - virtual void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, - su2double **val_Jacobian_ii, - su2double **val_Jacobian_ij, - su2double **val_Jacobian_ji, - su2double **val_Jacobian_jj, CConfig *config); - - /*! - * \overload - * \param[out] val_resconv_i - Pointer to the convective residual at point i. - * \param[out] val_resvisc_i - Pointer to the artificial viscosity residual at point i. - * \param[out] val_resconv_j - Pointer to the convective residual at point j. - * \param[out] val_resvisc_j - Pointer to the artificial viscosity residual at point j. - * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. - * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. - * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. - * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. - * \param[in] config - Definition of the particular problem. - */ - virtual void ComputeResidual(su2double *val_resconv_i, su2double *val_resvisc_i, - su2double *val_resconv_j, su2double *val_resvisc_j, - su2double **val_Jacobian_ii, - su2double **val_Jacobian_ij, - su2double **val_Jacobian_ji, - su2double **val_Jacobian_jj, CConfig *config); - - /*! - * \overload - * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. - * \param[in] config - Definition of the particular problem. - */ - virtual void ComputeResidual(su2double **val_stiffmatrix_elem, CConfig *config); - - /*! - * \overload - * \param[in] config - Definition of the particular problem. - * \param[out] val_residual - residual of the source terms - * \param[out] val_Jacobian_i - Jacobian of the source terms - */ - virtual void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, - CConfig *config); - - /*! - * \overload - * \param[out] - Matrix for storing the constants to be used in the calculation of the equilibrium extent of reaction Keq. - * \param[in] config - Definition of the particular problem. - */ - virtual void GetEq_Rxn_Coefficients(su2double **EqnRxnConstants, CConfig *config); - - /*! - * \brief Residual for source term integration. - * \param[out] val_residual - Pointer to the source residual containing chemistry terms. - * \param[in] config - Definition of the particular problem. - */ - virtual void ComputeResidual_Axisymmetric(su2double *val_residual, CConfig *config); - - /*! - * \brief Residual for source term integration. - * \param[out] val_residual - Pointer to the source residual containing chemistry terms. - * \param[in] config - Definition of the particular problem. - */ - virtual void ComputeResidual_Axisymmetric_ad(su2double *val_residual, su2double *val_residuald, CConfig *config); - - /*! - * \brief Calculation of axisymmetric source term Jacobian - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - virtual void SetJacobian_Axisymmetric(su2double **val_Jacobian_i, CConfig *config); - - /*! - * \brief Calculation of the translational-vibrational energy exchange source term - * \param[in] config - Definition of the particular problem. - * \param[out] val_residual - residual of the source terms - * \param[out] val_Jacobian_i - Jacobian of the source terms - */ - virtual void ComputeVibRelaxation(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config); - - /*! - * \brief Calculation of the chemistry source term - * \param[in] config - Definition of the particular problem. - * \param[out] val_residual - residual of the source terms - * \param[out] val_Jacobian_i - Jacobian of the source terms - */ - virtual void ComputeChemistry(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config); - - /*! - * \brief Calculates constants used for Keq correlation. - * \param[out] A - Pointer to coefficient array. - * \param[in] val_reaction - Reaction number indicator. - * \param[in] config - Definition of the particular problem. - */ - virtual void GetKeqConstants(su2double *A, unsigned short val_reaction, CConfig *config); - - /*! - * \brief Set intermittency for numerics (used in SA with LM transition model) - */ - virtual void SetIntermittency(su2double intermittency_in); - - /*! - * \brief Residual for source term integration. - * \param[in] val_production - Value of the Production. - */ - virtual void SetProduction(su2double val_production); - - /*! - * \brief Residual for source term integration. - * \param[in] val_destruction - Value of the Destruction. - */ - virtual void SetDestruction(su2double val_destruction); - - /*! - * \brief Residual for source term integration. - * \param[in] val_crossproduction - Value of the CrossProduction. - */ - virtual void SetCrossProduction(su2double val_crossproduction); - - /*! - * \brief Residual for source term integration. - * \param[in] val_production - Value of the Production. - */ - virtual su2double GetProduction(void); - - /*! - * \brief Residual for source term integration. - * \param[in] val_destruction - Value of the Destruction. - */ - virtual su2double GetDestruction(void); - - /*! - * \brief Residual for source term integration. - * \param[in] val_crossproduction - Value of the CrossProduction. - */ - virtual su2double GetCrossProduction(void); - - /*! - * \overload - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i - * \param[in] config - Definition of the particular problem. - */ - virtual void ComputeResidual(su2double **val_Jacobian_i, - su2double *val_Jacobian_mui, - su2double ***val_Jacobian_gradi, CConfig *config); - - /*! - * \overload - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i - * \param[in] config - Definition of the particular problem. - */ - virtual void ComputeResidual(su2double **val_Jacobian_i, - su2double *val_Jacobian_mui, - su2double ***val_Jacobian_gradi, - su2double **val_Jacobian_j, - su2double *val_Jacobian_muj, - su2double ***val_Jacobian_gradj, CConfig *config); - - /*! - * \brief Computing stiffness matrix of the Galerkin method. - * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetFEA_StiffMatrix2D(su2double **StiffMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d); - - /*! - * \brief Computing stiffness matrix of the Galerkin method. - * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetFEA_StiffMatrix3D(su2double **StiffMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes); - - /*! - * \brief Computing mass matrix of the Galerkin method. - * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetFEA_StiffMassMatrix2D(su2double **StiffMatrix_Elem, su2double **MassMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d); - - /*! - * \brief Computing mass matrix of the Galerkin method. - * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetFEA_StiffMassMatrix3D(su2double **StiffMatrix_Elem, su2double **MassMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes); - - /*! - * \brief Computing dead load vector of the Galerkin method. - * \param[out] val_deadloadvector_elem - Dead load at the nodes for Galerkin computation. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetFEA_DeadLoad2D(su2double *DeadLoadVector_Elem, su2double CoordCorners[8][3], unsigned short nNodes, su2double matDensity); - - /*! - * \brief Computing stiffness matrix of the Galerkin method. - * \param[out] val_deadloadvector_elem - Dead load at the nodes for Galerkin computation. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetFEA_DeadLoad3D(su2double *DeadLoadVector_Elem, su2double CoordCorners[8][3], unsigned short nNodes, su2double matDensity); - - - /*! - * \brief Computing stresses in FEA method. - * \param[in] config - Definition of the particular problem. - */ - virtual void GetFEA_StressNodal2D(su2double StressVector[8][3], su2double DispElement[8], su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d); - - - /*! - * \brief Computing stresses in FEA method. - * \param[in] config - Definition of the particular problem. - */ - virtual void GetFEA_StressNodal3D(su2double StressVector[8][6], su2double DispElement[24], su2double CoordCorners[8][3], unsigned short nNodes); - - /*! - * \brief A virtual member to linearly interpolate pressures - * \param[in] config - Definition of the particular problem. - */ - virtual void PressInt_Linear(su2double CoordCorners[4][3], su2double *tn_e, su2double Fnodal[12]); - - /*! - * \brief A virtual member to linearly interpolate viscous stresses - * \param[in] config - Definition of the particular problem. - */ - virtual void ViscTermInt_Linear(su2double CoordCorners[2][2], su2double Tau_0[3][3], su2double Tau_1[3][3], su2double FviscNodal[4]); - - /*! - * \brief Computes a basis of orthogonal vectors from a suppled vector - * \param[in] config - Normal vector - */ - void CreateBasis(su2double *val_Normal); - -}; - -/*! - * \class CUpwCUSP_Flow - * \brief Class for centered scheme - CUSP. - * \ingroup ConvDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CUpwCUSP_Flow : public CNumerics { - -private: - unsigned short iDim, iVar, jVar; /*!< \brief Iteration on dimension and variables. */ - su2double *Diff_U, *Diff_Flux, /*!< \brief Diference of conservative variables and undivided laplacians. */ - *Velocity_i, *Velocity_j, /*!< \brief Velocity at node 0 and 1. */ - *MeanVelocity, ProjVelocity, /*!< \brief Mean and projected velocities. */ - Density_i, Density_j, Energy_i, Energy_j, /*!< \brief Mean Density and energies. */ - sq_vel_i, sq_vel_j, /*!< \brief Modulus of the velocity and the normal vector. */ - MeanDensity, MeanPressure, MeanEnthalpy, MeanEnergy, /*!< \brief Mean values of primitive variables. */ - *ProjFlux, *ProjFlux_i, *ProjFlux_j, /*!< \brief Projected inviscid flux tensor. */ - cte_0, cte_1, /*!< \brief Artificial dissipation values. */ - LamdaNeg, LamdaPos, Beta, Nu_c, U_i[5], U_j[5], MeanSoundSpeed, Mach, - **Jacobian; /*!< \brief Projected grid velocity. */ - bool implicit, /*!< \brief Implicit calculation. */ - grid_movement; /*!< \brief Modification for grid movement. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimension of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwCUSP_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwCUSP_Flow(void); - - /*! - * \brief Compute the flow residual using a JST method. - * \param[out] val_residual - Pointer to the residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, - CConfig *config); -}; - -/*! - * \class CUpwRoe_Flow - * \brief Class for solving an approximate Riemann solver of Roe for the flow equations. - * \ingroup ConvDiscr - * \author A. Bueno, F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CUpwRoe_Flow : public CNumerics { -private: - bool implicit, grid_movement; - su2double *Diff_U; - su2double *Velocity_i, *Velocity_j, *RoeVelocity; - su2double *ProjFlux_i, *ProjFlux_j; - su2double *delta_wave, *delta_vel; - su2double *Lambda, *Epsilon, MaxLambda, Delta; - su2double **P_Tensor, **invP_Tensor; - su2double sq_vel, Proj_ModJac_Tensor_ij, Density_i, Energy_i, SoundSpeed_i, Pressure_i, Enthalpy_i, - Density_j, Energy_j, SoundSpeed_j, Pressure_j, Enthalpy_j, R, RoeDensity, RoeEnthalpy, RoeSoundSpeed, - ProjVelocity, ProjVelocity_i, ProjVelocity_j, proj_delta_vel, delta_p, delta_rho, RoeSoundSpeed2, kappa; - unsigned short iDim, iVar, jVar, kVar; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwRoe_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwRoe_Flow(void); - - /*! - * \brief Compute the Roe's flux between two nodes i and j. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - - -/*! - * \class CUpwGeneralRoe_Flow - * \brief Class for solving an approximate Riemann solver of Roe for the flow equations for a general fluid model. - * \ingroup ConvDiscr - * \author S.Vitale, G.Gori, M.Pini - * \version 4.0.1 "Cardinal" - */ -class CUpwGeneralRoe_Flow : public CNumerics { -private: + su2double *val_betainv2, su2double *val_normal, + su2double **val_p_tensor); + + /*! + * \brief Computation of the matrix P (artificial compresibility), this matrix diagonalize the conservative Jacobians in + * the form $P^{-1}(A.Normal)P=Lambda$. + * \param[in] val_density - Value of the density. + * \param[in] val_velocity - Value of the velocity. + * \param[in] val_betainv2 - Value of the compresibility factor. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[out] val_p_tensor - Pointer to the P matrix. + */ + void GetPArtComp_FreeSurf_Matrix(su2double *val_density, su2double *val_ddensity, + su2double *val_velocity, su2double *val_betainv2, + su2double *val_levelset, su2double *val_normal, + su2double **val_p_tensor); + + /*! + * \brief Computation of the matrix P^{-1}, this matrix diagonalize the conservative Jacobians + * in the form $P^{-1}(A.Normal)P=Lambda$. + * \param[in] val_density - Value of the density. + * \param[in] val_velocity - Value of the velocity. + * \param[in] val_soundspeed - Value of the sound speed. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[out] val_invp_tensor - Pointer to inverse of the P matrix. + */ + void GetPMatrix_inv(su2double **val_invp_tensor, su2double *val_density, + su2double *val_velocity, su2double *val_soundspeed, + su2double *val_chi, su2double *val_kappa, + su2double *val_normal); + + /*! + * \brief Computation of the matrix P^{-1}, this matrix diagonalize the conservative Jacobians + * in the form $P^{-1}(A.Normal)P=Lambda$. + * \param[in] val_density - Value of the density. + * \param[in] val_velocity - Value of the velocity. + * \param[in] val_soundspeed - Value of the sound speed. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[out] val_invp_tensor - Pointer to inverse of the P matrix. + */ + void GetPMatrix_inv(su2double *val_density, su2double *val_velocity, + su2double *val_soundspeed, su2double *val_normal, + su2double **val_invp_tensor); + + /*! + * \brief Computation of the matrix P^{-1} (artificial compresibility), this matrix diagonalize the conservative Jacobians + * in the form $P^{-1}(A.Normal)P=Lambda$. + * \param[in] val_density - Value of the density. + * \param[in] val_velocity - Value of the velocity. + * \param[in] val_betainv2 - Value of the compresibility factor. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[out] val_invp_tensor - Pointer to inverse of the P matrix. + */ + void GetPArtCompMatrix_inv(su2double *val_density, su2double *val_velocity, + su2double *val_betainv2, su2double *val_normal, + su2double **val_invp_tensor); + + /*! + * \brief Computation of the matrix P^{-1} (artificial compresibility), this matrix diagonalize the conservative Jacobians + * in the form $P^{-1}(A.Normal)P=Lambda$. + * \param[in] val_density - Value of the density. + * \param[in] val_velocity - Value of the velocity. + * \param[in] val_betainv2 - Value of the compresibility factor. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[out] val_invp_tensor - Pointer to inverse of the P matrix. + */ + void GetPArtComp_FreeSurf_Matrix_inv(su2double *val_density, + su2double *val_ddensity, + su2double *val_velocity, + su2double *val_betainv2, + su2double *val_levelset, + su2double *val_normal, + su2double **val_invp_tensor); + + /*! + * \brief Compute viscous residual and jacobian. + */ + void GetAdjViscousFlux_Jac(su2double Pressure_i, su2double Pressure_j, su2double Density_i, su2double Density_j, + su2double ViscDens_i, su2double ViscDens_j, su2double *Velocity_i, su2double *Velocity_j, + su2double sq_vel_i, su2double sq_vel_j, + su2double XiDens_i, su2double XiDens_j, su2double **Mean_GradPhi, su2double *Mean_GradPsiE, + su2double dPhiE_dn, su2double *Normal, su2double *Edge_Vector, su2double dist_ij_2, su2double *val_residual_i, + su2double *val_residual_j, + su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, + su2double **val_Jacobian_jj, bool implicit); + + /*! + * \brief Computation of the projected inviscid lambda (eingenvalues). + * \param[in] val_velocity - Value of the velocity. + * \param[in] val_soundspeed - Value of the sound speed. + * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. + * \param[in] val_Lambda_Vector - Pointer to Lambda matrix. + */ + void GetJacInviscidLambda_fabs(su2double *val_velocity, su2double val_soundspeed, + su2double *val_normal, su2double *val_Lambda_Vector); + + /*! + * \brief Compute the numerical residual. + * \param[out] val_residual - Pointer to the total residual. + * \param[in] config - Definition of the particular problem. + */ + virtual void ComputeResidual(su2double *val_residual, CConfig *config); + + /*! + * \overload + * \param[out] val_residual_i - Pointer to the total residual at point i. + * \param[out] val_residual_j - Pointer to the total residual at point j. + */ + virtual void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j); + + virtual void ComputeResidual_TransLM(su2double *val_residual, + su2double **val_Jacobian_i, + su2double **val_Jacobian_j, CConfig *config, + su2double &gamma_sep) ; + + /*! + * \overload + * \param[out] val_residual_i - Pointer to the total residual at point i. + * \param[out] val_residual_j - Pointer to the total residual at point j. + * \param[in] config - Definition of the particular problem. + */ + virtual void ComputeResidual(su2double *val_residual_i, + su2double *val_residual_j, CConfig *config); + + /*! + * \overload + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + virtual void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, + su2double **val_Jacobian_j, CConfig *config); + + /*! + * \overload + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[out] val_JacobianMeanFlow_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_JacobianMeanFlow_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + virtual void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, + su2double **val_Jacobian_j, + su2double **val_JacobianMeanFlow_i, + su2double **val_JacobianMeanFlow_j, + CConfig *config); + + /*! + * \overload + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + virtual void ComputeResidual(su2double **val_Jacobian_i, su2double **val_Jacobian_j, + CConfig *config); + + /*! + * \overload + * \param[out] val_resconv - Pointer to the convective residual. + * \param[out] val_resvisc - Pointer to the artificial viscosity residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + virtual void ComputeResidual(su2double *val_resconv, su2double *val_resvisc, + su2double **val_Jacobian_i, su2double **val_Jacobian_j, + CConfig *config); + + /*! + * \overload + * \param[out] val_residual_i - Pointer to the total residual at point i. + * \param[out] val_residual_j - Pointer to the total viscosity residual at point j. + * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. + * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. + * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. + * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. + * \param[in] config - Definition of the particular problem. + */ + virtual void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, + su2double **val_Jacobian_ii, + su2double **val_Jacobian_ij, + su2double **val_Jacobian_ji, + su2double **val_Jacobian_jj, CConfig *config); + + /*! + * \overload + * \param[out] val_resconv_i - Pointer to the convective residual at point i. + * \param[out] val_resvisc_i - Pointer to the artificial viscosity residual at point i. + * \param[out] val_resconv_j - Pointer to the convective residual at point j. + * \param[out] val_resvisc_j - Pointer to the artificial viscosity residual at point j. + * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. + * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. + * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. + * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. + * \param[in] config - Definition of the particular problem. + */ + virtual void ComputeResidual(su2double *val_resconv_i, su2double *val_resvisc_i, + su2double *val_resconv_j, su2double *val_resvisc_j, + su2double **val_Jacobian_ii, + su2double **val_Jacobian_ij, + su2double **val_Jacobian_ji, + su2double **val_Jacobian_jj, CConfig *config); + + /*! + * \overload + * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. + * \param[in] config - Definition of the particular problem. + */ + virtual void ComputeResidual(su2double **val_stiffmatrix_elem, CConfig *config); + + /*! + * \overload + * \param[in] config - Definition of the particular problem. + * \param[out] val_residual - residual of the source terms + * \param[out] val_Jacobian_i - Jacobian of the source terms + */ + virtual void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, + CConfig *config); + + /*! + * \overload + * \param[out] - Matrix for storing the constants to be used in the calculation of the equilibrium extent of reaction Keq. + * \param[in] config - Definition of the particular problem. + */ + virtual void GetEq_Rxn_Coefficients(su2double **EqnRxnConstants, CConfig *config); + + /*! + * \brief Residual for source term integration. + * \param[out] val_residual - Pointer to the source residual containing chemistry terms. + * \param[in] config - Definition of the particular problem. + */ + virtual void ComputeResidual_Axisymmetric(su2double *val_residual, CConfig *config); + + /*! + * \brief Residual for source term integration. + * \param[out] val_residual - Pointer to the source residual containing chemistry terms. + * \param[in] config - Definition of the particular problem. + */ + virtual void ComputeResidual_Axisymmetric_ad(su2double *val_residual, su2double *val_residuald, CConfig *config); + + /*! + * \brief Calculation of axisymmetric source term Jacobian + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + virtual void SetJacobian_Axisymmetric(su2double **val_Jacobian_i, CConfig *config); + + /*! + * \brief Calculation of the translational-vibrational energy exchange source term + * \param[in] config - Definition of the particular problem. + * \param[out] val_residual - residual of the source terms + * \param[out] val_Jacobian_i - Jacobian of the source terms + */ + virtual void ComputeVibRelaxation(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config); + + /*! + * \brief Calculation of the chemistry source term + * \param[in] config - Definition of the particular problem. + * \param[out] val_residual - residual of the source terms + * \param[out] val_Jacobian_i - Jacobian of the source terms + */ + virtual void ComputeChemistry(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config); + + /*! + * \brief Calculates constants used for Keq correlation. + * \param[out] A - Pointer to coefficient array. + * \param[in] val_reaction - Reaction number indicator. + * \param[in] config - Definition of the particular problem. + */ + virtual void GetKeqConstants(su2double *A, unsigned short val_reaction, CConfig *config); + + /*! + * \brief Set intermittency for numerics (used in SA with LM transition model) + */ + virtual void SetIntermittency(su2double intermittency_in); + + /*! + * \brief Residual for source term integration. + * \param[in] val_production - Value of the Production. + */ + virtual void SetProduction(su2double val_production); + + /*! + * \brief Residual for source term integration. + * \param[in] val_destruction - Value of the Destruction. + */ + virtual void SetDestruction(su2double val_destruction); + + /*! + * \brief Residual for source term integration. + * \param[in] val_crossproduction - Value of the CrossProduction. + */ + virtual void SetCrossProduction(su2double val_crossproduction); + + /*! + * \brief Residual for source term integration. + * \param[in] val_production - Value of the Production. + */ + virtual su2double GetProduction(void); + + /*! + * \brief Residual for source term integration. + * \param[in] val_destruction - Value of the Destruction. + */ + virtual su2double GetDestruction(void); + + /*! + * \brief Residual for source term integration. + * \param[in] val_crossproduction - Value of the CrossProduction. + */ + virtual su2double GetCrossProduction(void); + + /*! + * \overload + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i + * \param[in] config - Definition of the particular problem. + */ + virtual void ComputeResidual(su2double **val_Jacobian_i, + su2double *val_Jacobian_mui, + su2double ***val_Jacobian_gradi, CConfig *config); + + /*! + * \overload + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i + * \param[in] config - Definition of the particular problem. + */ + virtual void ComputeResidual(su2double **val_Jacobian_i, + su2double *val_Jacobian_mui, + su2double ***val_Jacobian_gradi, + su2double **val_Jacobian_j, + su2double *val_Jacobian_muj, + su2double ***val_Jacobian_gradj, CConfig *config); + + /*! + * \brief Computing stiffness matrix of the Galerkin method. + * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetFEA_StiffMatrix2D(su2double **StiffMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d); + + /*! + * \brief Computing stiffness matrix of the Galerkin method. + * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetFEA_StiffMatrix3D(su2double **StiffMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes); + + /*! + * \brief Computing mass matrix of the Galerkin method. + * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetFEA_StiffMassMatrix2D(su2double **StiffMatrix_Elem, su2double **MassMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d); + + /*! + * \brief Computing mass matrix of the Galerkin method. + * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetFEA_StiffMassMatrix3D(su2double **StiffMatrix_Elem, su2double **MassMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes); + + /*! + * \brief Computing dead load vector of the Galerkin method. + * \param[out] val_deadloadvector_elem - Dead load at the nodes for Galerkin computation. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetFEA_DeadLoad2D(su2double *DeadLoadVector_Elem, su2double CoordCorners[8][3], unsigned short nNodes, su2double matDensity); + + /*! + * \brief Computing stiffness matrix of the Galerkin method. + * \param[out] val_deadloadvector_elem - Dead load at the nodes for Galerkin computation. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetFEA_DeadLoad3D(su2double *DeadLoadVector_Elem, su2double CoordCorners[8][3], unsigned short nNodes, su2double matDensity); + + + /*! + * \brief Computing stresses in FEA method. + * \param[in] config - Definition of the particular problem. + */ + virtual void GetFEA_StressNodal2D(su2double StressVector[8][3], su2double DispElement[8], su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d); + + + /*! + * \brief Computing stresses in FEA method. + * \param[in] config - Definition of the particular problem. + */ + virtual void GetFEA_StressNodal3D(su2double StressVector[8][6], su2double DispElement[24], su2double CoordCorners[8][3], unsigned short nNodes); + + /*! + * \brief A virtual member to linearly interpolate pressures + * \param[in] config - Definition of the particular problem. + */ + virtual void PressInt_Linear(su2double CoordCorners[4][3], su2double *tn_e, su2double Fnodal[12]); + + /*! + * \brief A virtual member to linearly interpolate viscous stresses + * \param[in] config - Definition of the particular problem. + */ + virtual void ViscTermInt_Linear(su2double CoordCorners[2][2], su2double Tau_0[3][3], su2double Tau_1[3][3], su2double FviscNodal[4]); + + /*! + * \brief Computes a basis of orthogonal vectors from a suppled vector + * \param[in] config - Normal vector + */ + void CreateBasis(su2double *val_Normal); + +}; + +/*! + * \class CUpwCUSP_Flow + * \brief Class for centered scheme - CUSP. + * \ingroup ConvDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CUpwCUSP_Flow : public CNumerics { + +private: + unsigned short iDim, iVar, jVar; /*!< \brief Iteration on dimension and variables. */ + su2double *Diff_U, *Diff_Flux, /*!< \brief Diference of conservative variables and undivided laplacians. */ + *Velocity_i, *Velocity_j, /*!< \brief Velocity at node 0 and 1. */ + *MeanVelocity, ProjVelocity, /*!< \brief Mean and projected velocities. */ + Density_i, Density_j, Energy_i, Energy_j, /*!< \brief Mean Density and energies. */ + sq_vel_i, sq_vel_j, /*!< \brief Modulus of the velocity and the normal vector. */ + MeanDensity, MeanPressure, MeanEnthalpy, MeanEnergy, /*!< \brief Mean values of primitive variables. */ + *ProjFlux, *ProjFlux_i, *ProjFlux_j, /*!< \brief Projected inviscid flux tensor. */ + cte_0, cte_1, /*!< \brief Artificial dissipation values. */ + LamdaNeg, LamdaPos, Beta, Nu_c, U_i[5], U_j[5], MeanSoundSpeed, Mach, + **Jacobian; /*!< \brief Projected grid velocity. */ + bool implicit, /*!< \brief Implicit calculation. */ + grid_movement; /*!< \brief Modification for grid movement. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimension of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwCUSP_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwCUSP_Flow(void); + + /*! + * \brief Compute the flow residual using a JST method. + * \param[out] val_residual - Pointer to the residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, + CConfig *config); +}; + +/*! + * \class CUpwRoe_Flow + * \brief Class for solving an approximate Riemann solver of Roe for the flow equations. + * \ingroup ConvDiscr + * \author A. Bueno, F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CUpwRoe_Flow : public CNumerics { +private: + bool implicit, grid_movement; + su2double *Diff_U; + su2double *Velocity_i, *Velocity_j, *RoeVelocity; + su2double *ProjFlux_i, *ProjFlux_j; + su2double *delta_wave, *delta_vel; + su2double *Lambda, *Epsilon, MaxLambda, Delta; + su2double **P_Tensor, **invP_Tensor; + su2double sq_vel, Proj_ModJac_Tensor_ij, Density_i, Energy_i, SoundSpeed_i, Pressure_i, Enthalpy_i, + Density_j, Energy_j, SoundSpeed_j, Pressure_j, Enthalpy_j, R, RoeDensity, RoeEnthalpy, RoeSoundSpeed, + ProjVelocity, ProjVelocity_i, ProjVelocity_j, proj_delta_vel, delta_p, delta_rho, RoeSoundSpeed2, kappa; + unsigned short iDim, iVar, jVar, kVar; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwRoe_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwRoe_Flow(void); + + /*! + * \brief Compute the Roe's flux between two nodes i and j. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + + +/*! + * \class CUpwGeneralRoe_Flow + * \brief Class for solving an approximate Riemann solver of Roe for the flow equations for a general fluid model. + * \ingroup ConvDiscr + * \author S.Vitale, G.Gori, M.Pini + * \version 4.0.1 "Cardinal" + */ +class CUpwGeneralRoe_Flow : public CNumerics { +private: + + bool implicit, grid_movement; + + su2double *Diff_U; + su2double *Velocity_i, *Velocity_j, *RoeVelocity; + su2double *ProjFlux_i, *ProjFlux_j; + su2double *delta_wave, *delta_vel; + su2double *Lambda, *Epsilon, MaxLambda, Delta; + su2double **P_Tensor, **invP_Tensor; + su2double sq_vel, Proj_ModJac_Tensor_ij, Density_i, Energy_i, SoundSpeed_i, Pressure_i, Enthalpy_i, + + Density_j, Energy_j, SoundSpeed_j, Pressure_j, Enthalpy_j, R, RoeDensity, RoeEnthalpy, RoeSoundSpeed, RoeSoundSpeed2, + ProjVelocity, ProjVelocity_i, ProjVelocity_j, proj_delta_vel, delta_p, delta_rho, kappa; + unsigned short iDim, iVar, jVar, kVar; + + + su2double StaticEnthalpy_i, StaticEnergy_i, StaticEnthalpy_j, StaticEnergy_j, Kappa_i, Kappa_j, Chi_i, Chi_j, Velocity2_i, Velocity2_j; + su2double RoeKappa, RoeChi, RoeKappaStaticEnthalpy; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwGeneralRoe_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwGeneralRoe_Flow(void); + + /*! + * \brief Compute the Roe's flux between two nodes i and j. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); + + /*! + * \brief Compute the Average for a general fluid flux between two nodes i and j. + * Using the approach of Vinokur and Montagne' + */ + + void ComputeRoeAverage(); +}; + + +/*! + * \class CUpwMSW_Flow + * \brief Class for solving a flux-vector splitting method by Steger & Warming, modified version. + * \ingroup ConvDiscr + * \author S. Copeland + * \version 4.0.1 "Cardinal" + */ +class CUpwMSW_Flow : public CNumerics { +private: + bool implicit; + su2double *Diff_U; + su2double *u_i, *u_j, *ust_i, *ust_j; + su2double *Fc_i, *Fc_j; + su2double *Lambda_i, *Lambda_j; + su2double rhos_i, rhos_j; + su2double *Ust_i, *Ust_j, *Vst_i, *Vst_j, *Velst_i, *Velst_j; + su2double **P_Tensor, **invP_Tensor; + unsigned short nPrimVar, nVar, nDim; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwMSW_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwMSW_Flow(void); + + /*! + * \brief Compute the Roe's flux between two nodes i and j. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); + +}; + +/*! + * \class CUpwTurkel_Flow + * \brief Class for solving an approximate Riemann solver of Roe with Turkel Preconditioning for the flow equations. + * \ingroup ConvDiscr + * \author A. K. Lonkar + * \version 4.0.1 "Cardinal" + */ +class CUpwTurkel_Flow : public CNumerics { +private: + bool implicit, grid_movement; + su2double *Diff_U; + su2double *Velocity_i, *Velocity_j, *RoeVelocity; + su2double *ProjFlux_i, *ProjFlux_j; + su2double *Lambda, *Epsilon; + su2double **absPeJac, **invRinvPe, **R_Tensor, **Matrix, **Art_Visc; + su2double sq_vel, Density_i, Energy_i, SoundSpeed_i, Pressure_i, Enthalpy_i, + Density_j, Energy_j, SoundSpeed_j, Pressure_j, Enthalpy_j, R, RoePressure, RoeDensity, RoeEnthalpy, RoeSoundSpeed, + ProjVelocity, ProjVelocity_i, ProjVelocity_j; + unsigned short iDim, iVar, jVar, kVar; + su2double Beta, Beta_min, Beta_max; + su2double r_hat, s_hat, t_hat, rhoB2a2, sqr_one_m_Betasqr_Lam1; + su2double Beta2, one_m_Betasqr, one_p_Betasqr, sqr_two_Beta_c_Area; + su2double local_Mach; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwTurkel_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwTurkel_Flow(void); + + /*! + * \brief Compute the Roe's flux between two nodes i and j. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); + + /*! + * \brief Get the Preconditioning Beta. + * \return Beta - Value of the low Mach Preconditioner. + */ + su2double GetPrecond_Beta(); +}; + +/*! + * \class CUpwArtComp_Flow + * \brief Class for solving an approximate Riemann solver of Roe for the incompressible flow equations. + * \ingroup ConvDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CUpwArtComp_Flow : public CNumerics { +private: + bool implicit; + bool gravity; + su2double Froude; + su2double *Diff_U; + su2double *Velocity_i, *Velocity_j, *MeanVelocity; + su2double *ProjFlux_i, *ProjFlux_j; + su2double *Lambda, *Epsilon; + su2double **P_Tensor, **invP_Tensor; + su2double Proj_ModJac_Tensor_ij, Pressure_i, + Pressure_j, MeanDensity, MeanSoundSpeed, MeanPressure, MeanBetaInc2, + ProjVelocity; + unsigned short iDim, iVar, jVar, kVar; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwArtComp_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwArtComp_Flow(void); + + /*! + * \brief Compute the Roe's flux between two nodes i and j. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + +/*! + * \class CUpwArtComp_FreeSurf_Flow + * \brief Class for solving an approximate Riemann solver of Roe for the incompressible flow equations. + * \ingroup ConvDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CUpwArtComp_FreeSurf_Flow : public CNumerics { +private: + bool implicit; + bool gravity; + su2double Froude; + su2double *Diff_U; + su2double *Velocity_i, *Velocity_j, *MeanVelocity; + su2double *ProjFlux_i, *ProjFlux_j; + su2double *Lambda, *Epsilon; + su2double **P_Tensor, **invP_Tensor; + su2double Proj_ModJac_Tensor_ij, Pressure_i, LevelSet_i, dDensityInc_i, dDensityInc_j, + Pressure_j, LevelSet_j, MeanDensityInc, dMeanDensityInc, MeanPressure, MeanLevelSet, MeanBetaInc2, + ProjVelocity, Distance_i, Distance_j; + unsigned short iDim, iVar, jVar, kVar; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwArtComp_FreeSurf_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwArtComp_FreeSurf_Flow(void); + + /*! + * \brief Compute the Roe's flux between two nodes i and j. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + +/*! + * \class CUpwRoe_AdjFlow + * \brief Class for solving an approximate Riemann solver of Roe + * for the adjoint flow equations. + * \ingroup ConvDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CUpwRoe_AdjFlow : public CNumerics { +private: + su2double *Residual_Roe; + su2double area, Sx, Sy, Sz, rarea, nx, ny, nz, rho_l, u_l, v_l, w_l, h_l, rho_r, + u_r, v_r, w_r, h_r, psi1, psi2, psi3, psi4, psi5; + su2double h, u, v, w, c, psi1_l, psi2_l, psi3_l, psi4_l, psi5_l, + psi1_r, psi2_r, psi3_r, psi4_r, psi5_r, q_l, q_r, Q_l, Q_r, vn, + rrho_l, weight, rweight1, cc; + su2double l1psi, l2psi, absQ, absQp, absQm, q2, alpha, beta_u, beta_v, beta_w, Q, l1l2p, l1l2m, eta; + su2double RoeDensity, RoeSoundSpeed, *RoeVelocity, *Lambda, *Velocity_i, *Velocity_j, **ProjFlux_i, **ProjFlux_j, + Proj_ModJac_Tensor_ij, **Proj_ModJac_Tensor, Energy_i, Energy_j, **P_Tensor, **invP_Tensor; + unsigned short iDim, iVar, jVar, kVar; + bool implicit, grid_movement; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwRoe_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwRoe_AdjFlow(void); + + /*! + * \brief Compute the adjoint Roe's flux between two nodes i and j. + * \param[out] val_residual_i - Pointer to the total residual at point i. + * \param[out] val_residual_j - Pointer to the total residual at point j. + * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. + * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. + * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. + * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, su2double **val_Jacobian_ii, + su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); +}; + +/*! + * \class CUpwRoeArtComp_AdjFlow + * \brief Class for solving an approximate Riemann solver of Roe + * for the adjoint flow equations. + * \ingroup ConvDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CUpwRoeArtComp_AdjFlow : public CNumerics { +private: + su2double Area, *Lambda, *Velocity_i, *Velocity_j, **Proj_Jac_Tensor_i, **Proj_Jac_Tensor_j, + Proj_ModJac_Tensor_ij, **Proj_ModJac_Tensor, **P_Tensor, **invP_Tensor, MeanDensity, + MeanPressure, MeanBetaInc2, ProjVelocity, *MeanVelocity, MeanSoundSpeed; + unsigned short iDim, iVar, jVar, kVar; + bool implicit; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwRoeArtComp_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwRoeArtComp_AdjFlow(void); + + /*! + * \brief Compute the adjoint Roe's flux between two nodes i and j. + * \param[out] val_residual_i - Pointer to the total residual at point i. + * \param[out] val_residual_j - Pointer to the total residual at point j. + * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. + * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. + * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. + * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, su2double **val_Jacobian_ii, + su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); +}; + +/*! + * \class CUpwAUSM_Flow + * \brief Class for solving an approximate Riemann AUSM. + * \ingroup ConvDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CUpwAUSM_Flow : public CNumerics { +private: + bool implicit; + su2double *Diff_U; + su2double *Velocity_i, *Velocity_j, *RoeVelocity; + su2double *ProjFlux_i, *ProjFlux_j; + su2double *delta_wave, *delta_vel; + su2double *Lambda, *Epsilon; + su2double **P_Tensor, **invP_Tensor; + su2double sq_vel, Proj_ModJac_Tensor_ij, Density_i, Energy_i, SoundSpeed_i, Pressure_i, Enthalpy_i, + Density_j, Energy_j, SoundSpeed_j, Pressure_j, Enthalpy_j, R, RoeDensity, RoeEnthalpy, RoeSoundSpeed, + ProjVelocity, ProjVelocity_i, ProjVelocity_j; + unsigned short iDim, iVar, jVar, kVar; + su2double mL, mR, mLP, mRM, mF, pLP, pRM, pF, Phi; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwAUSM_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwAUSM_Flow(void); + + /*! + * \brief Compute the Roe's flux between two nodes i and j. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + +/*! + * \class CUpwHLLC_Flow + * \brief Class for solving an approximate Riemann AUSM. + * \ingroup ConvDiscr + * \author F. Palacios, based on the Joe code implementation + * \version 4.0.1 "Cardinal" + */ +class CUpwHLLC_Flow : public CNumerics { +private: + bool implicit; + su2double *Diff_U; + su2double *Velocity_i, *Velocity_j, *RoeVelocity; + su2double *ProjFlux_i, *ProjFlux_j; + su2double *delta_wave, *delta_vel; + su2double *Lambda, *Epsilon; + su2double **P_Tensor, **invP_Tensor; + su2double sq_vel_i, sq_vel_j, Proj_ModJac_Tensor_ij, Density_i, Energy_i, SoundSpeed_i, Pressure_i, Enthalpy_i, + Density_j, Energy_j, SoundSpeed_j, Pressure_j, Enthalpy_j, RoeDensity, RoeEnthalpy, RoeSoundSpeed, + RoeProjVelocity, ProjVelocity_i, ProjVelocity_j; + unsigned short iDim, iVar, jVar, kVar; + su2double Rrho, tmp, sq_velRoe, sL, sR, sM, pStar, invSLmSs, sLmuL, rhoSL, rhouSL[3], + eSL, invSRmSs, sRmuR, rhoSR, rhouSR[3], eSR; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwHLLC_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwHLLC_Flow(void); + + /*! + * \brief Compute the Roe's flux between two nodes i and j. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + +/*! + * \class CUpwGeneralHLLC_Flow + * \brief Class for solving an approximate Riemann AUSM. + * \ingroup ConvDiscr + * \author F. Palacios, based on the Joe code implementation + * \version 4.0.1 "Cardinal" + */ +class CUpwGeneralHLLC_Flow : public CNumerics { +private: + bool implicit; + unsigned short iDim, iVar, jVar, kVar; + + su2double *Diff_U; + su2double *Velocity_i, *Velocity_j, *RoeVelocity; + su2double *ProjFlux_i, *ProjFlux_j; + su2double *delta_wave, *delta_vel; + su2double *Lambda, *Epsilon; + su2double **P_Tensor, **invP_Tensor; + + su2double sq_vel_i, Density_i, Energy_i, SoundSpeed_i, Pressure_i, Enthalpy_i, ProjVelocity_i, StaticEnthalpy_i, StaticEnergy_i; + su2double sq_vel_j, Density_j, Energy_j, SoundSpeed_j, Pressure_j, Enthalpy_j, ProjVelocity_j, StaticEnthalpy_j, StaticEnergy_j; + + su2double sq_velRoe, Proj_ModJac_Tensor_ij, RoeDensity, RoeEnthalpy, RoeSoundSpeed, RoeSoundSpeed2, RoeProjVelocity; + su2double Kappa_i, Kappa_j, Chi_i, Chi_j, RoeKappa, RoeChi, RoeKappaStaticEnthalpy; + + su2double sL, sR, sM, pStar, invSLmSs, sLmuL, rhoSL, rhouSL[3], Rrho, eSL, invSRmSs, sRmuR, rhoSR, rhouSR[3], eSR, kappa; + + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwGeneralHLLC_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + + * \brief Destructor of the class. + */ + ~CUpwGeneralHLLC_Flow(void); + + /*! + + * \brief Compute the Roe's flux between two nodes i and j. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); + + /*! + + * \brief Compute the Average quantities for a general fluid flux between two nodes i and j. + + * Using the approach of Vinokur and Montagne' + + */ + + void VinokurMontagne(); + +}; + +/*! + * \class CUpwLin_TransLM + * \brief Class for performing a linear upwind solver for the Spalart-Allmaras turbulence model equations with transition + * \ingroup ConvDiscr + * \author A. Aranake + * \version 4.0.1 "Cardinal" + */ +class CUpwLin_TransLM : public CNumerics { +private: + su2double *Velocity_i; + su2double *Velocity_j; + bool implicit, grid_movement, incompressible; + su2double Density_i, Density_j, q_ij, a0, a1; + unsigned short iDim; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwLin_TransLM(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwLin_TransLM(void); + + /*! + * \brief Compute the upwind flux between two nodes i and j. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual (su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + +/*! + * \class CUpwLin_AdjLevelSet + * \brief Class for performing a linear upwind solver for the adjoint Level Set equations. + * \ingroup ConvDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CUpwLin_AdjLevelSet : public CNumerics { +private: + bool implicit; + su2double *Velocity_i; + su2double *Velocity_j; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwLin_AdjLevelSet(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwLin_AdjLevelSet(void); + + /*! + * \brief Compute the upwind flux between two nodes i and j. + * \param[out] val_residual_i - Pointer to the total residual at node i. + * \param[out] val_residual_j - Pointer to the total residual at node j. + * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_ij - Jacobian of the numerical method from node i to node j (implicit computation). + * \param[out] val_Jacobian_ji - Jacobian of the numerical method from node j to node i (implicit computation). + * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, su2double **val_Jacobian_ii, + su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); +}; + +/*! + * \class CUpwLin_AdjTurb + * \brief Class for performing a linear upwind solver for the adjoint turbulence equations. + * \ingroup ConvDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CUpwLin_AdjTurb : public CNumerics { +private: + su2double *Velocity_i; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwLin_AdjTurb(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwLin_AdjTurb(void); + + /*! + * \brief Compute the adjoint upwind flux between two nodes i and j. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual (su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + +/*! + * \class CUpwSca_TurbSA + * \brief Class for doing a scalar upwind solver for the Spalar-Allmaral turbulence model equations. + * \ingroup ConvDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CUpwSca_TurbSA : public CNumerics { +private: + su2double *Velocity_i, *Velocity_j; + bool implicit, grid_movement, incompressible; + su2double q_ij, a0, a1; + unsigned short iDim; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwSca_TurbSA(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwSca_TurbSA(void); + + /*! + * \brief Compute the scalar upwind flux between two nodes i and j. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + +/*! + * \class CUpwSca_TurbML + * \brief Class for doing a scalar upwind solver for the Spalar-Allmaral turbulence model equations. + * \ingroup ConvDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CUpwSca_TurbML : public CNumerics { +private: + su2double *Velocity_i, *Velocity_j; + bool implicit, grid_movement, incompressible; + su2double q_ij, a0, a1; + unsigned short iDim; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwSca_TurbML(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwSca_TurbML(void); + + /*! + * \brief Compute the scalar upwind flux between two nodes i and j. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + +/*! + * \class CUpwSca_TurbSST + * \brief Class for doing a scalar upwind solver for the Menter SST turbulence model equations. + * \ingroup ConvDiscr + * \author A. Campos. + * \version 4.0.1 "Cardinal" + */ +class CUpwSca_TurbSST : public CNumerics { +private: + su2double *Velocity_i, *Velocity_j; + bool implicit, grid_movement, incompressible; + su2double Density_i, Density_j, + q_ij, + a0, a1; + unsigned short iDim; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwSca_TurbSST(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwSca_TurbSST(void); + + /*! + * \brief Compute the scalar upwind flux between two nodes i and j. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + +/*! + * \class CUpwSca_TransLM + * \brief Class for doing a scalar upwind solver for the Spalart-Allmaras turbulence model equations with transition. + * \ingroup ConvDiscr + * \author A. Aranake. + * \version 4.0.1 "Cardinal" + */ +class CUpwSca_TransLM : public CNumerics { +private: + su2double *Velocity_i, *Velocity_j; + bool implicit, grid_movement; + su2double q_ij, a0, a1; + unsigned short iDim; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwSca_TransLM(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwSca_TransLM(void); + + /*! + * \brief Compute the scalar upwind flux between two nodes i and j. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + +/*! + * \class CUpwSca_AdjTurb + * \brief Class for doing a scalar upwind solver for the adjoint turbulence equations. + * \ingroup ConvDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CUpwSca_AdjTurb : public CNumerics { +private: + su2double *Velocity_i, *Velocity_j; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CUpwSca_AdjTurb(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CUpwSca_AdjTurb(void); + + /*! + * \param[out] val_residual_i - Pointer to the total residual at point i. + * \param[out] val_residual_j - Pointer to the total viscosity residual at point j. + * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. + * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. + * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. + * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, + su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); +}; + + +/*! + * \class CCentJST_Flow + * \brief Class for centered shceme - JST. + * \ingroup ConvDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CCentJST_KE_Flow : public CNumerics { + +private: + unsigned short iDim, iVar, jVar; /*!< \brief Iteration on dimension and variables. */ + su2double *Diff_U, *Diff_Lapl, /*!< \brief Diference of conservative variables and undivided laplacians. */ + *Velocity_i, *Velocity_j, /*!< \brief Velocity at node 0 and 1. */ + *MeanVelocity, ProjVelocity, ProjVelocity_i, ProjVelocity_j, /*!< \brief Mean and projected velocities. */ + Density_i, Density_j, Energy_i, Energy_j, /*!< \brief Mean Density and energies. */ + sq_vel_i, sq_vel_j, /*!< \brief Modulus of the velocity and the normal vector. */ + MeanDensity, MeanPressure, MeanEnthalpy, MeanEnergy, /*!< \brief Mean values of primitive variables. */ + Param_p, Param_Kappa_2, Param_Kappa_4, /*!< \brief Artificial dissipation parameters. */ + Local_Lambda_i, Local_Lambda_j, MeanLambda, /*!< \brief Local eingenvalues. */ + Phi_i, Phi_j, sc2, sc4, StretchingFactor, /*!< \brief Streching parameters. */ + *ProjFlux, /*!< \brief Projected inviscid flux tensor. */ + Epsilon_2, cte_0, cte_1, /*!< \brief Artificial dissipation values. */ + ProjGridVel; /*!< \brief Projected grid velocity. */ + bool implicit, /*!< \brief Implicit calculation. */ + grid_movement; /*!< \brief Modification for grid movement. */ + + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimension of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CCentJST_KE_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CCentJST_KE_Flow(void); + + /*! + * \brief Compute the flow residual using a JST method. + * \param[out] val_resconv - Pointer to the convective residual. + * \param[out] val_resvisc - Pointer to the artificial viscosity residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, + CConfig *config); +}; + +/*! + * \class CCentJST_Flow + * \brief Class for centered scheme - JST. + * \ingroup ConvDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CCentJST_Flow : public CNumerics { + +private: + unsigned short iDim, iVar, jVar; /*!< \brief Iteration on dimension and variables. */ + su2double *Diff_U, *Diff_Lapl, /*!< \brief Diference of conservative variables and undivided laplacians. */ + *Velocity_i, *Velocity_j, /*!< \brief Velocity at node 0 and 1. */ + *MeanVelocity, ProjVelocity, ProjVelocity_i, ProjVelocity_j, /*!< \brief Mean and projected velocities. */ + Density_i, Density_j, Energy_i, Energy_j, /*!< \brief Mean Density and energies. */ + sq_vel_i, sq_vel_j, /*!< \brief Modulus of the velocity and the normal vector. */ + MeanDensity, MeanPressure, MeanEnthalpy, MeanEnergy, /*!< \brief Mean values of primitive variables. */ + Param_p, Param_Kappa_2, Param_Kappa_4, /*!< \brief Artificial dissipation parameters. */ + Local_Lambda_i, Local_Lambda_j, MeanLambda, /*!< \brief Local eingenvalues. */ + Phi_i, Phi_j, sc2, sc4, StretchingFactor, /*!< \brief Streching parameters. */ + *ProjFlux, /*!< \brief Projected inviscid flux tensor. */ + Epsilon_2, Epsilon_4, cte_0, cte_1, /*!< \brief Artificial dissipation values. */ + ProjGridVel; /*!< \brief Projected grid velocity. */ + bool implicit, /*!< \brief Implicit calculation. */ + grid_movement; /*!< \brief Modification for grid movement. */ + + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimension of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CCentJST_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CCentJST_Flow(void); + + /*! + * \brief Compute the flow residual using a JST method. + * \param[out] val_resconv - Pointer to the convective residual. + * \param[out] val_resvisc - Pointer to the artificial viscosity residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, + CConfig *config); +}; + +/*! + * \class CCentJSTArtComp_Flow + * \brief Class for centered scheme - JST (artificial compressibility). + * \ingroup ConvDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CCentJSTArtComp_Flow : public CNumerics { + +private: + unsigned short iDim, iVar, jVar; /*!< \brief Iteration on dimension and variables. */ + su2double *Diff_U, *Diff_Lapl, /*!< \brief Diference of conservative variables and undivided laplacians. */ + *Velocity_i, *Velocity_j, /*!< \brief Velocity at node 0 and 1. */ + *MeanVelocity, ProjVelocity_i, ProjVelocity_j, /*!< \brief Mean and projected velocities. */ + sq_vel_i, sq_vel_j, /*!< \brief Modulus of the velocity and the normal vector. */ + MeanDensity, MeanPressure, MeanBetaInc2, /*!< \brief Mean values of primitive variables. */ + Param_p, Param_Kappa_2, Param_Kappa_4, /*!< \brief Artificial dissipation parameters. */ + Local_Lambda_i, Local_Lambda_j, MeanLambda, /*!< \brief Local eingenvalues. */ + Phi_i, Phi_j, sc2, sc4, StretchingFactor, /*!< \brief Streching parameters. */ + *ProjFlux, /*!< \brief Projected inviscid flux tensor. */ + Epsilon_2, Epsilon_4, cte_0, cte_1; /*!< \brief Artificial dissipation values. */ + bool implicit, /*!< \brief Implicit calculation. */ + grid_movement, /*!< \brief Modification for grid movement. */ + gravity; /*!< \brief computation with gravity force. */ + su2double Froude; /*!< \brief Froude number. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimension of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CCentJSTArtComp_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CCentJSTArtComp_Flow(void); + + /*! + * \brief Compute the flow residual using a JST method. + * \param[out] val_resconv - Pointer to the convective residual. + * \param[out] val_resvisc - Pointer to the artificial viscosity residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, + CConfig *config); +}; + +/*! + * \class CCentJST_AdjFlow + * \brief Class for and adjoint centered scheme - JST. + * \ingroup ConvDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CCentJST_AdjFlow : public CNumerics { +private: + su2double *Diff_Psi, *Diff_Lapl; + su2double *Velocity_i, *Velocity_j; + su2double *MeanPhi; + unsigned short iDim, jDim, iVar, jVar; + su2double Residual, ProjVelocity_i, ProjVelocity_j, ProjPhi, ProjPhi_Vel, sq_vel, phis1, phis2; + su2double MeanPsiRho, MeanPsiE, Param_p, Param_Kappa_4, Param_Kappa_2, Local_Lambda_i, Local_Lambda_j, MeanLambda; + su2double Phi_i, Phi_j, sc4, StretchingFactor, Epsilon_4, Epsilon_2; + bool implicit, grid_movement; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CCentJST_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CCentJST_AdjFlow(void); + + /*! + * \brief Compute the adjoint flow residual using a JST method. + * \param[out] val_resconv_i - Pointer to the convective residual at point i. + * \param[out] val_resvisc_i - Pointer to the artificial viscosity residual at point i. + * \param[out] val_resconv_j - Pointer to the convective residual at point j. + * \param[out] val_resvisc_j - Pointer to the artificial viscosity residual at point j. + * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. + * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. + * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. + * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual (su2double *val_resconv_i, su2double *val_resvisc_i, su2double *val_resconv_j, su2double *val_resvisc_j, + su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, + CConfig *config); +}; + +/*! + * \class CCentJSTArtComp_AdjFlow + * \brief Class for and adjoint centered scheme - JST. + * \ingroup ConvDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CCentJSTArtComp_AdjFlow : public CNumerics { +private: + su2double sc2, *Diff_Psi, *Diff_Lapl; + su2double *Velocity_i, *Velocity_j; + su2double **Proj_Jac_Tensor_i, **Proj_Jac_Tensor_j; + unsigned short iDim, iVar, jVar; + su2double Residual, ProjVelocity_i, ProjVelocity_j; + su2double Param_p, Param_Kappa_4, Param_Kappa_2, Local_Lambda_i, Local_Lambda_j, MeanLambda; + su2double Phi_i, Phi_j, sc4, StretchingFactor, Epsilon_4, Epsilon_2; + bool implicit; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CCentJSTArtComp_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CCentJSTArtComp_AdjFlow(void); + + /*! + * \brief Compute the adjoint flow residual using a JST method. + * \param[out] val_resconv_i - Pointer to the convective residual at point i. + * \param[out] val_resvisc_i - Pointer to the artificial viscosity residual at point i. + * \param[out] val_resconv_j - Pointer to the convective residual at point j. + * \param[out] val_resvisc_j - Pointer to the artificial viscosity residual at point j. + * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. + * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. + * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. + * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual (su2double *val_resconv_i, su2double *val_resvisc_i, su2double *val_resconv_j, su2double *val_resvisc_j, + su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, + CConfig *config); +}; + +/*! + * \class CCentLax_Flow + * \brief Class for computing the Lax-Friedrich centered scheme. + * \ingroup ConvDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CCentLax_Flow : public CNumerics { +private: + unsigned short iDim, iVar, jVar; /*!< \brief Iteration on dimension and variables. */ + su2double *Diff_U, /*!< \brief Difference of conservative variables. */ + *Velocity_i, *Velocity_j, /*!< \brief Velocity at node 0 and 1. */ + *MeanVelocity, ProjVelocity, ProjVelocity_i, ProjVelocity_j, /*!< \brief Mean and projected velocities. */ + *ProjFlux, /*!< \brief Projected inviscid flux tensor. */ + Density_i, Density_j, Energy_i, Energy_j, /*!< \brief Mean Density and energies. */ + sq_vel_i, sq_vel_j, /*!< \brief Modulus of the velocity and the normal vector. */ + MeanDensity, MeanPressure, MeanEnthalpy, MeanEnergy, /*!< \brief Mean values of primitive variables. */ + Param_p, Param_Kappa_0, /*!< \brief Artificial dissipation parameters. */ + Local_Lambda_i, Local_Lambda_j, MeanLambda, /*!< \brief Local eingenvalues. */ + Phi_i, Phi_j, sc0, StretchingFactor, /*!< \brief Streching parameters. */ + Epsilon_0, cte; /*!< \brief Artificial dissipation values. */ + bool implicit, /*!< \brief Implicit calculation. */ + grid_movement; /*!< \brief Modification for grid movement. */ + su2double ProjGridVel; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimension of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CCentLax_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CCentLax_Flow(void); + + /*! + * \brief Compute the flow residual using a Lax method. + * \param[out] val_resconv - Pointer to the convective residual. + * \param[out] val_resvisc - Pointer to the artificial viscosity residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, + CConfig *config); +}; + +/*! + * \class CCentLaxArtComp_Flow + * \brief Class for computing the Lax-Friedrich centered scheme (artificial compressibility). + * \ingroup ConvDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CCentLaxArtComp_Flow : public CNumerics { +private: + unsigned short iDim, iVar, jVar; /*!< \brief Iteration on dimension and variables. */ + su2double *Diff_U, /*!< \brief Difference of conservative variables. */ + *Velocity_i, *Velocity_j, /*!< \brief Velocity at node 0 and 1. */ + *MeanVelocity, ProjVelocity_i, ProjVelocity_j, /*!< \brief Mean and projected velocities. */ + *ProjFlux, /*!< \brief Projected inviscid flux tensor. */ + sq_vel_i, sq_vel_j, /*!< \brief Modulus of the velocity and the normal vector. */ + MeanDensity, MeanPressure, MeanBetaInc2, /*!< \brief Mean values of primitive variables. */ + Param_p, Param_Kappa_0, /*!< \brief Artificial dissipation parameters. */ + Local_Lambda_i, Local_Lambda_j, MeanLambda, /*!< \brief Local eingenvalues. */ + Phi_i, Phi_j, sc0, StretchingFactor, /*!< \brief Streching parameters. */ + Epsilon_0; /*!< \brief Artificial dissipation values. */ + bool implicit, /*!< \brief Implicit calculation. */ + grid_movement, /*!< \brief Modification for grid movement. */ + gravity; /*!< \brief Modification for for gravity force. */ + su2double Froude; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimension of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CCentLaxArtComp_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CCentLaxArtComp_Flow(void); + + /*! + * \brief Compute the flow residual using a Lax method. + * \param[out] val_resconv - Pointer to the convective residual. + * \param[out] val_resvisc - Pointer to the artificial viscosity residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, + CConfig *config); +}; + +/*! + * \class CCentLax_AdjFlow + * \brief Class for computing the Lax-Friedrich adjoint centered scheme. + * \ingroup ConvDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CCentLax_AdjFlow : public CNumerics { +private: + su2double *Diff_Psi; + su2double *Velocity_i, *Velocity_j; + su2double *MeanPhi; + unsigned short iDim, jDim, iVar, jVar; + su2double Residual, ProjVelocity_i, ProjVelocity_j, ProjPhi, ProjPhi_Vel, sq_vel, phis1, phis2, + MeanPsiRho, MeanPsiE, Param_p, Param_Kappa_0, Local_Lambda_i, Local_Lambda_j, MeanLambda, + Phi_i, Phi_j, sc2, StretchingFactor, Epsilon_0; + bool implicit, grid_movement; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CCentLax_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CCentLax_AdjFlow(void); + + /*! + * \brief Compute the adjoint flow residual using a Lax method. + * \param[out] val_resconv_i - Pointer to the convective residual at point i. + * \param[out] val_resvisc_i - Pointer to the artificial viscosity residual at point i. + * \param[out] val_resconv_j - Pointer to the convective residual at point j. + * \param[out] val_resvisc_j - Pointer to the artificial viscosity residual at point j. + * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. + * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. + * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. + * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual (su2double *val_resconv_i, su2double *val_resvisc_i, su2double *val_resconv_j, su2double *val_resvisc_j, + su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, + CConfig *config); +}; + +/*! + * \class CCentLaxArtComp_AdjFlow + * \brief Class for computing the Lax-Friedrich adjoint centered scheme. + * \ingroup ConvDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CCentLaxArtComp_AdjFlow : public CNumerics { +private: + su2double *Diff_Psi; + su2double *Velocity_i, *Velocity_j; + su2double *MeanPhi, **Proj_Jac_Tensor_i, **Proj_Jac_Tensor_j; + unsigned short iDim, iVar, jVar; + su2double Residual, ProjVelocity_i, ProjVelocity_j, Param_p, Param_Kappa_0, + Local_Lambda_i, Local_Lambda_j, MeanLambda, + Phi_i, Phi_j, sc2, StretchingFactor, Epsilon_0; + bool implicit; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CCentLaxArtComp_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CCentLaxArtComp_AdjFlow(void); + + /*! + * \brief Compute the adjoint flow residual using a Lax method. + * \param[out] val_resconv_i - Pointer to the convective residual at point i. + * \param[out] val_resvisc_i - Pointer to the artificial viscosity residual at point i. + * \param[out] val_resconv_j - Pointer to the convective residual at point j. + * \param[out] val_resvisc_j - Pointer to the artificial viscosity residual at point j. + * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. + * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. + * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. + * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual (su2double *val_resconv_i, su2double *val_resvisc_i, su2double *val_resconv_j, su2double *val_resvisc_j, + su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, + CConfig *config); +}; + +/*! + * \class CAvgGrad_Flow + * \brief Class for computing viscous term using the average of gradients. + * \ingroup ViscDiscr + * \author A. Bueno, and F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CAvgGrad_Flow : public CNumerics { +private: + unsigned short iDim, iVar, jVar; /*!< \brief Iterators in dimension an variable. */ + su2double *Mean_PrimVar, /*!< \brief Mean primitive variables. */ + *PrimVar_i, *PrimVar_j, /*!< \brief Primitives variables at point i and 1. */ + **Mean_GradPrimVar, /*!< \brief Mean value of the gradient. */ + Mean_Laminar_Viscosity, /*!< \brief Mean value of the viscosity. */ + Mean_Eddy_Viscosity, /*!< \brief Mean value of the eddy viscosity. */ + Mean_turb_ke, /*!< \brief Mean value of the turbulent kinetic energy. */ + dist_ij; /*!< \brief Length of the edge and face. */ + bool implicit; /*!< \brief Implicit calculus. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimension of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGrad_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGrad_Flow(void); + + /*! + * \brief Compute the viscous flow residual using an average of gradients. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + +/*! + * \class CGeneralAvgGrad_Flow + * \brief Class for computing viscous term using the average of gradients. + * \ingroup ViscDiscr + * \author M.Pini, S. Vitale + * \version 3.2.1 "eagle" + */ + +class CGeneralAvgGrad_Flow : public CNumerics { +private: + unsigned short iDim, iVar, jVar; /*!< \brief Iterators in dimension an variable. */ + su2double *Mean_PrimVar, /*!< \brief Mean primitive variables. */ + *Mean_SecVar, /*!< \brief Mean secondary variables. */ + *PrimVar_i, *PrimVar_j, /*!< \brief Primitives variables at point i and 1. */ + **Mean_GradPrimVar, /*!< \brief Mean value of the gradient. */ + Mean_Laminar_Viscosity, /*!< \brief Mean value of the viscosity. */ + Mean_Eddy_Viscosity, /*!< \brief Mean value of the eddy viscosity. */ + Mean_Thermal_Conductivity, /*!< \brief Mean value of the thermal conductivity. */ + Mean_Cp, /*!< \brief Mean value of the Cp. */ + Mean_turb_ke, /*!< \brief Mean value of the turbulent kinetic energy. */ + dist_ij; /*!< \brief Length of the edge and face. */ + bool implicit; /*!< \brief Implicit calculus. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimension of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CGeneralAvgGrad_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CGeneralAvgGrad_Flow(void); + + /*! + * \brief Compute the viscous flow residual using an average of gradients. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + +/*! + * \class CAvgGradArtComp_Flow + * \brief Class for computing viscous term using an average of gradients. + * \ingroup ViscDiscr + * \author A. Bueno, and F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CAvgGradArtComp_Flow : public CNumerics { +private: + unsigned short iDim, iVar, jVar; /*!< \brief Iterators in dimension an variable. */ + su2double **Mean_GradPrimVar, /*!< \brief Mean value of the gradient. */ + Mean_Laminar_Viscosity, Mean_Eddy_Viscosity, /*!< \brief Mean value of the viscosity. */ + dist_ij; /*!< \brief Length of the edge and face. */ + bool implicit; /*!< \brief Implicit calculus. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimension of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGradArtComp_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGradArtComp_Flow(void); + /*! + * \brief Compute the viscous flow residual using an average of gradients. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + +/*! + * \class CAvgGrad_TurbSA + * \brief Class for computing viscous term using average of gradients (Spalart-Allmaras Turbulence model). + * \ingroup ViscDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CAvgGrad_TurbSA : public CNumerics { +private: + + su2double **Mean_GradTurbVar; + su2double *Proj_Mean_GradTurbVar_Kappa, *Proj_Mean_GradTurbVar_Edge; + su2double *Edge_Vector; + bool implicit, incompressible; + su2double sigma; + su2double nu_i, nu_j, nu_e; + su2double dist_ij_2; + su2double proj_vector_ij; + unsigned short iVar, iDim; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGrad_TurbSA(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGrad_TurbSA(void); + + /*! + * \brief Compute the viscous turbulence terms residual using an average of gradients. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); +}; + +/*! + * \class CAvgGrad_TurbSA_Neg + * \brief Class for computing viscous term using average of gradients (Spalart-Allmaras Turbulence model). + * \ingroup ViscDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CAvgGrad_TurbSA_Neg : public CNumerics { +private: + + su2double **Mean_GradTurbVar; + su2double *Proj_Mean_GradTurbVar_Kappa, *Proj_Mean_GradTurbVar_Edge; + su2double *Edge_Vector; + bool implicit, incompressible; + su2double sigma; + su2double cn1, fn, Xi; + su2double nu_i, nu_j, nu_ij, nu_tilde_ij, nu_e; + su2double dist_ij_2; + su2double proj_vector_ij; + unsigned short iVar, iDim; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGrad_TurbSA_Neg(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGrad_TurbSA_Neg(void); + + /*! + * \brief Compute the viscous turbulence terms residual using an average of gradients. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); +}; + +/*! + * \class CAvgGrad_TurbML + * \brief Class for computing viscous term using average of gradients (Spalart-Allmaras Turbulence model). + * \ingroup ViscDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CAvgGrad_TurbML : public CNumerics { +private: + su2double **Mean_GradTurbVar; + su2double *Proj_Mean_GradTurbVar_Kappa, *Proj_Mean_GradTurbVar_Edge; + su2double *Edge_Vector; + bool implicit, incompressible; + su2double sigma; + su2double nu_i, nu_j, nu_e; + su2double dist_ij_2; + su2double proj_vector_ij; + unsigned short iVar, iDim; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGrad_TurbML(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGrad_TurbML(void); + + /*! + * \brief Compute the viscous turbulence terms residual using an average of gradients. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); +}; + +/*! + * \class CAvgGrad_TransLM + * \brief Class for computing viscous term using average of gradients (Spalart-Allmaras Turbulence model). + * \ingroup ViscDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CAvgGrad_TransLM : public CNumerics { +private: + su2double **Mean_GradTransVar; + su2double *Proj_Mean_GradTransVar_Kappa, *Proj_Mean_GradTransVar_Edge; + su2double *Edge_Vector; + bool implicit, incompressible; + su2double sigma; + su2double dist_ij_2; + su2double proj_vector_ij; + unsigned short iVar, iDim; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGrad_TransLM(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGrad_TransLM(void); + + /*! + * \brief Compute the viscous turbulence terms residual using an average of gradients. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); +}; + +/*! + * \class CAvgGrad_AdjFlow + * \brief Class for computing the adjoint viscous terms. + * \ingroup ViscDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CAvgGrad_AdjFlow : public CNumerics { +private: + su2double *Velocity_i; /*!< \brief Auxiliary vector for storing the velocity of point i. */ + su2double *Velocity_j; /*!< \brief Auxiliary vector for storing the velocity of point j. */ + su2double *Mean_Velocity; + su2double *Mean_GradPsiE; /*!< \brief Counter for dimensions of the problem. */ + su2double **Mean_GradPhi; /*!< \brief Counter for dimensions of the problem. */ + su2double *Edge_Vector; /*!< \brief Vector going from node i to node j. */ + bool implicit; /*!< \brief Implicit calculus. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGrad_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGrad_AdjFlow(void); + + /*! + * \brief Residual computation. + * \param[out] val_residual_i - Pointer to the total residual at point i. + * \param[out] val_residual_j - Pointer to the total residual at point j. + */ + void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, + su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, + su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); +}; + +/*! + * \class CAvgGradArtComp_AdjFlow + * \brief Class for computing the adjoint viscous terms. + * \ingroup ViscDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CAvgGradArtComp_AdjFlow : public CNumerics { +private: + unsigned short iDim, iVar, jVar; /*!< \brief Iterators in dimension an variable. */ + su2double **Mean_GradPsiVar, /*!< \brief Mean value of the gradient. */ + Mean_Laminar_Viscosity, Mean_Eddy_Viscosity, /*!< \brief Mean value of the viscosity. */ + dist_ij; /*!< \brief Length of the edge and face. */ + bool implicit; /*!< \brief Implicit calculus. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGradArtComp_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGradArtComp_AdjFlow(void); + + /*! + * \brief Residual computation. + * \param[out] val_residual_i - Pointer to the total residual at point i. + * \param[out] val_residual_j - Pointer to the total residual at point j. + */ + void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, + su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, + su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); +}; + +/*! + * \class CAvgGradCorrected_Flow + * \brief Class for computing viscous term using the average of gradients with a correction. + * \ingroup ViscDiscr + * \author A. Bueno, and F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CAvgGradCorrected_Flow : public CNumerics { +private: + unsigned short iDim, iVar, jVar; /*!< \brief Iterators in dimension an variable. */ + su2double *Mean_PrimVar, /*!< \brief Mean primitive variables. */ + *PrimVar_i, *PrimVar_j, /*!< \brief Primitives variables at point i and 1. */ + *Edge_Vector, /*!< \brief Vector form point i to point j. */ + **Mean_GradPrimVar, *Proj_Mean_GradPrimVar_Edge, /*!< \brief Mean value of the gradient. */ + Mean_Laminar_Viscosity, /*!< \brief Mean value of the laminar viscosity. */ + Mean_Eddy_Viscosity, /*!< \brief Mean value of the eddy viscosity. */ + Mean_turb_ke, /*!< \brief Mean value of the turbulent kinetic energy. */ + dist_ij_2; /*!< \brief Length of the edge and face. */ + bool implicit; /*!< \brief Implicit calculus. */ + bool limiter; /*!< \brief Viscous limiter. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimension of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGradCorrected_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGradCorrected_Flow(void); + + /*! + * \brief Compute the viscous flow residual using an average of gradients with correction. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + + +/*! + * \class CGeneralAvgGradCorrected_Flow + * \brief Class for computing viscous term using the average of gradients with a correction. + * \ingroup ViscDiscr + * \author M. Pini, S. Vitale + * \version 3.2.1 "eagle" + */ +class CGeneralAvgGradCorrected_Flow : public CNumerics { +private: + unsigned short iDim, iVar, jVar; /*!< \brief Iterators in dimension an variable. */ + su2double *Mean_PrimVar, /*!< \brief Mean primitive variables. */ + *Mean_SecVar, /*!< \brief Mean primitive variables. */ + *PrimVar_i, *PrimVar_j, /*!< \brief Primitives variables at point i and 1. */ + *Edge_Vector, /*!< \brief Vector form point i to point j. */ + **Mean_GradPrimVar, *Proj_Mean_GradPrimVar_Edge, /*!< \brief Mean value of the gradient. */ + Mean_Laminar_Viscosity, /*!< \brief Mean value of the laminar viscosity. */ + Mean_Eddy_Viscosity, /*!< \brief Mean value of the eddy viscosity. */ + Mean_Thermal_Conductivity, /*!< \brief Mean value of the thermal conductivity. */ + Mean_Cp, /*!< \brief Mean value of the specific heat. */ + Mean_turb_ke, /*!< \brief Mean value of the turbulent kinetic energy. */ + dist_ij_2; /*!< \brief Length of the edge and face. */ + bool implicit; /*!< \brief Implicit calculus. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimension of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CGeneralAvgGradCorrected_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CGeneralAvgGradCorrected_Flow(void); + + /*! + * \brief Compute the viscous flow residual using an average of gradients with correction. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + +/*! + * \class CAvgGradCorrectedArtComp_Flow + * \brief Class for computing viscous term using an average of gradients with correction (artificial compresibility). + * \ingroup ViscDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CAvgGradCorrectedArtComp_Flow : public CNumerics { +private: + unsigned short iDim, iVar, jVar; /*!< \brief Iterators in dimension an variable. */ + su2double *PrimVar_i, *PrimVar_j, /*!< \brief Primitives variables at point i and 1. */ + *Edge_Vector, /*!< \brief Vector form point i to point j. */ + **Mean_GradPrimVar, *Proj_Mean_GradPrimVar_Edge, /*!< \brief Mean value of the gradient. */ + Mean_Laminar_Viscosity, Mean_Eddy_Viscosity, /*!< \brief Mean value of the viscosity. */ + dist_ij_2; /*!< \brief Length of the edge and face. */ + bool implicit; /*!< \brief Implicit calculus. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimension of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGradCorrectedArtComp_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGradCorrectedArtComp_Flow(void); + + /*! + * \brief Compute the viscous flow residual using an average of gradients with correction. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + +/*! + * \class CAvgGradCorrected_TurbSA + * \brief Class for computing viscous term using average of gradients with correction (Spalart-Allmaras turbulence model). + * \ingroup ViscDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CAvgGradCorrected_TurbSA : public CNumerics { +private: + su2double **Mean_GradTurbVar; + su2double *Proj_Mean_GradTurbVar_Kappa, *Proj_Mean_GradTurbVar_Edge, *Proj_Mean_GradTurbVar_Corrected; + su2double *Edge_Vector; + bool implicit, incompressible; + su2double sigma, nu_i, nu_j, nu_e, dist_ij_2, proj_vector_ij; + unsigned short iVar, iDim; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGradCorrected_TurbSA(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGradCorrected_TurbSA(void); + + /*! + * \brief Compute the viscous turbulent residual using an average of gradients with correction. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); +}; + +/*! + * \class CAvgGradCorrected_TurbSA_Neg + * \brief Class for computing viscous term using average of gradients with correction (Spalart-Allmaras turbulence model). + * \ingroup ViscDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CAvgGradCorrected_TurbSA_Neg : public CNumerics { +private: + + su2double **Mean_GradTurbVar; + su2double *Proj_Mean_GradTurbVar_Kappa, *Proj_Mean_GradTurbVar_Edge, *Proj_Mean_GradTurbVar_Corrected; + su2double *Edge_Vector; + su2double sigma; + su2double cn1, fn, Xi; + su2double nu_ij, nu_tilde_ij; + bool implicit, incompressible; + su2double nu_i, nu_j, nu_e, dist_ij_2, proj_vector_ij; + unsigned short iVar, iDim; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGradCorrected_TurbSA_Neg(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGradCorrected_TurbSA_Neg(void); + + /*! + * \brief Compute the viscous turbulent residual using an average of gradients with correction. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); +}; + +/*! + * \class CAvgGradCorrected_TurbML + * \brief Class for computing viscous term using average of gradients with correction (Spalart-Allmaras turbulence model). + * \ingroup ViscDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CAvgGradCorrected_TurbML : public CNumerics { +private: + su2double **Mean_GradTurbVar; + su2double *Proj_Mean_GradTurbVar_Kappa, *Proj_Mean_GradTurbVar_Edge, *Proj_Mean_GradTurbVar_Corrected; + su2double *Edge_Vector; + bool implicit, incompressible; + su2double sigma, nu_i, nu_j, nu_e, dist_ij_2, proj_vector_ij; + unsigned short iVar, iDim; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGradCorrected_TurbML(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGradCorrected_TurbML(void); + + /*! + * \brief Compute the viscous turbulent residual using an average of gradients with correction. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); +}; + +/*! + * \class CAvgGradCorrected_TransLM + * \brief Class for computing viscous term using average of gradients with correction (Spalart-Allmaras turbulence model). + * \ingroup ViscDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CAvgGradCorrected_TransLM : public CNumerics { +private: + su2double **Mean_GradTurbVar; + su2double *Proj_Mean_GradTurbVar_Kappa, *Proj_Mean_GradTurbVar_Edge, *Proj_Mean_GradTurbVar_Corrected; + su2double *Edge_Vector; + bool implicit, incompressible; + su2double sigma; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGradCorrected_TransLM(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGradCorrected_TransLM(void); + + /*! + * \brief Compute the viscous turbulent residual using an average of gradients with correction. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); +}; + +/*! + * \class CAvgGrad_TurbSST + * \brief Class for computing viscous term using average of gradient with correction (Menter SST turbulence model). + * \ingroup ViscDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CAvgGrad_TurbSST : public CNumerics { +private: + su2double sigma_k1, /*!< \brief Constants for the viscous terms, k-w (1), k-eps (2)*/ + sigma_k2, + sigma_om1, + sigma_om2; + + su2double diff_kine, /*!< \brief Diffusivity for viscous terms of tke eq */ + diff_omega; /*!< \brief Diffusivity for viscous terms of omega eq */ + + su2double *Edge_Vector, /*!< \brief Vector from node i to node j. */ + dist_ij_2, /*!< \brief |Edge_Vector|^2 */ + proj_vector_ij; /*!< \brief (Edge_Vector DOT normal)/|Edge_Vector|^2 */ + + su2double **Mean_GradTurbVar, /*!< \brief Average of gradients at cell face */ + *Proj_Mean_GradTurbVar_Normal, /*!< \brief Mean_gradTurbVar DOT normal */ + *Proj_Mean_GradTurbVar_Edge, /*!< \brief Mean_gradTurbVar DOT Edge_Vector */ + *Proj_Mean_GradTurbVar_Corrected; + + su2double F1_i, F1_j; /*!< \brief Menter's first blending function */ + + bool implicit, incompressible; + unsigned short iVar, iDim; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGrad_TurbSST(unsigned short val_nDim, unsigned short val_nVar, su2double* constants, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGrad_TurbSST(void); + + /*! + * \brief Sets value of first blending function. + */ + void SetF1blending(su2double val_F1_i, su2double val_F1_j) { F1_i = val_F1_i; F1_j = val_F1_j;} + + /*! + * \brief Compute the viscous turbulent residual using an average of gradients wtih correction. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); + +}; + +/*! + * \class CAvgGradCorrected_TurbSST + * \brief Class for computing viscous term using average of gradient with correction (Menter SST turbulence model). + * \ingroup ViscDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CAvgGradCorrected_TurbSST : public CNumerics { +private: + su2double sigma_k1, /*!< \brief Constants for the viscous terms, k-w (1), k-eps (2)*/ + sigma_k2, + sigma_om1, + sigma_om2; + + su2double diff_kine, /*!< \brief Diffusivity for viscous terms of tke eq */ + diff_omega; /*!< \brief Diffusivity for viscous terms of omega eq */ + + su2double *Edge_Vector, /*!< \brief Vector from node i to node j. */ + dist_ij_2, /*!< \brief |Edge_Vector|^2 */ + proj_vector_ij; /*!< \brief (Edge_Vector DOT normal)/|Edge_Vector|^2 */ + + su2double **Mean_GradTurbVar, /*!< \brief Average of gradients at cell face */ + *Proj_Mean_GradTurbVar_Normal, /*!< \brief Mean_gradTurbVar DOT normal */ + *Proj_Mean_GradTurbVar_Edge, /*!< \brief Mean_gradTurbVar DOT Edge_Vector */ + *Proj_Mean_GradTurbVar_Corrected; + + su2double F1_i, F1_j; /*!< \brief Menter's first blending function */ + + bool implicit, incompressible; + unsigned short iVar, iDim; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGradCorrected_TurbSST(unsigned short val_nDim, unsigned short val_nVar, su2double* constants, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGradCorrected_TurbSST(void); + + /*! + * \brief Sets value of first blending function. + */ + void SetF1blending(su2double val_F1_i, su2double val_F1_j) { F1_i = val_F1_i; F1_j = val_F1_j;} + + /*! + * \brief Compute the viscous turbulent residual using an average of gradients wtih correction. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); + +}; + +/*! + * \class CAvgGradCorrected_AdjFlow + * \brief Class for computing the adjoint viscous terms, including correction. + * \ingroup ViscDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CAvgGradCorrected_AdjFlow : public CNumerics { +private: + su2double *Velocity_i; /*!< \brief Auxiliary vector for storing the velocity of point i. */ + su2double *Velocity_j; /*!< \brief Auxiliary vector for storing the velocity of point j. */ + su2double *Mean_Velocity; + su2double **Mean_GradPsiVar; /*!< \brief Counter for dimensions of the problem. */ + su2double *Edge_Vector; /*!< \brief Vector going from node i to node j. */ + su2double *Proj_Mean_GradPsiVar_Edge; /*!< \brief Projection of Mean_GradPsiVar onto Edge_Vector. */ + su2double *Mean_GradPsiE; /*!< \brief Counter for dimensions of the problem. */ + su2double **Mean_GradPhi; /*!< \brief Counter for dimensions of the problem. */ + bool implicit; /*!< \brief Boolean controlling Jacobian calculations. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGradCorrected_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGradCorrected_AdjFlow(void); + + /*! + * \brief Compute the adjoint flow viscous residual in a non-conservative way using an average of gradients and derivative correction. + * \param[out] val_residual_i - Pointer to the viscous residual at point i. + * \param[out] val_residual_j - Pointer to the viscous residual at point j. + * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. + * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. + * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. + * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, + su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); +}; + +/*! + * \class CAvgGradCorrectedArtComp_AdjFlow + * \brief Class for computing the adjoint viscous terms, including correction. + * \ingroup ViscDiscr + * \author F.Palacios + * \version 4.0.1 "Cardinal" + */ +class CAvgGradCorrectedArtComp_AdjFlow : public CNumerics { +private: + unsigned short iDim, iVar, jVar; /*!< \brief Iterators in dimension an variable. */ + su2double *PsiVar_i, *PsiVar_j, /*!< \brief Primitives variables at point i and 1. */ + *Edge_Vector, /*!< \brief Vector form point i to point j. */ + **Mean_GradPsiVar, *Proj_Mean_GradPsiVar_Edge, /*!< \brief Mean value of the gradient. */ + Mean_Laminar_Viscosity, Mean_Eddy_Viscosity, /*!< \brief Mean value of the viscosity. */ + dist_ij_2; /*!< \brief Length of the edge and face. */ + bool implicit; /*!< \brief Implicit calculus. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGradCorrectedArtComp_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGradCorrectedArtComp_AdjFlow(void); + + /*! + * \brief Compute the adjoint flow viscous residual in a non-conservative way using an average of gradients and derivative correction. + * \param[out] val_residual_i - Pointer to the viscous residual at point i. + * \param[out] val_residual_j - Pointer to the viscous residual at point j. + * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. + * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. + * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. + * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual (su2double *val_residual_i, su2double *val_residual_j, su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, + su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); +}; + +/*! + * \class CAvgGradCorrected_AdjTurb + * \brief Class for adjoint turbulent using average of gradients with a correction. + * \ingroup ViscDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CAvgGradCorrected_AdjTurb : public CNumerics { +private: + su2double **Mean_GradTurbPsi; + su2double *Proj_Mean_GradTurbPsi_Kappa, *Proj_Mean_GradTurbPsi_Edge, *Proj_Mean_GradTurbPsi_Corrected; + su2double *Edge_Vector; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGradCorrected_AdjTurb(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGradCorrected_AdjTurb(void); + + /*! + * \brief Compute the adjoint turbulent residual using average of gradients and a derivative correction. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); + + /*! + * \overload + * \param[out] val_residual_i - Pointer to the total residual at point i. + * \param[out] val_residual_j - Pointer to the total viscosity residual at point j. + * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. + * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. + * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. + * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, + su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); +}; + +/*! + * \class CAvgGrad_AdjTurb + * \brief Class for adjoint turbulent using average of gradients with a correction. + * \ingroup ViscDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CAvgGrad_AdjTurb : public CNumerics { +private: + su2double **Mean_GradTurbPsi; + su2double *Proj_Mean_GradTurbPsi_Kappa, *Proj_Mean_GradTurbPsi_Edge, *Proj_Mean_GradTurbPsi_Corrected; + su2double *Edge_Vector; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAvgGrad_AdjTurb(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAvgGrad_AdjTurb(void); + + /*! + * \brief Compute the adjoint turbulent residual using average of gradients and a derivative correction. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); + + /*! + * \overload + * \param[out] val_residual_i - Pointer to the total residual at point i. + * \param[out] val_residual_j - Pointer to the total viscosity residual at point j. + * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. + * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. + * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. + * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, + su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); +}; + +/*! + * \class CGalerkin_Flow + * \brief Class for computing the stiffness matrix of the Galerkin method. + * \ingroup ViscDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CGalerkin_Flow : public CNumerics { +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CGalerkin_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CGalerkin_Flow(void); + + /*! + * \brief Computing stiffness matrix of the Galerkin method. + * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual (su2double **val_stiffmatrix_elem, CConfig *config); +}; + +/*! + * \class CGalerkin_FEA + * \brief Class for computing the stiffness matrix of the Galerkin method. + * \ingroup ViscDiscr + * \author F. Palacios, R.Sanchez + * \version 4.0.1 "Cardinal" + */ +class CGalerkin_FEA : public CNumerics { + + su2double E; /*!< \brief Young's modulus of elasticity. */ + su2double Nu; /*!< \brief Poisson's ratio. */ + su2double Rho_s; /*!< \brief Structural density. */ + su2double Mu; /*!< \brief Lame's coeficient. */ + su2double Lambda; /*!< \brief Lame's coeficient. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CGalerkin_FEA(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CGalerkin_FEA(void); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Fnodal - Forces at the nodes in cartesian coordinates. + * \param[in] Pnodal - Pressure at the nodes. + * \param[in] CoordCorners[2][2] - Coordiantes of the corners. + */ + void PressInt_Linear(su2double CoordCorners[4][3], su2double *tn_e, su2double Fnodal[12]); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Tau_0 - Stress tensor at the node 0. + * \param[in] Tau_1 - Stress tensor at the node 1. + * \param[in] Fnodal - Forces at the nodes in cartesian coordinates. + * \param[in] CoordCorners[2][2] - Coordiantes of the corners. + */ + void ViscTermInt_Linear(su2double CoordCorners[2][2], su2double Tau_0[3][3], su2double Tau_1[3][3], su2double FviscNodal[4]); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] Mu - Local coordinates. + * \param[in] CoordCorners[8][3] - Coordiantes of the corners. + * \param[in] shp[8][4] - Shape function information + */ + su2double ShapeFunc_Triangle(su2double Xi, su2double Eta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] Mu - Local coordinates. + * \param[in] CoordCorners[8][3] - Coordiantes of the corners. + * \param[in] shp[8][4] - Shape function information + */ + su2double ShapeFunc_Quadrilateral(su2double Xi, su2double Eta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] Mu - Local coordinates. + * \param[in] CoordCorners[8][3] - Coordiantes of the corners. + * \param[in] shp[8][4] - Shape function information + */ + su2double ShapeFunc_Tetra(su2double Xi, su2double Eta, su2double Mu, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] Mu - Local coordinates. + * \param[in] CoordCorners[8][3] - Coordiantes of the corners. + * \param[in] shp[8][4] - Shape function information + */ + su2double ShapeFunc_Prism(su2double Xi, su2double Eta, su2double Mu, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] Mu - Local coordinates. + * \param[in] CoordCorners[8][3] - Coordiantes of the corners. + * \param[in] shp[8][4] - Shape function information + */ + su2double ShapeFunc_Pyram(su2double Xi, su2double Eta, su2double Mu, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] Mu - Local coordinates. + * \param[in] CoordCorners[8][3] - Coordiantes of the corners. + * \param[in] shp[8][4] - Shape function information + */ + su2double ShapeFunc_Hexa(su2double Xi, su2double Eta, su2double Mu, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); + + /*! + * \brief Computing stiffness matrix of the Galerkin method. + * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. + * \param[in] config - Definition of the particular problem. + */ + void SetFEA_StiffMatrix2D(su2double **StiffMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d); + + /*! + * \brief Computing stiffness matrix of the Galerkin method. + * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. + * \param[in] config - Definition of the particular problem. + */ + void SetFEA_StiffMatrix3D(su2double **StiffMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes); + + /*! + * \brief Computing mass matrix of the Galerkin method. + * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. + * \param[in] config - Definition of the particular problem. + */ + void SetFEA_StiffMassMatrix2D(su2double **StiffMatrix_Elem, su2double **MassMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d); + + /*! + * \brief Computing mass matrix of the Galerkin method. + * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. + * \param[in] config - Definition of the particular problem. + */ + void SetFEA_StiffMassMatrix3D(su2double **StiffMatrix_Elem, su2double **MassMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes); + + /*! + * \brief Computing stresses in FEA method at the nodes. + * \param[in] config - Definition of the particular problem. + */ + void GetFEA_StressNodal2D(su2double StressVector[8][3], su2double DispElement[8], su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d); + + + /*! + * \brief Computing stresses in FEA method at the nodes. + * \param[in] config - Definition of the particular problem. + */ + void GetFEA_StressNodal3D(su2double StressVector[8][6], su2double DispElement[24], su2double CoordCorners[8][3], unsigned short nNodes); + + /*! + * \brief Computing dead load vector of the Galerkin method. + * \param[out] val_deadloadvector_elem - Dead load at the nodes for Galerkin computation. + * \param[in] config - Definition of the particular problem. + */ + void SetFEA_DeadLoad2D(su2double *DeadLoadVector_Elem, su2double CoordCorners[8][3], unsigned short nNodes, su2double matDensity); + + /*! + * \brief Computing stiffness matrix of the Galerkin method. + * \param[out] val_deadloadvector_elem - Dead load at the nodes for Galerkin computation. + * \param[in] config - Definition of the particular problem. + */ + void SetFEA_DeadLoad3D(su2double *DeadLoadVector_Elem, su2double CoordCorners[8][3], unsigned short nNodes, su2double matDensity); + +}; + +/*! + * \class CSourceNothing + * \brief Dummy class. + * \ingroup SourceDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CSourceNothing : public CNumerics { +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CSourceNothing(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSourceNothing(void); +}; + +/*! + * \class CSourcePieceWise_TurbSA + * \brief Class for integrating the source terms of the Spalart-Allmaras turbulence model equation. + * \ingroup SourceDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CSourcePieceWise_TurbSA : public CNumerics { +private: + su2double cv1_3; + su2double k2; + su2double cb1; + su2double cw2; + su2double ct3; + su2double ct4; + su2double cw3_6; + su2double cb2_sigma; + su2double sigma; + su2double cb2; + su2double cw1; + unsigned short iDim; + su2double nu, Ji, fv1, fv2, ft2, Omega, S, Shat, inv_Shat, dist_i_2, Ji_2, Ji_3, inv_k2_d2; + su2double r, g, g_6, glim, fw; + su2double norm2_Grad; + su2double dfv1, dfv2, dShat; + su2double dr, dg, dfw; + bool incompressible; + bool rotating_frame; + su2double intermittency; + su2double Production, Destruction, CrossProduction; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CSourcePieceWise_TurbSA(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSourcePieceWise_TurbSA(void); + + /*! + * \brief Residual for source term integration. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); + + /*! + * \brief Residual for source term integration. + * \param[in] intermittency_in - Value of the intermittency. + */ + void SetIntermittency(su2double intermittency_in); + + /*! + * \brief Residual for source term integration. + * \param[in] val_production - Value of the Production. + */ + void SetProduction(su2double val_production); + + /*! + * \brief Residual for source term integration. + * \param[in] val_destruction - Value of the Destruction. + */ + void SetDestruction(su2double val_destruction); + + /*! + * \brief Residual for source term integration. + * \param[in] val_crossproduction - Value of the CrossProduction. + */ + void SetCrossProduction(su2double val_crossproduction); + + /*! + * \brief ______________. + */ + su2double GetProduction(void); + + /*! + * \brief ______________. + */ + su2double GetDestruction(void); + + /*! + * \brief ______________. + */ + su2double GetCrossProduction(void); +}; + +/*! + * \class CSourcePieceWise_TurbSA_Neg + * \brief Class for integrating the source terms of the Spalart-Allmaras turbulence model equation. + * \ingroup SourceDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CSourcePieceWise_TurbSA_Neg : public CNumerics { +private: + su2double cv1_3; + su2double k2; + su2double cb1; + su2double cw2; + su2double ct3; + su2double ct4; + su2double cw3_6; + su2double cb2_sigma; + su2double sigma; + su2double cb2; + su2double cw1; + unsigned short iDim; + su2double nu, Ji, fv1, fv2, ft2, Omega, S, Shat, inv_Shat, dist_i_2, Ji_2, Ji_3, inv_k2_d2; + su2double r, g, g_6, glim, fw; + su2double norm2_Grad; + su2double dfv1, dfv2, dShat; + su2double dr, dg, dfw; + bool incompressible; + bool rotating_frame; + su2double intermittency; + su2double Production, Destruction, CrossProduction; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CSourcePieceWise_TurbSA_Neg(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSourcePieceWise_TurbSA_Neg(void); + + /*! + * \brief Residual for source term integration. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); + + /*! + * \brief Residual for source term integration. + * \param[in] intermittency_in - Value of the intermittency. + */ + void SetIntermittency(su2double intermittency_in); + + /*! + * \brief Residual for source term integration. + * \param[in] val_production - Value of the Production. + */ + void SetProduction(su2double val_production); + + /*! + * \brief Residual for source term integration. + * \param[in] val_destruction - Value of the Destruction. + */ + void SetDestruction(su2double val_destruction); + + /*! + * \brief Residual for source term integration. + * \param[in] val_crossproduction - Value of the CrossProduction. + */ + void SetCrossProduction(su2double val_crossproduction); + + /*! + * \brief ______________. + */ + su2double GetProduction(void); + + /*! + * \brief ______________. + */ + su2double GetDestruction(void); + + /*! + * \brief ______________. + */ + su2double GetCrossProduction(void); +}; + +/*! + * \class CSourcePieceWise_TransLM + * \brief Class for integrating the source terms of the Spalart-Allmaras turbulence model equation. + * \ingroup SourceDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CSourcePieceWise_TransLM : public CNumerics { +private: + + /*-- SA model constants --*/ + su2double cv1_3; + su2double k2; + su2double cb1; + su2double cw2; + su2double cw3_6; + su2double sigma; + su2double cb2; + su2double cw1; + + /*-- gamma-theta model constants --*/ + su2double c_e1; + su2double c_a1; + su2double c_e2; + su2double c_a2; + su2double sigmaf; + su2double s1; + su2double c_theta; + su2double sigmat; + + /*-- Correlation constants --*/ + su2double flen_global; + su2double alpha_global; + su2double Vorticity; + + bool implicit; + +public: + bool debugme; // For debugging only, remove this. -AA + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CSourcePieceWise_TransLM(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSourcePieceWise_TransLM(void); + + /*! + * \brief Residual for source term integration. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual_TransLM(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config, su2double &gamma_sep); + + void CSourcePieceWise_TransLM__ComputeResidual_TransLM_d(su2double *TransVar_i, su2double *TransVar_id, su2double *val_residual, su2double *val_residuald, CConfig *config); +}; + +/*! + * \class CSourcePieceWise_TurbSST + * \brief Class for integrating the source terms of the Menter SST turbulence model equations. + * \ingroup SourceDiscr + * \author A. Campos. + * \version 4.0.1 "Cardinal" + */ +class CSourcePieceWise_TurbSST : public CNumerics { +private: + su2double F1_i, + F1_j, + F2_i, + F2_j; + + su2double alfa_1, + alfa_2, + beta_1, + beta_2, + sigma_omega_1, + sigma_omega_2, + beta_star, + a1; + + su2double CDkw_i, CDkw_j; + + bool incompressible; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CSourcePieceWise_TurbSST(unsigned short val_nDim, unsigned short val_nVar, su2double* constants, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSourcePieceWise_TurbSST(void); + + /*! + * \brief Set the value of the first blending function. + * \param[in] val_F1_i - Value of the first blending function at point i. + * \param[in] val_F1_j - Value of the first blending function at point j. + */ + void SetF1blending(su2double val_F1_i, su2double val_F1_j); + + /*! + * \brief Set the value of the second blending function. + * \param[in] val_F2_i - Value of the second blending function at point i. + * \param[in] val_F2_j - Value of the second blending function at point j. + */ + void SetF2blending(su2double val_F2_i, su2double val_F2_j); + + /*! + * \brief Set the value of the cross diffusion for the SST model. + * \param[in] val_CDkw_i - Value of the cross diffusion at point i. + * \param[in] val_CDkw_j - Value of the cross diffusion at point j. + */ + virtual void SetCrossDiff(su2double val_CDkw_i, su2double val_CDkw_j); + + /*! + * \brief Residual for source term integration. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); + +}; + +/*! + * \class CSourceGravity + * \brief Class for the source term integration of the gravity force. + * \ingroup SourceDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CSourceGravity : public CNumerics { + su2double Froude; + bool compressible, incompressible, freesurface; + +public: + + /*! + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CSourceGravity(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSourceGravity(void); + + /*! + * \brief Source term integration for the poissonal potential. + * \param[out] val_residual - Pointer to the total residual. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, CConfig *config); +}; + +/*! + * \class CSourceViscous_AdjFlow + * \brief Class for source term integration in adjoint problem. + * \ingroup SourceDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CSourceViscous_AdjFlow : public CNumerics { +private: + su2double *Velocity, *GradDensity, *GradInvDensity, *dPoDensity2, *alpha, *beta, *Sigma_5_vec; + su2double **GradVel_o_Rho, **sigma, **Sigma_phi, **Sigma_5_Tensor, **Sigma; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CSourceViscous_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSourceViscous_AdjFlow(void); + + /*! + * \brief Source term integration of the flow adjoint equation. + * \param[out] val_residual - Pointer to the total residual. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual (su2double *val_residual, CConfig *config); + +}; + +/*! + * \class CSourcePieceWise_AdjTurb + * \brief Class for source term integration of the adjoint turbulent equation. + * \ingroup SourceDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CSourcePieceWise_AdjTurb : public CNumerics { +private: + su2double **tau, *Velocity; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CSourcePieceWise_AdjTurb(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSourcePieceWise_AdjTurb(void); + + /*! + * \brief Source term integration of the adjoint turbulence equation. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + +/*! + * \class CSourcePieceWise_AdjLevelSet + * \brief Class for source term integration of the adjoint level set equation. + * \ingroup SourceDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CSourcePieceWise_AdjLevelSet : public CNumerics { +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CSourcePieceWise_AdjLevelSet(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSourcePieceWise_AdjLevelSet(void); + + /*! + * \brief Source term integration of the adjoint poisson potential equation. + * \param[out] val_residual - Pointer to the total residual. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, CConfig *config); +}; + +/*! + * \class CSourceConservative_AdjFlow + * \brief Class for source term integration in adjoint problem using a conservative scheme. + * \ingroup SourceDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CSourceConservative_AdjFlow : public CNumerics { +private: + su2double *Velocity, *Residual_i, *Residual_j, *Mean_Residual; + su2double **Mean_PrimVar_Grad; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CSourceConservative_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSourceConservative_AdjFlow(void); + + /*! + * \brief Source term integration using a conservative scheme. + * \param[out] val_residual - Pointer to the total residual. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, CConfig *config); +}; + +/*! + * \class CSourceConservative_AdjTurb + * \brief Class for source term integration in adjoint turbulent problem using a conservative scheme. + * \ingroup SourceDiscr + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CSourceConservative_AdjTurb : public CNumerics { +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CSourceConservative_AdjTurb(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSourceConservative_AdjTurb(void); + + /*! + * \brief Source term integration using a conservative scheme. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; + +/*! + * \class CSourceRotatingFrame_Flow + * \brief Class for a rotating frame source term. + * \ingroup SourceDiscr + * \author F. Palacios, T. Economon. + * \version 4.0.1 "Cardinal" + */ +class CSourceRotatingFrame_Flow : public CNumerics { +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CSourceRotatingFrame_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSourceRotatingFrame_Flow(void); + + /*! + * \brief Residual of the rotational frame source term. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config); +}; + +/*! + * \class CSourceRotatingFrame_AdjFlow + * \brief Source term class for rotating frame adjoint. + * \ingroup SourceDiscr + * \author T. Economon. + * \version 4.0.1 "Cardinal" + */ +class CSourceRotatingFrame_AdjFlow : public CNumerics { +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CSourceRotatingFrame_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSourceRotatingFrame_AdjFlow(void); + + /*! + * \brief Residual of the adjoint rotating frame source term. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config); +}; + +/*! + * \class CSourceAxisymmetric_Flow + * \brief Class for source term for solving axisymmetric problems. + * \ingroup SourceDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CSourceAxisymmetric_Flow : public CNumerics { +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CSourceAxisymmetric_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSourceAxisymmetric_Flow(void); + + /*! + * \brief Residual of the rotational frame source term. + * \param[out] val_residual - Pointer to the total residual. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, CConfig *config); + +}; + +/*! + * \class CSourceAxisymmetric_AdjFlow + * \brief Class for source term for solving axisymmetric problems. + * \ingroup SourceDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CSourceAxisymmetric_AdjFlow : public CNumerics { +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CSourceAxisymmetric_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSourceAxisymmetric_AdjFlow(void); + + /*! + * \brief Residual of the rotational frame source term. + * \param[out] val_residual - Pointer to the total residual. + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, CConfig *config); +}; + +/*! + * \class CSourceWindGust + * \brief Class for a source term due to a wind gust. + * \ingroup SourceDiscr + * \author S. Padrón + * \version 4.0.1 "Cardinal" + */ +class CSourceWindGust : public CNumerics { +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CSourceWindGust(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSourceWindGust(void); + + /*! + * \brief Residual of the wind gust source term. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config); +}; - bool implicit, grid_movement; +/*! + * \class CSource_Template + * \brief Dummy class. + * \ingroup SourceDiscr + * \author A. Lonkar. + * \version 4.0.1 "Cardinal" + */ +class CSource_Template : public CNumerics { +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Name of the input config file + * + */ + CSource_Template(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + + /*! + * \brief Residual for source term integration. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CSource_Template(void); +}; - su2double *Diff_U; - su2double *Velocity_i, *Velocity_j, *RoeVelocity; - su2double *ProjFlux_i, *ProjFlux_j; - su2double *delta_wave, *delta_vel; - su2double *Lambda, *Epsilon, MaxLambda, Delta; - su2double **P_Tensor, **invP_Tensor; - su2double sq_vel, Proj_ModJac_Tensor_ij, Density_i, Energy_i, SoundSpeed_i, Pressure_i, Enthalpy_i, +/*! + * \class CConvectiveTemplate + * \brief Class for setting up new method for spatial discretization of convective terms in flow Equations + * \ingroup ConvDiscr + * \author A. Lonkar + * \version 4.0.1 "Cardinal" + */ +class CConvective_Template : public CNumerics { +private: + + /* define private variables here */ + bool implicit; + su2double *Diff_U; + su2double *Velocity_i, *Velocity_j, *RoeVelocity; + su2double *ProjFlux_i, *ProjFlux_j; + su2double *delta_wave, *delta_vel; + su2double *Lambda, *Epsilon; + su2double **P_Tensor, **invP_Tensor; + su2double sq_vel, Proj_ModJac_Tensor_ij, Density_i, Energy_i, SoundSpeed_i, Pressure_i, Enthalpy_i, + Density_j, Energy_j, SoundSpeed_j, Pressure_j, Enthalpy_j, R, RoeDensity, RoeEnthalpy, RoeSoundSpeed, + ProjVelocity, ProjVelocity_i, ProjVelocity_j, proj_delta_vel, delta_p, delta_rho; + unsigned short iDim, iVar, jVar, kVar; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CConvective_Template(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CConvective_Template(void); + + /*! + * \brief Compute the Roe's flux between two nodes i and j. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; - Density_j, Energy_j, SoundSpeed_j, Pressure_j, Enthalpy_j, R, RoeDensity, RoeEnthalpy, RoeSoundSpeed, RoeSoundSpeed2, - ProjVelocity, ProjVelocity_i, ProjVelocity_j, proj_delta_vel, delta_p, delta_rho, kappa; - unsigned short iDim, iVar, jVar, kVar; - - - su2double StaticEnthalpy_i, StaticEnergy_i, StaticEnthalpy_j, StaticEnergy_j, Kappa_i, Kappa_j, Chi_i, Chi_j, Velocity2_i, Velocity2_j; - su2double RoeKappa, RoeChi, RoeKappaStaticEnthalpy; +/*! + * \class CViscous_Template + * \brief Class for computing viscous term using average of gradients. + * \ingroup ViscDiscr + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CViscous_Template : public CNumerics { +private: + +public: + + /*! + * \brief Constructor of the class. + * \param[in] val_nDim - Number of dimension of the problem. + * \param[in] val_nVar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CViscous_Template(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CViscous_Template(void); + + /*! + * \brief Compute the viscous flow residual using an average of gradients. + * \param[out] val_residual - Pointer to the total residual. + * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). + * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). + * \param[in] config - Definition of the particular problem. + */ + void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); +}; -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwGeneralRoe_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwGeneralRoe_Flow(void); - - /*! - * \brief Compute the Roe's flux between two nodes i and j. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); - - /*! - * \brief Compute the Average for a general fluid flux between two nodes i and j. - * Using the approach of Vinokur and Montagne' - */ - - void ComputeRoeAverage(); -}; - - -/*! - * \class CUpwMSW_Flow - * \brief Class for solving a flux-vector splitting method by Steger & Warming, modified version. - * \ingroup ConvDiscr - * \author S. Copeland - * \version 4.0.1 "Cardinal" - */ -class CUpwMSW_Flow : public CNumerics { -private: - bool implicit; - su2double *Diff_U; - su2double *u_i, *u_j, *ust_i, *ust_j; - su2double *Fc_i, *Fc_j; - su2double *Lambda_i, *Lambda_j; - su2double rhos_i, rhos_j; - su2double *Ust_i, *Ust_j, *Vst_i, *Vst_j, *Velst_i, *Velst_j; - su2double **P_Tensor, **invP_Tensor; - unsigned short nPrimVar, nVar, nDim; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwMSW_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwMSW_Flow(void); - - /*! - * \brief Compute the Roe's flux between two nodes i and j. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); - -}; - -/*! - * \class CUpwTurkel_Flow - * \brief Class for solving an approximate Riemann solver of Roe with Turkel Preconditioning for the flow equations. - * \ingroup ConvDiscr - * \author A. K. Lonkar - * \version 4.0.1 "Cardinal" - */ -class CUpwTurkel_Flow : public CNumerics { -private: - bool implicit, grid_movement; - su2double *Diff_U; - su2double *Velocity_i, *Velocity_j, *RoeVelocity; - su2double *ProjFlux_i, *ProjFlux_j; - su2double *Lambda, *Epsilon; - su2double **absPeJac, **invRinvPe, **R_Tensor, **Matrix, **Art_Visc; - su2double sq_vel, Density_i, Energy_i, SoundSpeed_i, Pressure_i, Enthalpy_i, - Density_j, Energy_j, SoundSpeed_j, Pressure_j, Enthalpy_j, R, RoePressure, RoeDensity, RoeEnthalpy, RoeSoundSpeed, - ProjVelocity, ProjVelocity_i, ProjVelocity_j; - unsigned short iDim, iVar, jVar, kVar; - su2double Beta, Beta_min, Beta_max; - su2double r_hat, s_hat, t_hat, rhoB2a2, sqr_one_m_Betasqr_Lam1; - su2double Beta2, one_m_Betasqr, one_p_Betasqr, sqr_two_Beta_c_Area; - su2double local_Mach; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwTurkel_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwTurkel_Flow(void); - - /*! - * \brief Compute the Roe's flux between two nodes i and j. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); - - /*! - * \brief Get the Preconditioning Beta. - * \return Beta - Value of the low Mach Preconditioner. - */ - su2double GetPrecond_Beta(); -}; - -/*! - * \class CUpwArtComp_Flow - * \brief Class for solving an approximate Riemann solver of Roe for the incompressible flow equations. - * \ingroup ConvDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CUpwArtComp_Flow : public CNumerics { -private: - bool implicit; - bool gravity; - su2double Froude; - su2double *Diff_U; - su2double *Velocity_i, *Velocity_j, *MeanVelocity; - su2double *ProjFlux_i, *ProjFlux_j; - su2double *Lambda, *Epsilon; - su2double **P_Tensor, **invP_Tensor; - su2double Proj_ModJac_Tensor_ij, Pressure_i, - Pressure_j, MeanDensity, MeanSoundSpeed, MeanPressure, MeanBetaInc2, - ProjVelocity; - unsigned short iDim, iVar, jVar, kVar; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwArtComp_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwArtComp_Flow(void); - - /*! - * \brief Compute the Roe's flux between two nodes i and j. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CUpwArtComp_FreeSurf_Flow - * \brief Class for solving an approximate Riemann solver of Roe for the incompressible flow equations. - * \ingroup ConvDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CUpwArtComp_FreeSurf_Flow : public CNumerics { -private: - bool implicit; - bool gravity; - su2double Froude; - su2double *Diff_U; - su2double *Velocity_i, *Velocity_j, *MeanVelocity; - su2double *ProjFlux_i, *ProjFlux_j; - su2double *Lambda, *Epsilon; - su2double **P_Tensor, **invP_Tensor; - su2double Proj_ModJac_Tensor_ij, Pressure_i, LevelSet_i, dDensityInc_i, dDensityInc_j, - Pressure_j, LevelSet_j, MeanDensityInc, dMeanDensityInc, MeanPressure, MeanLevelSet, MeanBetaInc2, - ProjVelocity, Distance_i, Distance_j; - unsigned short iDim, iVar, jVar, kVar; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwArtComp_FreeSurf_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwArtComp_FreeSurf_Flow(void); - - /*! - * \brief Compute the Roe's flux between two nodes i and j. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CUpwRoe_AdjFlow - * \brief Class for solving an approximate Riemann solver of Roe - * for the adjoint flow equations. - * \ingroup ConvDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CUpwRoe_AdjFlow : public CNumerics { -private: - su2double *Residual_Roe; - su2double area, Sx, Sy, Sz, rarea, nx, ny, nz, rho_l, u_l, v_l, w_l, h_l, rho_r, - u_r, v_r, w_r, h_r, psi1, psi2, psi3, psi4, psi5; - su2double h, u, v, w, c, psi1_l, psi2_l, psi3_l, psi4_l, psi5_l, - psi1_r, psi2_r, psi3_r, psi4_r, psi5_r, q_l, q_r, Q_l, Q_r, vn, - rrho_l, weight, rweight1, cc; - su2double l1psi, l2psi, absQ, absQp, absQm, q2, alpha, beta_u, beta_v, beta_w, Q, l1l2p, l1l2m, eta; - su2double RoeDensity, RoeSoundSpeed, *RoeVelocity, *Lambda, *Velocity_i, *Velocity_j, **ProjFlux_i, **ProjFlux_j, - Proj_ModJac_Tensor_ij, **Proj_ModJac_Tensor, Energy_i, Energy_j, **P_Tensor, **invP_Tensor; - unsigned short iDim, iVar, jVar, kVar; - bool implicit, grid_movement; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwRoe_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwRoe_AdjFlow(void); - - /*! - * \brief Compute the adjoint Roe's flux between two nodes i and j. - * \param[out] val_residual_i - Pointer to the total residual at point i. - * \param[out] val_residual_j - Pointer to the total residual at point j. - * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. - * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. - * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. - * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, su2double **val_Jacobian_ii, - su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); -}; - -/*! - * \class CUpwRoeArtComp_AdjFlow - * \brief Class for solving an approximate Riemann solver of Roe - * for the adjoint flow equations. - * \ingroup ConvDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CUpwRoeArtComp_AdjFlow : public CNumerics { -private: - su2double Area, *Lambda, *Velocity_i, *Velocity_j, **Proj_Jac_Tensor_i, **Proj_Jac_Tensor_j, - Proj_ModJac_Tensor_ij, **Proj_ModJac_Tensor, **P_Tensor, **invP_Tensor, MeanDensity, - MeanPressure, MeanBetaInc2, ProjVelocity, *MeanVelocity, MeanSoundSpeed; - unsigned short iDim, iVar, jVar, kVar; - bool implicit; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwRoeArtComp_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwRoeArtComp_AdjFlow(void); - - /*! - * \brief Compute the adjoint Roe's flux between two nodes i and j. - * \param[out] val_residual_i - Pointer to the total residual at point i. - * \param[out] val_residual_j - Pointer to the total residual at point j. - * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. - * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. - * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. - * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, su2double **val_Jacobian_ii, - su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); -}; - -/*! - * \class CUpwAUSM_Flow - * \brief Class for solving an approximate Riemann AUSM. - * \ingroup ConvDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CUpwAUSM_Flow : public CNumerics { -private: - bool implicit; - su2double *Diff_U; - su2double *Velocity_i, *Velocity_j, *RoeVelocity; - su2double *ProjFlux_i, *ProjFlux_j; - su2double *delta_wave, *delta_vel; - su2double *Lambda, *Epsilon; - su2double **P_Tensor, **invP_Tensor; - su2double sq_vel, Proj_ModJac_Tensor_ij, Density_i, Energy_i, SoundSpeed_i, Pressure_i, Enthalpy_i, - Density_j, Energy_j, SoundSpeed_j, Pressure_j, Enthalpy_j, R, RoeDensity, RoeEnthalpy, RoeSoundSpeed, - ProjVelocity, ProjVelocity_i, ProjVelocity_j; - unsigned short iDim, iVar, jVar, kVar; - su2double mL, mR, mLP, mRM, mF, pLP, pRM, pF, Phi; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwAUSM_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwAUSM_Flow(void); - - /*! - * \brief Compute the Roe's flux between two nodes i and j. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CUpwHLLC_Flow - * \brief Class for solving an approximate Riemann AUSM. - * \ingroup ConvDiscr - * \author F. Palacios, based on the Joe code implementation - * \version 4.0.1 "Cardinal" - */ -class CUpwHLLC_Flow : public CNumerics { -private: - bool implicit; - su2double *Diff_U; - su2double *Velocity_i, *Velocity_j, *RoeVelocity; - su2double *ProjFlux_i, *ProjFlux_j; - su2double *delta_wave, *delta_vel; - su2double *Lambda, *Epsilon; - su2double **P_Tensor, **invP_Tensor; - su2double sq_vel_i, sq_vel_j, Proj_ModJac_Tensor_ij, Density_i, Energy_i, SoundSpeed_i, Pressure_i, Enthalpy_i, - Density_j, Energy_j, SoundSpeed_j, Pressure_j, Enthalpy_j, RoeDensity, RoeEnthalpy, RoeSoundSpeed, - RoeProjVelocity, ProjVelocity_i, ProjVelocity_j; - unsigned short iDim, iVar, jVar, kVar; - su2double Rrho, tmp, sq_velRoe, sL, sR, sM, pStar, invSLmSs, sLmuL, rhoSL, rhouSL[3], - eSL, invSRmSs, sRmuR, rhoSR, rhouSR[3], eSR; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwHLLC_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwHLLC_Flow(void); - - /*! - * \brief Compute the Roe's flux between two nodes i and j. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CUpwGeneralHLLC_Flow - * \brief Class for solving an approximate Riemann AUSM. - * \ingroup ConvDiscr - * \author F. Palacios, based on the Joe code implementation - * \version 4.0.1 "Cardinal" - */ -class CUpwGeneralHLLC_Flow : public CNumerics { -private: - bool implicit; - unsigned short iDim, iVar, jVar, kVar; - - su2double *Diff_U; - su2double *Velocity_i, *Velocity_j, *RoeVelocity; - su2double *ProjFlux_i, *ProjFlux_j; - su2double *delta_wave, *delta_vel; - su2double *Lambda, *Epsilon; - su2double **P_Tensor, **invP_Tensor; - - su2double sq_vel_i, Density_i, Energy_i, SoundSpeed_i, Pressure_i, Enthalpy_i, ProjVelocity_i, StaticEnthalpy_i, StaticEnergy_i; - su2double sq_vel_j, Density_j, Energy_j, SoundSpeed_j, Pressure_j, Enthalpy_j, ProjVelocity_j, StaticEnthalpy_j, StaticEnergy_j; - - su2double sq_velRoe, Proj_ModJac_Tensor_ij, RoeDensity, RoeEnthalpy, RoeSoundSpeed, RoeSoundSpeed2, RoeProjVelocity; - su2double Kappa_i, Kappa_j, Chi_i, Chi_j, RoeKappa, RoeChi, RoeKappaStaticEnthalpy; - - su2double sL, sR, sM, pStar, invSLmSs, sLmuL, rhoSL, rhouSL[3], Rrho, eSL, invSRmSs, sRmuR, rhoSR, rhouSR[3], eSR, kappa; - - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwGeneralHLLC_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - - * \brief Destructor of the class. - */ - ~CUpwGeneralHLLC_Flow(void); - - /*! - - * \brief Compute the Roe's flux between two nodes i and j. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); - - /*! - - * \brief Compute the Average quantities for a general fluid flux between two nodes i and j. - - * Using the approach of Vinokur and Montagne' - - */ - - void VinokurMontagne(); - -}; - -/*! - * \class CUpwLin_TransLM - * \brief Class for performing a linear upwind solver for the Spalart-Allmaras turbulence model equations with transition - * \ingroup ConvDiscr - * \author A. Aranake - * \version 4.0.1 "Cardinal" - */ -class CUpwLin_TransLM : public CNumerics { -private: - su2double *Velocity_i; - su2double *Velocity_j; - bool implicit, grid_movement, incompressible; - su2double Density_i, Density_j, q_ij, a0, a1; - unsigned short iDim; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwLin_TransLM(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwLin_TransLM(void); - - /*! - * \brief Compute the upwind flux between two nodes i and j. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual (su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CUpwLin_AdjLevelSet - * \brief Class for performing a linear upwind solver for the adjoint Level Set equations. - * \ingroup ConvDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CUpwLin_AdjLevelSet : public CNumerics { -private: - bool implicit; - su2double *Velocity_i; - su2double *Velocity_j; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwLin_AdjLevelSet(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwLin_AdjLevelSet(void); - - /*! - * \brief Compute the upwind flux between two nodes i and j. - * \param[out] val_residual_i - Pointer to the total residual at node i. - * \param[out] val_residual_j - Pointer to the total residual at node j. - * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_ij - Jacobian of the numerical method from node i to node j (implicit computation). - * \param[out] val_Jacobian_ji - Jacobian of the numerical method from node j to node i (implicit computation). - * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, su2double **val_Jacobian_ii, - su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); -}; - -/*! - * \class CUpwLin_AdjTurb - * \brief Class for performing a linear upwind solver for the adjoint turbulence equations. - * \ingroup ConvDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CUpwLin_AdjTurb : public CNumerics { -private: - su2double *Velocity_i; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwLin_AdjTurb(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwLin_AdjTurb(void); - - /*! - * \brief Compute the adjoint upwind flux between two nodes i and j. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual (su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CUpwSca_TurbSA - * \brief Class for doing a scalar upwind solver for the Spalar-Allmaral turbulence model equations. - * \ingroup ConvDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CUpwSca_TurbSA : public CNumerics { -private: - su2double *Velocity_i, *Velocity_j; - bool implicit, grid_movement, incompressible; - su2double q_ij, a0, a1; - unsigned short iDim; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwSca_TurbSA(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwSca_TurbSA(void); - - /*! - * \brief Compute the scalar upwind flux between two nodes i and j. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CUpwSca_TurbML - * \brief Class for doing a scalar upwind solver for the Spalar-Allmaral turbulence model equations. - * \ingroup ConvDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CUpwSca_TurbML : public CNumerics { -private: - su2double *Velocity_i, *Velocity_j; - bool implicit, grid_movement, incompressible; - su2double q_ij, a0, a1; - unsigned short iDim; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwSca_TurbML(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwSca_TurbML(void); - - /*! - * \brief Compute the scalar upwind flux between two nodes i and j. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CUpwSca_TurbSST - * \brief Class for doing a scalar upwind solver for the Menter SST turbulence model equations. - * \ingroup ConvDiscr - * \author A. Campos. - * \version 4.0.1 "Cardinal" - */ -class CUpwSca_TurbSST : public CNumerics { -private: - su2double *Velocity_i, *Velocity_j; - bool implicit, grid_movement, incompressible; - su2double Density_i, Density_j, - q_ij, - a0, a1; - unsigned short iDim; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwSca_TurbSST(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwSca_TurbSST(void); - - /*! - * \brief Compute the scalar upwind flux between two nodes i and j. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CUpwSca_TransLM - * \brief Class for doing a scalar upwind solver for the Spalart-Allmaras turbulence model equations with transition. - * \ingroup ConvDiscr - * \author A. Aranake. - * \version 4.0.1 "Cardinal" - */ -class CUpwSca_TransLM : public CNumerics { -private: - su2double *Velocity_i, *Velocity_j; - bool implicit, grid_movement; - su2double q_ij, a0, a1; - unsigned short iDim; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwSca_TransLM(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwSca_TransLM(void); - - /*! - * \brief Compute the scalar upwind flux between two nodes i and j. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CUpwSca_AdjTurb - * \brief Class for doing a scalar upwind solver for the adjoint turbulence equations. - * \ingroup ConvDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CUpwSca_AdjTurb : public CNumerics { -private: - su2double *Velocity_i, *Velocity_j; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CUpwSca_AdjTurb(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CUpwSca_AdjTurb(void); - - /*! - * \param[out] val_residual_i - Pointer to the total residual at point i. - * \param[out] val_residual_j - Pointer to the total viscosity residual at point j. - * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. - * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. - * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. - * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, - su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); -}; - - -/*! - * \class CCentJST_Flow - * \brief Class for centered shceme - JST. - * \ingroup ConvDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CCentJST_KE_Flow : public CNumerics { - -private: - unsigned short iDim, iVar, jVar; /*!< \brief Iteration on dimension and variables. */ - su2double *Diff_U, *Diff_Lapl, /*!< \brief Diference of conservative variables and undivided laplacians. */ - *Velocity_i, *Velocity_j, /*!< \brief Velocity at node 0 and 1. */ - *MeanVelocity, ProjVelocity, ProjVelocity_i, ProjVelocity_j, /*!< \brief Mean and projected velocities. */ - Density_i, Density_j, Energy_i, Energy_j, /*!< \brief Mean Density and energies. */ - sq_vel_i, sq_vel_j, /*!< \brief Modulus of the velocity and the normal vector. */ - MeanDensity, MeanPressure, MeanEnthalpy, MeanEnergy, /*!< \brief Mean values of primitive variables. */ - Param_p, Param_Kappa_2, Param_Kappa_4, /*!< \brief Artificial dissipation parameters. */ - Local_Lambda_i, Local_Lambda_j, MeanLambda, /*!< \brief Local eingenvalues. */ - Phi_i, Phi_j, sc2, sc4, StretchingFactor, /*!< \brief Streching parameters. */ - *ProjFlux, /*!< \brief Projected inviscid flux tensor. */ - Epsilon_2, cte_0, cte_1, /*!< \brief Artificial dissipation values. */ - ProjGridVel; /*!< \brief Projected grid velocity. */ - bool implicit, /*!< \brief Implicit calculation. */ - grid_movement; /*!< \brief Modification for grid movement. */ - - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimension of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CCentJST_KE_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CCentJST_KE_Flow(void); - - /*! - * \brief Compute the flow residual using a JST method. - * \param[out] val_resconv - Pointer to the convective residual. - * \param[out] val_resvisc - Pointer to the artificial viscosity residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, - CConfig *config); -}; - -/*! - * \class CCentJST_Flow - * \brief Class for centered scheme - JST. - * \ingroup ConvDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CCentJST_Flow : public CNumerics { - -private: - unsigned short iDim, iVar, jVar; /*!< \brief Iteration on dimension and variables. */ - su2double *Diff_U, *Diff_Lapl, /*!< \brief Diference of conservative variables and undivided laplacians. */ - *Velocity_i, *Velocity_j, /*!< \brief Velocity at node 0 and 1. */ - *MeanVelocity, ProjVelocity, ProjVelocity_i, ProjVelocity_j, /*!< \brief Mean and projected velocities. */ - Density_i, Density_j, Energy_i, Energy_j, /*!< \brief Mean Density and energies. */ - sq_vel_i, sq_vel_j, /*!< \brief Modulus of the velocity and the normal vector. */ - MeanDensity, MeanPressure, MeanEnthalpy, MeanEnergy, /*!< \brief Mean values of primitive variables. */ - Param_p, Param_Kappa_2, Param_Kappa_4, /*!< \brief Artificial dissipation parameters. */ - Local_Lambda_i, Local_Lambda_j, MeanLambda, /*!< \brief Local eingenvalues. */ - Phi_i, Phi_j, sc2, sc4, StretchingFactor, /*!< \brief Streching parameters. */ - *ProjFlux, /*!< \brief Projected inviscid flux tensor. */ - Epsilon_2, Epsilon_4, cte_0, cte_1, /*!< \brief Artificial dissipation values. */ - ProjGridVel; /*!< \brief Projected grid velocity. */ - bool implicit, /*!< \brief Implicit calculation. */ - grid_movement; /*!< \brief Modification for grid movement. */ - - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimension of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CCentJST_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CCentJST_Flow(void); - - /*! - * \brief Compute the flow residual using a JST method. - * \param[out] val_resconv - Pointer to the convective residual. - * \param[out] val_resvisc - Pointer to the artificial viscosity residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, - CConfig *config); -}; - -/*! - * \class CCentJSTArtComp_Flow - * \brief Class for centered scheme - JST (artificial compressibility). - * \ingroup ConvDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CCentJSTArtComp_Flow : public CNumerics { - -private: - unsigned short iDim, iVar, jVar; /*!< \brief Iteration on dimension and variables. */ - su2double *Diff_U, *Diff_Lapl, /*!< \brief Diference of conservative variables and undivided laplacians. */ - *Velocity_i, *Velocity_j, /*!< \brief Velocity at node 0 and 1. */ - *MeanVelocity, ProjVelocity_i, ProjVelocity_j, /*!< \brief Mean and projected velocities. */ - sq_vel_i, sq_vel_j, /*!< \brief Modulus of the velocity and the normal vector. */ - MeanDensity, MeanPressure, MeanBetaInc2, /*!< \brief Mean values of primitive variables. */ - Param_p, Param_Kappa_2, Param_Kappa_4, /*!< \brief Artificial dissipation parameters. */ - Local_Lambda_i, Local_Lambda_j, MeanLambda, /*!< \brief Local eingenvalues. */ - Phi_i, Phi_j, sc2, sc4, StretchingFactor, /*!< \brief Streching parameters. */ - *ProjFlux, /*!< \brief Projected inviscid flux tensor. */ - Epsilon_2, Epsilon_4, cte_0, cte_1; /*!< \brief Artificial dissipation values. */ - bool implicit, /*!< \brief Implicit calculation. */ - grid_movement, /*!< \brief Modification for grid movement. */ - gravity; /*!< \brief computation with gravity force. */ - su2double Froude; /*!< \brief Froude number. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimension of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CCentJSTArtComp_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CCentJSTArtComp_Flow(void); - - /*! - * \brief Compute the flow residual using a JST method. - * \param[out] val_resconv - Pointer to the convective residual. - * \param[out] val_resvisc - Pointer to the artificial viscosity residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, - CConfig *config); -}; - -/*! - * \class CCentJST_AdjFlow - * \brief Class for and adjoint centered scheme - JST. - * \ingroup ConvDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CCentJST_AdjFlow : public CNumerics { -private: - su2double *Diff_Psi, *Diff_Lapl; - su2double *Velocity_i, *Velocity_j; - su2double *MeanPhi; - unsigned short iDim, jDim, iVar, jVar; - su2double Residual, ProjVelocity_i, ProjVelocity_j, ProjPhi, ProjPhi_Vel, sq_vel, phis1, phis2; - su2double MeanPsiRho, MeanPsiE, Param_p, Param_Kappa_4, Param_Kappa_2, Local_Lambda_i, Local_Lambda_j, MeanLambda; - su2double Phi_i, Phi_j, sc4, StretchingFactor, Epsilon_4, Epsilon_2; - bool implicit, grid_movement; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CCentJST_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CCentJST_AdjFlow(void); - - /*! - * \brief Compute the adjoint flow residual using a JST method. - * \param[out] val_resconv_i - Pointer to the convective residual at point i. - * \param[out] val_resvisc_i - Pointer to the artificial viscosity residual at point i. - * \param[out] val_resconv_j - Pointer to the convective residual at point j. - * \param[out] val_resvisc_j - Pointer to the artificial viscosity residual at point j. - * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. - * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. - * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. - * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual (su2double *val_resconv_i, su2double *val_resvisc_i, su2double *val_resconv_j, su2double *val_resvisc_j, - su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, - CConfig *config); -}; - -/*! - * \class CCentJSTArtComp_AdjFlow - * \brief Class for and adjoint centered scheme - JST. - * \ingroup ConvDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CCentJSTArtComp_AdjFlow : public CNumerics { -private: - su2double sc2, *Diff_Psi, *Diff_Lapl; - su2double *Velocity_i, *Velocity_j; - su2double **Proj_Jac_Tensor_i, **Proj_Jac_Tensor_j; - unsigned short iDim, iVar, jVar; - su2double Residual, ProjVelocity_i, ProjVelocity_j; - su2double Param_p, Param_Kappa_4, Param_Kappa_2, Local_Lambda_i, Local_Lambda_j, MeanLambda; - su2double Phi_i, Phi_j, sc4, StretchingFactor, Epsilon_4, Epsilon_2; - bool implicit; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CCentJSTArtComp_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CCentJSTArtComp_AdjFlow(void); - - /*! - * \brief Compute the adjoint flow residual using a JST method. - * \param[out] val_resconv_i - Pointer to the convective residual at point i. - * \param[out] val_resvisc_i - Pointer to the artificial viscosity residual at point i. - * \param[out] val_resconv_j - Pointer to the convective residual at point j. - * \param[out] val_resvisc_j - Pointer to the artificial viscosity residual at point j. - * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. - * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. - * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. - * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual (su2double *val_resconv_i, su2double *val_resvisc_i, su2double *val_resconv_j, su2double *val_resvisc_j, - su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, - CConfig *config); -}; - -/*! - * \class CCentLax_Flow - * \brief Class for computing the Lax-Friedrich centered scheme. - * \ingroup ConvDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CCentLax_Flow : public CNumerics { -private: - unsigned short iDim, iVar, jVar; /*!< \brief Iteration on dimension and variables. */ - su2double *Diff_U, /*!< \brief Difference of conservative variables. */ - *Velocity_i, *Velocity_j, /*!< \brief Velocity at node 0 and 1. */ - *MeanVelocity, ProjVelocity, ProjVelocity_i, ProjVelocity_j, /*!< \brief Mean and projected velocities. */ - *ProjFlux, /*!< \brief Projected inviscid flux tensor. */ - Density_i, Density_j, Energy_i, Energy_j, /*!< \brief Mean Density and energies. */ - sq_vel_i, sq_vel_j, /*!< \brief Modulus of the velocity and the normal vector. */ - MeanDensity, MeanPressure, MeanEnthalpy, MeanEnergy, /*!< \brief Mean values of primitive variables. */ - Param_p, Param_Kappa_0, /*!< \brief Artificial dissipation parameters. */ - Local_Lambda_i, Local_Lambda_j, MeanLambda, /*!< \brief Local eingenvalues. */ - Phi_i, Phi_j, sc0, StretchingFactor, /*!< \brief Streching parameters. */ - Epsilon_0, cte; /*!< \brief Artificial dissipation values. */ - bool implicit, /*!< \brief Implicit calculation. */ - grid_movement; /*!< \brief Modification for grid movement. */ - su2double ProjGridVel; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimension of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CCentLax_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CCentLax_Flow(void); - - /*! - * \brief Compute the flow residual using a Lax method. - * \param[out] val_resconv - Pointer to the convective residual. - * \param[out] val_resvisc - Pointer to the artificial viscosity residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, - CConfig *config); -}; - -/*! - * \class CCentLaxArtComp_Flow - * \brief Class for computing the Lax-Friedrich centered scheme (artificial compressibility). - * \ingroup ConvDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CCentLaxArtComp_Flow : public CNumerics { -private: - unsigned short iDim, iVar, jVar; /*!< \brief Iteration on dimension and variables. */ - su2double *Diff_U, /*!< \brief Difference of conservative variables. */ - *Velocity_i, *Velocity_j, /*!< \brief Velocity at node 0 and 1. */ - *MeanVelocity, ProjVelocity_i, ProjVelocity_j, /*!< \brief Mean and projected velocities. */ - *ProjFlux, /*!< \brief Projected inviscid flux tensor. */ - sq_vel_i, sq_vel_j, /*!< \brief Modulus of the velocity and the normal vector. */ - MeanDensity, MeanPressure, MeanBetaInc2, /*!< \brief Mean values of primitive variables. */ - Param_p, Param_Kappa_0, /*!< \brief Artificial dissipation parameters. */ - Local_Lambda_i, Local_Lambda_j, MeanLambda, /*!< \brief Local eingenvalues. */ - Phi_i, Phi_j, sc0, StretchingFactor, /*!< \brief Streching parameters. */ - Epsilon_0; /*!< \brief Artificial dissipation values. */ - bool implicit, /*!< \brief Implicit calculation. */ - grid_movement, /*!< \brief Modification for grid movement. */ - gravity; /*!< \brief Modification for for gravity force. */ - su2double Froude; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimension of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CCentLaxArtComp_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CCentLaxArtComp_Flow(void); - - /*! - * \brief Compute the flow residual using a Lax method. - * \param[out] val_resconv - Pointer to the convective residual. - * \param[out] val_resvisc - Pointer to the artificial viscosity residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, - CConfig *config); -}; - -/*! - * \class CCentLax_AdjFlow - * \brief Class for computing the Lax-Friedrich adjoint centered scheme. - * \ingroup ConvDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CCentLax_AdjFlow : public CNumerics { -private: - su2double *Diff_Psi; - su2double *Velocity_i, *Velocity_j; - su2double *MeanPhi; - unsigned short iDim, jDim, iVar, jVar; - su2double Residual, ProjVelocity_i, ProjVelocity_j, ProjPhi, ProjPhi_Vel, sq_vel, phis1, phis2, - MeanPsiRho, MeanPsiE, Param_p, Param_Kappa_0, Local_Lambda_i, Local_Lambda_j, MeanLambda, - Phi_i, Phi_j, sc2, StretchingFactor, Epsilon_0; - bool implicit, grid_movement; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CCentLax_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CCentLax_AdjFlow(void); - - /*! - * \brief Compute the adjoint flow residual using a Lax method. - * \param[out] val_resconv_i - Pointer to the convective residual at point i. - * \param[out] val_resvisc_i - Pointer to the artificial viscosity residual at point i. - * \param[out] val_resconv_j - Pointer to the convective residual at point j. - * \param[out] val_resvisc_j - Pointer to the artificial viscosity residual at point j. - * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. - * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. - * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. - * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual (su2double *val_resconv_i, su2double *val_resvisc_i, su2double *val_resconv_j, su2double *val_resvisc_j, - su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, - CConfig *config); -}; - -/*! - * \class CCentLaxArtComp_AdjFlow - * \brief Class for computing the Lax-Friedrich adjoint centered scheme. - * \ingroup ConvDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CCentLaxArtComp_AdjFlow : public CNumerics { -private: - su2double *Diff_Psi; - su2double *Velocity_i, *Velocity_j; - su2double *MeanPhi, **Proj_Jac_Tensor_i, **Proj_Jac_Tensor_j; - unsigned short iDim, iVar, jVar; - su2double Residual, ProjVelocity_i, ProjVelocity_j, Param_p, Param_Kappa_0, - Local_Lambda_i, Local_Lambda_j, MeanLambda, - Phi_i, Phi_j, sc2, StretchingFactor, Epsilon_0; - bool implicit; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CCentLaxArtComp_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CCentLaxArtComp_AdjFlow(void); - - /*! - * \brief Compute the adjoint flow residual using a Lax method. - * \param[out] val_resconv_i - Pointer to the convective residual at point i. - * \param[out] val_resvisc_i - Pointer to the artificial viscosity residual at point i. - * \param[out] val_resconv_j - Pointer to the convective residual at point j. - * \param[out] val_resvisc_j - Pointer to the artificial viscosity residual at point j. - * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. - * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. - * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. - * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual (su2double *val_resconv_i, su2double *val_resvisc_i, su2double *val_resconv_j, su2double *val_resvisc_j, - su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, - CConfig *config); -}; - -/*! - * \class CAvgGrad_Flow - * \brief Class for computing viscous term using the average of gradients. - * \ingroup ViscDiscr - * \author A. Bueno, and F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CAvgGrad_Flow : public CNumerics { -private: - unsigned short iDim, iVar, jVar; /*!< \brief Iterators in dimension an variable. */ - su2double *Mean_PrimVar, /*!< \brief Mean primitive variables. */ - *PrimVar_i, *PrimVar_j, /*!< \brief Primitives variables at point i and 1. */ - **Mean_GradPrimVar, /*!< \brief Mean value of the gradient. */ - Mean_Laminar_Viscosity, /*!< \brief Mean value of the viscosity. */ - Mean_Eddy_Viscosity, /*!< \brief Mean value of the eddy viscosity. */ - Mean_turb_ke, /*!< \brief Mean value of the turbulent kinetic energy. */ - dist_ij; /*!< \brief Length of the edge and face. */ - bool implicit; /*!< \brief Implicit calculus. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimension of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGrad_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGrad_Flow(void); - - /*! - * \brief Compute the viscous flow residual using an average of gradients. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CGeneralAvgGrad_Flow - * \brief Class for computing viscous term using the average of gradients. - * \ingroup ViscDiscr - * \author M.Pini, S. Vitale - * \version 3.2.1 "eagle" - */ - -class CGeneralAvgGrad_Flow : public CNumerics { -private: - unsigned short iDim, iVar, jVar; /*!< \brief Iterators in dimension an variable. */ - su2double *Mean_PrimVar, /*!< \brief Mean primitive variables. */ - *Mean_SecVar, /*!< \brief Mean secondary variables. */ - *PrimVar_i, *PrimVar_j, /*!< \brief Primitives variables at point i and 1. */ - **Mean_GradPrimVar, /*!< \brief Mean value of the gradient. */ - Mean_Laminar_Viscosity, /*!< \brief Mean value of the viscosity. */ - Mean_Eddy_Viscosity, /*!< \brief Mean value of the eddy viscosity. */ - Mean_Thermal_Conductivity, /*!< \brief Mean value of the thermal conductivity. */ - Mean_Cp, /*!< \brief Mean value of the Cp. */ - Mean_turb_ke, /*!< \brief Mean value of the turbulent kinetic energy. */ - dist_ij; /*!< \brief Length of the edge and face. */ - bool implicit; /*!< \brief Implicit calculus. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimension of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CGeneralAvgGrad_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CGeneralAvgGrad_Flow(void); - - /*! - * \brief Compute the viscous flow residual using an average of gradients. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CAvgGradArtComp_Flow - * \brief Class for computing viscous term using an average of gradients. - * \ingroup ViscDiscr - * \author A. Bueno, and F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CAvgGradArtComp_Flow : public CNumerics { -private: - unsigned short iDim, iVar, jVar; /*!< \brief Iterators in dimension an variable. */ - su2double **Mean_GradPrimVar, /*!< \brief Mean value of the gradient. */ - Mean_Laminar_Viscosity, Mean_Eddy_Viscosity, /*!< \brief Mean value of the viscosity. */ - dist_ij; /*!< \brief Length of the edge and face. */ - bool implicit; /*!< \brief Implicit calculus. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimension of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGradArtComp_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGradArtComp_Flow(void); - /*! - * \brief Compute the viscous flow residual using an average of gradients. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CAvgGrad_TurbSA - * \brief Class for computing viscous term using average of gradients (Spalart-Allmaras Turbulence model). - * \ingroup ViscDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CAvgGrad_TurbSA : public CNumerics { -private: - - su2double **Mean_GradTurbVar; - su2double *Proj_Mean_GradTurbVar_Kappa, *Proj_Mean_GradTurbVar_Edge; - su2double *Edge_Vector; - bool implicit, incompressible; - su2double sigma; - su2double nu_i, nu_j, nu_e; - su2double dist_ij_2; - su2double proj_vector_ij; - unsigned short iVar, iDim; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGrad_TurbSA(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGrad_TurbSA(void); - - /*! - * \brief Compute the viscous turbulence terms residual using an average of gradients. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); -}; - -/*! - * \class CAvgGrad_TurbSA_Neg - * \brief Class for computing viscous term using average of gradients (Spalart-Allmaras Turbulence model). - * \ingroup ViscDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CAvgGrad_TurbSA_Neg : public CNumerics { -private: - - su2double **Mean_GradTurbVar; - su2double *Proj_Mean_GradTurbVar_Kappa, *Proj_Mean_GradTurbVar_Edge; - su2double *Edge_Vector; - bool implicit, incompressible; - su2double sigma; - su2double cn1, fn, Xi; - su2double nu_i, nu_j, nu_ij, nu_tilde_ij, nu_e; - su2double dist_ij_2; - su2double proj_vector_ij; - unsigned short iVar, iDim; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGrad_TurbSA_Neg(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGrad_TurbSA_Neg(void); - - /*! - * \brief Compute the viscous turbulence terms residual using an average of gradients. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); -}; - -/*! - * \class CAvgGrad_TurbML - * \brief Class for computing viscous term using average of gradients (Spalart-Allmaras Turbulence model). - * \ingroup ViscDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CAvgGrad_TurbML : public CNumerics { -private: - su2double **Mean_GradTurbVar; - su2double *Proj_Mean_GradTurbVar_Kappa, *Proj_Mean_GradTurbVar_Edge; - su2double *Edge_Vector; - bool implicit, incompressible; - su2double sigma; - su2double nu_i, nu_j, nu_e; - su2double dist_ij_2; - su2double proj_vector_ij; - unsigned short iVar, iDim; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGrad_TurbML(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGrad_TurbML(void); - - /*! - * \brief Compute the viscous turbulence terms residual using an average of gradients. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); -}; - -/*! - * \class CAvgGrad_TransLM - * \brief Class for computing viscous term using average of gradients (Spalart-Allmaras Turbulence model). - * \ingroup ViscDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CAvgGrad_TransLM : public CNumerics { -private: - su2double **Mean_GradTransVar; - su2double *Proj_Mean_GradTransVar_Kappa, *Proj_Mean_GradTransVar_Edge; - su2double *Edge_Vector; - bool implicit, incompressible; - su2double sigma; - su2double dist_ij_2; - su2double proj_vector_ij; - unsigned short iVar, iDim; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGrad_TransLM(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGrad_TransLM(void); - - /*! - * \brief Compute the viscous turbulence terms residual using an average of gradients. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); -}; - -/*! - * \class CAvgGrad_AdjFlow - * \brief Class for computing the adjoint viscous terms. - * \ingroup ViscDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CAvgGrad_AdjFlow : public CNumerics { -private: - su2double *Velocity_i; /*!< \brief Auxiliary vector for storing the velocity of point i. */ - su2double *Velocity_j; /*!< \brief Auxiliary vector for storing the velocity of point j. */ - su2double *Mean_Velocity; - su2double *Mean_GradPsiE; /*!< \brief Counter for dimensions of the problem. */ - su2double **Mean_GradPhi; /*!< \brief Counter for dimensions of the problem. */ - su2double *Edge_Vector; /*!< \brief Vector going from node i to node j. */ - bool implicit; /*!< \brief Implicit calculus. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGrad_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGrad_AdjFlow(void); - - /*! - * \brief Residual computation. - * \param[out] val_residual_i - Pointer to the total residual at point i. - * \param[out] val_residual_j - Pointer to the total residual at point j. - */ - void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, - su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, - su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); -}; - -/*! - * \class CAvgGradArtComp_AdjFlow - * \brief Class for computing the adjoint viscous terms. - * \ingroup ViscDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CAvgGradArtComp_AdjFlow : public CNumerics { -private: - unsigned short iDim, iVar, jVar; /*!< \brief Iterators in dimension an variable. */ - su2double **Mean_GradPsiVar, /*!< \brief Mean value of the gradient. */ - Mean_Laminar_Viscosity, Mean_Eddy_Viscosity, /*!< \brief Mean value of the viscosity. */ - dist_ij; /*!< \brief Length of the edge and face. */ - bool implicit; /*!< \brief Implicit calculus. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGradArtComp_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGradArtComp_AdjFlow(void); - - /*! - * \brief Residual computation. - * \param[out] val_residual_i - Pointer to the total residual at point i. - * \param[out] val_residual_j - Pointer to the total residual at point j. - */ - void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, - su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, - su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); -}; - -/*! - * \class CAvgGradCorrected_Flow - * \brief Class for computing viscous term using the average of gradients with a correction. - * \ingroup ViscDiscr - * \author A. Bueno, and F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CAvgGradCorrected_Flow : public CNumerics { -private: - unsigned short iDim, iVar, jVar; /*!< \brief Iterators in dimension an variable. */ - su2double *Mean_PrimVar, /*!< \brief Mean primitive variables. */ - *PrimVar_i, *PrimVar_j, /*!< \brief Primitives variables at point i and 1. */ - *Edge_Vector, /*!< \brief Vector form point i to point j. */ - **Mean_GradPrimVar, *Proj_Mean_GradPrimVar_Edge, /*!< \brief Mean value of the gradient. */ - Mean_Laminar_Viscosity, /*!< \brief Mean value of the laminar viscosity. */ - Mean_Eddy_Viscosity, /*!< \brief Mean value of the eddy viscosity. */ - Mean_turb_ke, /*!< \brief Mean value of the turbulent kinetic energy. */ - dist_ij_2; /*!< \brief Length of the edge and face. */ - bool implicit; /*!< \brief Implicit calculus. */ - bool limiter; /*!< \brief Viscous limiter. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimension of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGradCorrected_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGradCorrected_Flow(void); - - /*! - * \brief Compute the viscous flow residual using an average of gradients with correction. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - - -/*! - * \class CGeneralAvgGradCorrected_Flow - * \brief Class for computing viscous term using the average of gradients with a correction. - * \ingroup ViscDiscr - * \author M. Pini, S. Vitale - * \version 3.2.1 "eagle" - */ -class CGeneralAvgGradCorrected_Flow : public CNumerics { -private: - unsigned short iDim, iVar, jVar; /*!< \brief Iterators in dimension an variable. */ - su2double *Mean_PrimVar, /*!< \brief Mean primitive variables. */ - *Mean_SecVar, /*!< \brief Mean primitive variables. */ - *PrimVar_i, *PrimVar_j, /*!< \brief Primitives variables at point i and 1. */ - *Edge_Vector, /*!< \brief Vector form point i to point j. */ - **Mean_GradPrimVar, *Proj_Mean_GradPrimVar_Edge, /*!< \brief Mean value of the gradient. */ - Mean_Laminar_Viscosity, /*!< \brief Mean value of the laminar viscosity. */ - Mean_Eddy_Viscosity, /*!< \brief Mean value of the eddy viscosity. */ - Mean_Thermal_Conductivity, /*!< \brief Mean value of the thermal conductivity. */ - Mean_Cp, /*!< \brief Mean value of the specific heat. */ - Mean_turb_ke, /*!< \brief Mean value of the turbulent kinetic energy. */ - dist_ij_2; /*!< \brief Length of the edge and face. */ - bool implicit; /*!< \brief Implicit calculus. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimension of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CGeneralAvgGradCorrected_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CGeneralAvgGradCorrected_Flow(void); - - /*! - * \brief Compute the viscous flow residual using an average of gradients with correction. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CAvgGradCorrectedArtComp_Flow - * \brief Class for computing viscous term using an average of gradients with correction (artificial compresibility). - * \ingroup ViscDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CAvgGradCorrectedArtComp_Flow : public CNumerics { -private: - unsigned short iDim, iVar, jVar; /*!< \brief Iterators in dimension an variable. */ - su2double *PrimVar_i, *PrimVar_j, /*!< \brief Primitives variables at point i and 1. */ - *Edge_Vector, /*!< \brief Vector form point i to point j. */ - **Mean_GradPrimVar, *Proj_Mean_GradPrimVar_Edge, /*!< \brief Mean value of the gradient. */ - Mean_Laminar_Viscosity, Mean_Eddy_Viscosity, /*!< \brief Mean value of the viscosity. */ - dist_ij_2; /*!< \brief Length of the edge and face. */ - bool implicit; /*!< \brief Implicit calculus. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimension of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGradCorrectedArtComp_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGradCorrectedArtComp_Flow(void); - - /*! - * \brief Compute the viscous flow residual using an average of gradients with correction. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CAvgGradCorrected_TurbSA - * \brief Class for computing viscous term using average of gradients with correction (Spalart-Allmaras turbulence model). - * \ingroup ViscDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CAvgGradCorrected_TurbSA : public CNumerics { -private: - su2double **Mean_GradTurbVar; - su2double *Proj_Mean_GradTurbVar_Kappa, *Proj_Mean_GradTurbVar_Edge, *Proj_Mean_GradTurbVar_Corrected; - su2double *Edge_Vector; - bool implicit, incompressible; - su2double sigma, nu_i, nu_j, nu_e, dist_ij_2, proj_vector_ij; - unsigned short iVar, iDim; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGradCorrected_TurbSA(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGradCorrected_TurbSA(void); - - /*! - * \brief Compute the viscous turbulent residual using an average of gradients with correction. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); -}; - -/*! - * \class CAvgGradCorrected_TurbSA_Neg - * \brief Class for computing viscous term using average of gradients with correction (Spalart-Allmaras turbulence model). - * \ingroup ViscDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CAvgGradCorrected_TurbSA_Neg : public CNumerics { -private: - - su2double **Mean_GradTurbVar; - su2double *Proj_Mean_GradTurbVar_Kappa, *Proj_Mean_GradTurbVar_Edge, *Proj_Mean_GradTurbVar_Corrected; - su2double *Edge_Vector; - su2double sigma; - su2double cn1, fn, Xi; - su2double nu_ij, nu_tilde_ij; - bool implicit, incompressible; - su2double nu_i, nu_j, nu_e, dist_ij_2, proj_vector_ij; - unsigned short iVar, iDim; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGradCorrected_TurbSA_Neg(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGradCorrected_TurbSA_Neg(void); - - /*! - * \brief Compute the viscous turbulent residual using an average of gradients with correction. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); -}; - -/*! - * \class CAvgGradCorrected_TurbML - * \brief Class for computing viscous term using average of gradients with correction (Spalart-Allmaras turbulence model). - * \ingroup ViscDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CAvgGradCorrected_TurbML : public CNumerics { -private: - su2double **Mean_GradTurbVar; - su2double *Proj_Mean_GradTurbVar_Kappa, *Proj_Mean_GradTurbVar_Edge, *Proj_Mean_GradTurbVar_Corrected; - su2double *Edge_Vector; - bool implicit, incompressible; - su2double sigma, nu_i, nu_j, nu_e, dist_ij_2, proj_vector_ij; - unsigned short iVar, iDim; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGradCorrected_TurbML(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGradCorrected_TurbML(void); - - /*! - * \brief Compute the viscous turbulent residual using an average of gradients with correction. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); -}; - -/*! - * \class CAvgGradCorrected_TransLM - * \brief Class for computing viscous term using average of gradients with correction (Spalart-Allmaras turbulence model). - * \ingroup ViscDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CAvgGradCorrected_TransLM : public CNumerics { -private: - su2double **Mean_GradTurbVar; - su2double *Proj_Mean_GradTurbVar_Kappa, *Proj_Mean_GradTurbVar_Edge, *Proj_Mean_GradTurbVar_Corrected; - su2double *Edge_Vector; - bool implicit, incompressible; - su2double sigma; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGradCorrected_TransLM(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGradCorrected_TransLM(void); - - /*! - * \brief Compute the viscous turbulent residual using an average of gradients with correction. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); -}; - -/*! - * \class CAvgGrad_TurbSST - * \brief Class for computing viscous term using average of gradient with correction (Menter SST turbulence model). - * \ingroup ViscDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CAvgGrad_TurbSST : public CNumerics { -private: - su2double sigma_k1, /*!< \brief Constants for the viscous terms, k-w (1), k-eps (2)*/ - sigma_k2, - sigma_om1, - sigma_om2; - - su2double diff_kine, /*!< \brief Diffusivity for viscous terms of tke eq */ - diff_omega; /*!< \brief Diffusivity for viscous terms of omega eq */ - - su2double *Edge_Vector, /*!< \brief Vector from node i to node j. */ - dist_ij_2, /*!< \brief |Edge_Vector|^2 */ - proj_vector_ij; /*!< \brief (Edge_Vector DOT normal)/|Edge_Vector|^2 */ - - su2double **Mean_GradTurbVar, /*!< \brief Average of gradients at cell face */ - *Proj_Mean_GradTurbVar_Normal, /*!< \brief Mean_gradTurbVar DOT normal */ - *Proj_Mean_GradTurbVar_Edge, /*!< \brief Mean_gradTurbVar DOT Edge_Vector */ - *Proj_Mean_GradTurbVar_Corrected; - - su2double F1_i, F1_j; /*!< \brief Menter's first blending function */ - - bool implicit, incompressible; - unsigned short iVar, iDim; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGrad_TurbSST(unsigned short val_nDim, unsigned short val_nVar, su2double* constants, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGrad_TurbSST(void); - - /*! - * \brief Sets value of first blending function. - */ - void SetF1blending(su2double val_F1_i, su2double val_F1_j) { F1_i = val_F1_i; F1_j = val_F1_j;} - - /*! - * \brief Compute the viscous turbulent residual using an average of gradients wtih correction. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); - -}; - -/*! - * \class CAvgGradCorrected_TurbSST - * \brief Class for computing viscous term using average of gradient with correction (Menter SST turbulence model). - * \ingroup ViscDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CAvgGradCorrected_TurbSST : public CNumerics { -private: - su2double sigma_k1, /*!< \brief Constants for the viscous terms, k-w (1), k-eps (2)*/ - sigma_k2, - sigma_om1, - sigma_om2; - - su2double diff_kine, /*!< \brief Diffusivity for viscous terms of tke eq */ - diff_omega; /*!< \brief Diffusivity for viscous terms of omega eq */ - - su2double *Edge_Vector, /*!< \brief Vector from node i to node j. */ - dist_ij_2, /*!< \brief |Edge_Vector|^2 */ - proj_vector_ij; /*!< \brief (Edge_Vector DOT normal)/|Edge_Vector|^2 */ - - su2double **Mean_GradTurbVar, /*!< \brief Average of gradients at cell face */ - *Proj_Mean_GradTurbVar_Normal, /*!< \brief Mean_gradTurbVar DOT normal */ - *Proj_Mean_GradTurbVar_Edge, /*!< \brief Mean_gradTurbVar DOT Edge_Vector */ - *Proj_Mean_GradTurbVar_Corrected; - - su2double F1_i, F1_j; /*!< \brief Menter's first blending function */ - - bool implicit, incompressible; - unsigned short iVar, iDim; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGradCorrected_TurbSST(unsigned short val_nDim, unsigned short val_nVar, su2double* constants, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGradCorrected_TurbSST(void); - - /*! - * \brief Sets value of first blending function. - */ - void SetF1blending(su2double val_F1_i, su2double val_F1_j) { F1_i = val_F1_i; F1_j = val_F1_j;} - - /*! - * \brief Compute the viscous turbulent residual using an average of gradients wtih correction. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, su2double **Jacobian_j, CConfig *config); - -}; - -/*! - * \class CAvgGradCorrected_AdjFlow - * \brief Class for computing the adjoint viscous terms, including correction. - * \ingroup ViscDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CAvgGradCorrected_AdjFlow : public CNumerics { -private: - su2double *Velocity_i; /*!< \brief Auxiliary vector for storing the velocity of point i. */ - su2double *Velocity_j; /*!< \brief Auxiliary vector for storing the velocity of point j. */ - su2double *Mean_Velocity; - su2double **Mean_GradPsiVar; /*!< \brief Counter for dimensions of the problem. */ - su2double *Edge_Vector; /*!< \brief Vector going from node i to node j. */ - su2double *Proj_Mean_GradPsiVar_Edge; /*!< \brief Projection of Mean_GradPsiVar onto Edge_Vector. */ - su2double *Mean_GradPsiE; /*!< \brief Counter for dimensions of the problem. */ - su2double **Mean_GradPhi; /*!< \brief Counter for dimensions of the problem. */ - bool implicit; /*!< \brief Boolean controlling Jacobian calculations. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGradCorrected_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGradCorrected_AdjFlow(void); - - /*! - * \brief Compute the adjoint flow viscous residual in a non-conservative way using an average of gradients and derivative correction. - * \param[out] val_residual_i - Pointer to the viscous residual at point i. - * \param[out] val_residual_j - Pointer to the viscous residual at point j. - * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. - * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. - * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. - * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, - su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); -}; - -/*! - * \class CAvgGradCorrectedArtComp_AdjFlow - * \brief Class for computing the adjoint viscous terms, including correction. - * \ingroup ViscDiscr - * \author F.Palacios - * \version 4.0.1 "Cardinal" - */ -class CAvgGradCorrectedArtComp_AdjFlow : public CNumerics { -private: - unsigned short iDim, iVar, jVar; /*!< \brief Iterators in dimension an variable. */ - su2double *PsiVar_i, *PsiVar_j, /*!< \brief Primitives variables at point i and 1. */ - *Edge_Vector, /*!< \brief Vector form point i to point j. */ - **Mean_GradPsiVar, *Proj_Mean_GradPsiVar_Edge, /*!< \brief Mean value of the gradient. */ - Mean_Laminar_Viscosity, Mean_Eddy_Viscosity, /*!< \brief Mean value of the viscosity. */ - dist_ij_2; /*!< \brief Length of the edge and face. */ - bool implicit; /*!< \brief Implicit calculus. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGradCorrectedArtComp_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGradCorrectedArtComp_AdjFlow(void); - - /*! - * \brief Compute the adjoint flow viscous residual in a non-conservative way using an average of gradients and derivative correction. - * \param[out] val_residual_i - Pointer to the viscous residual at point i. - * \param[out] val_residual_j - Pointer to the viscous residual at point j. - * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. - * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. - * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. - * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual (su2double *val_residual_i, su2double *val_residual_j, su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, - su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); -}; - -/*! - * \class CAvgGradCorrected_AdjTurb - * \brief Class for adjoint turbulent using average of gradients with a correction. - * \ingroup ViscDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CAvgGradCorrected_AdjTurb : public CNumerics { -private: - su2double **Mean_GradTurbPsi; - su2double *Proj_Mean_GradTurbPsi_Kappa, *Proj_Mean_GradTurbPsi_Edge, *Proj_Mean_GradTurbPsi_Corrected; - su2double *Edge_Vector; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGradCorrected_AdjTurb(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGradCorrected_AdjTurb(void); - - /*! - * \brief Compute the adjoint turbulent residual using average of gradients and a derivative correction. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); - - /*! - * \overload - * \param[out] val_residual_i - Pointer to the total residual at point i. - * \param[out] val_residual_j - Pointer to the total viscosity residual at point j. - * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. - * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. - * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. - * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, - su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); -}; - -/*! - * \class CAvgGrad_AdjTurb - * \brief Class for adjoint turbulent using average of gradients with a correction. - * \ingroup ViscDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CAvgGrad_AdjTurb : public CNumerics { -private: - su2double **Mean_GradTurbPsi; - su2double *Proj_Mean_GradTurbPsi_Kappa, *Proj_Mean_GradTurbPsi_Edge, *Proj_Mean_GradTurbPsi_Corrected; - su2double *Edge_Vector; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAvgGrad_AdjTurb(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAvgGrad_AdjTurb(void); - - /*! - * \brief Compute the adjoint turbulent residual using average of gradients and a derivative correction. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); - - /*! - * \overload - * \param[out] val_residual_i - Pointer to the total residual at point i. - * \param[out] val_residual_j - Pointer to the total viscosity residual at point j. - * \param[out] val_Jacobian_ii - Jacobian of the numerical method at node i (implicit computation) from node i. - * \param[out] val_Jacobian_ij - Jacobian of the numerical method at node i (implicit computation) from node j. - * \param[out] val_Jacobian_ji - Jacobian of the numerical method at node j (implicit computation) from node i. - * \param[out] val_Jacobian_jj - Jacobian of the numerical method at node j (implicit computation) from node j. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, - su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config); -}; - -/*! - * \class CGalerkin_Flow - * \brief Class for computing the stiffness matrix of the Galerkin method. - * \ingroup ViscDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CGalerkin_Flow : public CNumerics { -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CGalerkin_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CGalerkin_Flow(void); - - /*! - * \brief Computing stiffness matrix of the Galerkin method. - * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual (su2double **val_stiffmatrix_elem, CConfig *config); -}; - -/*! - * \class CGalerkin_FEA - * \brief Class for computing the stiffness matrix of the Galerkin method. - * \ingroup ViscDiscr - * \author F. Palacios, R.Sanchez - * \version 4.0.1 "Cardinal" - */ -class CGalerkin_FEA : public CNumerics { - - su2double E; /*!< \brief Young's modulus of elasticity. */ - su2double Nu; /*!< \brief Poisson's ratio. */ - su2double Rho_s; /*!< \brief Structural density. */ - su2double Mu; /*!< \brief Lame's coeficient. */ - su2double Lambda; /*!< \brief Lame's coeficient. */ - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CGalerkin_FEA(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CGalerkin_FEA(void); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Fnodal - Forces at the nodes in cartesian coordinates. - * \param[in] Pnodal - Pressure at the nodes. - * \param[in] CoordCorners[2][2] - Coordiantes of the corners. - */ - void PressInt_Linear(su2double CoordCorners[4][3], su2double *tn_e, su2double Fnodal[12]); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Tau_0 - Stress tensor at the node 0. - * \param[in] Tau_1 - Stress tensor at the node 1. - * \param[in] Fnodal - Forces at the nodes in cartesian coordinates. - * \param[in] CoordCorners[2][2] - Coordiantes of the corners. - */ - void ViscTermInt_Linear(su2double CoordCorners[2][2], su2double Tau_0[3][3], su2double Tau_1[3][3], su2double FviscNodal[4]); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] Mu - Local coordinates. - * \param[in] CoordCorners[8][3] - Coordiantes of the corners. - * \param[in] shp[8][4] - Shape function information - */ - su2double ShapeFunc_Triangle(su2double Xi, su2double Eta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] Mu - Local coordinates. - * \param[in] CoordCorners[8][3] - Coordiantes of the corners. - * \param[in] shp[8][4] - Shape function information - */ - su2double ShapeFunc_Quadrilateral(su2double Xi, su2double Eta, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] Mu - Local coordinates. - * \param[in] CoordCorners[8][3] - Coordiantes of the corners. - * \param[in] shp[8][4] - Shape function information - */ - su2double ShapeFunc_Tetra(su2double Xi, su2double Eta, su2double Mu, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] Mu - Local coordinates. - * \param[in] CoordCorners[8][3] - Coordiantes of the corners. - * \param[in] shp[8][4] - Shape function information - */ - su2double ShapeFunc_Prism(su2double Xi, su2double Eta, su2double Mu, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] Mu - Local coordinates. - * \param[in] CoordCorners[8][3] - Coordiantes of the corners. - * \param[in] shp[8][4] - Shape function information - */ - su2double ShapeFunc_Pyram(su2double Xi, su2double Eta, su2double Mu, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] Mu - Local coordinates. - * \param[in] CoordCorners[8][3] - Coordiantes of the corners. - * \param[in] shp[8][4] - Shape function information - */ - su2double ShapeFunc_Hexa(su2double Xi, su2double Eta, su2double Mu, su2double CoordCorners[8][3], su2double DShapeFunction[8][4]); - - /*! - * \brief Computing stiffness matrix of the Galerkin method. - * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. - * \param[in] config - Definition of the particular problem. - */ - void SetFEA_StiffMatrix2D(su2double **StiffMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d); - - /*! - * \brief Computing stiffness matrix of the Galerkin method. - * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. - * \param[in] config - Definition of the particular problem. - */ - void SetFEA_StiffMatrix3D(su2double **StiffMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes); - - /*! - * \brief Computing mass matrix of the Galerkin method. - * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. - * \param[in] config - Definition of the particular problem. - */ - void SetFEA_StiffMassMatrix2D(su2double **StiffMatrix_Elem, su2double **MassMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d); - - /*! - * \brief Computing mass matrix of the Galerkin method. - * \param[out] val_stiffmatrix_elem - Stiffness matrix for Galerkin computation. - * \param[in] config - Definition of the particular problem. - */ - void SetFEA_StiffMassMatrix3D(su2double **StiffMatrix_Elem, su2double **MassMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes); - - /*! - * \brief Computing stresses in FEA method at the nodes. - * \param[in] config - Definition of the particular problem. - */ - void GetFEA_StressNodal2D(su2double StressVector[8][3], su2double DispElement[8], su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d); - - - /*! - * \brief Computing stresses in FEA method at the nodes. - * \param[in] config - Definition of the particular problem. - */ - void GetFEA_StressNodal3D(su2double StressVector[8][6], su2double DispElement[24], su2double CoordCorners[8][3], unsigned short nNodes); - - /*! - * \brief Computing dead load vector of the Galerkin method. - * \param[out] val_deadloadvector_elem - Dead load at the nodes for Galerkin computation. - * \param[in] config - Definition of the particular problem. - */ - void SetFEA_DeadLoad2D(su2double *DeadLoadVector_Elem, su2double CoordCorners[8][3], unsigned short nNodes, su2double matDensity); - - /*! - * \brief Computing stiffness matrix of the Galerkin method. - * \param[out] val_deadloadvector_elem - Dead load at the nodes for Galerkin computation. - * \param[in] config - Definition of the particular problem. - */ - void SetFEA_DeadLoad3D(su2double *DeadLoadVector_Elem, su2double CoordCorners[8][3], unsigned short nNodes, su2double matDensity); - -}; - -/*! - * \class CSourceNothing - * \brief Dummy class. - * \ingroup SourceDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CSourceNothing : public CNumerics { -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CSourceNothing(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSourceNothing(void); -}; - -/*! - * \class CSourcePieceWise_TurbSA - * \brief Class for integrating the source terms of the Spalart-Allmaras turbulence model equation. - * \ingroup SourceDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CSourcePieceWise_TurbSA : public CNumerics { -private: - su2double cv1_3; - su2double k2; - su2double cb1; - su2double cw2; - su2double ct3; - su2double ct4; - su2double cw3_6; - su2double cb2_sigma; - su2double sigma; - su2double cb2; - su2double cw1; - unsigned short iDim; - su2double nu, Ji, fv1, fv2, ft2, Omega, S, Shat, inv_Shat, dist_i_2, Ji_2, Ji_3, inv_k2_d2; - su2double r, g, g_6, glim, fw; - su2double norm2_Grad; - su2double dfv1, dfv2, dShat; - su2double dr, dg, dfw; - bool incompressible; - bool rotating_frame; - su2double intermittency; - su2double Production, Destruction, CrossProduction; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CSourcePieceWise_TurbSA(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSourcePieceWise_TurbSA(void); - - /*! - * \brief Residual for source term integration. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); - - /*! - * \brief Residual for source term integration. - * \param[in] intermittency_in - Value of the intermittency. - */ - void SetIntermittency(su2double intermittency_in); - - /*! - * \brief Residual for source term integration. - * \param[in] val_production - Value of the Production. - */ - void SetProduction(su2double val_production); - - /*! - * \brief Residual for source term integration. - * \param[in] val_destruction - Value of the Destruction. - */ - void SetDestruction(su2double val_destruction); - - /*! - * \brief Residual for source term integration. - * \param[in] val_crossproduction - Value of the CrossProduction. - */ - void SetCrossProduction(su2double val_crossproduction); - - /*! - * \brief ______________. - */ - su2double GetProduction(void); - - /*! - * \brief ______________. - */ - su2double GetDestruction(void); - - /*! - * \brief ______________. - */ - su2double GetCrossProduction(void); -}; - -/*! - * \class CSourcePieceWise_TurbSA_Neg - * \brief Class for integrating the source terms of the Spalart-Allmaras turbulence model equation. - * \ingroup SourceDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CSourcePieceWise_TurbSA_Neg : public CNumerics { -private: - su2double cv1_3; - su2double k2; - su2double cb1; - su2double cw2; - su2double ct3; - su2double ct4; - su2double cw3_6; - su2double cb2_sigma; - su2double sigma; - su2double cb2; - su2double cw1; - unsigned short iDim; - su2double nu, Ji, fv1, fv2, ft2, Omega, S, Shat, inv_Shat, dist_i_2, Ji_2, Ji_3, inv_k2_d2; - su2double r, g, g_6, glim, fw; - su2double norm2_Grad; - su2double dfv1, dfv2, dShat; - su2double dr, dg, dfw; - bool incompressible; - bool rotating_frame; - su2double intermittency; - su2double Production, Destruction, CrossProduction; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CSourcePieceWise_TurbSA_Neg(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSourcePieceWise_TurbSA_Neg(void); - - /*! - * \brief Residual for source term integration. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); - - /*! - * \brief Residual for source term integration. - * \param[in] intermittency_in - Value of the intermittency. - */ - void SetIntermittency(su2double intermittency_in); - - /*! - * \brief Residual for source term integration. - * \param[in] val_production - Value of the Production. - */ - void SetProduction(su2double val_production); - - /*! - * \brief Residual for source term integration. - * \param[in] val_destruction - Value of the Destruction. - */ - void SetDestruction(su2double val_destruction); - - /*! - * \brief Residual for source term integration. - * \param[in] val_crossproduction - Value of the CrossProduction. - */ - void SetCrossProduction(su2double val_crossproduction); - - /*! - * \brief ______________. - */ - su2double GetProduction(void); - - /*! - * \brief ______________. - */ - su2double GetDestruction(void); - - /*! - * \brief ______________. - */ - su2double GetCrossProduction(void); -}; - -/*! - * \class CSourcePieceWise_TransLM - * \brief Class for integrating the source terms of the Spalart-Allmaras turbulence model equation. - * \ingroup SourceDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CSourcePieceWise_TransLM : public CNumerics { -private: - - /*-- SA model constants --*/ - su2double cv1_3; - su2double k2; - su2double cb1; - su2double cw2; - su2double cw3_6; - su2double sigma; - su2double cb2; - su2double cw1; - - /*-- gamma-theta model constants --*/ - su2double c_e1; - su2double c_a1; - su2double c_e2; - su2double c_a2; - su2double sigmaf; - su2double s1; - su2double c_theta; - su2double sigmat; - - /*-- Correlation constants --*/ - su2double flen_global; - su2double alpha_global; - su2double Vorticity; - - bool implicit; - -public: - bool debugme; // For debugging only, remove this. -AA - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CSourcePieceWise_TransLM(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSourcePieceWise_TransLM(void); - - /*! - * \brief Residual for source term integration. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual_TransLM(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config, su2double &gamma_sep); - - void CSourcePieceWise_TransLM__ComputeResidual_TransLM_d(su2double *TransVar_i, su2double *TransVar_id, su2double *val_residual, su2double *val_residuald, CConfig *config); -}; - -/*! - * \class CSourcePieceWise_TurbSST - * \brief Class for integrating the source terms of the Menter SST turbulence model equations. - * \ingroup SourceDiscr - * \author A. Campos. - * \version 4.0.1 "Cardinal" - */ -class CSourcePieceWise_TurbSST : public CNumerics { -private: - su2double F1_i, - F1_j, - F2_i, - F2_j; - - su2double alfa_1, - alfa_2, - beta_1, - beta_2, - sigma_omega_1, - sigma_omega_2, - beta_star, - a1; - - su2double CDkw_i, CDkw_j; - - bool incompressible; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CSourcePieceWise_TurbSST(unsigned short val_nDim, unsigned short val_nVar, su2double* constants, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSourcePieceWise_TurbSST(void); - - /*! - * \brief Set the value of the first blending function. - * \param[in] val_F1_i - Value of the first blending function at point i. - * \param[in] val_F1_j - Value of the first blending function at point j. - */ - void SetF1blending(su2double val_F1_i, su2double val_F1_j); - - /*! - * \brief Set the value of the second blending function. - * \param[in] val_F2_i - Value of the second blending function at point i. - * \param[in] val_F2_j - Value of the second blending function at point j. - */ - void SetF2blending(su2double val_F2_i, su2double val_F2_j); - - /*! - * \brief Set the value of the cross diffusion for the SST model. - * \param[in] val_CDkw_i - Value of the cross diffusion at point i. - * \param[in] val_CDkw_j - Value of the cross diffusion at point j. - */ - virtual void SetCrossDiff(su2double val_CDkw_i, su2double val_CDkw_j); - - /*! - * \brief Residual for source term integration. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); - -}; - -/*! - * \class CSourceGravity - * \brief Class for the source term integration of the gravity force. - * \ingroup SourceDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CSourceGravity : public CNumerics { - su2double Froude; - bool compressible, incompressible, freesurface; - -public: - - /*! - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CSourceGravity(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSourceGravity(void); - - /*! - * \brief Source term integration for the poissonal potential. - * \param[out] val_residual - Pointer to the total residual. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, CConfig *config); -}; - -/*! - * \class CSourceViscous_AdjFlow - * \brief Class for source term integration in adjoint problem. - * \ingroup SourceDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CSourceViscous_AdjFlow : public CNumerics { -private: - su2double *Velocity, *GradDensity, *GradInvDensity, *dPoDensity2, *alpha, *beta, *Sigma_5_vec; - su2double **GradVel_o_Rho, **sigma, **Sigma_phi, **Sigma_5_Tensor, **Sigma; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CSourceViscous_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSourceViscous_AdjFlow(void); - - /*! - * \brief Source term integration of the flow adjoint equation. - * \param[out] val_residual - Pointer to the total residual. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual (su2double *val_residual, CConfig *config); - -}; - -/*! - * \class CSourcePieceWise_AdjTurb - * \brief Class for source term integration of the adjoint turbulent equation. - * \ingroup SourceDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CSourcePieceWise_AdjTurb : public CNumerics { -private: - su2double **tau, *Velocity; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CSourcePieceWise_AdjTurb(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSourcePieceWise_AdjTurb(void); - - /*! - * \brief Source term integration of the adjoint turbulence equation. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CSourcePieceWise_AdjLevelSet - * \brief Class for source term integration of the adjoint level set equation. - * \ingroup SourceDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CSourcePieceWise_AdjLevelSet : public CNumerics { -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CSourcePieceWise_AdjLevelSet(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSourcePieceWise_AdjLevelSet(void); - - /*! - * \brief Source term integration of the adjoint poisson potential equation. - * \param[out] val_residual - Pointer to the total residual. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, CConfig *config); -}; - -/*! - * \class CSourceConservative_AdjFlow - * \brief Class for source term integration in adjoint problem using a conservative scheme. - * \ingroup SourceDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CSourceConservative_AdjFlow : public CNumerics { -private: - su2double *Velocity, *Residual_i, *Residual_j, *Mean_Residual; - su2double **Mean_PrimVar_Grad; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CSourceConservative_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSourceConservative_AdjFlow(void); - - /*! - * \brief Source term integration using a conservative scheme. - * \param[out] val_residual - Pointer to the total residual. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, CConfig *config); -}; - -/*! - * \class CSourceConservative_AdjTurb - * \brief Class for source term integration in adjoint turbulent problem using a conservative scheme. - * \ingroup SourceDiscr - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CSourceConservative_AdjTurb : public CNumerics { -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CSourceConservative_AdjTurb(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSourceConservative_AdjTurb(void); - - /*! - * \brief Source term integration using a conservative scheme. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CSourceRotatingFrame_Flow - * \brief Class for a rotating frame source term. - * \ingroup SourceDiscr - * \author F. Palacios, T. Economon. - * \version 4.0.1 "Cardinal" - */ -class CSourceRotatingFrame_Flow : public CNumerics { -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CSourceRotatingFrame_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSourceRotatingFrame_Flow(void); - - /*! - * \brief Residual of the rotational frame source term. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config); -}; - -/*! - * \class CSourceRotatingFrame_AdjFlow - * \brief Source term class for rotating frame adjoint. - * \ingroup SourceDiscr - * \author T. Economon. - * \version 4.0.1 "Cardinal" - */ -class CSourceRotatingFrame_AdjFlow : public CNumerics { -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CSourceRotatingFrame_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSourceRotatingFrame_AdjFlow(void); - - /*! - * \brief Residual of the adjoint rotating frame source term. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config); -}; - -/*! - * \class CSourceAxisymmetric_Flow - * \brief Class for source term for solving axisymmetric problems. - * \ingroup SourceDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CSourceAxisymmetric_Flow : public CNumerics { -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CSourceAxisymmetric_Flow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSourceAxisymmetric_Flow(void); - - /*! - * \brief Residual of the rotational frame source term. - * \param[out] val_residual - Pointer to the total residual. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, CConfig *config); - -}; - -/*! - * \class CSourceAxisymmetric_AdjFlow - * \brief Class for source term for solving axisymmetric problems. - * \ingroup SourceDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CSourceAxisymmetric_AdjFlow : public CNumerics { -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CSourceAxisymmetric_AdjFlow(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSourceAxisymmetric_AdjFlow(void); - - /*! - * \brief Residual of the rotational frame source term. - * \param[out] val_residual - Pointer to the total residual. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **Jacobian_i, CConfig *config); -}; - -/*! - * \class CSourceWindGust - * \brief Class for a source term due to a wind gust. - * \ingroup SourceDiscr - * \author S. Padrón - * \version 4.0.1 "Cardinal" - */ -class CSourceWindGust : public CNumerics { -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CSourceWindGust(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSourceWindGust(void); - - /*! - * \brief Residual of the wind gust source term. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config); -}; - -/*! - * \class CSource_Template - * \brief Dummy class. - * \ingroup SourceDiscr - * \author A. Lonkar. - * \version 4.0.1 "Cardinal" - */ -class CSource_Template : public CNumerics { -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Name of the input config file - * - */ - CSource_Template(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - - /*! - * \brief Residual for source term integration. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CSource_Template(void); -}; - -/*! - * \class CConvectiveTemplate - * \brief Class for setting up new method for spatial discretization of convective terms in flow Equations - * \ingroup ConvDiscr - * \author A. Lonkar - * \version 4.0.1 "Cardinal" - */ -class CConvective_Template : public CNumerics { -private: - - /* define private variables here */ - bool implicit; - su2double *Diff_U; - su2double *Velocity_i, *Velocity_j, *RoeVelocity; - su2double *ProjFlux_i, *ProjFlux_j; - su2double *delta_wave, *delta_vel; - su2double *Lambda, *Epsilon; - su2double **P_Tensor, **invP_Tensor; - su2double sq_vel, Proj_ModJac_Tensor_ij, Density_i, Energy_i, SoundSpeed_i, Pressure_i, Enthalpy_i, - Density_j, Energy_j, SoundSpeed_j, Pressure_j, Enthalpy_j, R, RoeDensity, RoeEnthalpy, RoeSoundSpeed, - ProjVelocity, ProjVelocity_i, ProjVelocity_j, proj_delta_vel, delta_p, delta_rho; - unsigned short iDim, iVar, jVar, kVar; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CConvective_Template(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CConvective_Template(void); - - /*! - * \brief Compute the Roe's flux between two nodes i and j. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -/*! - * \class CViscous_Template - * \brief Class for computing viscous term using average of gradients. - * \ingroup ViscDiscr - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CViscous_Template : public CNumerics { -private: - -public: - - /*! - * \brief Constructor of the class. - * \param[in] val_nDim - Number of dimension of the problem. - * \param[in] val_nVar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CViscous_Template(unsigned short val_nDim, unsigned short val_nVar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CViscous_Template(void); - - /*! - * \brief Compute the viscous flow residual using an average of gradients. - * \param[out] val_residual - Pointer to the total residual. - * \param[out] val_Jacobian_i - Jacobian of the numerical method at node i (implicit computation). - * \param[out] val_Jacobian_j - Jacobian of the numerical method at node j (implicit computation). - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config); -}; - -#include "numerics_structure.inl" +#include "numerics_structure.inl" diff --git a/SU2_CFD/include/numerics_structure.inl b/SU2_CFD/include/numerics_structure.inl index 9ebd593d499..33fce77e948 100644 --- a/SU2_CFD/include/numerics_structure.inl +++ b/SU2_CFD/include/numerics_structure.inl @@ -1,458 +1,458 @@ -/*! - * \file numerics_structure.inl - * \brief In-Line subroutines of the numerics_structure.hpp file. - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -inline su2double CNumerics::Determinant_3x3(su2double A00, su2double A01, su2double A02, su2double A10, su2double A11, su2double A12, su2double A20, su2double A21, su2double A22) { - return A00*(A11*A22-A12*A21) - A01*(A10*A22-A12*A20) + A02*(A10*A21-A11*A20); -} - -inline void CNumerics::SetFEA_StiffMatrix2D(su2double **StiffMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d) { } - -inline void CNumerics::SetFEA_StiffMatrix3D(su2double **StiffMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes) { } - -inline void CNumerics::SetFEA_StiffMassMatrix2D(su2double **StiffMatrix_Elem, su2double **MassMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d) { } - -inline void CNumerics::SetFEA_StiffMassMatrix3D(su2double **StiffMatrix_Elem, su2double **MassMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes) { } - -inline void CNumerics::GetFEA_StressNodal2D(su2double StressVector[8][3], su2double DispElement[8], su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d) { } - -inline void CNumerics::GetFEA_StressNodal3D(su2double StressVector[8][6], su2double DispElement[24], su2double CoordCorners[8][3], unsigned short nNodes) { } - -inline void CNumerics::SetFEA_DeadLoad2D(su2double *DeadLoadVector_Elem, su2double CoordCorners[8][3], unsigned short nNodes, su2double matDensity) { } - -inline void CNumerics::SetFEA_DeadLoad3D(su2double *DeadLoadVector_Elem, su2double CoordCorners[8][3], unsigned short nNodes, su2double matDensity) { } - -inline void CNumerics::PressInt_Linear(su2double CoordCorners[4][3], su2double *tn_e, su2double *Fnodal) { } - -inline void CNumerics::ViscTermInt_Linear(su2double CoordCorners[2][2], su2double Tau_0[3][3], su2double Tau_1[3][3], su2double FviscNodal[4]) { } - -inline void CNumerics::ComputeResidual(su2double *val_residual, CConfig *config) { } - -inline void CNumerics::ComputeResidual(su2double *val_residual_i, su2double *val_residual_j) { } - -inline void CNumerics::ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, CConfig *config) { } - -inline void CNumerics::ComputeResidual(su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config) { } - -inline void CNumerics::ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, - CConfig *config) { } - -inline void CNumerics::ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, - su2double **val_JacobianMeanFlow_i, su2double **val_JacobianMeanFlow_j, CConfig *config) { } - -inline void CNumerics::ComputeResidual(su2double *val_resconv, su2double *val_resvisc, su2double **val_Jacobian_i, - su2double **val_Jacobian_j, CConfig *config) { } - -inline void CNumerics::ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, - su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, - su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config) { } - -inline void CNumerics::ComputeResidual(su2double *val_resconv_i, su2double *val_resvisc_i, su2double *val_resconv_j, - su2double *val_resvisc_j, su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, - su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config) { } - -inline void CNumerics::ComputeResidual(su2double **val_stiffmatrix_elem, CConfig *config) { } - -inline void CNumerics::GetEq_Rxn_Coefficients(su2double **EqnRxnConstants, CConfig *config) { }; - -inline void CNumerics::ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config) { } - -inline void CNumerics::ComputeResidual_TransLM(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config, su2double &gamma_sep) {} - -inline void CNumerics::ComputeResidual_Axisymmetric(su2double *val_residual, CConfig *config) { } - -inline void CNumerics::ComputeResidual_Axisymmetric_ad(su2double *val_residual, su2double *val_residuald, CConfig *config) { } - -inline void CNumerics::SetJacobian_Axisymmetric(su2double **val_Jacobian_i, CConfig *config) { } - -inline void CNumerics::ComputeVibRelaxation(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config) { } - -inline void CNumerics::ComputeChemistry(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config) { } - -inline void CNumerics::GetKeqConstants(su2double *A, unsigned short val_reaction, CConfig *config) { } - -inline su2double CNumerics::GetPrecond_Beta() { return 0; } - -inline void CNumerics::SetRhosIndex(unsigned short val_Index) { RHOS_INDEX = val_Index; } - -inline void CNumerics::SetRhoIndex(unsigned short val_Index) { RHO_INDEX = val_Index; } - -inline void CNumerics::SetPIndex(unsigned short val_Index) { P_INDEX = val_Index; } - -inline void CNumerics::SetTIndex(unsigned short val_Index) { T_INDEX = val_Index; } - -inline void CNumerics::SetTveIndex(unsigned short val_Index) { TVE_INDEX = val_Index; } - -inline void CNumerics::SetVelIndex(unsigned short val_Index) { VEL_INDEX = val_Index; } - -inline void CNumerics::SetHIndex(unsigned short val_Index) { H_INDEX = val_Index; } - -inline void CNumerics::SetAIndex(unsigned short val_Index) { A_INDEX = val_Index; } - -inline void CNumerics::SetRhoCvtrIndex(unsigned short val_Index) { RHOCVTR_INDEX = val_Index; } - -inline void CNumerics::SetRhoCvveIndex(unsigned short val_Index) { RHOCVVE_INDEX = val_Index; } - -inline void CNumerics::SetdPdU(su2double *val_dPdU_i, su2double *val_dPdU_j) { dPdU_i = val_dPdU_i; dPdU_j = val_dPdU_j; } - -inline void CNumerics::SetdTdU(su2double *val_dTdU_i, su2double *val_dTdU_j) { dTdU_i = val_dTdU_i; dTdU_j = val_dTdU_j; } - -inline void CNumerics::SetdTvedU(su2double *val_dTvedU_i, su2double *val_dTvedU_j) { dTvedU_i = val_dTvedU_i; dTvedU_j = val_dTvedU_j; } - -inline void CNumerics::SetUndivided_Laplacian(su2double *val_und_lapl_i, su2double *val_und_lapl_j) { - Und_Lapl_i = val_und_lapl_i; - Und_Lapl_j = val_und_lapl_j; -} - -inline void CNumerics::SetSensor( su2double val_sensor_i, su2double val_sensor_j) { - Sensor_i = val_sensor_i; - Sensor_j = val_sensor_j; -} - -inline void CNumerics::SetConservative(su2double *val_u_i, su2double *val_u_j) { - U_i = val_u_i; - U_j = val_u_j; -} - -inline void CNumerics::SetConservative_ZeroOrder(su2double *val_u_i, su2double *val_u_j) { - UZeroOrder_i = val_u_i; - UZeroOrder_j = val_u_j; -} - -inline void CNumerics::SetPrimitive(su2double *val_v_i, su2double *val_v_j) { - V_i = val_v_i; - V_j = val_v_j; -} - -inline void CNumerics::SetSecondary(su2double *val_s_i, su2double *val_s_j) { - S_i = val_s_i; - S_j = val_s_j; -} - -inline void CNumerics::SetConservative(su2double *val_u_0, su2double *val_u_1, su2double *val_u_2) { - U_0 = val_u_0; - U_1 = val_u_1; - U_2 = val_u_2; -} - -inline void CNumerics::SetConservative(su2double *val_u_0, su2double *val_u_1, su2double *val_u_2, su2double *val_u_3) { - U_0 = val_u_0; - U_1 = val_u_1; - U_2 = val_u_2; - U_3 = val_u_3; -} - -inline void CNumerics::SetVelocity2_Inf(su2double velocity2) { - vel2_inf = velocity2; -} - -inline void CNumerics::SetVorticity(su2double *val_vorticity_i, su2double *val_vorticity_j) { - Vorticity_i = val_vorticity_i; - Vorticity_j = val_vorticity_j; -} - -inline void CNumerics::SetStrainMag(su2double val_strainmag_i, su2double val_strainmag_j) { - StrainMag_i = val_strainmag_i; - StrainMag_j = val_strainmag_j; -} - -inline void CNumerics::SetTimeStep(su2double val_timestep) {TimeStep = val_timestep;} - -inline void CNumerics::SetLaminarViscosity(su2double val_lam_viscosity_i, su2double val_lam_viscosity_j) { - Laminar_Viscosity_i = val_lam_viscosity_i; - Laminar_Viscosity_j = val_lam_viscosity_j; -} - -inline void CNumerics::SetThermalConductivity(su2double val_therm_conductivity_i, su2double val_therm_conductivity_j) { - Thermal_Conductivity_i = val_therm_conductivity_i; - Thermal_Conductivity_j = val_therm_conductivity_j; -} - -inline void CNumerics::SetThermalConductivity_ve(su2double val_therm_conductivity_ve_i, su2double val_therm_conductivity_ve_j) { - Thermal_Conductivity_ve_i = val_therm_conductivity_ve_i; - Thermal_Conductivity_ve_j = val_therm_conductivity_ve_j; -} - -inline void CNumerics::SetDiffusionCoeff(su2double* val_diffusioncoeff_i, su2double* val_diffusioncoeff_j) { - Diffusion_Coeff_i = val_diffusioncoeff_i; - Diffusion_Coeff_j = val_diffusioncoeff_j; -} - -inline void CNumerics::SetEddyViscosity(su2double val_eddy_viscosity_i, su2double val_eddy_viscosity_j) { - Eddy_Viscosity_i = val_eddy_viscosity_i; - Eddy_Viscosity_j = val_eddy_viscosity_j; -} - -inline void CNumerics::SetIntermittency(su2double intermittency_in) { } - -inline void CNumerics::SetProduction(su2double val_production) { } - -inline void CNumerics::SetDestruction(su2double val_destruction) { } - -inline void CNumerics::SetCrossProduction(su2double val_crossproduction) { } - -inline su2double CNumerics::GetProduction(void) { return 0; } - -inline su2double CNumerics::GetDestruction(void) { return 0; } - -inline su2double CNumerics::GetCrossProduction(void) { return 0; } - -inline void CNumerics::SetTurbKineticEnergy(su2double val_turb_ke_i, su2double val_turb_ke_j) { - turb_ke_i = val_turb_ke_i; - turb_ke_j = val_turb_ke_j; -} - -inline void CNumerics::SetDistance(su2double val_dist_i, su2double val_dist_j) { - dist_i = val_dist_i; - dist_j = val_dist_j; -} - -inline void CNumerics::SetAdjointVar(su2double *val_psi_i, su2double *val_psi_j) { - Psi_i = val_psi_i; - Psi_j = val_psi_j; -} - -inline void CNumerics::SetAdjointVarGradient(su2double **val_psivar_grad_i, su2double **val_psivar_grad_j) { - PsiVar_Grad_i = val_psivar_grad_i; - PsiVar_Grad_j = val_psivar_grad_j; -} - -inline void CNumerics::SetAdjointVarLimiter(su2double *val_psivar_lim_i, su2double *val_psivar_lim_j) { - PsiVar_Lim_i = val_psivar_lim_i; - PsiVar_Lim_j = val_psivar_lim_j; -} - -inline void CNumerics::SetTurbVar(su2double *val_turbvar_i, su2double *val_turbvar_j) { - TurbVar_i = val_turbvar_i; - TurbVar_j = val_turbvar_j; -} - -inline void CNumerics::SetTransVar(su2double *val_transvar_i, su2double *val_transvar_j) { - TransVar_i = val_transvar_i; - TransVar_j = val_transvar_j; -} - -inline void CNumerics::SetTurbVarGradient(su2double **val_turbvar_grad_i, su2double **val_turbvar_grad_j) { - TurbVar_Grad_i = val_turbvar_grad_i; - TurbVar_Grad_j = val_turbvar_grad_j; -} - -inline void CNumerics::SetTransVarGradient(su2double **val_transvar_grad_i, su2double **val_transvar_grad_j) { - TransVar_Grad_i = val_transvar_grad_i; - TransVar_Grad_j = val_transvar_grad_j; -} - -inline void CNumerics::SetLevelSetVar(su2double *val_levelsetvar_i, su2double *val_levelsetvar_j) { - LevelSetVar_i = val_levelsetvar_i; - LevelSetVar_j = val_levelsetvar_j; -} - -inline void CNumerics::SetLevelSetVarGradient(su2double **val_levelsetvar_grad_i, su2double **val_levelsetvar_grad_j) { - LevelSetVar_Grad_i = val_levelsetvar_grad_i; - LevelSetVar_Grad_j = val_levelsetvar_grad_j; -} - -inline void CNumerics::SetPrimVarGradient(su2double **val_primvar_grad_i, su2double **val_primvar_grad_j) { - PrimVar_Grad_i = val_primvar_grad_i; - PrimVar_Grad_j = val_primvar_grad_j; -} - -inline void CNumerics::SetPrimVarLimiter(su2double *val_primvar_lim_i, su2double *val_primvar_lim_j) { - PrimVar_Lim_i = val_primvar_lim_i; - PrimVar_Lim_j = val_primvar_lim_j; -} - -inline void CNumerics::SetConsVarGradient(su2double **val_consvar_grad_i, su2double **val_consvar_grad_j) { - ConsVar_Grad_i = val_consvar_grad_i; - ConsVar_Grad_j = val_consvar_grad_j; -} - -inline void CNumerics::SetConsVarGradient(su2double **val_consvar_grad_0, su2double **val_consvar_grad_1, su2double **val_consvar_grad_2) { - ConsVar_Grad_0 = val_consvar_grad_0; - ConsVar_Grad_1 = val_consvar_grad_1; - ConsVar_Grad_2 = val_consvar_grad_2; -} - -inline void CNumerics::SetConsVarGradient(su2double **val_consvar_grad_0, su2double **val_consvar_grad_1, su2double **val_consvar_grad_2, su2double **val_consvar_grad_3) { - ConsVar_Grad_0 = val_consvar_grad_0; - ConsVar_Grad_1 = val_consvar_grad_1; - ConsVar_Grad_2 = val_consvar_grad_2; - ConsVar_Grad_3 = val_consvar_grad_3; -} - -inline void CNumerics::SetConsVarGradient(su2double **val_consvar_grad) { - ConsVar_Grad = val_consvar_grad; -} - -inline void CNumerics::SetCoord(su2double *val_coord_i, su2double *val_coord_j) { - Coord_i = val_coord_i; - Coord_j = val_coord_j; -} - -inline void CNumerics::SetCoord(su2double *val_coord_0, su2double *val_coord_1, - su2double *val_coord_2) { - Coord_0 = val_coord_0; - Coord_1 = val_coord_1; - Coord_2 = val_coord_2; -} - -inline void CNumerics::SetCoord(su2double *val_coord_0, su2double *val_coord_1, - su2double *val_coord_2, su2double *val_coord_3) { - Coord_0 = val_coord_0; - Coord_1 = val_coord_1; - Coord_2 = val_coord_2; - Coord_3 = val_coord_3; -} - -inline void CNumerics::SetGridVel(su2double *val_gridvel_i, su2double *val_gridvel_j) { - GridVel_i = val_gridvel_i; - GridVel_j = val_gridvel_j; -} - -inline void CNumerics::SetWindGust(su2double *val_windgust_i, su2double *val_windgust_j) { - WindGust_i = val_windgust_i; - WindGust_j = val_windgust_j; -} - -inline void CNumerics::SetWindGustDer(su2double *val_windgustder_i, su2double *val_windgustder_j) { - WindGustDer_i = val_windgustder_i; - WindGustDer_j = val_windgustder_j; -} - -inline void CNumerics::SetPressure(su2double val_pressure_i, su2double val_pressure_j) { - Pressure_i = val_pressure_i; - Pressure_j = val_pressure_j; -} - -inline void CNumerics::SetDensityInc(su2double val_densityinc_i, su2double val_densityinc_j) { - DensityInc_i = val_densityinc_i; - DensityInc_j = val_densityinc_j; -} - -inline void CNumerics::SetBetaInc2(su2double val_betainc2_i, su2double val_betainc2_j) { - BetaInc2_i = val_betainc2_i; - BetaInc2_j = val_betainc2_j; -} - -inline void CNumerics::SetSoundSpeed(su2double val_soundspeed_i, su2double val_soundspeed_j) { - SoundSpeed_i = val_soundspeed_i; - SoundSpeed_j = val_soundspeed_j; -} - -inline void CNumerics::SetEnthalpy(su2double val_enthalpy_i, su2double val_enthalpy_j) { - Enthalpy_i = val_enthalpy_i; - Enthalpy_j = val_enthalpy_j; -} - -inline void CNumerics::SetLambda(su2double val_lambda_i, su2double val_lambda_j) { - Lambda_i = val_lambda_i; - Lambda_j = val_lambda_j; -} - -inline void CNumerics::SetNeighbor(unsigned short val_neighbor_i, unsigned short val_neighbor_j) { - Neighbor_i = val_neighbor_i; - Neighbor_j = val_neighbor_j; -} - -inline void CNumerics::SetTurbAdjointVar(su2double *val_turbpsivar_i, su2double *val_turbpsivar_j) { - TurbPsi_i = val_turbpsivar_i; - TurbPsi_j = val_turbpsivar_j; -} - -inline void CNumerics::SetTurbAdjointGradient(su2double **val_turbpsivar_grad_i, su2double **val_turbpsivar_grad_j) { - TurbPsi_Grad_i = val_turbpsivar_grad_i; - TurbPsi_Grad_j = val_turbpsivar_grad_j; -} - -inline void CNumerics::SetTemperature(su2double val_temp_i, su2double val_temp_j) { - Temp_i = val_temp_i; - Temp_j = val_temp_j; -} - -inline void CNumerics::SetAuxVarGrad(su2double *val_auxvargrad_i, su2double *val_auxvargrad_j) { - AuxVar_Grad_i = val_auxvargrad_i; - AuxVar_Grad_j = val_auxvargrad_j; -} - -inline void CNumerics::SetNormal(su2double *val_normal) { Normal = val_normal; } - -inline void CNumerics::SetVolume(su2double val_volume) { Volume = val_volume; } - -inline void CSourcePieceWise_TurbSST::SetF1blending(su2double val_F1_i, su2double val_F1_j) { - F1_i = val_F1_i; - F1_j = val_F1_j; -} - -inline void CSourcePieceWise_TurbSST::SetF2blending(su2double val_F2_i, su2double val_F2_j) { - F2_i = val_F2_i; - F2_j = val_F2_j; -} - -inline void CSourcePieceWise_TurbSST::SetCrossDiff(su2double val_CDkw_i, su2double val_CDkw_j) { - CDkw_i = val_CDkw_i; - CDkw_j = val_CDkw_j; -} - -inline void CSourcePieceWise_TurbSA::SetIntermittency(su2double intermittency_in) { intermittency = intermittency_in; } - -inline void CSourcePieceWise_TurbSA::SetProduction(su2double val_production) { Production = val_production; } - -inline void CSourcePieceWise_TurbSA::SetDestruction(su2double val_destruction) { Destruction = val_destruction; } - -inline void CSourcePieceWise_TurbSA::SetCrossProduction(su2double val_crossproduction) { CrossProduction = val_crossproduction; } - -inline su2double CSourcePieceWise_TurbSA::GetProduction(void) { return Production; } - -inline su2double CSourcePieceWise_TurbSA::GetDestruction(void) { return Destruction; } - -inline su2double CSourcePieceWise_TurbSA::GetCrossProduction(void) { return CrossProduction; } - -inline void CSourcePieceWise_TurbSA_Neg::SetIntermittency(su2double intermittency_in) { intermittency = intermittency_in; } - -inline void CSourcePieceWise_TurbSA_Neg::SetProduction(su2double val_production) { Production = val_production; } - -inline void CSourcePieceWise_TurbSA_Neg::SetDestruction(su2double val_destruction) { Destruction = val_destruction; } - -inline void CSourcePieceWise_TurbSA_Neg::SetCrossProduction(su2double val_crossproduction) { CrossProduction = val_crossproduction; } - -inline su2double CSourcePieceWise_TurbSA_Neg::GetProduction(void) { return Production; } - -inline su2double CSourcePieceWise_TurbSA_Neg::GetDestruction(void) { return Destruction; } - -inline su2double CSourcePieceWise_TurbSA_Neg::GetCrossProduction(void) { return CrossProduction; } - -inline su2double CUpwTurkel_Flow::GetPrecond_Beta() { return Beta; } - -inline void CNumerics::ComputeResidual(su2double **val_Jacobian_i, su2double *val_Jacobian_mui, su2double ***val_Jacobian_gradi, CConfig *config) { } - -inline void CNumerics::ComputeResidual(su2double **val_Jacobian_i, su2double *val_Jacobian_mui, su2double ***val_Jacobian_gradi, - su2double **val_Jacobian_j, su2double *val_Jacobian_muj, su2double ***val_Jacobian_gradj, CConfig *config) { } +/*! + * \file numerics_structure.inl + * \brief In-Line subroutines of the numerics_structure.hpp file. + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +inline su2double CNumerics::Determinant_3x3(su2double A00, su2double A01, su2double A02, su2double A10, su2double A11, su2double A12, su2double A20, su2double A21, su2double A22) { + return A00*(A11*A22-A12*A21) - A01*(A10*A22-A12*A20) + A02*(A10*A21-A11*A20); +} + +inline void CNumerics::SetFEA_StiffMatrix2D(su2double **StiffMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d) { } + +inline void CNumerics::SetFEA_StiffMatrix3D(su2double **StiffMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes) { } + +inline void CNumerics::SetFEA_StiffMassMatrix2D(su2double **StiffMatrix_Elem, su2double **MassMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d) { } + +inline void CNumerics::SetFEA_StiffMassMatrix3D(su2double **StiffMatrix_Elem, su2double **MassMatrix_Elem, su2double CoordCorners[8][3], unsigned short nNodes) { } + +inline void CNumerics::GetFEA_StressNodal2D(su2double StressVector[8][3], su2double DispElement[8], su2double CoordCorners[8][3], unsigned short nNodes, unsigned short form2d) { } + +inline void CNumerics::GetFEA_StressNodal3D(su2double StressVector[8][6], su2double DispElement[24], su2double CoordCorners[8][3], unsigned short nNodes) { } + +inline void CNumerics::SetFEA_DeadLoad2D(su2double *DeadLoadVector_Elem, su2double CoordCorners[8][3], unsigned short nNodes, su2double matDensity) { } + +inline void CNumerics::SetFEA_DeadLoad3D(su2double *DeadLoadVector_Elem, su2double CoordCorners[8][3], unsigned short nNodes, su2double matDensity) { } + +inline void CNumerics::PressInt_Linear(su2double CoordCorners[4][3], su2double *tn_e, su2double *Fnodal) { } + +inline void CNumerics::ViscTermInt_Linear(su2double CoordCorners[2][2], su2double Tau_0[3][3], su2double Tau_1[3][3], su2double FviscNodal[4]) { } + +inline void CNumerics::ComputeResidual(su2double *val_residual, CConfig *config) { } + +inline void CNumerics::ComputeResidual(su2double *val_residual_i, su2double *val_residual_j) { } + +inline void CNumerics::ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, CConfig *config) { } + +inline void CNumerics::ComputeResidual(su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config) { } + +inline void CNumerics::ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, + CConfig *config) { } + +inline void CNumerics::ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, + su2double **val_JacobianMeanFlow_i, su2double **val_JacobianMeanFlow_j, CConfig *config) { } + +inline void CNumerics::ComputeResidual(su2double *val_resconv, su2double *val_resvisc, su2double **val_Jacobian_i, + su2double **val_Jacobian_j, CConfig *config) { } + +inline void CNumerics::ComputeResidual(su2double *val_residual_i, su2double *val_residual_j, + su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, + su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config) { } + +inline void CNumerics::ComputeResidual(su2double *val_resconv_i, su2double *val_resvisc_i, su2double *val_resconv_j, + su2double *val_resvisc_j, su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, + su2double **val_Jacobian_ji, su2double **val_Jacobian_jj, CConfig *config) { } + +inline void CNumerics::ComputeResidual(su2double **val_stiffmatrix_elem, CConfig *config) { } + +inline void CNumerics::GetEq_Rxn_Coefficients(su2double **EqnRxnConstants, CConfig *config) { }; + +inline void CNumerics::ComputeResidual(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config) { } + +inline void CNumerics::ComputeResidual_TransLM(su2double *val_residual, su2double **val_Jacobian_i, su2double **val_Jacobian_j, CConfig *config, su2double &gamma_sep) {} + +inline void CNumerics::ComputeResidual_Axisymmetric(su2double *val_residual, CConfig *config) { } + +inline void CNumerics::ComputeResidual_Axisymmetric_ad(su2double *val_residual, su2double *val_residuald, CConfig *config) { } + +inline void CNumerics::SetJacobian_Axisymmetric(su2double **val_Jacobian_i, CConfig *config) { } + +inline void CNumerics::ComputeVibRelaxation(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config) { } + +inline void CNumerics::ComputeChemistry(su2double *val_residual, su2double **val_Jacobian_i, CConfig *config) { } + +inline void CNumerics::GetKeqConstants(su2double *A, unsigned short val_reaction, CConfig *config) { } + +inline su2double CNumerics::GetPrecond_Beta() { return 0; } + +inline void CNumerics::SetRhosIndex(unsigned short val_Index) { RHOS_INDEX = val_Index; } + +inline void CNumerics::SetRhoIndex(unsigned short val_Index) { RHO_INDEX = val_Index; } + +inline void CNumerics::SetPIndex(unsigned short val_Index) { P_INDEX = val_Index; } + +inline void CNumerics::SetTIndex(unsigned short val_Index) { T_INDEX = val_Index; } + +inline void CNumerics::SetTveIndex(unsigned short val_Index) { TVE_INDEX = val_Index; } + +inline void CNumerics::SetVelIndex(unsigned short val_Index) { VEL_INDEX = val_Index; } + +inline void CNumerics::SetHIndex(unsigned short val_Index) { H_INDEX = val_Index; } + +inline void CNumerics::SetAIndex(unsigned short val_Index) { A_INDEX = val_Index; } + +inline void CNumerics::SetRhoCvtrIndex(unsigned short val_Index) { RHOCVTR_INDEX = val_Index; } + +inline void CNumerics::SetRhoCvveIndex(unsigned short val_Index) { RHOCVVE_INDEX = val_Index; } + +inline void CNumerics::SetdPdU(su2double *val_dPdU_i, su2double *val_dPdU_j) { dPdU_i = val_dPdU_i; dPdU_j = val_dPdU_j; } + +inline void CNumerics::SetdTdU(su2double *val_dTdU_i, su2double *val_dTdU_j) { dTdU_i = val_dTdU_i; dTdU_j = val_dTdU_j; } + +inline void CNumerics::SetdTvedU(su2double *val_dTvedU_i, su2double *val_dTvedU_j) { dTvedU_i = val_dTvedU_i; dTvedU_j = val_dTvedU_j; } + +inline void CNumerics::SetUndivided_Laplacian(su2double *val_und_lapl_i, su2double *val_und_lapl_j) { + Und_Lapl_i = val_und_lapl_i; + Und_Lapl_j = val_und_lapl_j; +} + +inline void CNumerics::SetSensor( su2double val_sensor_i, su2double val_sensor_j) { + Sensor_i = val_sensor_i; + Sensor_j = val_sensor_j; +} + +inline void CNumerics::SetConservative(su2double *val_u_i, su2double *val_u_j) { + U_i = val_u_i; + U_j = val_u_j; +} + +inline void CNumerics::SetConservative_ZeroOrder(su2double *val_u_i, su2double *val_u_j) { + UZeroOrder_i = val_u_i; + UZeroOrder_j = val_u_j; +} + +inline void CNumerics::SetPrimitive(su2double *val_v_i, su2double *val_v_j) { + V_i = val_v_i; + V_j = val_v_j; +} + +inline void CNumerics::SetSecondary(su2double *val_s_i, su2double *val_s_j) { + S_i = val_s_i; + S_j = val_s_j; +} + +inline void CNumerics::SetConservative(su2double *val_u_0, su2double *val_u_1, su2double *val_u_2) { + U_0 = val_u_0; + U_1 = val_u_1; + U_2 = val_u_2; +} + +inline void CNumerics::SetConservative(su2double *val_u_0, su2double *val_u_1, su2double *val_u_2, su2double *val_u_3) { + U_0 = val_u_0; + U_1 = val_u_1; + U_2 = val_u_2; + U_3 = val_u_3; +} + +inline void CNumerics::SetVelocity2_Inf(su2double velocity2) { + vel2_inf = velocity2; +} + +inline void CNumerics::SetVorticity(su2double *val_vorticity_i, su2double *val_vorticity_j) { + Vorticity_i = val_vorticity_i; + Vorticity_j = val_vorticity_j; +} + +inline void CNumerics::SetStrainMag(su2double val_strainmag_i, su2double val_strainmag_j) { + StrainMag_i = val_strainmag_i; + StrainMag_j = val_strainmag_j; +} + +inline void CNumerics::SetTimeStep(su2double val_timestep) {TimeStep = val_timestep;} + +inline void CNumerics::SetLaminarViscosity(su2double val_lam_viscosity_i, su2double val_lam_viscosity_j) { + Laminar_Viscosity_i = val_lam_viscosity_i; + Laminar_Viscosity_j = val_lam_viscosity_j; +} + +inline void CNumerics::SetThermalConductivity(su2double val_therm_conductivity_i, su2double val_therm_conductivity_j) { + Thermal_Conductivity_i = val_therm_conductivity_i; + Thermal_Conductivity_j = val_therm_conductivity_j; +} + +inline void CNumerics::SetThermalConductivity_ve(su2double val_therm_conductivity_ve_i, su2double val_therm_conductivity_ve_j) { + Thermal_Conductivity_ve_i = val_therm_conductivity_ve_i; + Thermal_Conductivity_ve_j = val_therm_conductivity_ve_j; +} + +inline void CNumerics::SetDiffusionCoeff(su2double* val_diffusioncoeff_i, su2double* val_diffusioncoeff_j) { + Diffusion_Coeff_i = val_diffusioncoeff_i; + Diffusion_Coeff_j = val_diffusioncoeff_j; +} + +inline void CNumerics::SetEddyViscosity(su2double val_eddy_viscosity_i, su2double val_eddy_viscosity_j) { + Eddy_Viscosity_i = val_eddy_viscosity_i; + Eddy_Viscosity_j = val_eddy_viscosity_j; +} + +inline void CNumerics::SetIntermittency(su2double intermittency_in) { } + +inline void CNumerics::SetProduction(su2double val_production) { } + +inline void CNumerics::SetDestruction(su2double val_destruction) { } + +inline void CNumerics::SetCrossProduction(su2double val_crossproduction) { } + +inline su2double CNumerics::GetProduction(void) { return 0; } + +inline su2double CNumerics::GetDestruction(void) { return 0; } + +inline su2double CNumerics::GetCrossProduction(void) { return 0; } + +inline void CNumerics::SetTurbKineticEnergy(su2double val_turb_ke_i, su2double val_turb_ke_j) { + turb_ke_i = val_turb_ke_i; + turb_ke_j = val_turb_ke_j; +} + +inline void CNumerics::SetDistance(su2double val_dist_i, su2double val_dist_j) { + dist_i = val_dist_i; + dist_j = val_dist_j; +} + +inline void CNumerics::SetAdjointVar(su2double *val_psi_i, su2double *val_psi_j) { + Psi_i = val_psi_i; + Psi_j = val_psi_j; +} + +inline void CNumerics::SetAdjointVarGradient(su2double **val_psivar_grad_i, su2double **val_psivar_grad_j) { + PsiVar_Grad_i = val_psivar_grad_i; + PsiVar_Grad_j = val_psivar_grad_j; +} + +inline void CNumerics::SetAdjointVarLimiter(su2double *val_psivar_lim_i, su2double *val_psivar_lim_j) { + PsiVar_Lim_i = val_psivar_lim_i; + PsiVar_Lim_j = val_psivar_lim_j; +} + +inline void CNumerics::SetTurbVar(su2double *val_turbvar_i, su2double *val_turbvar_j) { + TurbVar_i = val_turbvar_i; + TurbVar_j = val_turbvar_j; +} + +inline void CNumerics::SetTransVar(su2double *val_transvar_i, su2double *val_transvar_j) { + TransVar_i = val_transvar_i; + TransVar_j = val_transvar_j; +} + +inline void CNumerics::SetTurbVarGradient(su2double **val_turbvar_grad_i, su2double **val_turbvar_grad_j) { + TurbVar_Grad_i = val_turbvar_grad_i; + TurbVar_Grad_j = val_turbvar_grad_j; +} + +inline void CNumerics::SetTransVarGradient(su2double **val_transvar_grad_i, su2double **val_transvar_grad_j) { + TransVar_Grad_i = val_transvar_grad_i; + TransVar_Grad_j = val_transvar_grad_j; +} + +inline void CNumerics::SetLevelSetVar(su2double *val_levelsetvar_i, su2double *val_levelsetvar_j) { + LevelSetVar_i = val_levelsetvar_i; + LevelSetVar_j = val_levelsetvar_j; +} + +inline void CNumerics::SetLevelSetVarGradient(su2double **val_levelsetvar_grad_i, su2double **val_levelsetvar_grad_j) { + LevelSetVar_Grad_i = val_levelsetvar_grad_i; + LevelSetVar_Grad_j = val_levelsetvar_grad_j; +} + +inline void CNumerics::SetPrimVarGradient(su2double **val_primvar_grad_i, su2double **val_primvar_grad_j) { + PrimVar_Grad_i = val_primvar_grad_i; + PrimVar_Grad_j = val_primvar_grad_j; +} + +inline void CNumerics::SetPrimVarLimiter(su2double *val_primvar_lim_i, su2double *val_primvar_lim_j) { + PrimVar_Lim_i = val_primvar_lim_i; + PrimVar_Lim_j = val_primvar_lim_j; +} + +inline void CNumerics::SetConsVarGradient(su2double **val_consvar_grad_i, su2double **val_consvar_grad_j) { + ConsVar_Grad_i = val_consvar_grad_i; + ConsVar_Grad_j = val_consvar_grad_j; +} + +inline void CNumerics::SetConsVarGradient(su2double **val_consvar_grad_0, su2double **val_consvar_grad_1, su2double **val_consvar_grad_2) { + ConsVar_Grad_0 = val_consvar_grad_0; + ConsVar_Grad_1 = val_consvar_grad_1; + ConsVar_Grad_2 = val_consvar_grad_2; +} + +inline void CNumerics::SetConsVarGradient(su2double **val_consvar_grad_0, su2double **val_consvar_grad_1, su2double **val_consvar_grad_2, su2double **val_consvar_grad_3) { + ConsVar_Grad_0 = val_consvar_grad_0; + ConsVar_Grad_1 = val_consvar_grad_1; + ConsVar_Grad_2 = val_consvar_grad_2; + ConsVar_Grad_3 = val_consvar_grad_3; +} + +inline void CNumerics::SetConsVarGradient(su2double **val_consvar_grad) { + ConsVar_Grad = val_consvar_grad; +} + +inline void CNumerics::SetCoord(su2double *val_coord_i, su2double *val_coord_j) { + Coord_i = val_coord_i; + Coord_j = val_coord_j; +} + +inline void CNumerics::SetCoord(su2double *val_coord_0, su2double *val_coord_1, + su2double *val_coord_2) { + Coord_0 = val_coord_0; + Coord_1 = val_coord_1; + Coord_2 = val_coord_2; +} + +inline void CNumerics::SetCoord(su2double *val_coord_0, su2double *val_coord_1, + su2double *val_coord_2, su2double *val_coord_3) { + Coord_0 = val_coord_0; + Coord_1 = val_coord_1; + Coord_2 = val_coord_2; + Coord_3 = val_coord_3; +} + +inline void CNumerics::SetGridVel(su2double *val_gridvel_i, su2double *val_gridvel_j) { + GridVel_i = val_gridvel_i; + GridVel_j = val_gridvel_j; +} + +inline void CNumerics::SetWindGust(su2double *val_windgust_i, su2double *val_windgust_j) { + WindGust_i = val_windgust_i; + WindGust_j = val_windgust_j; +} + +inline void CNumerics::SetWindGustDer(su2double *val_windgustder_i, su2double *val_windgustder_j) { + WindGustDer_i = val_windgustder_i; + WindGustDer_j = val_windgustder_j; +} + +inline void CNumerics::SetPressure(su2double val_pressure_i, su2double val_pressure_j) { + Pressure_i = val_pressure_i; + Pressure_j = val_pressure_j; +} + +inline void CNumerics::SetDensityInc(su2double val_densityinc_i, su2double val_densityinc_j) { + DensityInc_i = val_densityinc_i; + DensityInc_j = val_densityinc_j; +} + +inline void CNumerics::SetBetaInc2(su2double val_betainc2_i, su2double val_betainc2_j) { + BetaInc2_i = val_betainc2_i; + BetaInc2_j = val_betainc2_j; +} + +inline void CNumerics::SetSoundSpeed(su2double val_soundspeed_i, su2double val_soundspeed_j) { + SoundSpeed_i = val_soundspeed_i; + SoundSpeed_j = val_soundspeed_j; +} + +inline void CNumerics::SetEnthalpy(su2double val_enthalpy_i, su2double val_enthalpy_j) { + Enthalpy_i = val_enthalpy_i; + Enthalpy_j = val_enthalpy_j; +} + +inline void CNumerics::SetLambda(su2double val_lambda_i, su2double val_lambda_j) { + Lambda_i = val_lambda_i; + Lambda_j = val_lambda_j; +} + +inline void CNumerics::SetNeighbor(unsigned short val_neighbor_i, unsigned short val_neighbor_j) { + Neighbor_i = val_neighbor_i; + Neighbor_j = val_neighbor_j; +} + +inline void CNumerics::SetTurbAdjointVar(su2double *val_turbpsivar_i, su2double *val_turbpsivar_j) { + TurbPsi_i = val_turbpsivar_i; + TurbPsi_j = val_turbpsivar_j; +} + +inline void CNumerics::SetTurbAdjointGradient(su2double **val_turbpsivar_grad_i, su2double **val_turbpsivar_grad_j) { + TurbPsi_Grad_i = val_turbpsivar_grad_i; + TurbPsi_Grad_j = val_turbpsivar_grad_j; +} + +inline void CNumerics::SetTemperature(su2double val_temp_i, su2double val_temp_j) { + Temp_i = val_temp_i; + Temp_j = val_temp_j; +} + +inline void CNumerics::SetAuxVarGrad(su2double *val_auxvargrad_i, su2double *val_auxvargrad_j) { + AuxVar_Grad_i = val_auxvargrad_i; + AuxVar_Grad_j = val_auxvargrad_j; +} + +inline void CNumerics::SetNormal(su2double *val_normal) { Normal = val_normal; } + +inline void CNumerics::SetVolume(su2double val_volume) { Volume = val_volume; } + +inline void CSourcePieceWise_TurbSST::SetF1blending(su2double val_F1_i, su2double val_F1_j) { + F1_i = val_F1_i; + F1_j = val_F1_j; +} + +inline void CSourcePieceWise_TurbSST::SetF2blending(su2double val_F2_i, su2double val_F2_j) { + F2_i = val_F2_i; + F2_j = val_F2_j; +} + +inline void CSourcePieceWise_TurbSST::SetCrossDiff(su2double val_CDkw_i, su2double val_CDkw_j) { + CDkw_i = val_CDkw_i; + CDkw_j = val_CDkw_j; +} + +inline void CSourcePieceWise_TurbSA::SetIntermittency(su2double intermittency_in) { intermittency = intermittency_in; } + +inline void CSourcePieceWise_TurbSA::SetProduction(su2double val_production) { Production = val_production; } + +inline void CSourcePieceWise_TurbSA::SetDestruction(su2double val_destruction) { Destruction = val_destruction; } + +inline void CSourcePieceWise_TurbSA::SetCrossProduction(su2double val_crossproduction) { CrossProduction = val_crossproduction; } + +inline su2double CSourcePieceWise_TurbSA::GetProduction(void) { return Production; } + +inline su2double CSourcePieceWise_TurbSA::GetDestruction(void) { return Destruction; } + +inline su2double CSourcePieceWise_TurbSA::GetCrossProduction(void) { return CrossProduction; } + +inline void CSourcePieceWise_TurbSA_Neg::SetIntermittency(su2double intermittency_in) { intermittency = intermittency_in; } + +inline void CSourcePieceWise_TurbSA_Neg::SetProduction(su2double val_production) { Production = val_production; } + +inline void CSourcePieceWise_TurbSA_Neg::SetDestruction(su2double val_destruction) { Destruction = val_destruction; } + +inline void CSourcePieceWise_TurbSA_Neg::SetCrossProduction(su2double val_crossproduction) { CrossProduction = val_crossproduction; } + +inline su2double CSourcePieceWise_TurbSA_Neg::GetProduction(void) { return Production; } + +inline su2double CSourcePieceWise_TurbSA_Neg::GetDestruction(void) { return Destruction; } + +inline su2double CSourcePieceWise_TurbSA_Neg::GetCrossProduction(void) { return CrossProduction; } + +inline su2double CUpwTurkel_Flow::GetPrecond_Beta() { return Beta; } + +inline void CNumerics::ComputeResidual(su2double **val_Jacobian_i, su2double *val_Jacobian_mui, su2double ***val_Jacobian_gradi, CConfig *config) { } + +inline void CNumerics::ComputeResidual(su2double **val_Jacobian_i, su2double *val_Jacobian_mui, su2double ***val_Jacobian_gradi, + su2double **val_Jacobian_j, su2double *val_Jacobian_muj, su2double ***val_Jacobian_gradj, CConfig *config) { } diff --git a/SU2_CFD/include/variable_structure.hpp b/SU2_CFD/include/variable_structure.hpp index c6bea324aa5..c10da24dcff 100644 --- a/SU2_CFD/include/variable_structure.hpp +++ b/SU2_CFD/include/variable_structure.hpp @@ -1,3836 +1,3836 @@ -/*! - * \file variable_structure.hpp - * \brief Headers of the main subroutines for storing all the variables for - * each kind of governing equation (direct, adjoint and linearized). - * The subroutines and functions are in the variable_structure.cpp file. - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -#include "../../Common/include/mpi_structure.hpp" - -#include -#include -#include - -#include "../../Common/include/config_structure.hpp" -#include "fluid_model.hpp" - - -using namespace std; - -/*! - * \class CVariable - * \brief Main class for defining the variables. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CVariable { -protected: - - su2double *Solution, /*!< \brief Solution of the problem. */ - *Solution_Old; /*!< \brief Old solution of the problem R-K. */ - bool Non_Physical; /*!< \brief Non-physical points in the solution (force first order). */ - su2double *Solution_time_n, /*!< \brief Solution of the problem at time n for dual-time stepping technique. */ - *Solution_time_n1; /*!< \brief Solution of the problem at time n-1 for dual-time stepping technique. */ - su2double **Gradient; /*!< \brief Gradient of the solution of the problem. */ - su2double *Limiter; /*!< \brief Limiter of the solution of the problem. */ - su2double *Solution_Max; /*!< \brief Max solution for limiter computation. */ - su2double *Solution_Min; /*!< \brief Min solution for limiter computation. */ - su2double AuxVar; /*!< \brief Auxiliar variable for gradient computation. */ - su2double *Grad_AuxVar; /*!< \brief Gradient of the auxiliar variable. */ - su2double Delta_Time; /*!< \brief Time step. */ - su2double Max_Lambda, /*!< \brief Maximun eingenvalue. */ - Max_Lambda_Inv, /*!< \brief Maximun inviscid eingenvalue. */ - Max_Lambda_Visc, /*!< \brief Maximun viscous eingenvalue. */ - Lambda; /*!< \brief Value of the eingenvalue. */ - su2double Sensor; /*!< \brief Pressure sensor for high order central scheme. */ - su2double *Undivided_Laplacian; /*!< \brief Undivided laplacian of the solution. */ - su2double *Res_TruncError, /*!< \brief Truncation error for multigrid cycle. */ - *Residual_Old, /*!< \brief Auxiliar structure for residual smoothing. */ - *Residual_Sum; /*!< \brief Auxiliar structure for residual smoothing. */ - static unsigned short nDim; /*!< \brief Number of dimension of the problem. */ - unsigned short nVar; /*!< \brief Number of variables of the problem, - note that this variable cannnot be static, it is possible to - have different number of nVar in the same problem. */ - unsigned short nPrimVar, nPrimVarGrad; /*!< \brief Number of variables of the problem, - note that this variable cannnot be static, it is possible to - have different number of nVar in the same problem. */ - unsigned short nSecondaryVar, nSecondaryVarGrad; /*!< \brief Number of variables of the problem, - note that this variable cannnot be static, it is possible to - have different number of nVar in the same problem. */ - -public: - - /*! - * \brief Constructor of the class. - */ - CVariable(void); - - /*! - * \overload - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CVariable(unsigned short val_nvar, CConfig *config); - - /*! - * \overload - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CVariable(unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - virtual ~CVariable(void); - - /*! - * \brief Set the value of the solution. - * \param[in] val_solution - Solution of the problem. - */ - void SetSolution(su2double *val_solution); - - /*! - * \overload - * \param[in] val_var - Index of the variable. - * \param[in] val_solution - Value of the solution for the index val_var. - */ - void SetSolution(unsigned short val_var, su2double val_solution); - - /*! - * \brief Set the value of the non-physical point. - * \param[in] val_value - identification of the non-physical point. - */ - void SetNon_Physical(bool val_value); - - /*! - * \brief Get the value of the non-physical point. - * \return Value of the Non-physical point. - */ - su2double GetNon_Physical(void); - - /*! - * \brief Get the solution. - * \param[in] val_var - Index of the variable. - * \return Value of the solution for the index val_var. - */ - su2double GetSolution(unsigned short val_var); - - /*! - * \brief Get the old solution of the problem (Runge-Kutta method) - * \param[in] val_var - Index of the variable. - * \return Pointer to the old solution vector. - */ - su2double GetSolution_Old(unsigned short val_var); - - /*! - * \brief Set the value of the old solution. - * \param[in] val_solution_old - Pointer to the residual vector. - */ - void SetSolution_Old(su2double *val_solution_old); - - /*! - * \overload - * \param[in] val_var - Index of the variable. - * \param[in] val_solution_old - Value of the old solution for the index val_var. - */ - void SetSolution_Old(unsigned short val_var, su2double val_solution_old); - - /*! - * \brief Set old variables to the value of the current variables. - */ - void Set_OldSolution(void); - - /*! - * \brief Set variables to the value of the old variables. - */ - void Set_Solution(void); - - /*! - * \brief Set the variable solution at time n. - */ - void Set_Solution_time_n(void); - - /*! - * \brief Set the variable solution at time n-1. - */ - void Set_Solution_time_n1(void); - - /*! - * \brief Set the variable solution at time n. - */ - void Set_Solution_time_n(su2double* val_sol); - - /*! - * \brief Set the variable solution at time n-1. - */ - void Set_Solution_time_n1(su2double* val_sol); - - /*! - * \brief Set to zero the velocity components of the solution. - */ - void SetVelSolutionZero(void); - - /*! - * \brief Specify a vector to set the velocity components of the solution. - * \param[in] val_vector - Pointer to the vector. - */ - void SetVelSolutionVector(su2double *val_vector); - - /*! - * \brief Set to zero velocity components of the solution. - */ - void SetVelSolutionOldZero(void); - - /*! - * \brief Specify a vector to set the velocity components of the old solution. - * \param[in] val_vector - Pointer to the vector. - */ - void SetVelSolutionOldVector(su2double *val_vector); - - /*! - * \brief Set to zero the solution. - */ - void SetSolutionZero(void); - - /*! - * \brief Set to zero a particular solution. - */ - void SetSolutionZero(unsigned short val_var); - - /*! - * \brief Add a value to the solution. - * \param[in] val_var - Number of the variable. - * \param[in] val_solution - Value that we want to add to the solution. - */ - void AddSolution(unsigned short val_var, su2double val_solution); - - /*! - * \brief Add a value to the solution, clipping the values. - * \param[in] val_var - Index of the variable. - * \param[in] val_solution - Value of the solution change. - * \param[in] lowerlimit - Lower value. - * \param[in] upperlimit - Upper value. - */ - void AddClippedSolution(unsigned short val_var, su2double val_solution, - su2double lowerlimit, su2double upperlimit); - - /*! - * \brief Update the variables using a conservative format. - * \param[in] val_var - Index of the variable. - * \param[in] val_solution - Value of the solution change. - * \param[in] val_density - Value of the density. - * \param[in] val_density_old - Value of the old density. - */ - void AddConservativeSolution(unsigned short val_var, su2double val_solution, - su2double val_density, su2double val_density_old, su2double lowerlimit, - su2double upperlimit); - - /*! - * \brief Get the solution of the problem. - * \return Pointer to the solution vector. - */ - su2double *GetSolution(void); - - /*! - * \brief Get the old solution of the problem (Runge-Kutta method) - * \return Pointer to the old solution vector. - */ - su2double *GetSolution_Old(void); - - /*! - * \brief Get the solution at time n. - * \return Pointer to the solution (at time n) vector. - */ - su2double *GetSolution_time_n(void); - - /*! - * \brief Get the solution at time n-1. - * \return Pointer to the solution (at time n-1) vector. - */ - su2double *GetSolution_time_n1(void); - - /*! - * \brief Set the value of the old residual. - * \param[in] val_residual_old - Pointer to the residual vector. - */ - void SetResidual_Old(su2double *val_residual_old); - - /*! - * \brief Add a value to the summed residual vector. - * \param[in] val_residual - Pointer to the residual vector. - */ - void AddResidual_Sum(su2double *val_residual); - - /*! - * \brief Set summed residual vector to zero value. - */ - void SetResidualSumZero(void); - - /*! - * \brief Set the velocity of the truncation error to zero. - */ - virtual void SetVel_ResTruncError_Zero(unsigned short iSpecies); - - /*! - * \brief Get the value of the summed residual. - * \return Pointer to the summed residual. - */ - su2double *GetResidual_Sum(void); - - /*! - * \brief Get the value of the old residual. - * \return Pointer to the old residual. - */ - su2double *GetResidual_Old(void); - - /*! - * \brief Get the value of the summed residual. - * \param[in] val_residual - Pointer to the summed residual. - */ - void GetResidual_Sum(su2double *val_residual); - - /*! - * \brief Set auxiliar variables, we are looking for the gradient of that variable. - * \param[in] val_auxvar - Value of the auxiliar variable. - */ - void SetAuxVar(su2double val_auxvar); - - /*! - * \brief Get the value of the auxiliary variable. - * \return Value of the auxiliary variable. - */ - su2double GetAuxVar(void); - - /*! - * \brief Set the auxiliary variable gradient to zero value. - */ - void SetAuxVarGradientZero(void); - - /*! - * \brief Set the value of the auxiliary variable gradient. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_gradient - Value of the gradient for the index val_dim. - */ - void SetAuxVarGradient(unsigned short val_dim, su2double val_gradient); - - /*! - * \brief Add a value to the auxiliary variable gradient. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value of the gradient to be added for the index val_dim. - */ - void AddAuxVarGradient(unsigned short val_dim, su2double val_value); - - /*! - * \brief Subtract a value to the auxiliary variable gradient. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value of the gradient to be subtracted for the index val_dim. - */ - void SubtractAuxVarGradient(unsigned short val_dim, su2double val_value); - - /*! - * \brief Get the gradient of the auxiliary variable. - * \return Value of the gradient of the auxiliary variable. - */ - su2double *GetAuxVarGradient(void); - - /*! - * \brief Get the gradient of the auxiliary variable. - * \param[in] val_dim - Index of the dimension. - * \return Value of the gradient of the auxiliary variable for the dimension val_dim. - */ - su2double GetAuxVarGradient(unsigned short val_dim); - - /*! - * \brief Add a value to the truncation error. - * \param[in] val_truncation_error - Value that we want to add to the truncation error. - */ - void AddRes_TruncError(su2double *val_truncation_error); - - /*! - * \brief Subtract a value to the truncation error. - * \param[in] val_truncation_error - Value that we want to subtract to the truncation error. - */ - void SubtractRes_TruncError(su2double *val_truncation_error); - - /*! - * \brief Set the truncation error to zero. - */ - void SetRes_TruncErrorZero(void); - - /*! - * \brief Set the truncation error to zero. - */ - void SetVal_ResTruncError_Zero(unsigned short val_var); - - /*! - * \brief Set the velocity of the truncation error to zero. - */ - void SetVel_ResTruncError_Zero(void); - - /*! - * \brief Set the velocity of the truncation error to zero. - */ - void SetEnergy_ResTruncError_Zero(void); - - /*! - * \brief Get the truncation error. - * \return Pointer to the truncation error. - */ - su2double *GetResTruncError(void); - - /*! - * \brief Get the truncation error. - * \param[in] val_trunc_error - Pointer to the truncation error. - */ - void GetResTruncError(su2double *val_trunc_error); - - /*! - * \brief Set the gradient of the solution. - * \param[in] val_gradient - Gradient of the solution. - */ - void SetGradient(su2double **val_gradient); - - /*! - * \overload - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value of the gradient. - */ - void SetGradient(unsigned short val_var, unsigned short val_dim, su2double val_value); - - /*! - * \brief Set to zero the gradient of the solution. - */ - void SetGradientZero(void); - - /*! - * \brief Add val_value to the solution gradient. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value to add to the solution gradient. - */ - void AddGradient(unsigned short val_var, unsigned short val_dim, su2double val_value); - - /*! - * \brief Subtract val_value to the solution gradient. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value to subtract to the solution gradient. - */ - void SubtractGradient(unsigned short val_var, unsigned short val_dim, su2double val_value); - - /*! - * \brief Get the value of the solution gradient. - * \return Value of the gradient solution. - */ - su2double **GetGradient(void); - - /*! - * \brief Get the value of the solution gradient. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \return Value of the solution gradient. - */ - su2double GetGradient(unsigned short val_var, unsigned short val_dim); - - /*! - * \brief Set the value of the limiter. - * \param[in] val_var - Index of the variable. - * \param[in] val_limiter - Value of the limiter for the index val_var. - */ - void SetLimiter(unsigned short val_var, su2double val_limiter); - - /*! - * \brief Set the value of the limiter. - * \param[in] val_var - Index of the variable. - * \param[in] val_limiter - Value of the limiter for the index val_var. - */ - virtual void SetLimiterPrimitive(unsigned short val_species, unsigned short val_var, su2double val_limiter); - - /*! - * \brief Set the value of the limiter. - * \param[in] val_species - Value of the limiter for the index val_var. - * \param[in] val_var - Index of the variable. - */ - virtual su2double GetLimiterPrimitive(unsigned short val_species, unsigned short val_var); - - /*! - * \brief Set the value of the max solution. - * \param[in] val_var - Index of the variable. - * \param[in] val_solution - Value of the max solution for the index val_var. - */ - void SetSolution_Max(unsigned short val_var, su2double val_solution); - - /*! - * \brief Set the value of the min solution. - * \param[in] val_var - Index of the variable. - * \param[in] val_solution - Value of the min solution for the index val_var. - */ - void SetSolution_Min(unsigned short val_var, su2double val_solution); - - /*! - * \brief Get the value of the slope limiter. - * \return Pointer to the limiters vector. - */ - su2double *GetLimiter(void); - - /*! - * \brief Get the value of the slope limiter. - * \param[in] val_var - Index of the variable. - * \return Value of the limiter vector for the variable val_var. - */ - su2double GetLimiter(unsigned short val_var); - - /*! - * \brief Get the value of the min solution. - * \param[in] val_var - Index of the variable. - * \return Value of the min solution for the variable val_var. - */ - su2double GetSolution_Max(unsigned short val_var); - - /*! - * \brief Get the value of the min solution. - * \param[in] val_var - Index of the variable. - * \return Value of the min solution for the variable val_var. - */ - su2double GetSolution_Min(unsigned short val_var); - - /*! - * \brief Get the value of the preconditioner Beta. - * \return Value of the low Mach preconditioner variable Beta - */ - virtual su2double GetPreconditioner_Beta(); - - /*! - * \brief Set the value of the preconditioner Beta. - * \param[in] val_Beta - Value of the low Mach preconditioner variable Beta - */ - virtual void SetPreconditioner_Beta(su2double val_Beta); - - /*! - * \brief Get the value of the wind gust - * \return Value of the wind gust - */ - virtual su2double* GetWindGust(); - - /*! - * \brief Set the value of the wind gust - * \param[in] val_WindGust - Value of the wind gust - */ - virtual void SetWindGust(su2double* val_WindGust); - - /*! - * \brief Get the value of the derivatives of the wind gust - * \return Value of the derivatives of the wind gust - */ - virtual su2double* GetWindGustDer(); - - /*! - * \brief Set the value of the derivatives of the wind gust - * \param[in] val_WindGust - Value of the derivatives of the wind gust - */ - virtual void SetWindGustDer(su2double* val_WindGust); - - /*! - * \brief Set the value of the time step. - * \param[in] val_delta_time - Value of the time step. - */ - void SetDelta_Time(su2double val_delta_time); - - /*! - * \brief Set the value of the time step. - * \param[in] val_delta_time - Value of the time step. - * \param[in] iSpecies - Index of the Species . - */ - virtual void SetDelta_Time(su2double val_delta_time, unsigned short iSpecies); - - /*! - * \brief Get the value of the time step. - * \return Value of the time step. - */ - su2double GetDelta_Time(void); - - /*! - * \brief Get the value of the time step. - * \param[in] iSpecies - Index of the Species - * \return Value of the time step. - */ - virtual su2double GetDelta_Time(unsigned short iSpecies); - - /*! - * \brief Set the value of the maximum eigenvalue. - * \param[in] val_max_lambda - Value of the maximum eigenvalue. - */ - void SetMax_Lambda(su2double val_max_lambda); - - /*! - * \brief Set the value of the maximum eigenvalue for the inviscid terms of the PDE. - * \param[in] val_max_lambda - Value of the maximum eigenvalue for the inviscid terms of the PDE. - */ - void SetMax_Lambda_Inv(su2double val_max_lambda); - - /*! - * \brief Set the value of the maximum eigenvalue for the inviscid terms of the PDE. - * \param[in] val_max_lambda - Value of the maximum eigenvalue for the inviscid terms of the PDE. - * \param[in] val_species - Value of the species index to set the maximum eigenvalue. - */ - virtual void SetMax_Lambda_Inv(su2double val_max_lambda, unsigned short val_species); - - /*! - * \brief Set the value of the maximum eigenvalue for the viscous terms of the PDE. - * \param[in] val_max_lambda - Value of the maximum eigenvalue for the viscous terms of the PDE. - */ - void SetMax_Lambda_Visc(su2double val_max_lambda); - - /*! - * \brief Set the value of the maximum eigenvalue for the viscous terms of the PDE. - * \param[in] val_max_lambda - Value of the maximum eigenvalue for the viscous terms of the PDE. - * \param[in] val_species - Index of the species to set the maximum eigenvalue of the viscous terms. - */ - virtual void SetMax_Lambda_Visc(su2double val_max_lambda, unsigned short val_species); - - /*! - * \brief Add a value to the maximum eigenvalue. - * \param[in] val_max_lambda - Value of the maximum eigenvalue. - */ - void AddMax_Lambda(su2double val_max_lambda); - - /*! - * \brief Add a value to the maximum eigenvalue for the inviscid terms of the PDE. - * \param[in] val_max_lambda - Value of the maximum eigenvalue for the inviscid terms of the PDE. - */ - void AddMax_Lambda_Inv(su2double val_max_lambda); - - /*! - * \brief Add a value to the maximum eigenvalue for the viscous terms of the PDE. - * \param[in] val_max_lambda - Value of the maximum eigenvalue for the viscous terms of the PDE. - */ - void AddMax_Lambda_Visc(su2double val_max_lambda); - - /*! - * \brief Get the value of the maximum eigenvalue. - * \return the value of the maximum eigenvalue. - */ - su2double GetMax_Lambda(void); - - /*! - * \brief Get the value of the maximum eigenvalue for the inviscid terms of the PDE. - * \return the value of the maximum eigenvalue for the inviscid terms of the PDE. - */ - su2double GetMax_Lambda_Inv(void); - - /*! - * \brief Get the value of the maximum eigenvalue for the viscous terms of the PDE. - * \return the value of the maximum eigenvalue for the viscous terms of the PDE. - */ - su2double GetMax_Lambda_Visc(void); - - /*! - * \brief Set the value of the spectral radius. - * \param[in] val_lambda - Value of the spectral radius. - */ - void SetLambda(su2double val_lambda); - - /*! - * \brief Set the value of the spectral radius. - * \param[in] val_lambda - Value of the spectral radius. - * \param[in] val_iSpecies -Index of species - */ - virtual void SetLambda(su2double val_lambda, unsigned short val_iSpecies); - - /*! - * \brief Add the value of the spectral radius. - * \param[in] val_lambda - Value of the spectral radius. - */ - void AddLambda(su2double val_lambda); - - /*! - * \brief Add the value of the spectral radius. - * \param[in] val_iSpecies -Index of species - * \param[in] val_lambda - Value of the spectral radius. - */ - virtual void AddLambda(su2double val_lambda, unsigned short val_iSpecies); - - /*! - * \brief Get the value of the spectral radius. - * \return Value of the spectral radius. - */ - su2double GetLambda(void); - - /*! - * \brief Get the value of the spectral radius. - * \param[in] val_iSpecies -Index of species - * \return Value of the spectral radius. - */ - virtual su2double GetLambda(unsigned short val_iSpecies); - - /*! - * \brief Set pressure sensor. - * \param[in] val_sensor - Value of the pressure sensor. - */ - void SetSensor(su2double val_sensor); - - /*! - * \brief Set pressure sensor. - * \param[in] val_sensor - Value of the pressure sensor. - * \param[in] val_sensor - Index of the Species. - */ - virtual void SetSensor(su2double val_sensor, unsigned short iSpecies); - - /*! - * \brief Get the pressure sensor. - * \return Value of the pressure sensor. - */ - su2double GetSensor(void); - - /*! - * \brief Get the pressure sensor. - * \param[in] iSpecies - index of species - * \return Value of the pressure sensor. - */ - virtual su2double GetSensor(unsigned short iSpecies); - - /*! - * \brief Set the value of the undivided laplacian of the solution. - * \param[in] val_var - Index of the variable. - * \param[in] val_undivided_laplacian - Value of the undivided solution for the index val_var. - */ - void SetUndivided_Laplacian(unsigned short val_var, su2double val_undivided_laplacian); - - /*! - * \brief Add the value of the undivided laplacian of the solution. - * \param[in] val_und_lapl - Value of the undivided solution. - */ - void AddUnd_Lapl(su2double *val_und_lapl); - - /*! - * \brief Subtract the value of the undivided laplacian of the solution. - * \param[in] val_und_lapl - Value of the undivided solution. - */ - void SubtractUnd_Lapl(su2double *val_und_lapl); - - /*! - * \brief Subtract the value of the undivided laplacian of the solution. - * \param[in] val_var - Variable of the undivided laplacian. - * \param[in] val_und_lapl - Value of the undivided solution. - */ - void SubtractUnd_Lapl(unsigned short val_var, su2double val_und_lapl); - - /*! - * \brief Set the undivided laplacian of the solution to zero. - */ - void SetUnd_LaplZero(void); - - /*! - * \brief Set a value to the undivided laplacian. - * \param[in] val_var - Variable of the undivided laplacian. - * \param[in] val_und_lapl - Value of the undivided laplacian. - */ - void SetUnd_Lapl(unsigned short val_var, su2double val_und_lapl); - - /*! - * \brief Get the undivided laplacian of the solution. - * \return Pointer to the undivided laplacian vector. - */ - su2double *GetUndivided_Laplacian(void); - - /*! - * \brief Get the undivided laplacian of the solution. - * \param[in] val_var - Variable of the undivided laplacian. - * \return Value of the undivided laplacian vector. - */ - su2double GetUndivided_Laplacian(unsigned short val_var); - - /*! - * \brief A virtual member. - * \return Value of the flow density. - */ - virtual su2double GetDensity(void); - - /*! - * \brief A virtual member. - * \return Value of the flow density. - */ - virtual su2double GetDensity(unsigned short val_iSpecies); - - /*! - * \brief A virtual member. - * \param[in] val_Species - Index of species s. - * \return Value of the mass fraction of species s. - */ - virtual su2double GetMassFraction(unsigned short val_Species); - - /*! - * \brief A virtual member. - * \return Value of the flow energy. - */ - virtual su2double GetEnergy(void); - - /*! - * \brief A virtual member. - * \return Pointer to the force projection vector. - */ - virtual su2double *GetForceProj_Vector(void); - - /*! - * \brief A virtual member. - * \return Pointer to the objective function source. - */ - virtual su2double *GetObjFuncSource(void); - - /*! - * \brief A virtual member. - * \return Pointer to the internal boundary vector. - */ - virtual su2double *GetIntBoundary_Jump(void); - - /*! - * \brief A virtual member. - * \return Value of the eddy viscosity. - */ - virtual su2double GetEddyViscosity(void); - - /*! - * \brief A virtual member. - * \return Value of the eddy viscosity. - */ - virtual su2double GetEddyViscosityInc(void); - - /*! - * \brief A virtual member. - * \return Value of the flow enthalpy. - */ - virtual su2double GetEnthalpy(void); - - /*! - * \brief A virtual member. - * \return Value of the flow pressure. - */ - virtual su2double GetPressure(void); - - /*! - * \brief A virtual member. - * \return Value of the flow pressure. - */ - virtual su2double GetPressureInc(void); - - /*! - * \brief A virtual member. - * \param[in] val_vector - Direction of projection. - * \return Value of the projected velocity. - */ - virtual su2double GetProjVel(su2double *val_vector); - - /*! - * \brief A virtual member. - * \param[in] val_vector - Direction of projection. - * \param[in] val_species - Index of the desired species. - * \return Value of the projected velocity. - */ - virtual su2double GetProjVel(su2double *val_vector, unsigned short val_species); - - /*! - * \brief A virtual member. - * \return Value of the sound speed. - */ - virtual su2double GetSoundSpeed(void); - - /*! - * \brief A virtual member. - * \return Value of the density for the incompressible flow. - */ - virtual su2double GetDensityInc(void); - - /*! - * \brief A virtual member. - * \return Value of the levelset for the freesurface flows. - */ - virtual su2double GetLevelSet(void); - - /*! - * \brief A virtual member. - * \return Value of the distance for the freesurface flows. - */ - virtual su2double GetDistance(void); - - /*! - * \brief A virtual member. - * \return Value of the beta for the incompressible flow. - */ - virtual su2double GetBetaInc2(void); - - /*! - * \brief A virtual member. - * \return Value of the temperature. - */ - virtual su2double GetTemperature(void); - - /*! - * \brief A virtual member. - * \return Value of the vibrational-electronic temperature. - */ - virtual su2double GetTemperature_ve(void); - - /*! - * \brief A virtual member -- Get the mixture specific heat at constant volume (trans.-rot.). - * \return \f$\rho C^{t-r}_{v} \f$ - */ - virtual su2double GetRhoCv_tr(void); - - /*! - * \brief A virtual member -- Get the mixture specific heat at constant volume (vib.-el.). - * \return \f$\rho C^{v-e}_{v} \f$ - */ - virtual su2double GetRhoCv_ve(void); - - /*! - * \brief A virtual member. - * \param[in] val_dim - Index of the dimension. - * \return Value of the velocity for the dimension val_dim. - */ - virtual su2double GetVelocity(unsigned short val_dim); - - /*! - * \brief A virtual member. - * \return Norm 2 of the velocity vector. - */ - virtual su2double GetVelocity2(void); - - /*! - * \brief A virtual member. - * \return Norm 2 of the velocity vector of Fluid val_species. - */ - virtual su2double GetVelocity2(unsigned short val_species); - - /*! - * \brief A virtual member. - * \return The laminar viscosity of the flow. - */ - virtual su2double GetLaminarViscosity(void); - - /*! - * \brief A virtual member. - * \return The laminar viscosity of the incompressible flow. - */ - virtual su2double GetLaminarViscosityInc(void); - - /*! - * \brief A virtual member. - * \return The laminar viscosity of the flow. - */ - virtual su2double GetLaminarViscosity(unsigned short iSpecies); - - /*! - * \brief A virtual member. - * \return Value of the species diffusion coefficient. - */ - virtual su2double* GetDiffusionCoeff(void); - - /*! - * \brief A virtual member. - * \return Value of the thermal conductivity (translational/rotational) - */ - virtual su2double GetThermalConductivity(void); - - /*! - * \brief A virtual member. - * \return Value of the specific heat at constant P - */ - virtual su2double GetSpecificHeatCp(void); - - /*! - * \brief A virtual member. - * \return Value of the thermal conductivity (vibrational) - */ - virtual su2double GetThermalConductivity_ve(void); - - /*! - * \brief A virtual member. - * \return Sets separation intermittency - */ - virtual void SetGammaSep(su2double gamma_sep); - - /*! - * \brief A virtual member. - * \return Sets separation intermittency - */ - virtual void SetGammaEff(void); - - /*! - * \brief A virtual member. - * \return Returns intermittency - */ - virtual su2double GetIntermittency(); - - /*! - * \brief A virtual member. - * \param[in] val_dim - Index of the dimension. - * \return Value of the vorticity. - */ - virtual su2double *GetVorticity(void); - - /*! - * \brief A virtual member. - * \return Value of the rate of strain magnitude. - */ - virtual su2double GetStrainMag(void); - - /*! - * \brief A virtual member. - * \param[in] val_ForceProj_Vector - Pointer to the force projection vector. - */ - virtual void SetForceProj_Vector(su2double *val_ForceProj_Vector); - - /*! - * \brief A virtual member. - * \param[in] val_SetObjFuncSource - Pointer to the objective function source. - */ - virtual void SetObjFuncSource(su2double *val_SetObjFuncSource); - - /*! - * \brief A virtual member. - * \param[in] val_IntBoundary_Jump - Pointer to the interior boundary jump. - */ - virtual void SetIntBoundary_Jump(su2double *val_IntBoundary_Jump); - - /*! - * \brief A virtual member. - * \param[in] eddy_visc - Value of the eddy viscosity. - */ - virtual void SetEddyViscosity(su2double eddy_visc); - - /*! - * \brief A virtual member. - * \param[in] eddy_visc - Value of the eddy viscosity. - */ - virtual void SetEddyViscosityInc(su2double eddy_visc); - - /*! - * \brief A virtual member. - */ - virtual void SetEnthalpy(void); - - /*! - * \brief A virtual member. - */ - virtual bool SetPrimVar_Compressible(CConfig *config); - - /*! - * \brief A virtual member. - */ - virtual bool SetPrimVar_Compressible(CFluidModel *FluidModel); - - /*! - * \brief A virtual member. - */ - virtual void SetSecondaryVar_Compressible(CFluidModel *FluidModel); - - /*! - * \brief A virtual member. - */ - virtual bool Cons2PrimVar(CConfig *config, su2double *U, su2double *V, - su2double *dPdU, su2double *dTdU, - su2double *dTvedU); - /*! - * \brief A virtual member. - */ - virtual void Prim2ConsVar(CConfig *config, su2double *V, su2double *U); - - /*! - * \brief A virtual member. - */ - virtual bool SetPrimVar_Compressible(su2double SharpEdge_Distance, bool check, CConfig *config); - - /*! - * \brief A virtual member. - */ - virtual bool SetPrimVar_Incompressible(su2double SharpEdge_Distance, bool check, CConfig *config); - - /*! - * \brief A virtual member. - */ - virtual bool SetPrimVar_FreeSurface(su2double SharpEdge_Distance, bool check, CConfig *config); - - /*! - * \brief A virtual member. - */ - virtual bool SetPrimVar_Compressible(su2double eddy_visc, su2double turb_ke, CConfig *config); - - /*! - * \brief A virtual member. - */ - virtual bool SetPrimVar_Compressible(su2double eddy_visc, su2double turb_ke, CFluidModel *FluidModel); - - /*! - * \brief A virtual member. - */ - virtual bool SetPrimVar_Incompressible(su2double Density_Inf, CConfig *config); - - /*! - * \brief A virtual member. - */ - virtual bool SetPrimVar_FreeSurface(CConfig *config); - - /*! - * \brief A virtual member. - */ - virtual bool SetPrimVar_Incompressible(su2double Density_Inf, su2double Viscosity_Inf, su2double eddy_visc, su2double turb_ke, CConfig *config); - - /*! - * \brief A virtual member. - */ - virtual bool SetPrimVar_FreeSurface(su2double eddy_visc, su2double turb_ke, CConfig *config); - - /*! - * \brief A virtual member. - */ - virtual su2double GetPrimitive(unsigned short val_var); - - /*! - * \brief A virtual member. - */ - virtual void SetPrimitive(unsigned short val_var, su2double val_prim); - - /*! - * \brief A virtual member. - */ - virtual void SetPrimitive(su2double *val_prim); - - /*! - * \brief A virtual member. - */ - virtual su2double *GetPrimitive(void); - - /*! - * \brief A virtual member. - */ - virtual su2double GetSecondary(unsigned short val_var); - - /*! - * \brief A virtual member. - */ - virtual void SetSecondary(unsigned short val_var, su2double val_secondary); - - /*! - * \brief A virtual member. - */ - virtual void SetSecondary(su2double *val_secondary); - - /*! - * \brief A virtual member. - */ - virtual void SetdPdrho_e(su2double dPdrho_e); - - /*! - * \brief A virtual member. - */ - virtual void SetdPde_rho(su2double dPde_rho); - - /*! - * \brief A virtual member. - */ - virtual void SetdTdrho_e(su2double dTdrho_e); - - /*! - * \brief A virtual member. - */ - virtual void SetdTde_rho(su2double dTde_rho); - - /*! - * \brief A virtual member. - */ - virtual void Setdmudrho_T(su2double dmudrho_T); - - /*! - * \brief A virtual member. - */ - virtual void SetdmudT_rho(su2double dmudT_rho); - - /*! - * \brief A virtual member. - */ - virtual void Setdktdrho_T(su2double dktdrho_T); - - /*! - * \brief A virtual member. - */ - virtual void SetdktdT_rho(su2double dktdT_rho); - - /*! - * \brief A virtual member. - */ - virtual su2double *GetSecondary(void); - - /*! - * \brief A virtual member. - */ - virtual void SetDensityInc(su2double val_density); - - /*! - * \brief A virtual member. - */ - virtual void SetPressureInc(void); - - /*! - * \brief A virtual member. - */ - virtual void SetVelocityInc(void); - - /*! - * \brief A virtual member. - */ - virtual void SetBetaInc2(su2double val_betainc2); - - /*! - * \brief A virtual member. - * \param[in] val_phi - Value of the adjoint velocity. - */ - virtual void SetPhi_Old(su2double *val_phi); - - /*! - * \brief A virtual member. - * \param[in] Gamma - Ratio of Specific heats - */ - virtual bool SetPressure(su2double Gamma); - - /*! - * \brief A virtual member. - * \param[in] config - */ - virtual bool SetPressure(CConfig *config); - - /*! - * \brief A virtual member. - */ - virtual bool SetPressure(su2double Gamma, su2double turb_ke); - - /*! - * \brief A virtual member. - */ - virtual void SetPressure(void); - - /*! - * \brief Calculates vib.-el. energy per mass, \f$e^{vib-el}_s\f$, for input species (not including KE) - */ - virtual su2double CalcEve(su2double *V, CConfig *config, unsigned short val_Species); - - /*! - * \brief Calculates enthalpy per mass, \f$h_s\f$, for input species (not including KE) - */ - virtual su2double CalcHs(su2double *V, CConfig *config, unsigned short val_Species); - - /*! - * \brief Calculates enthalpy per mass, \f$Cv_s\f$, for input species (not including KE) - */ - virtual su2double CalcCvve(su2double val_Tve, CConfig *config, unsigned short val_Species); - - /*! - * \brief A virtual member. - * \param[in] config - Configuration settings - */ - virtual void CalcdPdU(su2double *V, CConfig *config, su2double *dPdU); - - /*! - * \brief Set partial derivative of temperature w.r.t. density \f$\frac{\partial P}{\partial \rho_s}\f$ - */ - virtual void CalcdTdU(su2double *V, CConfig *config, su2double *dTdU); - - /*! - * \brief Set partial derivative of temperature w.r.t. density \f$\frac{\partial P}{\partial \rho_s}\f$ - */ - virtual void CalcdTvedU(su2double *V, CConfig *config, su2double *dTdU); - - /*! - * \brief A virtual member. - */ - virtual su2double *GetdPdU(void); - - /*! - * \brief A virtual member. - */ - virtual su2double *GetdTdU(void); - - /*! - * \brief A virtual member. - */ - virtual su2double *GetdTvedU(void); - - /*! - * \brief A virtual member. - */ - virtual bool SetDensity(void); - - /*! - * \brief A virtual member. - * \param[in] val_velocity - Value of the velocity. - * \param[in] Gamma - Ratio of Specific heats - */ - virtual void SetDeltaPressure(su2double *val_velocity, su2double Gamma); - - /*! - * \brief A virtual member. - * \param[in] Gamma - Ratio of specific heats. - */ - virtual bool SetSoundSpeed(su2double Gamma); - - /*! - * \brief A virtual member. - * \param[in] config - Configuration parameters. - */ - virtual bool SetSoundSpeed(CConfig *config); - - /*! - * \brief A virtual member. - */ - virtual bool SetSoundSpeed(void); - - /*! - * \brief A virtual member. - * \param[in] Gas_Constant - Value of the Gas Constant - */ - virtual bool SetTemperature(su2double Gas_Constant); - - /*! - * \brief Sets the vibrational electronic temperature of the flow. - * \return Value of the temperature of the flow. - */ - virtual bool SetTemperature_ve(su2double val_Tve); - - /*! - * \brief A virtual member. - * \param[in] config - Configuration parameters. - */ - virtual bool SetTemperature(CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] config - Configuration parameters. - */ - virtual void SetPrimitive(CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] config - Configuration parameters. - */ - virtual void SetPrimitive(CConfig *config, su2double *Coord); - - /*! - * \brief A virtual member. - * \param[in] Temperature_Wall - Value of the Temperature at the wall - */ - virtual void SetWallTemperature(su2double Temperature_Wall); - - /*! - * \brief A virtual member. - * \param[in] Temperature_Wall - Value of the Temperature at the wall - */ - virtual void SetWallTemperature(su2double* Temperature_Wall); - - /*! - * \brief Set the thermal coefficient. - * \param[in] config - Configuration parameters. - */ - virtual void SetThermalCoeff(CConfig *config); - - /*! - * \brief A virtual member. - */ - virtual void SetVelocity(void); - - /*! - * \brief A virtual member. - */ - virtual void SetStress(unsigned short iVar, unsigned short jVar, su2double val_stress); - - /*! - * \brief A virtual member. - */ - virtual void AddStress(unsigned short iVar, unsigned short jVar, su2double val_stress); - - /*! - * \brief A virtual member. - - */ - virtual su2double **GetStress(void); - - /*! - * \brief A virtual member. - */ - virtual void SetVonMises_Stress(su2double val_stress); - - /*! - * \brief A virtual member. - - */ - virtual su2double GetVonMises_Stress(void); - - /*! - * \brief A virtual member. - */ - virtual void SetFlow_Pressure(su2double val_pressure); - - /*! - * \brief A virtual member. - - */ - virtual su2double GetFlow_Pressure(void); - - /*! - * \brief A virtual member. - */ - virtual void Initialize_Connectivity(void); - - /*! - * \brief A virtual member. - */ - virtual void Upgrade_Connectivity(void); - - /*! - * \brief A virtual member. - */ - virtual unsigned short Get_Connectivity(void); - - - /*! - * \brief A virtual member. - */ - virtual void SetTraction(unsigned short iVar, unsigned short jVar, su2double val_traction); - - /*! - * \brief A virtual member. - */ - virtual void AddTraction(unsigned short iVar, unsigned short jVar, su2double val_traction); - - /*! - * \brief A virtual member. - - */ - virtual su2double **GetTraction(void); - - - /*! - * \brief A virtual member. - */ - virtual void SetVelocity2(void); - - /*! - * \brief A virtual member. - * \param[in] val_velocity - Pointer to the velocity. - */ - virtual void SetVelocity_Old(su2double *val_velocity); - - /*! - * \brief A virtual member. - * \param[in] val_velocity - Pointer to the velocity. - */ - virtual void SetVelocityInc_Old(su2double *val_velocity); - - /*! - * \brief A virtual member. - * \param[in] laminarViscosity - */ - virtual void SetLaminarViscosity(su2double laminarViscosity); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetLaminarViscosity(CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] val_laminar_viscosity_inc - Value of the laminar viscosity (incompressible flows). - */ - virtual void SetLaminarViscosityInc(su2double val_laminar_viscosity_inc); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetThermalConductivity(su2double thermalConductivity); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetThermalConductivity(CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetSpecificHeatCp(su2double Cp); - - /*! - * \brief A virtual member. - */ - virtual bool SetVorticity(bool val_limiter); - - /*! - * \brief A virtual member. - */ - virtual bool SetStrainMag(bool val_limiter); - - /*! - * \brief A virtual member. - */ - virtual void SetVelSolutionOldDVector(void); - - /*! - * \brief A virtual member. - */ - virtual void SetVelSolutionDVector(void); - - /*! - * \brief A virtual member. - */ - virtual void SetGradient_PrimitiveZero(unsigned short val_primvar); - - /*! - * \brief A virtual member. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value to add to the gradient of the primitive variables. - */ - virtual void AddGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value); - - /*! - * \brief A virtual member. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value to subtract to the gradient of the primitive variables. - */ - virtual void SubtractGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value); - - /*! - * \brief A virtual member. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \return Value of the primitive variables gradient. - */ - virtual su2double GetGradient_Primitive(unsigned short val_var, unsigned short val_dim); - - /*! - * \brief A virtual member. - * \param[in] val_var - Index of the variable. - * \return Value of the primitive variables gradient. - */ - virtual su2double GetLimiter_Primitive(unsigned short val_var); - - /*! - * \brief A virtual member. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value of the gradient. - */ - virtual void SetGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value); - - /*! - * \brief A virtual member. - * \param[in] val_var - Index of the variable. - * \param[in] val_value - Value of the gradient. - */ - virtual void SetLimiter_Primitive(unsigned short val_var, su2double val_value); - - /*! - * \brief A virtual member. - * \return Value of the primitive variables gradient. - */ - virtual su2double **GetGradient_Primitive(void); - - /*! - * \brief A virtual member. - * \return Value of the primitive variables gradient. - */ - virtual su2double *GetLimiter_Primitive(void); - - /*! - * \brief A virtual member. - */ - virtual void SetGradient_SecondaryZero(unsigned short val_secondaryvar); - - /*! - * \brief A virtual member. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value to add to the gradient of the Secondary variables. - */ - virtual void AddGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value); - - /*! - * \brief A virtual member. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value to subtract to the gradient of the Secondary variables. - */ - virtual void SubtractGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value); - - /*! - * \brief A virtual member. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \return Value of the Secondary variables gradient. - */ - virtual su2double GetGradient_Secondary(unsigned short val_var, unsigned short val_dim); - - /*! - * \brief A virtual member. - * \param[in] val_var - Index of the variable. - * \return Value of the Secondary variables gradient. - */ - virtual su2double GetLimiter_Secondary(unsigned short val_var); - - /*! - * \brief A virtual member. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value of the gradient. - */ - virtual void SetGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value); - - /*! - * \brief A virtual member. - * \param[in] val_var - Index of the variable. - * \param[in] val_value - Value of the gradient. - */ - virtual void SetLimiter_Secondary(unsigned short val_var, su2double val_value); - - /*! - * \brief A virtual member. - * \return Value of the Secondary variables gradient. - */ - virtual su2double **GetGradient_Secondary(void); - - /*! - * \brief A virtual member. - * \return Value of the Secondary variables gradient. - */ - virtual su2double *GetLimiter_Secondary(void); - - /*! - * \brief Set the blending function for the blending of k-w and k-eps. - * \param[in] val_viscosity - Value of the vicosity. - * \param[in] val_density - Value of the density. - * \param[in] val_dist - Value of the distance to the wall. - */ - virtual void SetBlendingFunc(su2double val_viscosity, su2double val_dist, su2double val_density); - - /*! - * \brief Get the first blending function of the SST model. - */ - virtual su2double GetF1blending(void); - - /*! - * \brief Get the second blending function of the SST model. - */ - virtual su2double GetF2blending(void); - - /*! - * \brief Get the value of the cross diffusion of tke and omega. - */ - virtual su2double GetCrossDiff(void) { return 0.0; }; - - /*! - * \brief Get the value of the eddy viscosity. - * \return the value of the eddy viscosity. - */ - virtual su2double GetmuT(void); - - /*! - * \brief Set the value of the eddy viscosity. - * \param[in] val_muT - */ - virtual void SetmuT(su2double val_muT); - - /*! - * \brief Add a value to the maximum eigenvalue for the inviscid terms of the PDE. - * \param[in] val_max_lambda - Value of the maximum eigenvalue for the inviscid terms of the PDE. - * \param[in] iSpecies - Value of iSpecies to which the eigenvalue belongs - */ - virtual void AddMax_Lambda_Inv(su2double val_max_lambda, unsigned short iSpecies); - - /*! - * \brief Add a value to the maximum eigenvalue for the viscous terms of the PDE. - * \param[in] val_max_lambda - Value of the maximum eigenvalue for the viscous terms of the PDE. - * \param[in] iSpecies - Value of iSpecies to which the eigenvalue belongs - */ - virtual void AddMax_Lambda_Visc(su2double val_max_lambda, unsigned short iSpecies); - - /*! - * \brief A virtual member. - * \param[in] val_difflevelset - Value of the diff level set (value-target). - */ - virtual void SetDiffLevelSet(su2double val_difflevelset); - - /*! - * \brief A virtual member. - */ - virtual su2double GetDiffLevelSet(void); - - /*! - * \brief A virtual member. - * \param[in] val_source - Value of the time spectral source. - */ - virtual void SetTimeSpectral_Source(unsigned short val_var, su2double val_source); - - /*! - * \brief A virtual member. - */ - virtual su2double GetTimeSpectral_Source(unsigned short val_var); - - /*! - * \brief Set the Eddy Viscosity Sensitivity of the problem. - * \param[in] val_EddyViscSens - Eddy Viscosity Sensitivity. - */ - virtual void SetEddyViscSens(su2double *val_EddyViscSens, unsigned short numTotalVar); - - /*! - * \brief Get the Eddy Viscosity Sensitivity of the problem. - * \return Pointer to the Eddy Viscosity Sensitivity. - */ - virtual su2double *GetEddyViscSens(void); - - /*! - * \brief A virtual member. Set the direct solution for the adjoint solver. - * \param[in] val_solution_direct - Value of the direct solution. - */ - virtual void SetSolution_Direct(su2double *val_solution_direct); - - /*! - * \brief A virtual member. Get the direct solution for the adjoint solver. - * \return Pointer to the direct solution vector. - */ - virtual su2double *GetSolution_Direct(void); - - - /*! - * STRUCTURAL ANALYSIS: NEW VARIABLES - */ - - /*! - * \brief Set the value of the old solution. - * \param[in] val_solution_old - Pointer to the residual vector. - */ - virtual void SetSolution_time_n(void); - - /*! - * \brief Set the value of the old solution. - * \param[in] val_solution_old - Pointer to the residual vector. - */ - virtual void SetSolution_time_n(su2double *val_solution_time_n); - - - /*! - * \brief Set the value of the velocity (Structural Analysis). - * \param[in] val_solution - Solution of the problem (velocity). - */ - virtual void SetSolution_Vel(su2double *val_solution); - - /*! - * \overload - * \param[in] val_var - Index of the variable. - * \param[in] val_solution - Value of the solution for the index val_var. - */ - virtual void SetSolution_Vel(unsigned short val_var, su2double val_solution_vel); - - /*! - * \brief Set the value of the velocity (Structural Analysis) at time n. - * \param[in] val_solution_old - Pointer to the residual vector. - */ - virtual void SetSolution_Vel_time_n(su2double *val_solution_vel_time_n); - - /*! - * \brief Set the value of the velocity (Structural Analysis) at time n. - * \param[in] val_solution_old - Pointer to the residual vector. - */ - virtual void SetSolution_Vel_time_n(void); - - /*! - * \overload - * \param[in] val_var - Index of the variable. - * \param[in] val_solution_old - Value of the old solution for the index val_var. - */ - virtual void SetSolution_Vel_time_n(unsigned short val_var, su2double val_solution_vel_time_n); - - /*! - * \brief Get the solution at time n. - * \param[in] val_var - Index of the variable. - * \return Value of the solution for the index val_var. - */ - virtual su2double GetSolution_time_n(unsigned short val_var); - - /*! - * \brief Get the velocity (Structural Analysis). - * \param[in] val_var - Index of the variable. - * \return Value of the solution for the index val_var. - */ - virtual su2double GetSolution_Vel(unsigned short val_var); - - /*! - * \brief Get the solution of the problem. - * \return Pointer to the solution vector. - */ - virtual su2double *GetSolution_Vel(void); - - /*! - * \brief Get the velocity of the nodes (Structural Analysis) at time n. - * \param[in] val_var - Index of the variable. - * \return Pointer to the old solution vector. - */ - virtual su2double GetSolution_Vel_time_n(unsigned short val_var); - - /*! - * \brief Get the solution at time n. - * \return Pointer to the solution (at time n) vector. - */ - virtual su2double *GetSolution_Vel_time_n(void); - - - /*! - * \brief Set the value of the acceleration (Structural Analysis). - * \param[in] val_solution - Solution of the problem (acceleration). - */ - virtual void SetSolution_Accel(su2double *val_solution_accel); - - /*! - * \overload - * \param[in] val_var - Index of the variable. - * \param[in] val_solution - Value of the solution for the index val_var. - */ - virtual void SetSolution_Accel(unsigned short val_var, su2double val_solution_accel); - - /*! - * \brief Set the value of the acceleration (Structural Analysis) at time n. - * \param[in] val_solution_old - Pointer to the residual vector. - */ - virtual void SetSolution_Accel_time_n(su2double *val_solution_accel_time_n); - - /*! - * \brief Set the value of the acceleration (Structural Analysis) at time n. - * \param[in] val_solution_old - Pointer to the residual vector. - */ - virtual void SetSolution_Accel_time_n(void); - - /*! - * \overload - * \param[in] val_var - Index of the variable. - * \param[in] val_solution_old - Value of the old solution for the index val_var. - */ - virtual void SetSolution_Accel_time_n(unsigned short val_var, su2double val_solution_accel_time_n); - - /*! - * \brief Get the acceleration (Structural Analysis). - * \param[in] val_var - Index of the variable. - * \return Value of the solution for the index val_var. - */ - virtual su2double GetSolution_Accel(unsigned short val_var); - - /*! - * \brief Get the solution of the problem. - * \return Pointer to the solution vector. - */ - virtual su2double *GetSolution_Accel(void); - - /*! - * \brief Get the acceleration of the nodes (Structural Analysis) at time n. - * \param[in] val_var - Index of the variable. - * \return Pointer to the old solution vector. - */ - virtual su2double GetSolution_Accel_time_n(unsigned short val_var); - - /*! - * \brief Get the solution at time n. - * \return Pointer to the solution (at time n) vector. - */ - virtual su2double *GetSolution_Accel_time_n(void); - - - /*! - * \brief A virtual member. Set the value of the solution predictor. - */ - virtual void SetSolution_Pred(void); - - /*! - * \brief A virtual member. Set the value of the old solution. - * \param[in] val_solution_old - Pointer to the residual vector. - */ - virtual void SetSolution_Pred(su2double *val_solution_pred); - - /*! - * \brief A virtual member. Get the value of the solution predictor. - * \param[in] val_var - Index of the variable. - * \return Pointer to the old solution vector. - */ - virtual su2double GetSolution_Pred(unsigned short val_var); - - /*! - * \brief A virtual member. Get the solution at time n. - * \return Pointer to the solution (at time n) vector. - */ - virtual su2double *GetSolution_Pred(void); - - /*! - * \brief A virtual member. Set the value of the solution predictor. - */ - virtual void SetSolution_Pred_Old(void); - - /*! - * \brief A virtual member. Set the value of the old solution. - * \param[in] val_solution_old - Pointer to the residual vector. - */ - virtual void SetSolution_Pred_Old(su2double *val_solution_pred_Old); - - /*! - * \brief A virtual member. Get the value of the solution predictor. - * \param[in] val_var - Index of the variable. - * \return Pointer to the old solution vector. - */ - virtual su2double GetSolution_Pred_Old(unsigned short val_var); - - /*! - * \brief A virtual member. Get the solution at time n. - * \return Pointer to the solution (at time n) vector. - */ - virtual su2double *GetSolution_Pred_Old(void); - - /*! - * \brief Register the variables in the solution array as input/output variable. - * \param[in] input - input or output variables. - */ - void RegisterSolution(bool input); - - /*! - * \brief Register the variables in the solution_time_n array as input/output variable. - */ - void RegisterSolution_time_n(); - - /*! - * \brief Register the variables in the solution_time_n1 array as input/output variable. - */ - void RegisterSolution_time_n1(); - - /*! - * \brief Set the adjoint values of the solution. - * \param[in] adj_sol - The adjoint values of the solution. - */ - void SetAdjointSolution(su2double *adj_sol); - - /*! - * \brief Get the adjoint values of the solution. - * \param[in] adj_sol - The adjoint values of the solution. - */ - void GetAdjointSolution(su2double *adj_sol); - - /*! - * \brief Set the adjoint values of the solution at time n. - * \param[in] adj_sol - The adjoint values of the solution. - */ - void SetAdjointSolution_time_n(su2double *adj_sol); - - /*! - * \brief Get the adjoint values of the solution at time n. - * \param[in] adj_sol - The adjoint values of the solution. - */ - void GetAdjointSolution_time_n(su2double *adj_sol); - - /*! - * \brief Set the adjoint values of the solution at time n-1. - * \param[in] adj_sol - The adjoint values of the solution. - */ - void SetAdjointSolution_time_n1(su2double *adj_sol); - - /*! - * \brief Get the adjoint values of the solution at time n-1. - * \param[in] adj_sol - The adjoint values of the solution. - */ - void GetAdjointSolution_time_n1(su2double *adj_sol); - - /*! - * \brief Set the sensitivity at the node - * \param[in] iDim - spacial component - * \param[in] val - value of the Sensitivity - */ - virtual void SetSensitivity(unsigned short iDim, su2double val); - - /*! - * \brief Get the Sensitivity at the node - * \param[in] iDim - spacial component - * \return value of the Sensitivity - */ - virtual su2double GetSensitivity(unsigned short iDim); - - virtual void SetDual_Time_Derivative(unsigned short iVar, su2double der); - - virtual void SetDual_Time_Derivative_n(unsigned short iVar, su2double der); - - virtual su2double GetDual_Time_Derivative(unsigned short iVar); - - virtual su2double GetDual_Time_Derivative_n(unsigned short iVar); -}; - -/*! - * \class CBaselineVariable - * \brief Main class for defining the variables of a baseline solution from a restart file (for output). - * \author F. Palacios, T. Economon. - * \version 4.0.1 "Cardinal" - */ -class CBaselineVariable : public CVariable { -public: - - /*! - * \brief Constructor of the class. - */ - CBaselineVariable(void); - - /*! - * \overload - * \param[in] val_solution - Pointer to the flow value (initialization value). - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CBaselineVariable(su2double *val_solution, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - virtual ~CBaselineVariable(void); - -}; - -/*! - * \class CPotentialVariable - * \brief Main class for defining the variables of the potential solver. - * \ingroup Potential_Flow_Equation - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CPotentialVariable : public CVariable { - su2double *Charge_Density; -public: - - /*! - * \brief Constructor of the class. - */ - CPotentialVariable(void); - - /*! - * \overload - * \param[in] val_potential - Value of the potential solution (initialization value). - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CPotentialVariable(su2double val_potential, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CPotentialVariable(void); - - /*! - * \brief A virtual member. - */ - su2double* GetChargeDensity(); - - /*! - * \brief A virtual member. - * \param[in] positive_charge - Mass density of positive charge. - * \param[in] negative_charge - Mass density of negative charge. - */ - void SetChargeDensity(su2double positive_charge, su2double negative_charge); - -}; - -/*! - * \class CWaveVariable - * \brief Main class for defining the variables of the wave equation solver. - * \ingroup Potential_Flow_Equation - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CWaveVariable : public CVariable { -protected: - su2double *Solution_Direct; /*!< \brief Direct solution container for use in the adjoint wave solver. */ - -public: - - /*! - * \brief Constructor of the class. - */ - CWaveVariable(void); - - /*! - * \overload - * \param[in] val_wave - Values of the wave solution (initialization value). - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CWaveVariable(su2double *val_wave, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CWaveVariable(void); - - /*! - * \brief Set the direct solution for the adjoint solver. - * \param[in] val_solution_direct - Value of the direct solution. - */ - void SetSolution_Direct(su2double *val_solution_direct); - - /*! - * \brief Get the direct solution for the adjoint solver. - * \return Pointer to the direct solution vector. - */ - su2double *GetSolution_Direct(void); - -}; - -/*! - * \class CHeatVariable - * \brief Main class for defining the variables of the Heat equation solver. - * \ingroup Potential_Flow_Equation - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CHeatVariable : public CVariable { -protected: - su2double *Solution_Direct; /*!< \brief Direct solution container for use in the adjoint Heat solver. */ - -public: - - /*! - * \brief Constructor of the class. - */ - CHeatVariable(void); - - /*! - * \overload - * \param[in] val_Heat - Values of the Heat solution (initialization value). - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CHeatVariable(su2double *val_Heat, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CHeatVariable(void); - - /*! - * \brief Set the direct solution for the adjoint solver. - * \param[in] val_solution_direct - Value of the direct solution. - */ - void SetSolution_Direct(su2double *val_solution_direct); - - /*! - * \brief Get the direct solution for the adjoint solver. - * \return Pointer to the direct solution vector. - */ - su2double *GetSolution_Direct(void); - -}; - -/*! - * \class CFEAVariable - * \brief Main class for defining the variables of the FEA equation solver. - * \ingroup Structural Finite Element Analysis Variables - * \author F. Palacios, R. Sanchez. - * \version 4.0.1 "Cardinal" - */ -class CFEAVariable : public CVariable { -protected: - su2double Flow_Pressure; /*!< \brief Pressure of the fluid. */ - - bool dynamicFEA; /*!< \brief Non-physical points in the solution (force first order). */ - - su2double **Stress; /*!< \brief Stress tensor. */ - su2double VonMises_Stress; /*!< \brief Von Mises stress. */ - unsigned short nAttachedElements; /*!< \brief Number of elements connected to the node. */ - - su2double *Solution_Vel, /*!< \brief Velocity of the nodes. */ - *Solution_Vel_time_n; /*!< \brief Velocity of the nodes at time n. */ - - su2double *Solution_Accel, /*!< \brief Acceleration of the nodes. */ - *Solution_Accel_time_n; /*!< \brief Acceleration of the nodes at time n. */ - - su2double *Solution_Pred; /*!< \brief Predictor of the solution (for FSI applications) */ - su2double *Solution_Pred_Old; /*!< \brief Predictor of the solution (for FSI applications) in the iter k-1 */ - -public: - - /*! - * \brief Constructor of the class. - */ - CFEAVariable(void); - - /*! - * \overload - * \param[in] val_fea - Values of the fea solution (initialization value). - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CFEAVariable(su2double *val_fea, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CFEAVariable(void); - - /*! - * \brief Set the value of the stress. - * \param[in] iVar - i index. - * \param[in] jVar - j index. - * \param[in] val_stress - Value of the stress. - */ - void SetStress(unsigned short iVar, unsigned short jVar, su2double val_stress); - - /*! - * \brief Add a value to the stress matrix in the element. - * \param[in] iVar - i index. - * \param[in] jVar - j index. - * \param[in] val_stress - Value of the stress. - */ - void AddStress(unsigned short iVar, unsigned short jVar, su2double val_stress); - - /*! - * \brief Get the value of the stress. - * \return Value of the stress. - */ - su2double **GetStress(void); - - /*! - * \brief Set the value of the Von Mises stress. - * \param[in] val_stress - Value of the Von Mises stress. - */ - void SetVonMises_Stress(su2double val_stress); - - /*! - * \brief Get the value of the Von Mises stress. - * \return Value of the Von Mises stress. - */ - su2double GetVonMises_Stress(void); - - /*! - * \brief Set the value of the Von Mises stress. - * \param[in] val_stress - Value of the Von Mises stress. - */ - void SetFlow_Pressure(su2double val_pressure); - - /*! - * \brief Get the value of the Von Mises stress. - * \return Value of the Von Mises stress. - */ - su2double GetFlow_Pressure(void); - - /*! - * \brief Initialize the value of the number of attached elements to a node. - * \return Value of the Von Mises stress. - */ - void Initialize_Connectivity(void); - - - /*! - * \brief Add a 1 to the value of the number of attached elements to a node. - * \return Value of the Von Mises stress. - */ - void Upgrade_Connectivity(void); - - - /*! - * \brief Returns the value of the number of attached elements to a node. - * \return Value of the Von Mises stress. - */ - unsigned short Get_Connectivity(void); - - /*! - * \brief Set the value of the old solution. - * \param[in] val_solution_old - Pointer to the residual vector. - */ - void SetSolution_time_n(void); - - /*! - * \brief Set the value of the old solution. - * \param[in] val_solution_old - Pointer to the residual vector. - */ - void SetSolution_time_n(su2double *val_solution_time_n); - - - /*! - * \brief Set the value of the velocity (Structural Analysis). - * \param[in] val_solution - Solution of the problem (velocity). - */ - void SetSolution_Vel(su2double *val_solution_vel); - - /*! - * \overload - * \param[in] val_var - Index of the variable. - * \param[in] val_solution - Value of the solution for the index val_var. - */ - void SetSolution_Vel(unsigned short val_var, su2double 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(void); - - /*! - * \brief Set the value of the velocity (Structural Analysis) at time n. - * \param[in] val_solution_old - Pointer to the residual vector. - */ - void SetSolution_Vel_time_n(su2double *val_solution_vel_time_n); - - /*! - * \overload - * \param[in] val_var - Index of the variable. - * \param[in] val_solution_old - Value of the old solution for the index val_var. - */ - void SetSolution_Vel_time_n(unsigned short val_var, su2double val_solution_vel_time_n); - - /*! - * \brief Get the solution at time n. - * \param[in] val_var - Index of the variable. - * \return Value of the solution for the index val_var. - */ - su2double GetSolution_time_n(unsigned short val_var); - - /*! - * \brief Get the velocity (Structural Analysis). - * \param[in] val_var - Index of the variable. - * \return Value of the solution for the index val_var. - */ - su2double GetSolution_Vel(unsigned short val_var); - - /*! - * \brief Get the solution of the problem. - * \return Pointer to the solution vector. - */ - su2double *GetSolution_Vel(void); - - /*! - * \brief Get the velocity of the nodes (Structural Analysis) at time n. - * \param[in] val_var - Index of the variable. - * \return Pointer to the old solution vector. - */ - su2double GetSolution_Vel_time_n(unsigned short val_var); - - /*! - * \brief Get the solution at time n. - * \return Pointer to the solution (at time n) vector. - */ - su2double *GetSolution_Vel_time_n(void); - - /*! - * \brief Set the value of the acceleration (Structural Analysis). - * \param[in] val_solution - Solution of the problem (acceleration). - */ - void SetSolution_Accel(su2double *val_solution_accel); - - /*! - * \overload - * \param[in] val_var - Index of the variable. - * \param[in] val_solution - Value of the solution for the index val_var. - */ - void SetSolution_Accel(unsigned short val_var, su2double val_solution_accel); - - /*! - * \brief Set the value of the acceleration (Structural Analysis) at time n. - * \param[in] val_solution_old - Pointer to the residual vector. - */ - void SetSolution_Accel_time_n(su2double *val_solution_accel_time_n); - - /*! - * \brief Set the value of the acceleration (Structural Analysis) at time n. - * \param[in] val_solution - Solution of the problem (acceleration). - */ - void SetSolution_Accel_time_n(void); - - /*! - * \overload - * \param[in] val_var - Index of the variable. - * \param[in] val_solution_old - Value of the old solution for the index val_var. - */ - void SetSolution_Accel_time_n(unsigned short val_var, su2double val_solution_accel_time_n); - - /*! - * \brief Get the acceleration (Structural Analysis). - * \param[in] val_var - Index of the variable. - * \return Value of the solution for the index val_var. - */ - su2double GetSolution_Accel(unsigned short val_var); - - /*! - * \brief Get the solution of the problem. - * \return Pointer to the solution vector. - */ - su2double *GetSolution_Accel(void); - - /*! - * \brief Get the acceleration of the nodes (Structural Analysis) at time n. - * \param[in] val_var - Index of the variable. - * \return Pointer to the old solution vector. - */ - su2double GetSolution_Accel_time_n(unsigned short val_var); - - /*! - * \brief Get the solution at time n. - * \return Pointer to the solution (at time n) vector. - */ - su2double *GetSolution_Accel_time_n(void); - - - /*! - * \brief Set the value of the solution predictor. - */ - void SetSolution_Pred(void); - - /*! - * \brief Set the value of the old solution. - * \param[in] val_solution_old - Pointer to the residual vector. - */ - void SetSolution_Pred(su2double *val_solution_pred); - - /*! - * \brief Get the value of the solution predictor. - * \param[in] val_var - Index of the variable. - * \return Pointer to the old solution vector. - */ - su2double GetSolution_Pred(unsigned short val_var); - - /*! - * \brief Get the solution at time n. - * \return Pointer to the solution (at time n) vector. - */ - su2double *GetSolution_Pred(void); - - /*! - * \brief Set the value of the solution predictor. - */ - void SetSolution_Pred_Old(void); - - /*! - * \brief Set the value of the old solution. - * \param[in] val_solution_old - Pointer to the residual vector. - */ - void SetSolution_Pred_Old(su2double *val_solution_pred_Old); - - /*! - * \brief Get the value of the solution predictor. - * \param[in] val_var - Index of the variable. - * \return Pointer to the old solution vector. - */ - su2double GetSolution_Pred_Old(unsigned short val_var); - - /*! - * \brief Get the solution at time n. - * \return Pointer to the solution (at time n) vector. - */ - su2double *GetSolution_Pred_Old(void); - - - -}; - - -/*! - * \class CFEABoundVariable - * \brief Main class for defining the variables on the FEA boundaries for FSI applications. - * \author R. Sanchez. - * \version 3.2.3 "eagle" - */ -class CFEABoundVariable : public CVariable { -protected: - su2double **Traction; /*!< \brief Stress tensor. */ - -public: - - /*! - * \brief Constructor of the class. - */ - CFEABoundVariable(void); - - /*! - * \overload - * \param[in] val_fea - Values of the fea solution (initialization value). - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] val_nElBound - Number of elements in the boundary - * \param[in] config - Definition of the particular problem. - */ - CFEABoundVariable(unsigned short val_nDim, unsigned short val_nvar, unsigned short val_nElBound, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CFEABoundVariable(void); - - /*! - * \brief Set the value of the stress. - * \param[in] iVar - index of the traction vector. - * \param[in] jVar - index of the boundary element. - * \param[in] val_stress - Value of the stress. - */ - void SetTraction(unsigned short iVar, unsigned short jVar, su2double val_traction); - - /*! - * \brief Add a value to the stress matrix in the element. - * \param[in] iVar - index of the traction vector. - * \param[in] jVar - index of the boundary element. - * \param[in] val_stress - Value of the stress. - */ - void AddTraction(unsigned short iVar, unsigned short jVar, su2double val_traction); - - /*! - * \brief Get the value of the stress. - * \return Value of the stress. - */ - su2double **GetTraction(void); - -}; - -/*! - * \class CEulerVariable - * \brief Main class for defining the variables of the Euler's solver. - * \ingroup Euler_Equations - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CEulerVariable : public CVariable { -protected: - su2double Velocity2; /*!< \brief Square of the velocity vector. */ - su2double *TS_Source; /*!< \brief Time spectral source term. */ - su2double Precond_Beta; /*!< \brief Low Mach number preconditioner value, Beta. */ - su2double *WindGust; /*! < \brief Wind gust value */ - su2double *WindGustDer; /*! < \brief Wind gust derivatives value */ - - /*--- Primitive variable definition ---*/ - - su2double *Primitive; /*!< \brief Primitive variables (T, vx, vy, vz, P, rho, h, c) in compressible flows. */ - su2double **Gradient_Primitive; /*!< \brief Gradient of the primitive variables (T, vx, vy, vz, P, rho). */ - su2double *Limiter_Primitive; /*!< \brief Limiter of the primitive variables (T, vx, vy, vz, P, rho). */ - - /*--- Secondary variable definition ---*/ - - su2double *Secondary; /*!< \brief Primitive variables (T, vx, vy, vz, P, rho, h, c) in compressible flows. */ - su2double **Gradient_Secondary; /*!< \brief Gradient of the primitive variables (T, vx, vy, vz, P, rho). */ - su2double *Limiter_Secondary; /*!< \brief Limiter of the primitive variables (T, vx, vy, vz, P, rho). */ - -public: - - /*! - * \brief Constructor of the class. - */ - CEulerVariable(void); - - /*! - * \overload - * \param[in] val_density - Value of the flow density (initialization value). - * \param[in] val_velocity - Value of the flow velocity (initialization value). - * \param[in] val_energy - Value of the flow energy (initialization value). - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CEulerVariable(su2double val_density, su2double *val_velocity, su2double val_energy, unsigned short val_nDim, - unsigned short val_nvar, CConfig *config); - - /*! - * \overload - * \param[in] val_solution - Pointer to the flow value (initialization value). - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CEulerVariable(su2double *val_solution, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - virtual ~CEulerVariable(void); - - /*! - * \brief Set to zero the gradient of the primitive variables. - */ - void SetGradient_PrimitiveZero(unsigned short val_primvar); - - /*! - * \brief Add val_value to the gradient of the primitive variables. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value to add to the gradient of the primitive variables. - */ - void AddGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value); - - /*! - * \brief Subtract val_value to the gradient of the primitive variables. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value to subtract to the gradient of the primitive variables. - */ - void SubtractGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value); - - /*! - * \brief Get the value of the primitive variables gradient. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \return Value of the primitive variables gradient. - */ - su2double GetGradient_Primitive(unsigned short val_var, unsigned short val_dim); - - /*! - * \brief Get the value of the primitive variables gradient. - * \param[in] val_var - Index of the variable. - * \return Value of the primitive variables gradient. - */ - su2double GetLimiter_Primitive(unsigned short val_var); - - /*! - * \brief Set the gradient of the primitive variables. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value of the gradient. - */ - void SetGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value); - - /*! - * \brief Set the gradient of the primitive variables. - * \param[in] val_var - Index of the variable. - * \param[in] val_value - Value of the gradient. - */ - void SetLimiter_Primitive(unsigned short val_var, su2double val_value); - - /*! - * \brief Get the value of the primitive variables gradient. - * \return Value of the primitive variables gradient. - */ - su2double **GetGradient_Primitive(void); - - /*! - * \brief Get the value of the primitive variables gradient. - * \return Value of the primitive variables gradient. - */ - su2double *GetLimiter_Primitive(void); - - /*! - * \brief Set to zero the gradient of the primitive variables. - */ - void SetGradient_SecondaryZero(unsigned short val_secondaryvar); - - /*! - * \brief Add val_value to the gradient of the primitive variables. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value to add to the gradient of the primitive variables. - */ - void AddGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value); - - /*! - * \brief Subtract val_value to the gradient of the primitive variables. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value to subtract to the gradient of the primitive variables. - */ - void SubtractGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value); - - /*! - * \brief Get the value of the primitive variables gradient. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \return Value of the primitive variables gradient. - */ - su2double GetGradient_Secondary(unsigned short val_var, unsigned short val_dim); - - /*! - * \brief Get the value of the primitive variables gradient. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \return Value of the primitive variables gradient. - */ - su2double GetLimiter_Secondary(unsigned short val_var); - - /*! - * \brief Set the gradient of the primitive variables. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value of the gradient. - */ - void SetGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value); - - /*! - * \brief Set the gradient of the primitive variables. - * \param[in] val_var - Index of the variable. - * \param[in] val_dim - Index of the dimension. - * \param[in] val_value - Value of the gradient. - */ - void SetLimiter_Secondary(unsigned short val_var, su2double val_value); - - /*! - * \brief Get the value of the primitive variables gradient. - * \return Value of the primitive variables gradient. - */ - su2double **GetGradient_Secondary(void); - - /*! - * \brief Get the value of the primitive variables gradient. - * \return Value of the primitive variables gradient. - */ - su2double *GetLimiter_Secondary(void); - - /*! - * \brief A virtual member. - */ - void SetdPdrho_e(su2double dPdrho_e); - - /*! - * \brief A virtual member. - */ - void SetdPde_rho(su2double dPde_rho); - - /*! - * \brief Set the value of the pressure. - */ - bool SetPressure(su2double Gamma); - - /*! - * \brief Set the value of the speed of the sound. - * \param[in] Gamma - Value of Gamma. - */ - bool SetSoundSpeed(su2double Gamma); - - /*! - * \brief Set the value of the enthalpy. - */ - void SetEnthalpy(void); - -// /*! -// * \brief Set all the primitive variables for compressible flows. -// */ -// bool SetPrimVar_Compressible(CConfig *config); - - /*! - * \brief Set all the primitive variables for compressible flows. - */ - bool SetPrimVar_Compressible(CFluidModel *FluidModel); - using CVariable::SetPrimVar_Compressible; - - /*! - * \brief A virtual member. - */ - void SetSecondaryVar_Compressible(CFluidModel *FluidModel); - - /*! - * \brief Set all the primitive variables for incompressible flows. - */ - bool SetPrimVar_Incompressible(su2double Density_Inf, CConfig *config); - using CVariable::SetPrimVar_Incompressible; - - /*! - * \brief Set all the primitive variables for incompressible flows. - */ - bool SetPrimVar_FreeSurface(CConfig *config); - using CVariable::SetPrimVar_FreeSurface; - - /*! - * \brief Get the primitive variables. - * \param[in] val_var - Index of the variable. - * \return Value of the primitive variable for the index val_var. - */ - su2double GetPrimitive(unsigned short val_var); - - /*! - * \brief Set the value of the primitive variables. - * \param[in] val_var - Index of the variable. - * \param[in] val_var - Index of the variable. - * \return Set the value of the primitive variable for the index val_var. - */ - void SetPrimitive(unsigned short val_var, su2double val_prim); - - /*! - * \brief Set the value of the primitive variables. - * \param[in] val_prim - Primitive variables. - * \return Set the value of the primitive variable for the index val_var. - */ - void SetPrimitive(su2double *val_prim); - - /*! - * \brief Get the primitive variables of the problem. - * \return Pointer to the primitive variable vector. - */ - su2double *GetPrimitive(void); - - /*! - * \brief Get the primitive variables. - * \param[in] val_var - Index of the variable. - * \return Value of the primitive variable for the index val_var. - */ - su2double GetSecondary(unsigned short val_var); - - /*! - * \brief Set the value of the primitive variables. - * \param[in] val_var - Index of the variable. - * \param[in] val_var - Index of the variable. - * \return Set the value of the primitive variable for the index val_var. - */ - void SetSecondary(unsigned short val_var, su2double val_secondary); - - /*! - * \brief Set the value of the primitive variables. - * \param[in] val_prim - Primitive variables. - * \return Set the value of the primitive variable for the index val_var. - */ - void SetSecondary(su2double *val_secondary); - - /*! - * \brief Get the primitive variables of the problem. - * \return Pointer to the primitive variable vector. - */ - su2double *GetSecondary(void); - - /*! - * \brief Set the value of the density for the incompressible flows. - */ - void SetDensityInc(su2double val_density); - - /*! - * \brief Set the value of the density for the incompressible flows. - */ - bool SetDensity(void); - - /*! - * \brief Set the value of the density for the incompressible flows. - */ - void SetPressureInc(void); - - /*! - * \brief Set the value of the density for the incompressible flows. - */ - void SetVelocityInc(void); - - /*! - * \brief Set the value of the beta coeffient for incompressible flows. - */ - void SetBetaInc2(su2double val_betainc2); - - /*! - * \brief Set the value of the temperature. - * \param[in] Gas_Constant - Value of Gas Constant - */ - bool SetTemperature(su2double Gas_Constant); - - /*! - * \brief Get the norm 2 of the velocity. - * \return Norm 2 of the velocity vector. - */ - su2double GetVelocity2(void); - - /*! - * \brief Get the flow pressure. - * \return Value of the flow pressure. - */ - su2double GetPressure(void); - - /*! - * \brief Get the flow pressure. - * \return Value of the flow pressure. - */ - su2double GetPressureInc(void); - - /*! - * \brief Get the speed of the sound. - * \return Value of speed of the sound. - */ - su2double GetSoundSpeed(void); - - /*! - * \brief Get the value of density for the incompressible flow - * \return Value of beta squared. - */ - su2double GetDensityInc(void); - - /*! - * \brief Get the value of levelset for the freesurface flows - * \return Value of beta squared. - */ - su2double GetLevelSet(void); - - /*! - * \brief Get the value of distance for the freesurface flows - * \return Value of beta squared. - */ - su2double GetDistance(void); - - /*! - * \brief Get the value of beta squared for the incompressible flow - * \return Value of beta squared. - */ - su2double GetBetaInc2(void); - - /*! - * \brief Get the enthalpy of the flow. - * \return Value of the enthalpy of the flow. - */ - su2double GetEnthalpy(void); - - /*! - * \brief Get the density of the flow. - * \return Value of the density of the flow. - */ - su2double GetDensity(void); - - /*! - * \brief Get the energy of the flow. - * \return Value of the energy of the flow. - */ - su2double GetEnergy(void); - - /*! - * \brief Get the temperature of the flow. - * \return Value of the temperature of the flow. - */ - su2double GetTemperature(void); - - /*! - * \brief Get the velocity of the flow. - * \param[in] val_dim - Index of the dimension. - * \return Value of the velocity for the dimension val_dim. - */ - su2double GetVelocity(unsigned short val_dim); - - /*! - * \brief Get the projected velocity in a unitary vector direction (compressible solver). - * \param[in] val_vector - Direction of projection. - * \return Value of the projected velocity. - */ - su2double GetProjVel(su2double *val_vector); - - /*! - * \brief Set the velocity vector from the solution. - * \param[in] val_velocity - Pointer to the velocity. - */ - void SetVelocity(void); - - /*! - * \brief Set the velocity vector from the old solution. - * \param[in] val_velocity - Pointer to the velocity. - */ - void SetVelocity_Old(su2double *val_velocity); - - /*! - * \brief Set the velocity vector from the old solution. - * \param[in] val_velocity - Pointer to the velocity. - */ - void SetVelocityInc_Old(su2double *val_velocity); - - /*! - * \brief Set the time spectral source term. - * \param[in] val_var - Index of the variable. - * \param[in] val_solution - Value of the time spectral source term. for the index val_var. - */ - void SetTimeSpectral_Source(unsigned short val_var, su2double val_source); - - /*! - * \brief Get the time spectral source term. - * \param[in] val_var - Index of the variable. - * \return Value of the time spectral source term for the index val_var. - */ - su2double GetTimeSpectral_Source(unsigned short val_var); - - /*! - * \brief Get the value of the preconditioner Beta. - * \return Value of the low Mach preconditioner variable Beta - */ - su2double GetPreconditioner_Beta(); - - /*! - * \brief Set the value of the preconditioner Beta. - * \param[in] Value of the low Mach preconditioner variable Beta - */ - void SetPreconditioner_Beta(su2double val_Beta); - - /*! - * \brief Get the value of the wind gust - * \return Value of the wind gust - */ - su2double* GetWindGust(); - - /*! - * \brief Set the value of the wind gust - * \param[in] Value of the wind gust - */ - void SetWindGust(su2double* val_WindGust); - - /*! - * \brief Get the value of the derivatives of the wind gust - * \return Value of the derivatives of the wind gust - */ - su2double* GetWindGustDer(); - - /*! - * \brief Set the value of the derivatives of the wind gust - * \param[in] Value of the derivatives of the wind gust - */ - void SetWindGustDer(su2double* val_WindGust); -}; - -/*! - * \class CNSVariable - * \brief Main class for defining the variables of the Navier-Stokes' solver. - * \ingroup Navier_Stokes_Equations - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CNSVariable : public CEulerVariable { -private: - su2double Prandtl_Lam; /*!< \brief Laminar Prandtl number. */ - su2double Prandtl_Turb; /*!< \brief Turbulent Prandtl number. */ - su2double Temperature_Ref; /*!< \brief Reference temperature of the fluid. */ - su2double Viscosity_Ref; /*!< \brief Reference viscosity of the fluid. */ - su2double Viscosity_Inf; /*!< \brief Viscosity of the fluid at the infinity. */ - su2double Vorticity[3]; /*!< \brief Vorticity of the fluid. */ - su2double StrainMag; /*!< \brief Magnitude of rate of strain tensor. */ -public: - - /*! - * \brief Constructor of the class. - */ - CNSVariable(void); - - /*! - * \overload - * \param[in] val_density - Value of the flow density (initialization value). - * \param[in] val_velocity - Value of the flow velocity (initialization value). - * \param[in] val_energy - Value of the flow energy (initialization value). - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CNSVariable(su2double val_density, su2double *val_velocity, - su2double val_energy, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \overload - * \param[in] val_solution - Pointer to the flow value (initialization value). - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CNSVariable(su2double *val_solution, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CNSVariable(void); - - /*! - * \brief Set the laminar viscosity. - */ - void SetLaminarViscosity(su2double laminarViscosity); - - /*! - * \overload - * \param[in] val_laminar_viscosity_inc - Value of the laminar viscosity (incompressible flows). - */ - void SetLaminarViscosityInc(su2double val_laminar_viscosity_inc); - - /*! - * \brief Set the laminar viscosity. - */ - void SetThermalConductivity(su2double thermalConductivity); - - /*! - * \brief Set the specific heat Cp. - */ - void SetSpecificHeatCp(su2double Cp); - - /*! - * \brief Set the vorticity value. - */ - bool SetVorticity(bool val_limiter); - - /*! - * \brief Set the rate of strain magnitude. - */ - bool SetStrainMag(bool val_limiter); - - /*! - * \overload - * \param[in] eddy_visc - Value of the eddy viscosity. - */ - void SetEddyViscosity(su2double eddy_visc); - - /*! - * \overload - * \param[in] eddy_visc - Value of the eddy viscosity. - */ - void SetEddyViscosityInc(su2double eddy_visc); - - /*! - * \brief Get the laminar viscosity of the flow. - * \return Value of the laminar viscosity of the flow. - */ - su2double GetLaminarViscosity(void); - - /*! - * \brief Get the laminar viscosity of the incompressible flow. - * \return Value of the laminar viscosity of the incompressible flow. - */ - su2double GetLaminarViscosityInc(void); - - /*! - * \brief Get the thermal conductivity of the flow. - * \return Value of the laminar viscosity of the flow. - */ - su2double GetThermalConductivity(void); - - /*! - * \brief Get the eddy viscosity of the flow. - * \return The eddy viscosity of the flow. - */ - su2double GetEddyViscosity(void); - - /*! - * \brief Get the specific heat at constant P of the flow. - * \return Value of the specific heat at constant P of the flow. - */ - su2double GetSpecificHeatCp(void); - - /*! - * \brief Get the eddy viscosity of the flow. - * \return The eddy viscosity of the flow. - */ - su2double GetEddyViscosityInc(void); - - /*! - * \brief Set the temperature at the wall - */ - void SetWallTemperature(su2double temperature_wall); - - /*! - * \brief Get the value of the vorticity. - * \param[in] val_dim - Index of the dimension. - * \return Value of the vorticity. - */ - su2double *GetVorticity(void); - - /*! - * \brief Get the value of the magnitude of rate of strain. - * \return Value of the rate of strain magnitude. - */ - su2double GetStrainMag(void); - - /*! - * \brief Set the derivative of temperature with respect to density (at constant internal energy). - */ - void SetdTdrho_e(su2double dTdrho_e); - - /*! - * \brief Set the derivative of temperature with respect to internal energy (at constant density). - */ - void SetdTde_rho(su2double dTde_rho); - - /*! - * \brief Set the derivative of laminar viscosity with respect to density (at constant temperature). - */ - void Setdmudrho_T(su2double dmudrho_T); - - /*! - * \brief Set the derivative of laminar viscosity with respect to temperature (at constant density). - */ - void SetdmudT_rho(su2double dmudT_rho); - - /*! - * \brief Set the derivative of thermal conductivity with respect to density (at constant temperature). - */ - void Setdktdrho_T(su2double dktdrho_T); - - /*! - * \brief Set the derivative of thermal conductivity with respect to temperature (at constant density). - */ - void SetdktdT_rho(su2double dktdT_rho); - - /*! - * \brief Set all the primitive variables for compressible flows - */ - bool SetPrimVar_Compressible(su2double eddy_visc, su2double turb_ke, CFluidModel *FluidModel); - using CVariable::SetPrimVar_Compressible; - - /*! - * \brief Set all the secondary variables (partial derivatives) for compressible flows - */ - void SetSecondaryVar_Compressible(CFluidModel *FluidModel); - - /*! - * \brief Set all the primitive variables for incompressible flows - */ - bool SetPrimVar_Incompressible(su2double Density_Inf, su2double Viscosity_Inf, su2double eddy_visc, su2double turb_ke, CConfig *config); - using CVariable::SetPrimVar_Incompressible; - - /*! - * \brief Set all the primitive variables for incompressible flows - */ - bool SetPrimVar_FreeSurface(su2double eddy_visc, su2double turb_ke, CConfig *config); - using CVariable::SetPrimVar_FreeSurface; - -}; - -/*! - * \class CTurbVariable - * \brief Main class for defining the variables of the turbulence model. - * \ingroup Turbulence_Model - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CTurbVariable : public CVariable { -protected: - su2double muT; /*!< \brief Eddy viscosity. */ - su2double *TS_Source; /*!< \brief Time spectral source term. */ - -public: - /*! - * \brief Constructor of the class. - */ - CTurbVariable(void); - - /*! - * \overload - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CTurbVariable(unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - virtual ~CTurbVariable(void); - - /*! - * \brief Get the value of the eddy viscosity. - * \return the value of the eddy viscosity. - */ - su2double GetmuT(); - - /*! - * \brief Set the value of the eddy viscosity. - * \param[in] val_muT - Value of the eddy viscosity. - */ - void SetmuT(su2double val_muT); -}; - -/*! - * \class CTurbSAVariable - * \brief Main class for defining the variables of the turbulence model. - * \ingroup Turbulence_Model - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ - -class CTurbSAVariable : public CTurbVariable { -public: - /*! - * \brief Constructor of the class. - */ - CTurbSAVariable(void); - - /*! - * \overload - * \param[in] val_nu_tilde - Turbulent variable value (initialization value). - * \param[in] val_muT - The eddy viscosity - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CTurbSAVariable(void); - - /*! - * \brief Set the time spectral source term. - * \param[in] val_var - Index of the variable. - * \param[in] val_source - Value of the time spectral source term. for the index val_var. - */ - void SetTimeSpectral_Source(unsigned short val_var, su2double val_source); - - /*! - * \brief Get the time spectral source term. - * \param[in] val_var - Index of the variable. - * \return Value of the time spectral source term for the index val_var. - */ - su2double GetTimeSpectral_Source(unsigned short val_var); - -}; - - -/*! - * \class CTurbMLVariable - * \brief Main class for defining the variables of the turbulence model. - * \ingroup Turbulence_Model - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ - -class CTurbMLVariable : public CTurbVariable { -public: - /*! - * \brief Constructor of the class. - */ - CTurbMLVariable(void); - - /*! - * \overload - * \param[in] val_nu_tilde - Turbulent variable value (initialization value). - * \param[in] val_muT - The eddy viscosity - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CTurbMLVariable(su2double val_nu_tilde, su2double val_muT, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CTurbMLVariable(void); - - /*! - * \brief Set the time spectral source term. - * \param[in] val_var - Index of the variable. - * \param[in] val_source - Value of the time spectral source term. for the index val_var. - */ - void SetTimeSpectral_Source(unsigned short val_var, su2double val_source); - - /*! - * \brief Get the time spectral source term. - * \param[in] val_var - Index of the variable. - * \return Value of the time spectral source term for the index val_var. - */ - su2double GetTimeSpectral_Source(unsigned short val_var); - -}; - -/*! - * \class CTransLMVariable - * \brief Main class for defining the variables of the turbulence model. - * \ingroup Turbulence_Model - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ - -class CTransLMVariable : public CTurbVariable { -protected: - su2double gamma_sep; - -public: - - /*! - * \brief Constructor of the class. - */ - CTransLMVariable(void); - - /*! - * \overload - * \param[in] val_nu_tilde - Turbulent variable value (initialization value). - * \param[in] val_REth - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CTransLMVariable(su2double val_nu_tilde, su2double val_intermittency, su2double val_REth, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CTransLMVariable(void); - - /*! - * \brief ________________. - */ - su2double GetIntermittency(void); - - /*! - * \brief ________________. - * \param[in] gamma_sep_in - */ - void SetGammaSep(su2double gamma_sep_in); - - /*! - * \brief ________________. - */ - void SetGammaEff(void); - -}; - -/*! - * \class CTurbSSTVariable - * \brief Main class for defining the variables of the turbulence model. - * \ingroup Turbulence_Model - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ - -class CTurbSSTVariable : public CTurbVariable { -protected: - su2double sigma_om2, - beta_star; - su2double F1, /*!< \brief Menter blending function for blending of k-w and k-eps. */ - F2, /*!< \brief Menter blending function for stress limiter. */ - CDkw; /*!< \brief Cross-diffusion. */ - -public: - /*! - * \brief Constructor of the class. - */ - CTurbSSTVariable(void); - - /*! - * \overload - * \param[in] val_rho_kine - Turbulent variable value (initialization value). - * \param[in] val_rho_omega - Turbulent variable value (initialization value). - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CTurbSSTVariable(su2double val_rho_kine, su2double val_rho_omega, su2double val_muT, unsigned short val_nDim, unsigned short val_nvar, - su2double *constants, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CTurbSSTVariable(void); - - /*! - * \brief Set the blending function for the blending of k-w and k-eps. - * \param[in] val_viscosity - Value of the vicosity. - * \param[in] val_dist - Value of the distance to the wall. - * \param[in] val_density - Value of the density. - */ - void SetBlendingFunc(su2double val_viscosity, su2double val_dist, su2double val_density); - - /*! - * \brief Get the first blending function. - */ - su2double GetF1blending(void); - - /*! - * \brief Get the second blending function. - */ - su2double GetF2blending(void); - - /*! - * \brief Get the value of the cross diffusion of tke and omega. - */ - su2double GetCrossDiff(void); -}; - - -/*! - * \class CAdjEulerVariable - * \brief Main class for defining the variables of the adjoint Euler solver. - * \ingroup Euler_Equations - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CAdjEulerVariable : public CVariable { -protected: - su2double *Psi; /*!< \brief Vector of the adjoint variables. */ - su2double *ForceProj_Vector; /*!< \brief Vector d. */ - su2double *ObjFuncSource; /*!< \brief Vector containing objective function sensitivity for discrete adjoint. */ - su2double *IntBoundary_Jump; /*!< \brief Interior boundary jump vector. */ - su2double *TS_Source; /*!< \brief Time spectral source term. */ - bool incompressible; -public: - - /*! - * \brief Constructor of the class. - */ - CAdjEulerVariable(void); - - /*! - * \overload - * \param[in] val_psirho - Value of the adjoint density (initialization value). - * \param[in] val_phi - Value of the adjoint velocity (initialization value). - * \param[in] val_psie - Value of the adjoint energy (initialization value). - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAdjEulerVariable(su2double val_psirho, su2double *val_phi, su2double val_psie, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \overload - * \param[in] val_solution - Pointer to the adjoint value (initialization value). - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAdjEulerVariable(su2double *val_solution, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - virtual ~CAdjEulerVariable(void); - - /*! - * \brief Set all the primitive variables for compressible flows. - */ - bool SetPrimVar_Compressible(su2double SharpEdge_Distance, bool check, CConfig *config); - using CVariable::SetPrimVar_Compressible; - - /*! - * \brief Set all the primitive variables for compressible flows. - */ - bool SetPrimVar_Incompressible(su2double SharpEdge_Distance, bool check, CConfig *config); - using CVariable::SetPrimVar_Incompressible; - - /*! - * \brief Set all the primitive variables for compressible flows. - */ - bool SetPrimVar_FreeSurface(su2double SharpEdge_Distance, bool check, CConfig *config); - using CVariable::SetPrimVar_FreeSurface; - - /*! - * \brief Set the value of the adjoint velocity. - * \param[in] val_phi - Value of the adjoint velocity. - */ - void SetPhi_Old(su2double *val_phi); - - /*! - * \brief Set the value of the force projection vector. - * \param[in] val_ForceProj_Vector - Pointer to the force projection vector. - */ - void SetForceProj_Vector(su2double *val_ForceProj_Vector); - - /*! - * \brief Set the value of the objective function source. - * \param[in] val_SetObjFuncSource - Pointer to the objective function source. - */ - void SetObjFuncSource(su2double *val_SetObjFuncSource); - - /*! - * \brief Set the value of the interior boundary jump vector vector. - * \param[in] val_IntBoundary_Jump - Pointer to the interior boundary jump vector. - */ - void SetIntBoundary_Jump(su2double *val_IntBoundary_Jump); - - /*! - * \brief Get the value of the force projection vector. - * \return Pointer to the force projection vector. - */ - su2double *GetForceProj_Vector(void); - - /*! - * \brief Get the value of the objective function source. - * \param[in] val_SetObjFuncSource - Pointer to the objective function source. - */ - su2double *GetObjFuncSource(void); - - /*! - * \brief Get the value of the force projection vector. - * \return Pointer to the force projection vector. - */ - su2double *GetIntBoundary_Jump(void); - - /*! - * \brief Set the time spectral source term. - * \param[in] val_var - Index of the variable. - * \param[in] val_solution - Value of the time spectral source term. for the index val_var. - */ - void SetTimeSpectral_Source(unsigned short val_var, su2double val_source); - - /*! - * \brief Get the time spectral source term. - * \param[in] val_var - Index of the variable. - * \return Value of the time spectral source term for the index val_var. - */ - su2double GetTimeSpectral_Source(unsigned short val_var); -}; - -/*! - * \class CAdjNSVariable - * \brief Main class for defining the variables of the adjoint Navier-Stokes solver. - * \ingroup Navier_Stokes_Equations - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CAdjNSVariable : public CAdjEulerVariable { -private: - -public: - - /*! - * \brief Constructor of the class. - */ - CAdjNSVariable(void); - - /*! - * \overload - * \param[in] val_psirho - Value of the adjoint density (initialization value). - * \param[in] val_phi - Value of the adjoint velocity (initialization value). - * \param[in] val_psie - Value of the adjoint energy (initialization value). - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAdjNSVariable(su2double val_psirho, su2double *val_phi, su2double val_psie, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \overload - * \param[in] val_solution - Pointer to the adjoint value (initialization value). - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAdjNSVariable(su2double *val_solution, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAdjNSVariable(void); - - /*! - * \brief Set the value of the adjoint velocity. - * \param[in] val_phi - Value of the adjoint velocity. - */ - void SetPhi_Old(su2double *val_phi); - - /*! - * \brief Set the value of the force projection vector. - * \param[in] val_ForceProj_Vector - Pointer to the force projection vector. - */ - void SetForceProj_Vector(su2double *val_ForceProj_Vector); - - /*! - * \brief Get the value of the force projection vector. - * \return Pointer to the force projection vector. - */ - su2double *GetForceProj_Vector(void); - - /*! - * \brief Set the value of the force projection vector on the solution vector. - */ - void SetVelSolutionOldDVector(void); - - /*! - * \brief Set the value of the force projection vector on the old solution vector. - */ - void SetVelSolutionDVector(void); - -}; - -/*! - * \class CAdjTurbVariable - * \brief Main class for defining the variables of the adjoint turbulence model. - * \ingroup Turbulence_Model - * \author A. Bueno. - * \version 4.0.1 "Cardinal" - */ -class CAdjTurbVariable : public CVariable { -protected: - su2double *dmuT_dUTvar; /*!< \brief Sensitivity of eddy viscosity to mean flow and turbulence vars. */ - su2double **dRTstar_dUTvar; /*!< \brief Sensitivity of modified turbulence residual (no boundary flux) - to mean flow and turbulence vars. */ - su2double **dFT_dUTvar; /*!< \brief Sensitivity of boundary flux - to mean flow and turbulence vars. */ - su2double *EddyViscSens; /*!< \brief Eddy Viscosity Sensitivity. */ - -public: - - /*! - * \brief Constructor of the class. - */ - CAdjTurbVariable(void); - - /*! - * \overload - * \param[in] val_psinu_inf - Value of the adjoint turbulence variable at the infinity (initialization value). - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAdjTurbVariable(su2double val_psinu_inf, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CAdjTurbVariable(void); - - /*! - * \brief Set the Eddy Viscosity Sensitivity of the problem. - * \param[in] val_EddyViscSens - Eddy Viscosity Sensitivity. - */ - void SetEddyViscSens(su2double *val_EddyViscSens, unsigned short numTotalVar); - - /*! - * \brief Get the Eddy Viscosity Sensitivity of the problem. - * \return Pointer to the Eddy Viscosity Sensitivity. - */ - su2double *GetEddyViscSens(void); -}; - -/*! - * \class CAdjLevelSetVariable - * \brief Main class for defining the variables of the Level Set. - * \ingroup LevelSet_Model - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CAdjLevelSetVariable : public CVariable { -public: - /*! - * \brief Constructor of the class. - */ - CAdjLevelSetVariable(void); - - /*! - * \overload - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAdjLevelSetVariable(unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \overload - * \param[in] val_levelset - Level set variable value (initialization value). - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CAdjLevelSetVariable(su2double val_levelset, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - virtual ~CAdjLevelSetVariable(void); - -}; - -/*! - * \class CTemplateVariable - * \brief Main class for defining the variables of the potential solver. - * \ingroup Potential_Flow_Equation - * \author F. Palacios - * \version 4.0.1 "Cardinal" - */ -class CTemplateVariable : public CVariable { -public: - - /*! - * \brief Constructor of the class. - */ - CTemplateVariable(void); - - /*! - * \overload - * \param[in] val_potential - Value of the potential solution (initialization value). - * \param[in] val_nDim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CTemplateVariable(su2double val_potential, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CTemplateVariable(void); -}; - -/*! - * \class CDiscAdjVariable - * \brief Main class for defining the variables of the adjoint solver. - * \ingroup Discrete_Adjoint - * \author T. Albring. - * \version 4.0.1 "Cardinal" - */ -class CDiscAdjVariable : public CVariable { -private: - su2double* Sensitivity; /* Vector holding the derivative of target functional with respect to the coordinates at this node*/ - su2double* Solution_Direct; - su2double* DualTime_Derivative; - su2double* DualTime_Derivative_n; - -public: - /*! - * \brief Constructor of the class. - */ - CDiscAdjVariable(void); - - /*! - * \brief Destructor of the class. - */ - ~CDiscAdjVariable(void); - - /*! - * \overload - * \param[in] val_solution - Pointer to the adjoint value (initialization value). - * \param[in] val_ndim - Number of dimensions of the problem. - * \param[in] val_nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - CDiscAdjVariable(su2double *val_solution, unsigned short val_ndim, unsigned short val_nvar, CConfig *config); - - /*! - * \brief Set the sensitivity at the node - * \param[in] iDim - spacial component - * \param[in] val - value of the Sensitivity - */ - void SetSensitivity(unsigned short iDim, su2double val); - - /*! - * \brief Get the Sensitivity at the node - * \param[in] iDim - spacial component - * \return value of the Sensitivity - */ - su2double GetSensitivity(unsigned short iDim); - - void SetDual_Time_Derivative(unsigned short iVar, su2double der); - - void SetDual_Time_Derivative_n(unsigned short iVar, su2double der); - - su2double GetDual_Time_Derivative(unsigned short iVar); - - su2double GetDual_Time_Derivative_n(unsigned short iVar); - - void SetSolution_Direct(su2double *sol); - - su2double* GetSolution_Direct(); -}; - - -#include "variable_structure.inl" +/*! + * \file variable_structure.hpp + * \brief Headers of the main subroutines for storing all the variables for + * each kind of governing equation (direct, adjoint and linearized). + * The subroutines and functions are in the variable_structure.cpp file. + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +#include "../../Common/include/mpi_structure.hpp" + +#include +#include +#include + +#include "../../Common/include/config_structure.hpp" +#include "fluid_model.hpp" + + +using namespace std; + +/*! + * \class CVariable + * \brief Main class for defining the variables. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CVariable { +protected: + + su2double *Solution, /*!< \brief Solution of the problem. */ + *Solution_Old; /*!< \brief Old solution of the problem R-K. */ + bool Non_Physical; /*!< \brief Non-physical points in the solution (force first order). */ + su2double *Solution_time_n, /*!< \brief Solution of the problem at time n for dual-time stepping technique. */ + *Solution_time_n1; /*!< \brief Solution of the problem at time n-1 for dual-time stepping technique. */ + su2double **Gradient; /*!< \brief Gradient of the solution of the problem. */ + su2double *Limiter; /*!< \brief Limiter of the solution of the problem. */ + su2double *Solution_Max; /*!< \brief Max solution for limiter computation. */ + su2double *Solution_Min; /*!< \brief Min solution for limiter computation. */ + su2double AuxVar; /*!< \brief Auxiliar variable for gradient computation. */ + su2double *Grad_AuxVar; /*!< \brief Gradient of the auxiliar variable. */ + su2double Delta_Time; /*!< \brief Time step. */ + su2double Max_Lambda, /*!< \brief Maximun eingenvalue. */ + Max_Lambda_Inv, /*!< \brief Maximun inviscid eingenvalue. */ + Max_Lambda_Visc, /*!< \brief Maximun viscous eingenvalue. */ + Lambda; /*!< \brief Value of the eingenvalue. */ + su2double Sensor; /*!< \brief Pressure sensor for high order central scheme. */ + su2double *Undivided_Laplacian; /*!< \brief Undivided laplacian of the solution. */ + su2double *Res_TruncError, /*!< \brief Truncation error for multigrid cycle. */ + *Residual_Old, /*!< \brief Auxiliar structure for residual smoothing. */ + *Residual_Sum; /*!< \brief Auxiliar structure for residual smoothing. */ + static unsigned short nDim; /*!< \brief Number of dimension of the problem. */ + unsigned short nVar; /*!< \brief Number of variables of the problem, + note that this variable cannnot be static, it is possible to + have different number of nVar in the same problem. */ + unsigned short nPrimVar, nPrimVarGrad; /*!< \brief Number of variables of the problem, + note that this variable cannnot be static, it is possible to + have different number of nVar in the same problem. */ + unsigned short nSecondaryVar, nSecondaryVarGrad; /*!< \brief Number of variables of the problem, + note that this variable cannnot be static, it is possible to + have different number of nVar in the same problem. */ + +public: + + /*! + * \brief Constructor of the class. + */ + CVariable(void); + + /*! + * \overload + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CVariable(unsigned short val_nvar, CConfig *config); + + /*! + * \overload + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CVariable(unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + virtual ~CVariable(void); + + /*! + * \brief Set the value of the solution. + * \param[in] val_solution - Solution of the problem. + */ + void SetSolution(su2double *val_solution); + + /*! + * \overload + * \param[in] val_var - Index of the variable. + * \param[in] val_solution - Value of the solution for the index val_var. + */ + void SetSolution(unsigned short val_var, su2double val_solution); + + /*! + * \brief Set the value of the non-physical point. + * \param[in] val_value - identification of the non-physical point. + */ + void SetNon_Physical(bool val_value); + + /*! + * \brief Get the value of the non-physical point. + * \return Value of the Non-physical point. + */ + su2double GetNon_Physical(void); + + /*! + * \brief Get the solution. + * \param[in] val_var - Index of the variable. + * \return Value of the solution for the index val_var. + */ + su2double GetSolution(unsigned short val_var); + + /*! + * \brief Get the old solution of the problem (Runge-Kutta method) + * \param[in] val_var - Index of the variable. + * \return Pointer to the old solution vector. + */ + su2double GetSolution_Old(unsigned short val_var); + + /*! + * \brief Set the value of the old solution. + * \param[in] val_solution_old - Pointer to the residual vector. + */ + void SetSolution_Old(su2double *val_solution_old); + + /*! + * \overload + * \param[in] val_var - Index of the variable. + * \param[in] val_solution_old - Value of the old solution for the index val_var. + */ + void SetSolution_Old(unsigned short val_var, su2double val_solution_old); + + /*! + * \brief Set old variables to the value of the current variables. + */ + void Set_OldSolution(void); + + /*! + * \brief Set variables to the value of the old variables. + */ + void Set_Solution(void); + + /*! + * \brief Set the variable solution at time n. + */ + void Set_Solution_time_n(void); + + /*! + * \brief Set the variable solution at time n-1. + */ + void Set_Solution_time_n1(void); + + /*! + * \brief Set the variable solution at time n. + */ + void Set_Solution_time_n(su2double* val_sol); + + /*! + * \brief Set the variable solution at time n-1. + */ + void Set_Solution_time_n1(su2double* val_sol); + + /*! + * \brief Set to zero the velocity components of the solution. + */ + void SetVelSolutionZero(void); + + /*! + * \brief Specify a vector to set the velocity components of the solution. + * \param[in] val_vector - Pointer to the vector. + */ + void SetVelSolutionVector(su2double *val_vector); + + /*! + * \brief Set to zero velocity components of the solution. + */ + void SetVelSolutionOldZero(void); + + /*! + * \brief Specify a vector to set the velocity components of the old solution. + * \param[in] val_vector - Pointer to the vector. + */ + void SetVelSolutionOldVector(su2double *val_vector); + + /*! + * \brief Set to zero the solution. + */ + void SetSolutionZero(void); + + /*! + * \brief Set to zero a particular solution. + */ + void SetSolutionZero(unsigned short val_var); + + /*! + * \brief Add a value to the solution. + * \param[in] val_var - Number of the variable. + * \param[in] val_solution - Value that we want to add to the solution. + */ + void AddSolution(unsigned short val_var, su2double val_solution); + + /*! + * \brief Add a value to the solution, clipping the values. + * \param[in] val_var - Index of the variable. + * \param[in] val_solution - Value of the solution change. + * \param[in] lowerlimit - Lower value. + * \param[in] upperlimit - Upper value. + */ + void AddClippedSolution(unsigned short val_var, su2double val_solution, + su2double lowerlimit, su2double upperlimit); + + /*! + * \brief Update the variables using a conservative format. + * \param[in] val_var - Index of the variable. + * \param[in] val_solution - Value of the solution change. + * \param[in] val_density - Value of the density. + * \param[in] val_density_old - Value of the old density. + */ + void AddConservativeSolution(unsigned short val_var, su2double val_solution, + su2double val_density, su2double val_density_old, su2double lowerlimit, + su2double upperlimit); + + /*! + * \brief Get the solution of the problem. + * \return Pointer to the solution vector. + */ + su2double *GetSolution(void); + + /*! + * \brief Get the old solution of the problem (Runge-Kutta method) + * \return Pointer to the old solution vector. + */ + su2double *GetSolution_Old(void); + + /*! + * \brief Get the solution at time n. + * \return Pointer to the solution (at time n) vector. + */ + su2double *GetSolution_time_n(void); + + /*! + * \brief Get the solution at time n-1. + * \return Pointer to the solution (at time n-1) vector. + */ + su2double *GetSolution_time_n1(void); + + /*! + * \brief Set the value of the old residual. + * \param[in] val_residual_old - Pointer to the residual vector. + */ + void SetResidual_Old(su2double *val_residual_old); + + /*! + * \brief Add a value to the summed residual vector. + * \param[in] val_residual - Pointer to the residual vector. + */ + void AddResidual_Sum(su2double *val_residual); + + /*! + * \brief Set summed residual vector to zero value. + */ + void SetResidualSumZero(void); + + /*! + * \brief Set the velocity of the truncation error to zero. + */ + virtual void SetVel_ResTruncError_Zero(unsigned short iSpecies); + + /*! + * \brief Get the value of the summed residual. + * \return Pointer to the summed residual. + */ + su2double *GetResidual_Sum(void); + + /*! + * \brief Get the value of the old residual. + * \return Pointer to the old residual. + */ + su2double *GetResidual_Old(void); + + /*! + * \brief Get the value of the summed residual. + * \param[in] val_residual - Pointer to the summed residual. + */ + void GetResidual_Sum(su2double *val_residual); + + /*! + * \brief Set auxiliar variables, we are looking for the gradient of that variable. + * \param[in] val_auxvar - Value of the auxiliar variable. + */ + void SetAuxVar(su2double val_auxvar); + + /*! + * \brief Get the value of the auxiliary variable. + * \return Value of the auxiliary variable. + */ + su2double GetAuxVar(void); + + /*! + * \brief Set the auxiliary variable gradient to zero value. + */ + void SetAuxVarGradientZero(void); + + /*! + * \brief Set the value of the auxiliary variable gradient. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_gradient - Value of the gradient for the index val_dim. + */ + void SetAuxVarGradient(unsigned short val_dim, su2double val_gradient); + + /*! + * \brief Add a value to the auxiliary variable gradient. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value of the gradient to be added for the index val_dim. + */ + void AddAuxVarGradient(unsigned short val_dim, su2double val_value); + + /*! + * \brief Subtract a value to the auxiliary variable gradient. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value of the gradient to be subtracted for the index val_dim. + */ + void SubtractAuxVarGradient(unsigned short val_dim, su2double val_value); + + /*! + * \brief Get the gradient of the auxiliary variable. + * \return Value of the gradient of the auxiliary variable. + */ + su2double *GetAuxVarGradient(void); + + /*! + * \brief Get the gradient of the auxiliary variable. + * \param[in] val_dim - Index of the dimension. + * \return Value of the gradient of the auxiliary variable for the dimension val_dim. + */ + su2double GetAuxVarGradient(unsigned short val_dim); + + /*! + * \brief Add a value to the truncation error. + * \param[in] val_truncation_error - Value that we want to add to the truncation error. + */ + void AddRes_TruncError(su2double *val_truncation_error); + + /*! + * \brief Subtract a value to the truncation error. + * \param[in] val_truncation_error - Value that we want to subtract to the truncation error. + */ + void SubtractRes_TruncError(su2double *val_truncation_error); + + /*! + * \brief Set the truncation error to zero. + */ + void SetRes_TruncErrorZero(void); + + /*! + * \brief Set the truncation error to zero. + */ + void SetVal_ResTruncError_Zero(unsigned short val_var); + + /*! + * \brief Set the velocity of the truncation error to zero. + */ + void SetVel_ResTruncError_Zero(void); + + /*! + * \brief Set the velocity of the truncation error to zero. + */ + void SetEnergy_ResTruncError_Zero(void); + + /*! + * \brief Get the truncation error. + * \return Pointer to the truncation error. + */ + su2double *GetResTruncError(void); + + /*! + * \brief Get the truncation error. + * \param[in] val_trunc_error - Pointer to the truncation error. + */ + void GetResTruncError(su2double *val_trunc_error); + + /*! + * \brief Set the gradient of the solution. + * \param[in] val_gradient - Gradient of the solution. + */ + void SetGradient(su2double **val_gradient); + + /*! + * \overload + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value of the gradient. + */ + void SetGradient(unsigned short val_var, unsigned short val_dim, su2double val_value); + + /*! + * \brief Set to zero the gradient of the solution. + */ + void SetGradientZero(void); + + /*! + * \brief Add val_value to the solution gradient. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value to add to the solution gradient. + */ + void AddGradient(unsigned short val_var, unsigned short val_dim, su2double val_value); + + /*! + * \brief Subtract val_value to the solution gradient. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value to subtract to the solution gradient. + */ + void SubtractGradient(unsigned short val_var, unsigned short val_dim, su2double val_value); + + /*! + * \brief Get the value of the solution gradient. + * \return Value of the gradient solution. + */ + su2double **GetGradient(void); + + /*! + * \brief Get the value of the solution gradient. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \return Value of the solution gradient. + */ + su2double GetGradient(unsigned short val_var, unsigned short val_dim); + + /*! + * \brief Set the value of the limiter. + * \param[in] val_var - Index of the variable. + * \param[in] val_limiter - Value of the limiter for the index val_var. + */ + void SetLimiter(unsigned short val_var, su2double val_limiter); + + /*! + * \brief Set the value of the limiter. + * \param[in] val_var - Index of the variable. + * \param[in] val_limiter - Value of the limiter for the index val_var. + */ + virtual void SetLimiterPrimitive(unsigned short val_species, unsigned short val_var, su2double val_limiter); + + /*! + * \brief Set the value of the limiter. + * \param[in] val_species - Value of the limiter for the index val_var. + * \param[in] val_var - Index of the variable. + */ + virtual su2double GetLimiterPrimitive(unsigned short val_species, unsigned short val_var); + + /*! + * \brief Set the value of the max solution. + * \param[in] val_var - Index of the variable. + * \param[in] val_solution - Value of the max solution for the index val_var. + */ + void SetSolution_Max(unsigned short val_var, su2double val_solution); + + /*! + * \brief Set the value of the min solution. + * \param[in] val_var - Index of the variable. + * \param[in] val_solution - Value of the min solution for the index val_var. + */ + void SetSolution_Min(unsigned short val_var, su2double val_solution); + + /*! + * \brief Get the value of the slope limiter. + * \return Pointer to the limiters vector. + */ + su2double *GetLimiter(void); + + /*! + * \brief Get the value of the slope limiter. + * \param[in] val_var - Index of the variable. + * \return Value of the limiter vector for the variable val_var. + */ + su2double GetLimiter(unsigned short val_var); + + /*! + * \brief Get the value of the min solution. + * \param[in] val_var - Index of the variable. + * \return Value of the min solution for the variable val_var. + */ + su2double GetSolution_Max(unsigned short val_var); + + /*! + * \brief Get the value of the min solution. + * \param[in] val_var - Index of the variable. + * \return Value of the min solution for the variable val_var. + */ + su2double GetSolution_Min(unsigned short val_var); + + /*! + * \brief Get the value of the preconditioner Beta. + * \return Value of the low Mach preconditioner variable Beta + */ + virtual su2double GetPreconditioner_Beta(); + + /*! + * \brief Set the value of the preconditioner Beta. + * \param[in] val_Beta - Value of the low Mach preconditioner variable Beta + */ + virtual void SetPreconditioner_Beta(su2double val_Beta); + + /*! + * \brief Get the value of the wind gust + * \return Value of the wind gust + */ + virtual su2double* GetWindGust(); + + /*! + * \brief Set the value of the wind gust + * \param[in] val_WindGust - Value of the wind gust + */ + virtual void SetWindGust(su2double* val_WindGust); + + /*! + * \brief Get the value of the derivatives of the wind gust + * \return Value of the derivatives of the wind gust + */ + virtual su2double* GetWindGustDer(); + + /*! + * \brief Set the value of the derivatives of the wind gust + * \param[in] val_WindGust - Value of the derivatives of the wind gust + */ + virtual void SetWindGustDer(su2double* val_WindGust); + + /*! + * \brief Set the value of the time step. + * \param[in] val_delta_time - Value of the time step. + */ + void SetDelta_Time(su2double val_delta_time); + + /*! + * \brief Set the value of the time step. + * \param[in] val_delta_time - Value of the time step. + * \param[in] iSpecies - Index of the Species . + */ + virtual void SetDelta_Time(su2double val_delta_time, unsigned short iSpecies); + + /*! + * \brief Get the value of the time step. + * \return Value of the time step. + */ + su2double GetDelta_Time(void); + + /*! + * \brief Get the value of the time step. + * \param[in] iSpecies - Index of the Species + * \return Value of the time step. + */ + virtual su2double GetDelta_Time(unsigned short iSpecies); + + /*! + * \brief Set the value of the maximum eigenvalue. + * \param[in] val_max_lambda - Value of the maximum eigenvalue. + */ + void SetMax_Lambda(su2double val_max_lambda); + + /*! + * \brief Set the value of the maximum eigenvalue for the inviscid terms of the PDE. + * \param[in] val_max_lambda - Value of the maximum eigenvalue for the inviscid terms of the PDE. + */ + void SetMax_Lambda_Inv(su2double val_max_lambda); + + /*! + * \brief Set the value of the maximum eigenvalue for the inviscid terms of the PDE. + * \param[in] val_max_lambda - Value of the maximum eigenvalue for the inviscid terms of the PDE. + * \param[in] val_species - Value of the species index to set the maximum eigenvalue. + */ + virtual void SetMax_Lambda_Inv(su2double val_max_lambda, unsigned short val_species); + + /*! + * \brief Set the value of the maximum eigenvalue for the viscous terms of the PDE. + * \param[in] val_max_lambda - Value of the maximum eigenvalue for the viscous terms of the PDE. + */ + void SetMax_Lambda_Visc(su2double val_max_lambda); + + /*! + * \brief Set the value of the maximum eigenvalue for the viscous terms of the PDE. + * \param[in] val_max_lambda - Value of the maximum eigenvalue for the viscous terms of the PDE. + * \param[in] val_species - Index of the species to set the maximum eigenvalue of the viscous terms. + */ + virtual void SetMax_Lambda_Visc(su2double val_max_lambda, unsigned short val_species); + + /*! + * \brief Add a value to the maximum eigenvalue. + * \param[in] val_max_lambda - Value of the maximum eigenvalue. + */ + void AddMax_Lambda(su2double val_max_lambda); + + /*! + * \brief Add a value to the maximum eigenvalue for the inviscid terms of the PDE. + * \param[in] val_max_lambda - Value of the maximum eigenvalue for the inviscid terms of the PDE. + */ + void AddMax_Lambda_Inv(su2double val_max_lambda); + + /*! + * \brief Add a value to the maximum eigenvalue for the viscous terms of the PDE. + * \param[in] val_max_lambda - Value of the maximum eigenvalue for the viscous terms of the PDE. + */ + void AddMax_Lambda_Visc(su2double val_max_lambda); + + /*! + * \brief Get the value of the maximum eigenvalue. + * \return the value of the maximum eigenvalue. + */ + su2double GetMax_Lambda(void); + + /*! + * \brief Get the value of the maximum eigenvalue for the inviscid terms of the PDE. + * \return the value of the maximum eigenvalue for the inviscid terms of the PDE. + */ + su2double GetMax_Lambda_Inv(void); + + /*! + * \brief Get the value of the maximum eigenvalue for the viscous terms of the PDE. + * \return the value of the maximum eigenvalue for the viscous terms of the PDE. + */ + su2double GetMax_Lambda_Visc(void); + + /*! + * \brief Set the value of the spectral radius. + * \param[in] val_lambda - Value of the spectral radius. + */ + void SetLambda(su2double val_lambda); + + /*! + * \brief Set the value of the spectral radius. + * \param[in] val_lambda - Value of the spectral radius. + * \param[in] val_iSpecies -Index of species + */ + virtual void SetLambda(su2double val_lambda, unsigned short val_iSpecies); + + /*! + * \brief Add the value of the spectral radius. + * \param[in] val_lambda - Value of the spectral radius. + */ + void AddLambda(su2double val_lambda); + + /*! + * \brief Add the value of the spectral radius. + * \param[in] val_iSpecies -Index of species + * \param[in] val_lambda - Value of the spectral radius. + */ + virtual void AddLambda(su2double val_lambda, unsigned short val_iSpecies); + + /*! + * \brief Get the value of the spectral radius. + * \return Value of the spectral radius. + */ + su2double GetLambda(void); + + /*! + * \brief Get the value of the spectral radius. + * \param[in] val_iSpecies -Index of species + * \return Value of the spectral radius. + */ + virtual su2double GetLambda(unsigned short val_iSpecies); + + /*! + * \brief Set pressure sensor. + * \param[in] val_sensor - Value of the pressure sensor. + */ + void SetSensor(su2double val_sensor); + + /*! + * \brief Set pressure sensor. + * \param[in] val_sensor - Value of the pressure sensor. + * \param[in] val_sensor - Index of the Species. + */ + virtual void SetSensor(su2double val_sensor, unsigned short iSpecies); + + /*! + * \brief Get the pressure sensor. + * \return Value of the pressure sensor. + */ + su2double GetSensor(void); + + /*! + * \brief Get the pressure sensor. + * \param[in] iSpecies - index of species + * \return Value of the pressure sensor. + */ + virtual su2double GetSensor(unsigned short iSpecies); + + /*! + * \brief Set the value of the undivided laplacian of the solution. + * \param[in] val_var - Index of the variable. + * \param[in] val_undivided_laplacian - Value of the undivided solution for the index val_var. + */ + void SetUndivided_Laplacian(unsigned short val_var, su2double val_undivided_laplacian); + + /*! + * \brief Add the value of the undivided laplacian of the solution. + * \param[in] val_und_lapl - Value of the undivided solution. + */ + void AddUnd_Lapl(su2double *val_und_lapl); + + /*! + * \brief Subtract the value of the undivided laplacian of the solution. + * \param[in] val_und_lapl - Value of the undivided solution. + */ + void SubtractUnd_Lapl(su2double *val_und_lapl); + + /*! + * \brief Subtract the value of the undivided laplacian of the solution. + * \param[in] val_var - Variable of the undivided laplacian. + * \param[in] val_und_lapl - Value of the undivided solution. + */ + void SubtractUnd_Lapl(unsigned short val_var, su2double val_und_lapl); + + /*! + * \brief Set the undivided laplacian of the solution to zero. + */ + void SetUnd_LaplZero(void); + + /*! + * \brief Set a value to the undivided laplacian. + * \param[in] val_var - Variable of the undivided laplacian. + * \param[in] val_und_lapl - Value of the undivided laplacian. + */ + void SetUnd_Lapl(unsigned short val_var, su2double val_und_lapl); + + /*! + * \brief Get the undivided laplacian of the solution. + * \return Pointer to the undivided laplacian vector. + */ + su2double *GetUndivided_Laplacian(void); + + /*! + * \brief Get the undivided laplacian of the solution. + * \param[in] val_var - Variable of the undivided laplacian. + * \return Value of the undivided laplacian vector. + */ + su2double GetUndivided_Laplacian(unsigned short val_var); + + /*! + * \brief A virtual member. + * \return Value of the flow density. + */ + virtual su2double GetDensity(void); + + /*! + * \brief A virtual member. + * \return Value of the flow density. + */ + virtual su2double GetDensity(unsigned short val_iSpecies); + + /*! + * \brief A virtual member. + * \param[in] val_Species - Index of species s. + * \return Value of the mass fraction of species s. + */ + virtual su2double GetMassFraction(unsigned short val_Species); + + /*! + * \brief A virtual member. + * \return Value of the flow energy. + */ + virtual su2double GetEnergy(void); + + /*! + * \brief A virtual member. + * \return Pointer to the force projection vector. + */ + virtual su2double *GetForceProj_Vector(void); + + /*! + * \brief A virtual member. + * \return Pointer to the objective function source. + */ + virtual su2double *GetObjFuncSource(void); + + /*! + * \brief A virtual member. + * \return Pointer to the internal boundary vector. + */ + virtual su2double *GetIntBoundary_Jump(void); + + /*! + * \brief A virtual member. + * \return Value of the eddy viscosity. + */ + virtual su2double GetEddyViscosity(void); + + /*! + * \brief A virtual member. + * \return Value of the eddy viscosity. + */ + virtual su2double GetEddyViscosityInc(void); + + /*! + * \brief A virtual member. + * \return Value of the flow enthalpy. + */ + virtual su2double GetEnthalpy(void); + + /*! + * \brief A virtual member. + * \return Value of the flow pressure. + */ + virtual su2double GetPressure(void); + + /*! + * \brief A virtual member. + * \return Value of the flow pressure. + */ + virtual su2double GetPressureInc(void); + + /*! + * \brief A virtual member. + * \param[in] val_vector - Direction of projection. + * \return Value of the projected velocity. + */ + virtual su2double GetProjVel(su2double *val_vector); + + /*! + * \brief A virtual member. + * \param[in] val_vector - Direction of projection. + * \param[in] val_species - Index of the desired species. + * \return Value of the projected velocity. + */ + virtual su2double GetProjVel(su2double *val_vector, unsigned short val_species); + + /*! + * \brief A virtual member. + * \return Value of the sound speed. + */ + virtual su2double GetSoundSpeed(void); + + /*! + * \brief A virtual member. + * \return Value of the density for the incompressible flow. + */ + virtual su2double GetDensityInc(void); + + /*! + * \brief A virtual member. + * \return Value of the levelset for the freesurface flows. + */ + virtual su2double GetLevelSet(void); + + /*! + * \brief A virtual member. + * \return Value of the distance for the freesurface flows. + */ + virtual su2double GetDistance(void); + + /*! + * \brief A virtual member. + * \return Value of the beta for the incompressible flow. + */ + virtual su2double GetBetaInc2(void); + + /*! + * \brief A virtual member. + * \return Value of the temperature. + */ + virtual su2double GetTemperature(void); + + /*! + * \brief A virtual member. + * \return Value of the vibrational-electronic temperature. + */ + virtual su2double GetTemperature_ve(void); + + /*! + * \brief A virtual member -- Get the mixture specific heat at constant volume (trans.-rot.). + * \return \f$\rho C^{t-r}_{v} \f$ + */ + virtual su2double GetRhoCv_tr(void); + + /*! + * \brief A virtual member -- Get the mixture specific heat at constant volume (vib.-el.). + * \return \f$\rho C^{v-e}_{v} \f$ + */ + virtual su2double GetRhoCv_ve(void); + + /*! + * \brief A virtual member. + * \param[in] val_dim - Index of the dimension. + * \return Value of the velocity for the dimension val_dim. + */ + virtual su2double GetVelocity(unsigned short val_dim); + + /*! + * \brief A virtual member. + * \return Norm 2 of the velocity vector. + */ + virtual su2double GetVelocity2(void); + + /*! + * \brief A virtual member. + * \return Norm 2 of the velocity vector of Fluid val_species. + */ + virtual su2double GetVelocity2(unsigned short val_species); + + /*! + * \brief A virtual member. + * \return The laminar viscosity of the flow. + */ + virtual su2double GetLaminarViscosity(void); + + /*! + * \brief A virtual member. + * \return The laminar viscosity of the incompressible flow. + */ + virtual su2double GetLaminarViscosityInc(void); + + /*! + * \brief A virtual member. + * \return The laminar viscosity of the flow. + */ + virtual su2double GetLaminarViscosity(unsigned short iSpecies); + + /*! + * \brief A virtual member. + * \return Value of the species diffusion coefficient. + */ + virtual su2double* GetDiffusionCoeff(void); + + /*! + * \brief A virtual member. + * \return Value of the thermal conductivity (translational/rotational) + */ + virtual su2double GetThermalConductivity(void); + + /*! + * \brief A virtual member. + * \return Value of the specific heat at constant P + */ + virtual su2double GetSpecificHeatCp(void); + + /*! + * \brief A virtual member. + * \return Value of the thermal conductivity (vibrational) + */ + virtual su2double GetThermalConductivity_ve(void); + + /*! + * \brief A virtual member. + * \return Sets separation intermittency + */ + virtual void SetGammaSep(su2double gamma_sep); + + /*! + * \brief A virtual member. + * \return Sets separation intermittency + */ + virtual void SetGammaEff(void); + + /*! + * \brief A virtual member. + * \return Returns intermittency + */ + virtual su2double GetIntermittency(); + + /*! + * \brief A virtual member. + * \param[in] val_dim - Index of the dimension. + * \return Value of the vorticity. + */ + virtual su2double *GetVorticity(void); + + /*! + * \brief A virtual member. + * \return Value of the rate of strain magnitude. + */ + virtual su2double GetStrainMag(void); + + /*! + * \brief A virtual member. + * \param[in] val_ForceProj_Vector - Pointer to the force projection vector. + */ + virtual void SetForceProj_Vector(su2double *val_ForceProj_Vector); + + /*! + * \brief A virtual member. + * \param[in] val_SetObjFuncSource - Pointer to the objective function source. + */ + virtual void SetObjFuncSource(su2double *val_SetObjFuncSource); + + /*! + * \brief A virtual member. + * \param[in] val_IntBoundary_Jump - Pointer to the interior boundary jump. + */ + virtual void SetIntBoundary_Jump(su2double *val_IntBoundary_Jump); + + /*! + * \brief A virtual member. + * \param[in] eddy_visc - Value of the eddy viscosity. + */ + virtual void SetEddyViscosity(su2double eddy_visc); + + /*! + * \brief A virtual member. + * \param[in] eddy_visc - Value of the eddy viscosity. + */ + virtual void SetEddyViscosityInc(su2double eddy_visc); + + /*! + * \brief A virtual member. + */ + virtual void SetEnthalpy(void); + + /*! + * \brief A virtual member. + */ + virtual bool SetPrimVar_Compressible(CConfig *config); + + /*! + * \brief A virtual member. + */ + virtual bool SetPrimVar_Compressible(CFluidModel *FluidModel); + + /*! + * \brief A virtual member. + */ + virtual void SetSecondaryVar_Compressible(CFluidModel *FluidModel); + + /*! + * \brief A virtual member. + */ + virtual bool Cons2PrimVar(CConfig *config, su2double *U, su2double *V, + su2double *dPdU, su2double *dTdU, + su2double *dTvedU); + /*! + * \brief A virtual member. + */ + virtual void Prim2ConsVar(CConfig *config, su2double *V, su2double *U); + + /*! + * \brief A virtual member. + */ + virtual bool SetPrimVar_Compressible(su2double SharpEdge_Distance, bool check, CConfig *config); + + /*! + * \brief A virtual member. + */ + virtual bool SetPrimVar_Incompressible(su2double SharpEdge_Distance, bool check, CConfig *config); + + /*! + * \brief A virtual member. + */ + virtual bool SetPrimVar_FreeSurface(su2double SharpEdge_Distance, bool check, CConfig *config); + + /*! + * \brief A virtual member. + */ + virtual bool SetPrimVar_Compressible(su2double eddy_visc, su2double turb_ke, CConfig *config); + + /*! + * \brief A virtual member. + */ + virtual bool SetPrimVar_Compressible(su2double eddy_visc, su2double turb_ke, CFluidModel *FluidModel); + + /*! + * \brief A virtual member. + */ + virtual bool SetPrimVar_Incompressible(su2double Density_Inf, CConfig *config); + + /*! + * \brief A virtual member. + */ + virtual bool SetPrimVar_FreeSurface(CConfig *config); + + /*! + * \brief A virtual member. + */ + virtual bool SetPrimVar_Incompressible(su2double Density_Inf, su2double Viscosity_Inf, su2double eddy_visc, su2double turb_ke, CConfig *config); + + /*! + * \brief A virtual member. + */ + virtual bool SetPrimVar_FreeSurface(su2double eddy_visc, su2double turb_ke, CConfig *config); + + /*! + * \brief A virtual member. + */ + virtual su2double GetPrimitive(unsigned short val_var); + + /*! + * \brief A virtual member. + */ + virtual void SetPrimitive(unsigned short val_var, su2double val_prim); + + /*! + * \brief A virtual member. + */ + virtual void SetPrimitive(su2double *val_prim); + + /*! + * \brief A virtual member. + */ + virtual su2double *GetPrimitive(void); + + /*! + * \brief A virtual member. + */ + virtual su2double GetSecondary(unsigned short val_var); + + /*! + * \brief A virtual member. + */ + virtual void SetSecondary(unsigned short val_var, su2double val_secondary); + + /*! + * \brief A virtual member. + */ + virtual void SetSecondary(su2double *val_secondary); + + /*! + * \brief A virtual member. + */ + virtual void SetdPdrho_e(su2double dPdrho_e); + + /*! + * \brief A virtual member. + */ + virtual void SetdPde_rho(su2double dPde_rho); + + /*! + * \brief A virtual member. + */ + virtual void SetdTdrho_e(su2double dTdrho_e); + + /*! + * \brief A virtual member. + */ + virtual void SetdTde_rho(su2double dTde_rho); + + /*! + * \brief A virtual member. + */ + virtual void Setdmudrho_T(su2double dmudrho_T); + + /*! + * \brief A virtual member. + */ + virtual void SetdmudT_rho(su2double dmudT_rho); + + /*! + * \brief A virtual member. + */ + virtual void Setdktdrho_T(su2double dktdrho_T); + + /*! + * \brief A virtual member. + */ + virtual void SetdktdT_rho(su2double dktdT_rho); + + /*! + * \brief A virtual member. + */ + virtual su2double *GetSecondary(void); + + /*! + * \brief A virtual member. + */ + virtual void SetDensityInc(su2double val_density); + + /*! + * \brief A virtual member. + */ + virtual void SetPressureInc(void); + + /*! + * \brief A virtual member. + */ + virtual void SetVelocityInc(void); + + /*! + * \brief A virtual member. + */ + virtual void SetBetaInc2(su2double val_betainc2); + + /*! + * \brief A virtual member. + * \param[in] val_phi - Value of the adjoint velocity. + */ + virtual void SetPhi_Old(su2double *val_phi); + + /*! + * \brief A virtual member. + * \param[in] Gamma - Ratio of Specific heats + */ + virtual bool SetPressure(su2double Gamma); + + /*! + * \brief A virtual member. + * \param[in] config + */ + virtual bool SetPressure(CConfig *config); + + /*! + * \brief A virtual member. + */ + virtual bool SetPressure(su2double Gamma, su2double turb_ke); + + /*! + * \brief A virtual member. + */ + virtual void SetPressure(void); + + /*! + * \brief Calculates vib.-el. energy per mass, \f$e^{vib-el}_s\f$, for input species (not including KE) + */ + virtual su2double CalcEve(su2double *V, CConfig *config, unsigned short val_Species); + + /*! + * \brief Calculates enthalpy per mass, \f$h_s\f$, for input species (not including KE) + */ + virtual su2double CalcHs(su2double *V, CConfig *config, unsigned short val_Species); + + /*! + * \brief Calculates enthalpy per mass, \f$Cv_s\f$, for input species (not including KE) + */ + virtual su2double CalcCvve(su2double val_Tve, CConfig *config, unsigned short val_Species); + + /*! + * \brief A virtual member. + * \param[in] config - Configuration settings + */ + virtual void CalcdPdU(su2double *V, CConfig *config, su2double *dPdU); + + /*! + * \brief Set partial derivative of temperature w.r.t. density \f$\frac{\partial P}{\partial \rho_s}\f$ + */ + virtual void CalcdTdU(su2double *V, CConfig *config, su2double *dTdU); + + /*! + * \brief Set partial derivative of temperature w.r.t. density \f$\frac{\partial P}{\partial \rho_s}\f$ + */ + virtual void CalcdTvedU(su2double *V, CConfig *config, su2double *dTdU); + + /*! + * \brief A virtual member. + */ + virtual su2double *GetdPdU(void); + + /*! + * \brief A virtual member. + */ + virtual su2double *GetdTdU(void); + + /*! + * \brief A virtual member. + */ + virtual su2double *GetdTvedU(void); + + /*! + * \brief A virtual member. + */ + virtual bool SetDensity(void); + + /*! + * \brief A virtual member. + * \param[in] val_velocity - Value of the velocity. + * \param[in] Gamma - Ratio of Specific heats + */ + virtual void SetDeltaPressure(su2double *val_velocity, su2double Gamma); + + /*! + * \brief A virtual member. + * \param[in] Gamma - Ratio of specific heats. + */ + virtual bool SetSoundSpeed(su2double Gamma); + + /*! + * \brief A virtual member. + * \param[in] config - Configuration parameters. + */ + virtual bool SetSoundSpeed(CConfig *config); + + /*! + * \brief A virtual member. + */ + virtual bool SetSoundSpeed(void); + + /*! + * \brief A virtual member. + * \param[in] Gas_Constant - Value of the Gas Constant + */ + virtual bool SetTemperature(su2double Gas_Constant); + + /*! + * \brief Sets the vibrational electronic temperature of the flow. + * \return Value of the temperature of the flow. + */ + virtual bool SetTemperature_ve(su2double val_Tve); + + /*! + * \brief A virtual member. + * \param[in] config - Configuration parameters. + */ + virtual bool SetTemperature(CConfig *config); + + /*! + * \brief A virtual member. + * \param[in] config - Configuration parameters. + */ + virtual void SetPrimitive(CConfig *config); + + /*! + * \brief A virtual member. + * \param[in] config - Configuration parameters. + */ + virtual void SetPrimitive(CConfig *config, su2double *Coord); + + /*! + * \brief A virtual member. + * \param[in] Temperature_Wall - Value of the Temperature at the wall + */ + virtual void SetWallTemperature(su2double Temperature_Wall); + + /*! + * \brief A virtual member. + * \param[in] Temperature_Wall - Value of the Temperature at the wall + */ + virtual void SetWallTemperature(su2double* Temperature_Wall); + + /*! + * \brief Set the thermal coefficient. + * \param[in] config - Configuration parameters. + */ + virtual void SetThermalCoeff(CConfig *config); + + /*! + * \brief A virtual member. + */ + virtual void SetVelocity(void); + + /*! + * \brief A virtual member. + */ + virtual void SetStress(unsigned short iVar, unsigned short jVar, su2double val_stress); + + /*! + * \brief A virtual member. + */ + virtual void AddStress(unsigned short iVar, unsigned short jVar, su2double val_stress); + + /*! + * \brief A virtual member. + + */ + virtual su2double **GetStress(void); + + /*! + * \brief A virtual member. + */ + virtual void SetVonMises_Stress(su2double val_stress); + + /*! + * \brief A virtual member. + + */ + virtual su2double GetVonMises_Stress(void); + + /*! + * \brief A virtual member. + */ + virtual void SetFlow_Pressure(su2double val_pressure); + + /*! + * \brief A virtual member. + + */ + virtual su2double GetFlow_Pressure(void); + + /*! + * \brief A virtual member. + */ + virtual void Initialize_Connectivity(void); + + /*! + * \brief A virtual member. + */ + virtual void Upgrade_Connectivity(void); + + /*! + * \brief A virtual member. + */ + virtual unsigned short Get_Connectivity(void); + + + /*! + * \brief A virtual member. + */ + virtual void SetTraction(unsigned short iVar, unsigned short jVar, su2double val_traction); + + /*! + * \brief A virtual member. + */ + virtual void AddTraction(unsigned short iVar, unsigned short jVar, su2double val_traction); + + /*! + * \brief A virtual member. + + */ + virtual su2double **GetTraction(void); + + + /*! + * \brief A virtual member. + */ + virtual void SetVelocity2(void); + + /*! + * \brief A virtual member. + * \param[in] val_velocity - Pointer to the velocity. + */ + virtual void SetVelocity_Old(su2double *val_velocity); + + /*! + * \brief A virtual member. + * \param[in] val_velocity - Pointer to the velocity. + */ + virtual void SetVelocityInc_Old(su2double *val_velocity); + + /*! + * \brief A virtual member. + * \param[in] laminarViscosity + */ + virtual void SetLaminarViscosity(su2double laminarViscosity); + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetLaminarViscosity(CConfig *config); + + /*! + * \brief A virtual member. + * \param[in] val_laminar_viscosity_inc - Value of the laminar viscosity (incompressible flows). + */ + virtual void SetLaminarViscosityInc(su2double val_laminar_viscosity_inc); + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetThermalConductivity(su2double thermalConductivity); + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetThermalConductivity(CConfig *config); + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetSpecificHeatCp(su2double Cp); + + /*! + * \brief A virtual member. + */ + virtual bool SetVorticity(bool val_limiter); + + /*! + * \brief A virtual member. + */ + virtual bool SetStrainMag(bool val_limiter); + + /*! + * \brief A virtual member. + */ + virtual void SetVelSolutionOldDVector(void); + + /*! + * \brief A virtual member. + */ + virtual void SetVelSolutionDVector(void); + + /*! + * \brief A virtual member. + */ + virtual void SetGradient_PrimitiveZero(unsigned short val_primvar); + + /*! + * \brief A virtual member. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value to add to the gradient of the primitive variables. + */ + virtual void AddGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value); + + /*! + * \brief A virtual member. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value to subtract to the gradient of the primitive variables. + */ + virtual void SubtractGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value); + + /*! + * \brief A virtual member. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \return Value of the primitive variables gradient. + */ + virtual su2double GetGradient_Primitive(unsigned short val_var, unsigned short val_dim); + + /*! + * \brief A virtual member. + * \param[in] val_var - Index of the variable. + * \return Value of the primitive variables gradient. + */ + virtual su2double GetLimiter_Primitive(unsigned short val_var); + + /*! + * \brief A virtual member. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value of the gradient. + */ + virtual void SetGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value); + + /*! + * \brief A virtual member. + * \param[in] val_var - Index of the variable. + * \param[in] val_value - Value of the gradient. + */ + virtual void SetLimiter_Primitive(unsigned short val_var, su2double val_value); + + /*! + * \brief A virtual member. + * \return Value of the primitive variables gradient. + */ + virtual su2double **GetGradient_Primitive(void); + + /*! + * \brief A virtual member. + * \return Value of the primitive variables gradient. + */ + virtual su2double *GetLimiter_Primitive(void); + + /*! + * \brief A virtual member. + */ + virtual void SetGradient_SecondaryZero(unsigned short val_secondaryvar); + + /*! + * \brief A virtual member. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value to add to the gradient of the Secondary variables. + */ + virtual void AddGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value); + + /*! + * \brief A virtual member. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value to subtract to the gradient of the Secondary variables. + */ + virtual void SubtractGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value); + + /*! + * \brief A virtual member. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \return Value of the Secondary variables gradient. + */ + virtual su2double GetGradient_Secondary(unsigned short val_var, unsigned short val_dim); + + /*! + * \brief A virtual member. + * \param[in] val_var - Index of the variable. + * \return Value of the Secondary variables gradient. + */ + virtual su2double GetLimiter_Secondary(unsigned short val_var); + + /*! + * \brief A virtual member. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value of the gradient. + */ + virtual void SetGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value); + + /*! + * \brief A virtual member. + * \param[in] val_var - Index of the variable. + * \param[in] val_value - Value of the gradient. + */ + virtual void SetLimiter_Secondary(unsigned short val_var, su2double val_value); + + /*! + * \brief A virtual member. + * \return Value of the Secondary variables gradient. + */ + virtual su2double **GetGradient_Secondary(void); + + /*! + * \brief A virtual member. + * \return Value of the Secondary variables gradient. + */ + virtual su2double *GetLimiter_Secondary(void); + + /*! + * \brief Set the blending function for the blending of k-w and k-eps. + * \param[in] val_viscosity - Value of the vicosity. + * \param[in] val_density - Value of the density. + * \param[in] val_dist - Value of the distance to the wall. + */ + virtual void SetBlendingFunc(su2double val_viscosity, su2double val_dist, su2double val_density); + + /*! + * \brief Get the first blending function of the SST model. + */ + virtual su2double GetF1blending(void); + + /*! + * \brief Get the second blending function of the SST model. + */ + virtual su2double GetF2blending(void); + + /*! + * \brief Get the value of the cross diffusion of tke and omega. + */ + virtual su2double GetCrossDiff(void) { return 0.0; }; + + /*! + * \brief Get the value of the eddy viscosity. + * \return the value of the eddy viscosity. + */ + virtual su2double GetmuT(void); + + /*! + * \brief Set the value of the eddy viscosity. + * \param[in] val_muT + */ + virtual void SetmuT(su2double val_muT); + + /*! + * \brief Add a value to the maximum eigenvalue for the inviscid terms of the PDE. + * \param[in] val_max_lambda - Value of the maximum eigenvalue for the inviscid terms of the PDE. + * \param[in] iSpecies - Value of iSpecies to which the eigenvalue belongs + */ + virtual void AddMax_Lambda_Inv(su2double val_max_lambda, unsigned short iSpecies); + + /*! + * \brief Add a value to the maximum eigenvalue for the viscous terms of the PDE. + * \param[in] val_max_lambda - Value of the maximum eigenvalue for the viscous terms of the PDE. + * \param[in] iSpecies - Value of iSpecies to which the eigenvalue belongs + */ + virtual void AddMax_Lambda_Visc(su2double val_max_lambda, unsigned short iSpecies); + + /*! + * \brief A virtual member. + * \param[in] val_difflevelset - Value of the diff level set (value-target). + */ + virtual void SetDiffLevelSet(su2double val_difflevelset); + + /*! + * \brief A virtual member. + */ + virtual su2double GetDiffLevelSet(void); + + /*! + * \brief A virtual member. + * \param[in] val_source - Value of the time spectral source. + */ + virtual void SetTimeSpectral_Source(unsigned short val_var, su2double val_source); + + /*! + * \brief A virtual member. + */ + virtual su2double GetTimeSpectral_Source(unsigned short val_var); + + /*! + * \brief Set the Eddy Viscosity Sensitivity of the problem. + * \param[in] val_EddyViscSens - Eddy Viscosity Sensitivity. + */ + virtual void SetEddyViscSens(su2double *val_EddyViscSens, unsigned short numTotalVar); + + /*! + * \brief Get the Eddy Viscosity Sensitivity of the problem. + * \return Pointer to the Eddy Viscosity Sensitivity. + */ + virtual su2double *GetEddyViscSens(void); + + /*! + * \brief A virtual member. Set the direct solution for the adjoint solver. + * \param[in] val_solution_direct - Value of the direct solution. + */ + virtual void SetSolution_Direct(su2double *val_solution_direct); + + /*! + * \brief A virtual member. Get the direct solution for the adjoint solver. + * \return Pointer to the direct solution vector. + */ + virtual su2double *GetSolution_Direct(void); + + + /*! + * STRUCTURAL ANALYSIS: NEW VARIABLES + */ + + /*! + * \brief Set the value of the old solution. + * \param[in] val_solution_old - Pointer to the residual vector. + */ + virtual void SetSolution_time_n(void); + + /*! + * \brief Set the value of the old solution. + * \param[in] val_solution_old - Pointer to the residual vector. + */ + virtual void SetSolution_time_n(su2double *val_solution_time_n); + + + /*! + * \brief Set the value of the velocity (Structural Analysis). + * \param[in] val_solution - Solution of the problem (velocity). + */ + virtual void SetSolution_Vel(su2double *val_solution); + + /*! + * \overload + * \param[in] val_var - Index of the variable. + * \param[in] val_solution - Value of the solution for the index val_var. + */ + virtual void SetSolution_Vel(unsigned short val_var, su2double val_solution_vel); + + /*! + * \brief Set the value of the velocity (Structural Analysis) at time n. + * \param[in] val_solution_old - Pointer to the residual vector. + */ + virtual void SetSolution_Vel_time_n(su2double *val_solution_vel_time_n); + + /*! + * \brief Set the value of the velocity (Structural Analysis) at time n. + * \param[in] val_solution_old - Pointer to the residual vector. + */ + virtual void SetSolution_Vel_time_n(void); + + /*! + * \overload + * \param[in] val_var - Index of the variable. + * \param[in] val_solution_old - Value of the old solution for the index val_var. + */ + virtual void SetSolution_Vel_time_n(unsigned short val_var, su2double val_solution_vel_time_n); + + /*! + * \brief Get the solution at time n. + * \param[in] val_var - Index of the variable. + * \return Value of the solution for the index val_var. + */ + virtual su2double GetSolution_time_n(unsigned short val_var); + + /*! + * \brief Get the velocity (Structural Analysis). + * \param[in] val_var - Index of the variable. + * \return Value of the solution for the index val_var. + */ + virtual su2double GetSolution_Vel(unsigned short val_var); + + /*! + * \brief Get the solution of the problem. + * \return Pointer to the solution vector. + */ + virtual su2double *GetSolution_Vel(void); + + /*! + * \brief Get the velocity of the nodes (Structural Analysis) at time n. + * \param[in] val_var - Index of the variable. + * \return Pointer to the old solution vector. + */ + virtual su2double GetSolution_Vel_time_n(unsigned short val_var); + + /*! + * \brief Get the solution at time n. + * \return Pointer to the solution (at time n) vector. + */ + virtual su2double *GetSolution_Vel_time_n(void); + + + /*! + * \brief Set the value of the acceleration (Structural Analysis). + * \param[in] val_solution - Solution of the problem (acceleration). + */ + virtual void SetSolution_Accel(su2double *val_solution_accel); + + /*! + * \overload + * \param[in] val_var - Index of the variable. + * \param[in] val_solution - Value of the solution for the index val_var. + */ + virtual void SetSolution_Accel(unsigned short val_var, su2double val_solution_accel); + + /*! + * \brief Set the value of the acceleration (Structural Analysis) at time n. + * \param[in] val_solution_old - Pointer to the residual vector. + */ + virtual void SetSolution_Accel_time_n(su2double *val_solution_accel_time_n); + + /*! + * \brief Set the value of the acceleration (Structural Analysis) at time n. + * \param[in] val_solution_old - Pointer to the residual vector. + */ + virtual void SetSolution_Accel_time_n(void); + + /*! + * \overload + * \param[in] val_var - Index of the variable. + * \param[in] val_solution_old - Value of the old solution for the index val_var. + */ + virtual void SetSolution_Accel_time_n(unsigned short val_var, su2double val_solution_accel_time_n); + + /*! + * \brief Get the acceleration (Structural Analysis). + * \param[in] val_var - Index of the variable. + * \return Value of the solution for the index val_var. + */ + virtual su2double GetSolution_Accel(unsigned short val_var); + + /*! + * \brief Get the solution of the problem. + * \return Pointer to the solution vector. + */ + virtual su2double *GetSolution_Accel(void); + + /*! + * \brief Get the acceleration of the nodes (Structural Analysis) at time n. + * \param[in] val_var - Index of the variable. + * \return Pointer to the old solution vector. + */ + virtual su2double GetSolution_Accel_time_n(unsigned short val_var); + + /*! + * \brief Get the solution at time n. + * \return Pointer to the solution (at time n) vector. + */ + virtual su2double *GetSolution_Accel_time_n(void); + + + /*! + * \brief A virtual member. Set the value of the solution predictor. + */ + virtual void SetSolution_Pred(void); + + /*! + * \brief A virtual member. Set the value of the old solution. + * \param[in] val_solution_old - Pointer to the residual vector. + */ + virtual void SetSolution_Pred(su2double *val_solution_pred); + + /*! + * \brief A virtual member. Get the value of the solution predictor. + * \param[in] val_var - Index of the variable. + * \return Pointer to the old solution vector. + */ + virtual su2double GetSolution_Pred(unsigned short val_var); + + /*! + * \brief A virtual member. Get the solution at time n. + * \return Pointer to the solution (at time n) vector. + */ + virtual su2double *GetSolution_Pred(void); + + /*! + * \brief A virtual member. Set the value of the solution predictor. + */ + virtual void SetSolution_Pred_Old(void); + + /*! + * \brief A virtual member. Set the value of the old solution. + * \param[in] val_solution_old - Pointer to the residual vector. + */ + virtual void SetSolution_Pred_Old(su2double *val_solution_pred_Old); + + /*! + * \brief A virtual member. Get the value of the solution predictor. + * \param[in] val_var - Index of the variable. + * \return Pointer to the old solution vector. + */ + virtual su2double GetSolution_Pred_Old(unsigned short val_var); + + /*! + * \brief A virtual member. Get the solution at time n. + * \return Pointer to the solution (at time n) vector. + */ + virtual su2double *GetSolution_Pred_Old(void); + + /*! + * \brief Register the variables in the solution array as input/output variable. + * \param[in] input - input or output variables. + */ + void RegisterSolution(bool input); + + /*! + * \brief Register the variables in the solution_time_n array as input/output variable. + */ + void RegisterSolution_time_n(); + + /*! + * \brief Register the variables in the solution_time_n1 array as input/output variable. + */ + void RegisterSolution_time_n1(); + + /*! + * \brief Set the adjoint values of the solution. + * \param[in] adj_sol - The adjoint values of the solution. + */ + void SetAdjointSolution(su2double *adj_sol); + + /*! + * \brief Get the adjoint values of the solution. + * \param[in] adj_sol - The adjoint values of the solution. + */ + void GetAdjointSolution(su2double *adj_sol); + + /*! + * \brief Set the adjoint values of the solution at time n. + * \param[in] adj_sol - The adjoint values of the solution. + */ + void SetAdjointSolution_time_n(su2double *adj_sol); + + /*! + * \brief Get the adjoint values of the solution at time n. + * \param[in] adj_sol - The adjoint values of the solution. + */ + void GetAdjointSolution_time_n(su2double *adj_sol); + + /*! + * \brief Set the adjoint values of the solution at time n-1. + * \param[in] adj_sol - The adjoint values of the solution. + */ + void SetAdjointSolution_time_n1(su2double *adj_sol); + + /*! + * \brief Get the adjoint values of the solution at time n-1. + * \param[in] adj_sol - The adjoint values of the solution. + */ + void GetAdjointSolution_time_n1(su2double *adj_sol); + + /*! + * \brief Set the sensitivity at the node + * \param[in] iDim - spacial component + * \param[in] val - value of the Sensitivity + */ + virtual void SetSensitivity(unsigned short iDim, su2double val); + + /*! + * \brief Get the Sensitivity at the node + * \param[in] iDim - spacial component + * \return value of the Sensitivity + */ + virtual su2double GetSensitivity(unsigned short iDim); + + virtual void SetDual_Time_Derivative(unsigned short iVar, su2double der); + + virtual void SetDual_Time_Derivative_n(unsigned short iVar, su2double der); + + virtual su2double GetDual_Time_Derivative(unsigned short iVar); + + virtual su2double GetDual_Time_Derivative_n(unsigned short iVar); +}; + +/*! + * \class CBaselineVariable + * \brief Main class for defining the variables of a baseline solution from a restart file (for output). + * \author F. Palacios, T. Economon. + * \version 4.0.1 "Cardinal" + */ +class CBaselineVariable : public CVariable { +public: + + /*! + * \brief Constructor of the class. + */ + CBaselineVariable(void); + + /*! + * \overload + * \param[in] val_solution - Pointer to the flow value (initialization value). + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CBaselineVariable(su2double *val_solution, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + virtual ~CBaselineVariable(void); + +}; + +/*! + * \class CPotentialVariable + * \brief Main class for defining the variables of the potential solver. + * \ingroup Potential_Flow_Equation + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CPotentialVariable : public CVariable { + su2double *Charge_Density; +public: + + /*! + * \brief Constructor of the class. + */ + CPotentialVariable(void); + + /*! + * \overload + * \param[in] val_potential - Value of the potential solution (initialization value). + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CPotentialVariable(su2double val_potential, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CPotentialVariable(void); + + /*! + * \brief A virtual member. + */ + su2double* GetChargeDensity(); + + /*! + * \brief A virtual member. + * \param[in] positive_charge - Mass density of positive charge. + * \param[in] negative_charge - Mass density of negative charge. + */ + void SetChargeDensity(su2double positive_charge, su2double negative_charge); + +}; + +/*! + * \class CWaveVariable + * \brief Main class for defining the variables of the wave equation solver. + * \ingroup Potential_Flow_Equation + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CWaveVariable : public CVariable { +protected: + su2double *Solution_Direct; /*!< \brief Direct solution container for use in the adjoint wave solver. */ + +public: + + /*! + * \brief Constructor of the class. + */ + CWaveVariable(void); + + /*! + * \overload + * \param[in] val_wave - Values of the wave solution (initialization value). + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CWaveVariable(su2double *val_wave, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CWaveVariable(void); + + /*! + * \brief Set the direct solution for the adjoint solver. + * \param[in] val_solution_direct - Value of the direct solution. + */ + void SetSolution_Direct(su2double *val_solution_direct); + + /*! + * \brief Get the direct solution for the adjoint solver. + * \return Pointer to the direct solution vector. + */ + su2double *GetSolution_Direct(void); + +}; + +/*! + * \class CHeatVariable + * \brief Main class for defining the variables of the Heat equation solver. + * \ingroup Potential_Flow_Equation + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CHeatVariable : public CVariable { +protected: + su2double *Solution_Direct; /*!< \brief Direct solution container for use in the adjoint Heat solver. */ + +public: + + /*! + * \brief Constructor of the class. + */ + CHeatVariable(void); + + /*! + * \overload + * \param[in] val_Heat - Values of the Heat solution (initialization value). + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CHeatVariable(su2double *val_Heat, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CHeatVariable(void); + + /*! + * \brief Set the direct solution for the adjoint solver. + * \param[in] val_solution_direct - Value of the direct solution. + */ + void SetSolution_Direct(su2double *val_solution_direct); + + /*! + * \brief Get the direct solution for the adjoint solver. + * \return Pointer to the direct solution vector. + */ + su2double *GetSolution_Direct(void); + +}; + +/*! + * \class CFEAVariable + * \brief Main class for defining the variables of the FEA equation solver. + * \ingroup Structural Finite Element Analysis Variables + * \author F. Palacios, R. Sanchez. + * \version 4.0.1 "Cardinal" + */ +class CFEAVariable : public CVariable { +protected: + su2double Flow_Pressure; /*!< \brief Pressure of the fluid. */ + + bool dynamicFEA; /*!< \brief Non-physical points in the solution (force first order). */ + + su2double **Stress; /*!< \brief Stress tensor. */ + su2double VonMises_Stress; /*!< \brief Von Mises stress. */ + unsigned short nAttachedElements; /*!< \brief Number of elements connected to the node. */ + + su2double *Solution_Vel, /*!< \brief Velocity of the nodes. */ + *Solution_Vel_time_n; /*!< \brief Velocity of the nodes at time n. */ + + su2double *Solution_Accel, /*!< \brief Acceleration of the nodes. */ + *Solution_Accel_time_n; /*!< \brief Acceleration of the nodes at time n. */ + + su2double *Solution_Pred; /*!< \brief Predictor of the solution (for FSI applications) */ + su2double *Solution_Pred_Old; /*!< \brief Predictor of the solution (for FSI applications) in the iter k-1 */ + +public: + + /*! + * \brief Constructor of the class. + */ + CFEAVariable(void); + + /*! + * \overload + * \param[in] val_fea - Values of the fea solution (initialization value). + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CFEAVariable(su2double *val_fea, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CFEAVariable(void); + + /*! + * \brief Set the value of the stress. + * \param[in] iVar - i index. + * \param[in] jVar - j index. + * \param[in] val_stress - Value of the stress. + */ + void SetStress(unsigned short iVar, unsigned short jVar, su2double val_stress); + + /*! + * \brief Add a value to the stress matrix in the element. + * \param[in] iVar - i index. + * \param[in] jVar - j index. + * \param[in] val_stress - Value of the stress. + */ + void AddStress(unsigned short iVar, unsigned short jVar, su2double val_stress); + + /*! + * \brief Get the value of the stress. + * \return Value of the stress. + */ + su2double **GetStress(void); + + /*! + * \brief Set the value of the Von Mises stress. + * \param[in] val_stress - Value of the Von Mises stress. + */ + void SetVonMises_Stress(su2double val_stress); + + /*! + * \brief Get the value of the Von Mises stress. + * \return Value of the Von Mises stress. + */ + su2double GetVonMises_Stress(void); + + /*! + * \brief Set the value of the Von Mises stress. + * \param[in] val_stress - Value of the Von Mises stress. + */ + void SetFlow_Pressure(su2double val_pressure); + + /*! + * \brief Get the value of the Von Mises stress. + * \return Value of the Von Mises stress. + */ + su2double GetFlow_Pressure(void); + + /*! + * \brief Initialize the value of the number of attached elements to a node. + * \return Value of the Von Mises stress. + */ + void Initialize_Connectivity(void); + + + /*! + * \brief Add a 1 to the value of the number of attached elements to a node. + * \return Value of the Von Mises stress. + */ + void Upgrade_Connectivity(void); + + + /*! + * \brief Returns the value of the number of attached elements to a node. + * \return Value of the Von Mises stress. + */ + unsigned short Get_Connectivity(void); + + /*! + * \brief Set the value of the old solution. + * \param[in] val_solution_old - Pointer to the residual vector. + */ + void SetSolution_time_n(void); + + /*! + * \brief Set the value of the old solution. + * \param[in] val_solution_old - Pointer to the residual vector. + */ + void SetSolution_time_n(su2double *val_solution_time_n); + + + /*! + * \brief Set the value of the velocity (Structural Analysis). + * \param[in] val_solution - Solution of the problem (velocity). + */ + void SetSolution_Vel(su2double *val_solution_vel); + + /*! + * \overload + * \param[in] val_var - Index of the variable. + * \param[in] val_solution - Value of the solution for the index val_var. + */ + void SetSolution_Vel(unsigned short val_var, su2double 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(void); + + /*! + * \brief Set the value of the velocity (Structural Analysis) at time n. + * \param[in] val_solution_old - Pointer to the residual vector. + */ + void SetSolution_Vel_time_n(su2double *val_solution_vel_time_n); + + /*! + * \overload + * \param[in] val_var - Index of the variable. + * \param[in] val_solution_old - Value of the old solution for the index val_var. + */ + void SetSolution_Vel_time_n(unsigned short val_var, su2double val_solution_vel_time_n); + + /*! + * \brief Get the solution at time n. + * \param[in] val_var - Index of the variable. + * \return Value of the solution for the index val_var. + */ + su2double GetSolution_time_n(unsigned short val_var); + + /*! + * \brief Get the velocity (Structural Analysis). + * \param[in] val_var - Index of the variable. + * \return Value of the solution for the index val_var. + */ + su2double GetSolution_Vel(unsigned short val_var); + + /*! + * \brief Get the solution of the problem. + * \return Pointer to the solution vector. + */ + su2double *GetSolution_Vel(void); + + /*! + * \brief Get the velocity of the nodes (Structural Analysis) at time n. + * \param[in] val_var - Index of the variable. + * \return Pointer to the old solution vector. + */ + su2double GetSolution_Vel_time_n(unsigned short val_var); + + /*! + * \brief Get the solution at time n. + * \return Pointer to the solution (at time n) vector. + */ + su2double *GetSolution_Vel_time_n(void); + + /*! + * \brief Set the value of the acceleration (Structural Analysis). + * \param[in] val_solution - Solution of the problem (acceleration). + */ + void SetSolution_Accel(su2double *val_solution_accel); + + /*! + * \overload + * \param[in] val_var - Index of the variable. + * \param[in] val_solution - Value of the solution for the index val_var. + */ + void SetSolution_Accel(unsigned short val_var, su2double val_solution_accel); + + /*! + * \brief Set the value of the acceleration (Structural Analysis) at time n. + * \param[in] val_solution_old - Pointer to the residual vector. + */ + void SetSolution_Accel_time_n(su2double *val_solution_accel_time_n); + + /*! + * \brief Set the value of the acceleration (Structural Analysis) at time n. + * \param[in] val_solution - Solution of the problem (acceleration). + */ + void SetSolution_Accel_time_n(void); + + /*! + * \overload + * \param[in] val_var - Index of the variable. + * \param[in] val_solution_old - Value of the old solution for the index val_var. + */ + void SetSolution_Accel_time_n(unsigned short val_var, su2double val_solution_accel_time_n); + + /*! + * \brief Get the acceleration (Structural Analysis). + * \param[in] val_var - Index of the variable. + * \return Value of the solution for the index val_var. + */ + su2double GetSolution_Accel(unsigned short val_var); + + /*! + * \brief Get the solution of the problem. + * \return Pointer to the solution vector. + */ + su2double *GetSolution_Accel(void); + + /*! + * \brief Get the acceleration of the nodes (Structural Analysis) at time n. + * \param[in] val_var - Index of the variable. + * \return Pointer to the old solution vector. + */ + su2double GetSolution_Accel_time_n(unsigned short val_var); + + /*! + * \brief Get the solution at time n. + * \return Pointer to the solution (at time n) vector. + */ + su2double *GetSolution_Accel_time_n(void); + + + /*! + * \brief Set the value of the solution predictor. + */ + void SetSolution_Pred(void); + + /*! + * \brief Set the value of the old solution. + * \param[in] val_solution_old - Pointer to the residual vector. + */ + void SetSolution_Pred(su2double *val_solution_pred); + + /*! + * \brief Get the value of the solution predictor. + * \param[in] val_var - Index of the variable. + * \return Pointer to the old solution vector. + */ + su2double GetSolution_Pred(unsigned short val_var); + + /*! + * \brief Get the solution at time n. + * \return Pointer to the solution (at time n) vector. + */ + su2double *GetSolution_Pred(void); + + /*! + * \brief Set the value of the solution predictor. + */ + void SetSolution_Pred_Old(void); + + /*! + * \brief Set the value of the old solution. + * \param[in] val_solution_old - Pointer to the residual vector. + */ + void SetSolution_Pred_Old(su2double *val_solution_pred_Old); + + /*! + * \brief Get the value of the solution predictor. + * \param[in] val_var - Index of the variable. + * \return Pointer to the old solution vector. + */ + su2double GetSolution_Pred_Old(unsigned short val_var); + + /*! + * \brief Get the solution at time n. + * \return Pointer to the solution (at time n) vector. + */ + su2double *GetSolution_Pred_Old(void); + + + +}; + + +/*! + * \class CFEABoundVariable + * \brief Main class for defining the variables on the FEA boundaries for FSI applications. + * \author R. Sanchez. + * \version 3.2.3 "eagle" + */ +class CFEABoundVariable : public CVariable { +protected: + su2double **Traction; /*!< \brief Stress tensor. */ + +public: + + /*! + * \brief Constructor of the class. + */ + CFEABoundVariable(void); + + /*! + * \overload + * \param[in] val_fea - Values of the fea solution (initialization value). + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] val_nElBound - Number of elements in the boundary + * \param[in] config - Definition of the particular problem. + */ + CFEABoundVariable(unsigned short val_nDim, unsigned short val_nvar, unsigned short val_nElBound, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CFEABoundVariable(void); + + /*! + * \brief Set the value of the stress. + * \param[in] iVar - index of the traction vector. + * \param[in] jVar - index of the boundary element. + * \param[in] val_stress - Value of the stress. + */ + void SetTraction(unsigned short iVar, unsigned short jVar, su2double val_traction); + + /*! + * \brief Add a value to the stress matrix in the element. + * \param[in] iVar - index of the traction vector. + * \param[in] jVar - index of the boundary element. + * \param[in] val_stress - Value of the stress. + */ + void AddTraction(unsigned short iVar, unsigned short jVar, su2double val_traction); + + /*! + * \brief Get the value of the stress. + * \return Value of the stress. + */ + su2double **GetTraction(void); + +}; + +/*! + * \class CEulerVariable + * \brief Main class for defining the variables of the Euler's solver. + * \ingroup Euler_Equations + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CEulerVariable : public CVariable { +protected: + su2double Velocity2; /*!< \brief Square of the velocity vector. */ + su2double *TS_Source; /*!< \brief Time spectral source term. */ + su2double Precond_Beta; /*!< \brief Low Mach number preconditioner value, Beta. */ + su2double *WindGust; /*! < \brief Wind gust value */ + su2double *WindGustDer; /*! < \brief Wind gust derivatives value */ + + /*--- Primitive variable definition ---*/ + + su2double *Primitive; /*!< \brief Primitive variables (T, vx, vy, vz, P, rho, h, c) in compressible flows. */ + su2double **Gradient_Primitive; /*!< \brief Gradient of the primitive variables (T, vx, vy, vz, P, rho). */ + su2double *Limiter_Primitive; /*!< \brief Limiter of the primitive variables (T, vx, vy, vz, P, rho). */ + + /*--- Secondary variable definition ---*/ + + su2double *Secondary; /*!< \brief Primitive variables (T, vx, vy, vz, P, rho, h, c) in compressible flows. */ + su2double **Gradient_Secondary; /*!< \brief Gradient of the primitive variables (T, vx, vy, vz, P, rho). */ + su2double *Limiter_Secondary; /*!< \brief Limiter of the primitive variables (T, vx, vy, vz, P, rho). */ + +public: + + /*! + * \brief Constructor of the class. + */ + CEulerVariable(void); + + /*! + * \overload + * \param[in] val_density - Value of the flow density (initialization value). + * \param[in] val_velocity - Value of the flow velocity (initialization value). + * \param[in] val_energy - Value of the flow energy (initialization value). + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CEulerVariable(su2double val_density, su2double *val_velocity, su2double val_energy, unsigned short val_nDim, + unsigned short val_nvar, CConfig *config); + + /*! + * \overload + * \param[in] val_solution - Pointer to the flow value (initialization value). + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CEulerVariable(su2double *val_solution, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + virtual ~CEulerVariable(void); + + /*! + * \brief Set to zero the gradient of the primitive variables. + */ + void SetGradient_PrimitiveZero(unsigned short val_primvar); + + /*! + * \brief Add val_value to the gradient of the primitive variables. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value to add to the gradient of the primitive variables. + */ + void AddGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value); + + /*! + * \brief Subtract val_value to the gradient of the primitive variables. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value to subtract to the gradient of the primitive variables. + */ + void SubtractGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value); + + /*! + * \brief Get the value of the primitive variables gradient. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \return Value of the primitive variables gradient. + */ + su2double GetGradient_Primitive(unsigned short val_var, unsigned short val_dim); + + /*! + * \brief Get the value of the primitive variables gradient. + * \param[in] val_var - Index of the variable. + * \return Value of the primitive variables gradient. + */ + su2double GetLimiter_Primitive(unsigned short val_var); + + /*! + * \brief Set the gradient of the primitive variables. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value of the gradient. + */ + void SetGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value); + + /*! + * \brief Set the gradient of the primitive variables. + * \param[in] val_var - Index of the variable. + * \param[in] val_value - Value of the gradient. + */ + void SetLimiter_Primitive(unsigned short val_var, su2double val_value); + + /*! + * \brief Get the value of the primitive variables gradient. + * \return Value of the primitive variables gradient. + */ + su2double **GetGradient_Primitive(void); + + /*! + * \brief Get the value of the primitive variables gradient. + * \return Value of the primitive variables gradient. + */ + su2double *GetLimiter_Primitive(void); + + /*! + * \brief Set to zero the gradient of the primitive variables. + */ + void SetGradient_SecondaryZero(unsigned short val_secondaryvar); + + /*! + * \brief Add val_value to the gradient of the primitive variables. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value to add to the gradient of the primitive variables. + */ + void AddGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value); + + /*! + * \brief Subtract val_value to the gradient of the primitive variables. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value to subtract to the gradient of the primitive variables. + */ + void SubtractGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value); + + /*! + * \brief Get the value of the primitive variables gradient. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \return Value of the primitive variables gradient. + */ + su2double GetGradient_Secondary(unsigned short val_var, unsigned short val_dim); + + /*! + * \brief Get the value of the primitive variables gradient. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \return Value of the primitive variables gradient. + */ + su2double GetLimiter_Secondary(unsigned short val_var); + + /*! + * \brief Set the gradient of the primitive variables. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value of the gradient. + */ + void SetGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value); + + /*! + * \brief Set the gradient of the primitive variables. + * \param[in] val_var - Index of the variable. + * \param[in] val_dim - Index of the dimension. + * \param[in] val_value - Value of the gradient. + */ + void SetLimiter_Secondary(unsigned short val_var, su2double val_value); + + /*! + * \brief Get the value of the primitive variables gradient. + * \return Value of the primitive variables gradient. + */ + su2double **GetGradient_Secondary(void); + + /*! + * \brief Get the value of the primitive variables gradient. + * \return Value of the primitive variables gradient. + */ + su2double *GetLimiter_Secondary(void); + + /*! + * \brief A virtual member. + */ + void SetdPdrho_e(su2double dPdrho_e); + + /*! + * \brief A virtual member. + */ + void SetdPde_rho(su2double dPde_rho); + + /*! + * \brief Set the value of the pressure. + */ + bool SetPressure(su2double Gamma); + + /*! + * \brief Set the value of the speed of the sound. + * \param[in] Gamma - Value of Gamma. + */ + bool SetSoundSpeed(su2double Gamma); + + /*! + * \brief Set the value of the enthalpy. + */ + void SetEnthalpy(void); + +// /*! +// * \brief Set all the primitive variables for compressible flows. +// */ +// bool SetPrimVar_Compressible(CConfig *config); + + /*! + * \brief Set all the primitive variables for compressible flows. + */ + bool SetPrimVar_Compressible(CFluidModel *FluidModel); + using CVariable::SetPrimVar_Compressible; + + /*! + * \brief A virtual member. + */ + void SetSecondaryVar_Compressible(CFluidModel *FluidModel); + + /*! + * \brief Set all the primitive variables for incompressible flows. + */ + bool SetPrimVar_Incompressible(su2double Density_Inf, CConfig *config); + using CVariable::SetPrimVar_Incompressible; + + /*! + * \brief Set all the primitive variables for incompressible flows. + */ + bool SetPrimVar_FreeSurface(CConfig *config); + using CVariable::SetPrimVar_FreeSurface; + + /*! + * \brief Get the primitive variables. + * \param[in] val_var - Index of the variable. + * \return Value of the primitive variable for the index val_var. + */ + su2double GetPrimitive(unsigned short val_var); + + /*! + * \brief Set the value of the primitive variables. + * \param[in] val_var - Index of the variable. + * \param[in] val_var - Index of the variable. + * \return Set the value of the primitive variable for the index val_var. + */ + void SetPrimitive(unsigned short val_var, su2double val_prim); + + /*! + * \brief Set the value of the primitive variables. + * \param[in] val_prim - Primitive variables. + * \return Set the value of the primitive variable for the index val_var. + */ + void SetPrimitive(su2double *val_prim); + + /*! + * \brief Get the primitive variables of the problem. + * \return Pointer to the primitive variable vector. + */ + su2double *GetPrimitive(void); + + /*! + * \brief Get the primitive variables. + * \param[in] val_var - Index of the variable. + * \return Value of the primitive variable for the index val_var. + */ + su2double GetSecondary(unsigned short val_var); + + /*! + * \brief Set the value of the primitive variables. + * \param[in] val_var - Index of the variable. + * \param[in] val_var - Index of the variable. + * \return Set the value of the primitive variable for the index val_var. + */ + void SetSecondary(unsigned short val_var, su2double val_secondary); + + /*! + * \brief Set the value of the primitive variables. + * \param[in] val_prim - Primitive variables. + * \return Set the value of the primitive variable for the index val_var. + */ + void SetSecondary(su2double *val_secondary); + + /*! + * \brief Get the primitive variables of the problem. + * \return Pointer to the primitive variable vector. + */ + su2double *GetSecondary(void); + + /*! + * \brief Set the value of the density for the incompressible flows. + */ + void SetDensityInc(su2double val_density); + + /*! + * \brief Set the value of the density for the incompressible flows. + */ + bool SetDensity(void); + + /*! + * \brief Set the value of the density for the incompressible flows. + */ + void SetPressureInc(void); + + /*! + * \brief Set the value of the density for the incompressible flows. + */ + void SetVelocityInc(void); + + /*! + * \brief Set the value of the beta coeffient for incompressible flows. + */ + void SetBetaInc2(su2double val_betainc2); + + /*! + * \brief Set the value of the temperature. + * \param[in] Gas_Constant - Value of Gas Constant + */ + bool SetTemperature(su2double Gas_Constant); + + /*! + * \brief Get the norm 2 of the velocity. + * \return Norm 2 of the velocity vector. + */ + su2double GetVelocity2(void); + + /*! + * \brief Get the flow pressure. + * \return Value of the flow pressure. + */ + su2double GetPressure(void); + + /*! + * \brief Get the flow pressure. + * \return Value of the flow pressure. + */ + su2double GetPressureInc(void); + + /*! + * \brief Get the speed of the sound. + * \return Value of speed of the sound. + */ + su2double GetSoundSpeed(void); + + /*! + * \brief Get the value of density for the incompressible flow + * \return Value of beta squared. + */ + su2double GetDensityInc(void); + + /*! + * \brief Get the value of levelset for the freesurface flows + * \return Value of beta squared. + */ + su2double GetLevelSet(void); + + /*! + * \brief Get the value of distance for the freesurface flows + * \return Value of beta squared. + */ + su2double GetDistance(void); + + /*! + * \brief Get the value of beta squared for the incompressible flow + * \return Value of beta squared. + */ + su2double GetBetaInc2(void); + + /*! + * \brief Get the enthalpy of the flow. + * \return Value of the enthalpy of the flow. + */ + su2double GetEnthalpy(void); + + /*! + * \brief Get the density of the flow. + * \return Value of the density of the flow. + */ + su2double GetDensity(void); + + /*! + * \brief Get the energy of the flow. + * \return Value of the energy of the flow. + */ + su2double GetEnergy(void); + + /*! + * \brief Get the temperature of the flow. + * \return Value of the temperature of the flow. + */ + su2double GetTemperature(void); + + /*! + * \brief Get the velocity of the flow. + * \param[in] val_dim - Index of the dimension. + * \return Value of the velocity for the dimension val_dim. + */ + su2double GetVelocity(unsigned short val_dim); + + /*! + * \brief Get the projected velocity in a unitary vector direction (compressible solver). + * \param[in] val_vector - Direction of projection. + * \return Value of the projected velocity. + */ + su2double GetProjVel(su2double *val_vector); + + /*! + * \brief Set the velocity vector from the solution. + * \param[in] val_velocity - Pointer to the velocity. + */ + void SetVelocity(void); + + /*! + * \brief Set the velocity vector from the old solution. + * \param[in] val_velocity - Pointer to the velocity. + */ + void SetVelocity_Old(su2double *val_velocity); + + /*! + * \brief Set the velocity vector from the old solution. + * \param[in] val_velocity - Pointer to the velocity. + */ + void SetVelocityInc_Old(su2double *val_velocity); + + /*! + * \brief Set the time spectral source term. + * \param[in] val_var - Index of the variable. + * \param[in] val_solution - Value of the time spectral source term. for the index val_var. + */ + void SetTimeSpectral_Source(unsigned short val_var, su2double val_source); + + /*! + * \brief Get the time spectral source term. + * \param[in] val_var - Index of the variable. + * \return Value of the time spectral source term for the index val_var. + */ + su2double GetTimeSpectral_Source(unsigned short val_var); + + /*! + * \brief Get the value of the preconditioner Beta. + * \return Value of the low Mach preconditioner variable Beta + */ + su2double GetPreconditioner_Beta(); + + /*! + * \brief Set the value of the preconditioner Beta. + * \param[in] Value of the low Mach preconditioner variable Beta + */ + void SetPreconditioner_Beta(su2double val_Beta); + + /*! + * \brief Get the value of the wind gust + * \return Value of the wind gust + */ + su2double* GetWindGust(); + + /*! + * \brief Set the value of the wind gust + * \param[in] Value of the wind gust + */ + void SetWindGust(su2double* val_WindGust); + + /*! + * \brief Get the value of the derivatives of the wind gust + * \return Value of the derivatives of the wind gust + */ + su2double* GetWindGustDer(); + + /*! + * \brief Set the value of the derivatives of the wind gust + * \param[in] Value of the derivatives of the wind gust + */ + void SetWindGustDer(su2double* val_WindGust); +}; + +/*! + * \class CNSVariable + * \brief Main class for defining the variables of the Navier-Stokes' solver. + * \ingroup Navier_Stokes_Equations + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CNSVariable : public CEulerVariable { +private: + su2double Prandtl_Lam; /*!< \brief Laminar Prandtl number. */ + su2double Prandtl_Turb; /*!< \brief Turbulent Prandtl number. */ + su2double Temperature_Ref; /*!< \brief Reference temperature of the fluid. */ + su2double Viscosity_Ref; /*!< \brief Reference viscosity of the fluid. */ + su2double Viscosity_Inf; /*!< \brief Viscosity of the fluid at the infinity. */ + su2double Vorticity[3]; /*!< \brief Vorticity of the fluid. */ + su2double StrainMag; /*!< \brief Magnitude of rate of strain tensor. */ +public: + + /*! + * \brief Constructor of the class. + */ + CNSVariable(void); + + /*! + * \overload + * \param[in] val_density - Value of the flow density (initialization value). + * \param[in] val_velocity - Value of the flow velocity (initialization value). + * \param[in] val_energy - Value of the flow energy (initialization value). + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CNSVariable(su2double val_density, su2double *val_velocity, + su2double val_energy, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \overload + * \param[in] val_solution - Pointer to the flow value (initialization value). + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CNSVariable(su2double *val_solution, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CNSVariable(void); + + /*! + * \brief Set the laminar viscosity. + */ + void SetLaminarViscosity(su2double laminarViscosity); + + /*! + * \overload + * \param[in] val_laminar_viscosity_inc - Value of the laminar viscosity (incompressible flows). + */ + void SetLaminarViscosityInc(su2double val_laminar_viscosity_inc); + + /*! + * \brief Set the laminar viscosity. + */ + void SetThermalConductivity(su2double thermalConductivity); + + /*! + * \brief Set the specific heat Cp. + */ + void SetSpecificHeatCp(su2double Cp); + + /*! + * \brief Set the vorticity value. + */ + bool SetVorticity(bool val_limiter); + + /*! + * \brief Set the rate of strain magnitude. + */ + bool SetStrainMag(bool val_limiter); + + /*! + * \overload + * \param[in] eddy_visc - Value of the eddy viscosity. + */ + void SetEddyViscosity(su2double eddy_visc); + + /*! + * \overload + * \param[in] eddy_visc - Value of the eddy viscosity. + */ + void SetEddyViscosityInc(su2double eddy_visc); + + /*! + * \brief Get the laminar viscosity of the flow. + * \return Value of the laminar viscosity of the flow. + */ + su2double GetLaminarViscosity(void); + + /*! + * \brief Get the laminar viscosity of the incompressible flow. + * \return Value of the laminar viscosity of the incompressible flow. + */ + su2double GetLaminarViscosityInc(void); + + /*! + * \brief Get the thermal conductivity of the flow. + * \return Value of the laminar viscosity of the flow. + */ + su2double GetThermalConductivity(void); + + /*! + * \brief Get the eddy viscosity of the flow. + * \return The eddy viscosity of the flow. + */ + su2double GetEddyViscosity(void); + + /*! + * \brief Get the specific heat at constant P of the flow. + * \return Value of the specific heat at constant P of the flow. + */ + su2double GetSpecificHeatCp(void); + + /*! + * \brief Get the eddy viscosity of the flow. + * \return The eddy viscosity of the flow. + */ + su2double GetEddyViscosityInc(void); + + /*! + * \brief Set the temperature at the wall + */ + void SetWallTemperature(su2double temperature_wall); + + /*! + * \brief Get the value of the vorticity. + * \param[in] val_dim - Index of the dimension. + * \return Value of the vorticity. + */ + su2double *GetVorticity(void); + + /*! + * \brief Get the value of the magnitude of rate of strain. + * \return Value of the rate of strain magnitude. + */ + su2double GetStrainMag(void); + + /*! + * \brief Set the derivative of temperature with respect to density (at constant internal energy). + */ + void SetdTdrho_e(su2double dTdrho_e); + + /*! + * \brief Set the derivative of temperature with respect to internal energy (at constant density). + */ + void SetdTde_rho(su2double dTde_rho); + + /*! + * \brief Set the derivative of laminar viscosity with respect to density (at constant temperature). + */ + void Setdmudrho_T(su2double dmudrho_T); + + /*! + * \brief Set the derivative of laminar viscosity with respect to temperature (at constant density). + */ + void SetdmudT_rho(su2double dmudT_rho); + + /*! + * \brief Set the derivative of thermal conductivity with respect to density (at constant temperature). + */ + void Setdktdrho_T(su2double dktdrho_T); + + /*! + * \brief Set the derivative of thermal conductivity with respect to temperature (at constant density). + */ + void SetdktdT_rho(su2double dktdT_rho); + + /*! + * \brief Set all the primitive variables for compressible flows + */ + bool SetPrimVar_Compressible(su2double eddy_visc, su2double turb_ke, CFluidModel *FluidModel); + using CVariable::SetPrimVar_Compressible; + + /*! + * \brief Set all the secondary variables (partial derivatives) for compressible flows + */ + void SetSecondaryVar_Compressible(CFluidModel *FluidModel); + + /*! + * \brief Set all the primitive variables for incompressible flows + */ + bool SetPrimVar_Incompressible(su2double Density_Inf, su2double Viscosity_Inf, su2double eddy_visc, su2double turb_ke, CConfig *config); + using CVariable::SetPrimVar_Incompressible; + + /*! + * \brief Set all the primitive variables for incompressible flows + */ + bool SetPrimVar_FreeSurface(su2double eddy_visc, su2double turb_ke, CConfig *config); + using CVariable::SetPrimVar_FreeSurface; + +}; + +/*! + * \class CTurbVariable + * \brief Main class for defining the variables of the turbulence model. + * \ingroup Turbulence_Model + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CTurbVariable : public CVariable { +protected: + su2double muT; /*!< \brief Eddy viscosity. */ + su2double *TS_Source; /*!< \brief Time spectral source term. */ + +public: + /*! + * \brief Constructor of the class. + */ + CTurbVariable(void); + + /*! + * \overload + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CTurbVariable(unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + virtual ~CTurbVariable(void); + + /*! + * \brief Get the value of the eddy viscosity. + * \return the value of the eddy viscosity. + */ + su2double GetmuT(); + + /*! + * \brief Set the value of the eddy viscosity. + * \param[in] val_muT - Value of the eddy viscosity. + */ + void SetmuT(su2double val_muT); +}; + +/*! + * \class CTurbSAVariable + * \brief Main class for defining the variables of the turbulence model. + * \ingroup Turbulence_Model + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ + +class CTurbSAVariable : public CTurbVariable { +public: + /*! + * \brief Constructor of the class. + */ + CTurbSAVariable(void); + + /*! + * \overload + * \param[in] val_nu_tilde - Turbulent variable value (initialization value). + * \param[in] val_muT - The eddy viscosity + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CTurbSAVariable(void); + + /*! + * \brief Set the time spectral source term. + * \param[in] val_var - Index of the variable. + * \param[in] val_source - Value of the time spectral source term. for the index val_var. + */ + void SetTimeSpectral_Source(unsigned short val_var, su2double val_source); + + /*! + * \brief Get the time spectral source term. + * \param[in] val_var - Index of the variable. + * \return Value of the time spectral source term for the index val_var. + */ + su2double GetTimeSpectral_Source(unsigned short val_var); + +}; + + +/*! + * \class CTurbMLVariable + * \brief Main class for defining the variables of the turbulence model. + * \ingroup Turbulence_Model + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ + +class CTurbMLVariable : public CTurbVariable { +public: + /*! + * \brief Constructor of the class. + */ + CTurbMLVariable(void); + + /*! + * \overload + * \param[in] val_nu_tilde - Turbulent variable value (initialization value). + * \param[in] val_muT - The eddy viscosity + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CTurbMLVariable(su2double val_nu_tilde, su2double val_muT, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CTurbMLVariable(void); + + /*! + * \brief Set the time spectral source term. + * \param[in] val_var - Index of the variable. + * \param[in] val_source - Value of the time spectral source term. for the index val_var. + */ + void SetTimeSpectral_Source(unsigned short val_var, su2double val_source); + + /*! + * \brief Get the time spectral source term. + * \param[in] val_var - Index of the variable. + * \return Value of the time spectral source term for the index val_var. + */ + su2double GetTimeSpectral_Source(unsigned short val_var); + +}; + +/*! + * \class CTransLMVariable + * \brief Main class for defining the variables of the turbulence model. + * \ingroup Turbulence_Model + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ + +class CTransLMVariable : public CTurbVariable { +protected: + su2double gamma_sep; + +public: + + /*! + * \brief Constructor of the class. + */ + CTransLMVariable(void); + + /*! + * \overload + * \param[in] val_nu_tilde - Turbulent variable value (initialization value). + * \param[in] val_REth + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CTransLMVariable(su2double val_nu_tilde, su2double val_intermittency, su2double val_REth, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CTransLMVariable(void); + + /*! + * \brief ________________. + */ + su2double GetIntermittency(void); + + /*! + * \brief ________________. + * \param[in] gamma_sep_in + */ + void SetGammaSep(su2double gamma_sep_in); + + /*! + * \brief ________________. + */ + void SetGammaEff(void); + +}; + +/*! + * \class CTurbSSTVariable + * \brief Main class for defining the variables of the turbulence model. + * \ingroup Turbulence_Model + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ + +class CTurbSSTVariable : public CTurbVariable { +protected: + su2double sigma_om2, + beta_star; + su2double F1, /*!< \brief Menter blending function for blending of k-w and k-eps. */ + F2, /*!< \brief Menter blending function for stress limiter. */ + CDkw; /*!< \brief Cross-diffusion. */ + +public: + /*! + * \brief Constructor of the class. + */ + CTurbSSTVariable(void); + + /*! + * \overload + * \param[in] val_rho_kine - Turbulent variable value (initialization value). + * \param[in] val_rho_omega - Turbulent variable value (initialization value). + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CTurbSSTVariable(su2double val_rho_kine, su2double val_rho_omega, su2double val_muT, unsigned short val_nDim, unsigned short val_nvar, + su2double *constants, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CTurbSSTVariable(void); + + /*! + * \brief Set the blending function for the blending of k-w and k-eps. + * \param[in] val_viscosity - Value of the vicosity. + * \param[in] val_dist - Value of the distance to the wall. + * \param[in] val_density - Value of the density. + */ + void SetBlendingFunc(su2double val_viscosity, su2double val_dist, su2double val_density); + + /*! + * \brief Get the first blending function. + */ + su2double GetF1blending(void); + + /*! + * \brief Get the second blending function. + */ + su2double GetF2blending(void); + + /*! + * \brief Get the value of the cross diffusion of tke and omega. + */ + su2double GetCrossDiff(void); +}; + + +/*! + * \class CAdjEulerVariable + * \brief Main class for defining the variables of the adjoint Euler solver. + * \ingroup Euler_Equations + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CAdjEulerVariable : public CVariable { +protected: + su2double *Psi; /*!< \brief Vector of the adjoint variables. */ + su2double *ForceProj_Vector; /*!< \brief Vector d. */ + su2double *ObjFuncSource; /*!< \brief Vector containing objective function sensitivity for discrete adjoint. */ + su2double *IntBoundary_Jump; /*!< \brief Interior boundary jump vector. */ + su2double *TS_Source; /*!< \brief Time spectral source term. */ + bool incompressible; +public: + + /*! + * \brief Constructor of the class. + */ + CAdjEulerVariable(void); + + /*! + * \overload + * \param[in] val_psirho - Value of the adjoint density (initialization value). + * \param[in] val_phi - Value of the adjoint velocity (initialization value). + * \param[in] val_psie - Value of the adjoint energy (initialization value). + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAdjEulerVariable(su2double val_psirho, su2double *val_phi, su2double val_psie, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \overload + * \param[in] val_solution - Pointer to the adjoint value (initialization value). + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAdjEulerVariable(su2double *val_solution, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + virtual ~CAdjEulerVariable(void); + + /*! + * \brief Set all the primitive variables for compressible flows. + */ + bool SetPrimVar_Compressible(su2double SharpEdge_Distance, bool check, CConfig *config); + using CVariable::SetPrimVar_Compressible; + + /*! + * \brief Set all the primitive variables for compressible flows. + */ + bool SetPrimVar_Incompressible(su2double SharpEdge_Distance, bool check, CConfig *config); + using CVariable::SetPrimVar_Incompressible; + + /*! + * \brief Set all the primitive variables for compressible flows. + */ + bool SetPrimVar_FreeSurface(su2double SharpEdge_Distance, bool check, CConfig *config); + using CVariable::SetPrimVar_FreeSurface; + + /*! + * \brief Set the value of the adjoint velocity. + * \param[in] val_phi - Value of the adjoint velocity. + */ + void SetPhi_Old(su2double *val_phi); + + /*! + * \brief Set the value of the force projection vector. + * \param[in] val_ForceProj_Vector - Pointer to the force projection vector. + */ + void SetForceProj_Vector(su2double *val_ForceProj_Vector); + + /*! + * \brief Set the value of the objective function source. + * \param[in] val_SetObjFuncSource - Pointer to the objective function source. + */ + void SetObjFuncSource(su2double *val_SetObjFuncSource); + + /*! + * \brief Set the value of the interior boundary jump vector vector. + * \param[in] val_IntBoundary_Jump - Pointer to the interior boundary jump vector. + */ + void SetIntBoundary_Jump(su2double *val_IntBoundary_Jump); + + /*! + * \brief Get the value of the force projection vector. + * \return Pointer to the force projection vector. + */ + su2double *GetForceProj_Vector(void); + + /*! + * \brief Get the value of the objective function source. + * \param[in] val_SetObjFuncSource - Pointer to the objective function source. + */ + su2double *GetObjFuncSource(void); + + /*! + * \brief Get the value of the force projection vector. + * \return Pointer to the force projection vector. + */ + su2double *GetIntBoundary_Jump(void); + + /*! + * \brief Set the time spectral source term. + * \param[in] val_var - Index of the variable. + * \param[in] val_solution - Value of the time spectral source term. for the index val_var. + */ + void SetTimeSpectral_Source(unsigned short val_var, su2double val_source); + + /*! + * \brief Get the time spectral source term. + * \param[in] val_var - Index of the variable. + * \return Value of the time spectral source term for the index val_var. + */ + su2double GetTimeSpectral_Source(unsigned short val_var); +}; + +/*! + * \class CAdjNSVariable + * \brief Main class for defining the variables of the adjoint Navier-Stokes solver. + * \ingroup Navier_Stokes_Equations + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CAdjNSVariable : public CAdjEulerVariable { +private: + +public: + + /*! + * \brief Constructor of the class. + */ + CAdjNSVariable(void); + + /*! + * \overload + * \param[in] val_psirho - Value of the adjoint density (initialization value). + * \param[in] val_phi - Value of the adjoint velocity (initialization value). + * \param[in] val_psie - Value of the adjoint energy (initialization value). + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAdjNSVariable(su2double val_psirho, su2double *val_phi, su2double val_psie, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \overload + * \param[in] val_solution - Pointer to the adjoint value (initialization value). + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAdjNSVariable(su2double *val_solution, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAdjNSVariable(void); + + /*! + * \brief Set the value of the adjoint velocity. + * \param[in] val_phi - Value of the adjoint velocity. + */ + void SetPhi_Old(su2double *val_phi); + + /*! + * \brief Set the value of the force projection vector. + * \param[in] val_ForceProj_Vector - Pointer to the force projection vector. + */ + void SetForceProj_Vector(su2double *val_ForceProj_Vector); + + /*! + * \brief Get the value of the force projection vector. + * \return Pointer to the force projection vector. + */ + su2double *GetForceProj_Vector(void); + + /*! + * \brief Set the value of the force projection vector on the solution vector. + */ + void SetVelSolutionOldDVector(void); + + /*! + * \brief Set the value of the force projection vector on the old solution vector. + */ + void SetVelSolutionDVector(void); + +}; + +/*! + * \class CAdjTurbVariable + * \brief Main class for defining the variables of the adjoint turbulence model. + * \ingroup Turbulence_Model + * \author A. Bueno. + * \version 4.0.1 "Cardinal" + */ +class CAdjTurbVariable : public CVariable { +protected: + su2double *dmuT_dUTvar; /*!< \brief Sensitivity of eddy viscosity to mean flow and turbulence vars. */ + su2double **dRTstar_dUTvar; /*!< \brief Sensitivity of modified turbulence residual (no boundary flux) + to mean flow and turbulence vars. */ + su2double **dFT_dUTvar; /*!< \brief Sensitivity of boundary flux + to mean flow and turbulence vars. */ + su2double *EddyViscSens; /*!< \brief Eddy Viscosity Sensitivity. */ + +public: + + /*! + * \brief Constructor of the class. + */ + CAdjTurbVariable(void); + + /*! + * \overload + * \param[in] val_psinu_inf - Value of the adjoint turbulence variable at the infinity (initialization value). + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAdjTurbVariable(su2double val_psinu_inf, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAdjTurbVariable(void); + + /*! + * \brief Set the Eddy Viscosity Sensitivity of the problem. + * \param[in] val_EddyViscSens - Eddy Viscosity Sensitivity. + */ + void SetEddyViscSens(su2double *val_EddyViscSens, unsigned short numTotalVar); + + /*! + * \brief Get the Eddy Viscosity Sensitivity of the problem. + * \return Pointer to the Eddy Viscosity Sensitivity. + */ + su2double *GetEddyViscSens(void); +}; + +/*! + * \class CAdjLevelSetVariable + * \brief Main class for defining the variables of the Level Set. + * \ingroup LevelSet_Model + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CAdjLevelSetVariable : public CVariable { +public: + /*! + * \brief Constructor of the class. + */ + CAdjLevelSetVariable(void); + + /*! + * \overload + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAdjLevelSetVariable(unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \overload + * \param[in] val_levelset - Level set variable value (initialization value). + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CAdjLevelSetVariable(su2double val_levelset, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + virtual ~CAdjLevelSetVariable(void); + +}; + +/*! + * \class CTemplateVariable + * \brief Main class for defining the variables of the potential solver. + * \ingroup Potential_Flow_Equation + * \author F. Palacios + * \version 4.0.1 "Cardinal" + */ +class CTemplateVariable : public CVariable { +public: + + /*! + * \brief Constructor of the class. + */ + CTemplateVariable(void); + + /*! + * \overload + * \param[in] val_potential - Value of the potential solution (initialization value). + * \param[in] val_nDim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CTemplateVariable(su2double val_potential, unsigned short val_nDim, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CTemplateVariable(void); +}; + +/*! + * \class CDiscAdjVariable + * \brief Main class for defining the variables of the adjoint solver. + * \ingroup Discrete_Adjoint + * \author T. Albring. + * \version 4.0.1 "Cardinal" + */ +class CDiscAdjVariable : public CVariable { +private: + su2double* Sensitivity; /* Vector holding the derivative of target functional with respect to the coordinates at this node*/ + su2double* Solution_Direct; + su2double* DualTime_Derivative; + su2double* DualTime_Derivative_n; + +public: + /*! + * \brief Constructor of the class. + */ + CDiscAdjVariable(void); + + /*! + * \brief Destructor of the class. + */ + ~CDiscAdjVariable(void); + + /*! + * \overload + * \param[in] val_solution - Pointer to the adjoint value (initialization value). + * \param[in] val_ndim - Number of dimensions of the problem. + * \param[in] val_nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + CDiscAdjVariable(su2double *val_solution, unsigned short val_ndim, unsigned short val_nvar, CConfig *config); + + /*! + * \brief Set the sensitivity at the node + * \param[in] iDim - spacial component + * \param[in] val - value of the Sensitivity + */ + void SetSensitivity(unsigned short iDim, su2double val); + + /*! + * \brief Get the Sensitivity at the node + * \param[in] iDim - spacial component + * \return value of the Sensitivity + */ + su2double GetSensitivity(unsigned short iDim); + + void SetDual_Time_Derivative(unsigned short iVar, su2double der); + + void SetDual_Time_Derivative_n(unsigned short iVar, su2double der); + + su2double GetDual_Time_Derivative(unsigned short iVar); + + su2double GetDual_Time_Derivative_n(unsigned short iVar); + + void SetSolution_Direct(su2double *sol); + + su2double* GetSolution_Direct(); +}; + + +#include "variable_structure.inl" diff --git a/SU2_CFD/include/variable_structure.inl b/SU2_CFD/include/variable_structure.inl index ba731fb7696..2e7d67d90dc 100644 --- a/SU2_CFD/include/variable_structure.inl +++ b/SU2_CFD/include/variable_structure.inl @@ -1,1003 +1,1003 @@ -/*! - * \file variable_structure.inl - * \brief In-Line subroutines of the variable_structure.hpp file. - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -inline bool CVariable::SetDensity(void) { return 0; } - -inline void CVariable::SetVelSolutionOldDVector(void) { } - -inline void CVariable::SetVelSolutionDVector(void) { } - -inline void CVariable::SetTraction(unsigned short iVar, unsigned short jVar, su2double val_traction) { } - -inline void CVariable::AddTraction(unsigned short iVar, unsigned short jVar, su2double val_traction) { } - -inline su2double **CVariable::GetTraction(void) { return NULL; } - -inline void CVariable::SetStress(unsigned short iVar, unsigned short jVar, su2double val_stress) { } - -inline void CVariable::AddStress(unsigned short iVar, unsigned short jVar, su2double val_stress) { } - -inline su2double **CVariable::GetStress(void) { return 0; } - -inline void CVariable::SetVonMises_Stress(su2double val_stress) { } - -inline su2double CVariable::GetVonMises_Stress(void) { return 0; } - -inline void CVariable::SetFlow_Pressure(su2double val_pressure) { } - -inline su2double CVariable::GetFlow_Pressure(void) { return 0; } - -inline void CVariable::Initialize_Connectivity(void) { } - -inline void CVariable::Upgrade_Connectivity(void) { } - -inline unsigned short CVariable::Get_Connectivity(void) { return 0; } - -inline su2double CVariable::GetBetaInc2(void) { return 0; } - -inline su2double CVariable::GetDiffLevelSet(void) { return 0; } - -inline su2double CVariable::GetDensityInc(void) { return 0; } - -inline su2double CVariable::GetLevelSet(void) { return 0; } - -inline su2double CVariable::GetDistance(void) { return 0; } - -inline su2double CVariable::GetMassFraction(unsigned short val_Species) { return 0; } - -inline void CVariable::SetNon_Physical(bool val_value) { Non_Physical = !val_value; } - -inline su2double CVariable::GetNon_Physical(void) { return su2double(Non_Physical); } - -inline void CVariable::SetSolution(unsigned short val_var, su2double val_solution) { Solution[val_var] = val_solution; } - -inline void CVariable::SetUndivided_Laplacian(unsigned short val_var, su2double val_undivided_laplacian) { Undivided_Laplacian[val_var] = val_undivided_laplacian; } - -inline void CVariable::SetAuxVar(su2double val_auxvar) { AuxVar = val_auxvar; } - -inline void CVariable::SetSolution_Old(unsigned short val_var, su2double val_solution_old) { Solution_Old[val_var] = val_solution_old; } - -inline void CVariable::SetLimiter(unsigned short val_var, su2double val_limiter) { Limiter[val_var] = val_limiter; } - -inline void CVariable::SetLimiterPrimitive(unsigned short val_species, unsigned short val_var, su2double val_limiter) { } - -inline su2double CVariable::GetLimiterPrimitive(unsigned short val_species, unsigned short val_var) { return 0.0; } - -inline void CVariable::SetSolution_Max(unsigned short val_var, su2double val_solution) { Solution_Max[val_var] = val_solution; } - -inline void CVariable::SetSolution_Min(unsigned short val_var, su2double val_solution) { Solution_Min[val_var] = val_solution; } - -inline void CVariable::SetAuxVarGradient(unsigned short iDim, su2double val_gradient) { Grad_AuxVar[iDim] = val_gradient; } - -inline su2double *CVariable::GetSolution(void) { return Solution; } - -inline su2double *CVariable::GetSolution_Old(void) { return Solution_Old; } - -inline su2double *CVariable::GetSolution_time_n(void) { return Solution_time_n; } - -inline su2double *CVariable::GetSolution_time_n1(void) { return Solution_time_n1; } - -inline su2double CVariable::GetAuxVar(void) { return AuxVar; } - -inline su2double *CVariable::GetUndivided_Laplacian(void) { return Undivided_Laplacian; } - -inline su2double CVariable::GetUndivided_Laplacian(unsigned short val_var) { return Undivided_Laplacian[val_var]; } - -inline su2double CVariable::GetSolution(unsigned short val_var) { return Solution[val_var]; } - -inline su2double CVariable::GetSolution_Old(unsigned short val_var) { return Solution_Old[val_var]; } - -inline su2double *CVariable::GetResidual_Sum(void) { return Residual_Sum; } - -inline su2double *CVariable::GetResidual_Old(void) { return Residual_Old; } - -inline void CVariable::SetGradient(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient[val_var][val_dim] = val_value; } - -inline void CVariable::AddGradient(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient[val_var][val_dim] += val_value; } - -inline void CVariable::SubtractGradient(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient[val_var][val_dim] -= val_value; } - -inline void CVariable::AddAuxVarGradient(unsigned short val_dim, su2double val_value) { Grad_AuxVar[val_dim] += val_value; } - -inline void CVariable::SubtractAuxVarGradient(unsigned short val_dim, su2double val_value) { Grad_AuxVar[val_dim] -= val_value; } - -inline su2double CVariable::GetGradient(unsigned short val_var, unsigned short val_dim) { return Gradient[val_var][val_dim]; } - -inline su2double CVariable::GetLimiter(unsigned short val_var) { return Limiter[val_var]; } - -inline su2double CVariable::GetSolution_Max(unsigned short val_var) { return Solution_Max[val_var]; } - -inline su2double CVariable::GetSolution_Min(unsigned short val_var) { return Solution_Min[val_var]; } - -inline su2double CVariable::GetPreconditioner_Beta() { return 0; } - -inline void CVariable::SetPreconditioner_Beta( su2double val_Beta) { } - -inline su2double* CVariable::GetWindGust() { return 0; } - -inline void CVariable::SetWindGust( su2double* val_WindGust) {} - -inline su2double* CVariable::GetWindGustDer() { return 0; } - -inline void CVariable::SetWindGustDer( su2double* val_WindGustDer) {} - -inline su2double **CVariable::GetGradient(void) { return Gradient; } - -inline su2double *CVariable::GetLimiter(void) { return Limiter; } - -inline su2double *CVariable::GetAuxVarGradient(void) { return Grad_AuxVar; } - -inline su2double CVariable::GetAuxVarGradient(unsigned short val_dim) { return Grad_AuxVar[val_dim]; } - -inline su2double *CVariable::GetResTruncError(void) { return Res_TruncError; } - -inline void CVariable::SetDelta_Time(su2double val_delta_time) { Delta_Time = val_delta_time; } - -inline void CVariable::SetDelta_Time(su2double val_delta_time, unsigned short iSpecies) { } - -inline su2double CVariable::GetDelta_Time(void) { return Delta_Time; } - -inline su2double CVariable::GetDelta_Time(unsigned short iSpecies) { return 0;} - -inline void CVariable::SetMax_Lambda(su2double val_max_lambda) { Max_Lambda = val_max_lambda; } - -inline void CVariable::SetMax_Lambda_Inv(su2double val_max_lambda) { Max_Lambda_Inv = val_max_lambda; } - -inline void CVariable::SetMax_Lambda_Inv(su2double val_max_lambda, unsigned short val_species) { } - -inline void CVariable::SetMax_Lambda_Visc(su2double val_max_lambda) { Max_Lambda_Visc = val_max_lambda; } - -inline void CVariable::SetMax_Lambda_Visc(su2double val_max_lambda, unsigned short val_species) { } - -inline void CVariable::SetLambda(su2double val_lambda) { Lambda = val_lambda; } - -inline void CVariable::SetLambda(su2double val_lambda, unsigned short iSpecies) {} - -inline void CVariable::AddMax_Lambda(su2double val_max_lambda) { Max_Lambda += val_max_lambda; } - -inline void CVariable::AddMax_Lambda_Inv(su2double val_max_lambda) { Max_Lambda_Inv += val_max_lambda; } - -inline void CVariable::AddMax_Lambda_Visc(su2double val_max_lambda) { Max_Lambda_Visc += val_max_lambda; } - -inline void CVariable::AddLambda(su2double val_lambda) { Lambda += val_lambda; } - -inline void CVariable::AddLambda(su2double val_lambda, unsigned short iSpecies) {} - -inline su2double CVariable::GetMax_Lambda(void) { return Max_Lambda; } - -inline su2double CVariable::GetMax_Lambda_Inv(void) { return Max_Lambda_Inv; } - -inline su2double CVariable::GetMax_Lambda_Visc(void) { return Max_Lambda_Visc; } - -inline su2double CVariable::GetLambda(void) { return Lambda; } - -inline su2double CVariable::GetLambda(unsigned short iSpecies) { return 0; } - -inline su2double CVariable::GetSensor(void) { return Sensor; } - -inline su2double CVariable::GetSensor(unsigned short iSpecies) { return 0;} - -inline void CVariable::AddMax_Lambda_Inv(su2double val_max_lambda, unsigned short iSpecies) { } - -inline void CVariable::AddMax_Lambda_Visc(su2double val_max_lambda, unsigned short iSpecies) { } - -inline void CVariable::SetSensor(su2double val_sensor) { Sensor = val_sensor; } - -inline void CVariable::SetSensor(su2double val_sensor, unsigned short val_iSpecies) {} - -inline su2double CVariable::GetDensity(void) { return 0; } - -inline su2double CVariable::GetDensity(unsigned short val_iSpecies) { return 0; } - -inline su2double CVariable::GetEnergy(void) { return 0; } - -inline su2double *CVariable::GetForceProj_Vector(void) { return NULL; } - -inline su2double *CVariable::GetObjFuncSource(void) { return NULL; } - -inline su2double *CVariable::GetIntBoundary_Jump(void) { return NULL; } - -inline su2double CVariable::GetEddyViscosity(void) { return 0; } - -inline su2double CVariable::GetEddyViscosityInc(void) { return 0; } - -inline void CVariable::SetGammaEff(void) { } - -inline void CVariable::SetGammaSep(su2double gamma_sep) { } - -inline su2double CVariable::GetIntermittency(void) { return 0; } - -inline su2double CVariable::GetEnthalpy(void) { return 0; } - -inline su2double CVariable::GetPressure(void) { return 0; } - -inline su2double CVariable::GetPressureInc(void) { return 0; } - -inline su2double CVariable::GetProjVel(su2double *val_vector) { return 0; } - -inline su2double CVariable::GetProjVel(su2double *val_vector, unsigned short val_species) { return 0; } - -inline su2double CVariable::GetSoundSpeed(void) { return 0; } - -inline su2double CVariable::GetTemperature(void) { return 0; } - -inline su2double CVariable::GetTemperature_ve(void) { return 0; } - -inline su2double CVariable::GetRhoCv_tr(void) { return 0; } - -inline su2double CVariable::GetRhoCv_ve(void) { return 0; } - -inline su2double CVariable::GetVelocity(unsigned short val_dim) { return 0; } - -inline su2double CVariable::GetVelocity2(void) { return 0; } - -inline su2double CVariable::GetVelocity2(unsigned short val_species) { return 0;} - -inline su2double CVariable::GetLaminarViscosity(void) { return 0; } - -inline su2double CVariable::GetLaminarViscosityInc(void) { return 0; } - -inline su2double CVariable::GetLaminarViscosity(unsigned short iSpecies) { return 0; } - -inline su2double* CVariable::GetDiffusionCoeff(void) { return NULL; } - -inline su2double CVariable::GetThermalConductivity(void) { return 0; } - -inline su2double CVariable::GetSpecificHeatCp(void) { return 0; } - -inline su2double CVariable::GetThermalConductivity_ve(void) { return 0; } - -inline su2double* CVariable::GetVorticity(void) { return 0; } - -inline su2double CVariable::GetStrainMag(void) { return 0; } - -inline void CVariable::SetForceProj_Vector(su2double *val_ForceProj_Vector) { } - -inline void CVariable::SetObjFuncSource(su2double *val_ObjFuncSource) { } - -inline void CVariable::SetIntBoundary_Jump(su2double *val_IntBoundary_Jump) { } - -inline void CVariable::SetEnthalpy(void) { } - -inline bool CVariable::SetPrimVar_Compressible(su2double SharpEdge_Distance, bool check, CConfig *config) { return true; } - -inline bool CVariable::SetPrimVar_Incompressible(su2double SharpEdge_Distance, bool check, CConfig *config) { return true; } - -inline bool CVariable::SetPrimVar_FreeSurface(su2double SharpEdge_Distance, bool check, CConfig *config) { return true; } - -inline bool CVariable::SetPrimVar_Compressible(CConfig *config) { return true; } - -inline bool CVariable::SetPrimVar_Compressible(CFluidModel *FluidModel) { return true; } - -inline void CVariable::SetSecondaryVar_Compressible(CFluidModel *FluidModel) { } - -inline bool CVariable::SetPrimVar_Compressible(su2double eddy_visc, su2double turb_ke, CConfig *config) { return true; } - -inline bool CVariable::SetPrimVar_Compressible(su2double eddy_visc, su2double turb_ke, CFluidModel *FluidModel) { return true; } - -inline bool CVariable::SetPrimVar_Incompressible(su2double Density_Inf, CConfig *config) { return true; } - -inline bool CVariable::SetPrimVar_FreeSurface(CConfig *config) { return true; } - -inline bool CVariable::SetPrimVar_Incompressible(su2double Density_Inf, su2double Viscosity_Inf, su2double eddy_visc, su2double turb_ke, CConfig *config) { return true; } - -inline bool CVariable::SetPrimVar_FreeSurface(su2double eddy_visc, su2double turb_ke, CConfig *config) { return true; } - -inline su2double CVariable::GetPrimitive(unsigned short val_var) { return 0; } - -inline su2double *CVariable::GetPrimitive(void) { return NULL; } - -inline void CVariable::SetPrimitive(unsigned short val_var, su2double val_prim) { } - -inline void CVariable::SetPrimitive(su2double *val_prim) { } - -inline su2double CVariable::GetSecondary(unsigned short val_var) { return 0; } - -inline su2double *CVariable::GetSecondary(void) { return NULL; } - -inline void CVariable::SetSecondary(unsigned short val_var, su2double val_secondary) { } - -inline void CVariable::SetSecondary(su2double *val_prim) { } - -inline bool CVariable::Cons2PrimVar(CConfig *config, su2double *U, su2double *V, - su2double *val_dPdU, su2double *val_dTdU, - su2double *val_dTvedU) { return false; } - -inline void CVariable::Prim2ConsVar(CConfig *config, su2double *V, su2double *U) { return; } - -inline void CVariable::SetBetaInc2(su2double val_betainc2) { } - -inline void CVariable::SetDensityInc(su2double val_density) { } - -inline void CVariable::SetPressureInc(void) { } - -inline void CVariable::SetVelocityInc(void) { } - -inline void CVariable::SetPhi_Old(su2double *val_phi) { } - -inline void CVariable::SetDiffLevelSet(su2double val_difflevelset) { } - -inline void CVariable::SetdPdrho_e(su2double dPdrho_e) { } - -inline void CVariable::SetdPde_rho(su2double dPde_rho) { } - -inline void CVariable::SetdTdrho_e(su2double dTdrho_e) { } - -inline void CVariable::SetdTde_rho(su2double dTde_rho) { } - -inline void CVariable::Setdmudrho_T(su2double dmudrho_T) { } - -inline void CVariable::SetdmudT_rho(su2double dmudT_rho) { } - -inline void CVariable::Setdktdrho_T(su2double dktdrho_T) { } - -inline void CVariable::SetdktdT_rho(su2double dktdT_rho) { } - -inline bool CVariable::SetPressure(su2double Gamma) { return false; } - -inline bool CVariable::SetPressure(CConfig *config) { return false; } - -inline bool CVariable::SetPressure(su2double Gamma, su2double turb_ke) { return false; } - -inline void CVariable::SetPressure() { } - -inline su2double *CVariable::GetdPdU() { return NULL; } - -inline su2double *CVariable::GetdTdU() { return NULL; } - -inline su2double *CVariable::GetdTvedU() { return NULL; } - -inline su2double CVariable::CalcEve(su2double *V, CConfig *config, unsigned short val_Species) { return 0; } - -inline su2double CVariable::CalcHs(su2double *V, CConfig *config, unsigned short val_Species) { return 0; } - -inline su2double CVariable::CalcCvve(su2double val_Tve, CConfig *config, unsigned short val_Species) { return 0; } - -inline void CVariable::CalcdPdU(su2double *V, CConfig *config, su2double *dPdU) { } - -inline void CVariable::CalcdTdU(su2double *V, CConfig *config, su2double *dTdU) { } - -inline void CVariable::CalcdTvedU(su2double *V, CConfig *config, su2double *dTvedU) { } - -inline void CVariable::SetDeltaPressure(su2double *val_velocity, su2double Gamma) { } - -inline bool CVariable::SetSoundSpeed(CConfig *config) { return false; } - -inline bool CVariable::SetSoundSpeed() { return false; } - -inline bool CVariable::SetSoundSpeed(su2double Gamma) { return false; } - -inline bool CVariable::SetTemperature(su2double Gas_Constant) { return false; } - -inline bool CVariable::SetTemperature_ve(su2double val_Tve) {return false; } - -inline bool CVariable::SetTemperature(CConfig *config) { return false; } - -inline void CVariable::SetPrimitive(CConfig *config) { } - -inline void CVariable::SetPrimitive(CConfig *config, su2double *Coord) { } - -inline void CVariable::SetWallTemperature(su2double Temperature_Wall) { } - -inline void CVariable::SetWallTemperature(su2double* Temperature_Wall) { } - -inline void CVariable::SetThermalCoeff(CConfig *config) { } - -inline void CVariable::SetVelocity(void) { } - -inline void CVariable::SetVelocity2(void) { } - -inline void CVariable::SetVelocity_Old(su2double *val_velocity) { } - -inline void CVariable::SetVelocityInc_Old(su2double *val_velocity) { } - -inline void CVariable::SetVel_ResTruncError_Zero(unsigned short iSpecies) { } - -inline void CVariable::SetLaminarViscosity(su2double laminarViscosity) { } - -inline void CVariable::SetLaminarViscosity(CConfig *config) { } - -inline void CVariable::SetLaminarViscosityInc(su2double val_laminar_viscosity_inc) { } - -inline void CVariable::SetEddyViscosity(su2double eddy_visc) { } - -inline void CVariable::SetEddyViscosityInc(su2double eddy_visc) { } - -inline void CVariable::SetThermalConductivity(su2double thermalConductivity) { } - -inline void CVariable::SetThermalConductivity(CConfig *config) { } - -inline void CVariable::SetSpecificHeatCp(su2double Cp) { } - -inline bool CVariable::SetVorticity(bool val_limiter) { return false; } - -inline bool CVariable::SetStrainMag(bool val_limiter) { return false; } - -inline void CVariable::SetGradient_PrimitiveZero(unsigned short val_primvar) { } - -inline void CVariable::AddGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value) { } - -inline void CVariable::SubtractGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value) { } - -inline su2double CVariable::GetGradient_Primitive(unsigned short val_var, unsigned short val_dim) { return 0; } - -inline su2double CVariable::GetLimiter_Primitive(unsigned short val_var) { return 0; } - -inline void CVariable::SetGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value) { } - -inline void CVariable::SetLimiter_Primitive(unsigned short val_var, su2double val_value) { } - -inline su2double **CVariable::GetGradient_Primitive(void) { return NULL; } - -inline su2double *CVariable::GetLimiter_Primitive(void) { return NULL; } - -inline void CVariable::SetGradient_SecondaryZero(unsigned short val_secondaryvar) { } - -inline void CVariable::AddGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value) { } - -inline void CVariable::SubtractGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value) { } - -inline su2double CVariable::GetGradient_Secondary(unsigned short val_var, unsigned short val_dim) { return 0; } - -inline su2double CVariable::GetLimiter_Secondary(unsigned short val_var) { return 0; } - -inline void CVariable::SetGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value) { } - -inline void CVariable::SetLimiter_Secondary(unsigned short val_var, su2double val_value) { } - -inline su2double **CVariable::GetGradient_Secondary(void) { return NULL; } - -inline su2double *CVariable::GetLimiter_Secondary(void) { return NULL; } - -inline void CVariable::SetBlendingFunc(su2double val_viscosity, su2double val_dist, su2double val_density) { } - -inline su2double CVariable::GetF1blending(void) { return 0; } - -inline su2double CVariable::GetF2blending(void) { return 0; } - -inline su2double CVariable::GetmuT() { return 0;} - -inline void CVariable::SetmuT(su2double val_muT) { } - -inline su2double* CVariable::GetSolution_Direct() { return NULL; } - -inline void CVariable::SetSolution_Direct(su2double *val_solution_direct) { } - -inline void CVariable::SetTimeSpectral_Source(unsigned short val_var, su2double val_source) { } - -inline su2double CVariable::GetTimeSpectral_Source(unsigned short val_var) { return 0; } - -inline void CVariable::SetEddyViscSens(su2double *val_EddyViscSens, unsigned short numTotalVar) { } - -inline su2double *CVariable::GetEddyViscSens(void) { return NULL; } - -inline void CVariable::SetSolution_time_n(void) { } - -inline void CVariable::SetSolution_Vel(su2double *val_solution_vel) { } - -inline void CVariable::SetSolution_Vel(unsigned short val_var, su2double val_solution_vel) { } - -inline void CVariable::SetSolution_Vel_time_n(su2double *val_solution_vel_time_n) { } - -inline void CVariable::SetSolution_Vel_time_n(void) { } - -inline void CVariable::SetSolution_Vel_time_n(unsigned short val_var, su2double val_solution_vel_time_n) { } - -inline su2double CVariable::GetSolution_time_n(unsigned short val_var) { return 0; } - -inline su2double CVariable::GetSolution_Vel(unsigned short val_var) { return 0; } - -inline su2double *CVariable::GetSolution_Vel(void) { return NULL; } - -inline su2double CVariable::GetSolution_Vel_time_n(unsigned short val_var) { return 0; } - -inline su2double *CVariable::GetSolution_Vel_time_n(void) { return NULL; } - -inline void CVariable::SetSolution_Accel(su2double *val_solution_accel) { } - -inline void CVariable::SetSolution_Accel(unsigned short val_var, su2double val_solution_accel) { } - -inline void CVariable::SetSolution_Accel_time_n(su2double *val_solution_accel_time_n) { } - -inline void CVariable::SetSolution_Accel_time_n(void) { } - -inline void CVariable::SetSolution_Accel_time_n(unsigned short val_var, su2double val_solution_accel_time_n) { } - -inline su2double CVariable::GetSolution_Accel(unsigned short val_var) { return 0; } - -inline su2double *CVariable::GetSolution_Accel(void) { return NULL; } - -inline su2double CVariable::GetSolution_Accel_time_n(unsigned short val_var) { return 0; } - -inline su2double *CVariable::GetSolution_Accel_time_n(void) { return NULL; } - -inline void CVariable::SetSolution_Pred(su2double *val_solution_pred){ } - -inline void CVariable::SetSolution_Pred(void){ } - -inline su2double CVariable::GetSolution_Pred(unsigned short val_var){ return 0.0; } - -inline su2double *CVariable::GetSolution_Pred(void){ return NULL; } - -inline void CVariable::SetSolution_Pred_Old(su2double *val_solution_pred_Old){ } - -inline void CVariable::SetSolution_Pred_Old(void){ } - -inline su2double CVariable::GetSolution_Pred_Old(unsigned short val_var){ return 0.0; } - -inline su2double *CVariable::GetSolution_Pred_Old(void){ return NULL; } - -inline su2double CEulerVariable::GetDensity(void) { return Solution[0]; } - -inline su2double CEulerVariable::GetDensityInc(void) { return Primitive[nDim+1]; } - -inline su2double CEulerVariable::GetLevelSet(void) { return Primitive[nDim+5]; } - -inline su2double CEulerVariable::GetDistance(void) { return Primitive[nDim+6]; } - -inline su2double CEulerVariable::GetBetaInc2(void) { return Primitive[nDim+2]; } - -inline su2double CEulerVariable::GetEnergy(void) { return Solution[nVar-1]/Solution[0]; }; - -inline su2double CEulerVariable::GetEnthalpy(void) { return Primitive[nDim+3]; } - -inline su2double CEulerVariable::GetPressure(void) { return Primitive[nDim+1]; } - -inline su2double CEulerVariable::GetPressureInc(void) { return Primitive[0]; } - -inline su2double CEulerVariable::GetSoundSpeed(void) { return Primitive[nDim+4]; } - -inline su2double CEulerVariable::GetTemperature(void) { return Primitive[0]; } - -inline su2double CEulerVariable::GetVelocity(unsigned short val_dim) { return Primitive[val_dim+1]; } - -inline su2double CEulerVariable::GetVelocity2(void) { return Velocity2; } - -inline bool CEulerVariable::SetDensity(void) { - Primitive[nDim+2] = Solution[0]; - if (Primitive[nDim+2] > 0.0) return false; - else return true; -} - -inline void CEulerVariable::SetDensityInc(su2double val_density) { Primitive[nDim+1] = val_density; } - -inline bool CEulerVariable::SetPressure(su2double pressure) { - Primitive[nDim+1] = pressure; - if (Primitive[nDim+1] > 0.0) return false; - else return true; -} - -inline void CEulerVariable::SetPressureInc(void) { Primitive[0] = Solution[0]; } - -inline void CEulerVariable::SetVelocity(void) { - Velocity2 = 0.0; - for (unsigned short iDim = 0; iDim < nDim; iDim++) { - Primitive[iDim+1] = Solution[iDim+1] / Solution[0]; - Velocity2 += Primitive[iDim+1]*Primitive[iDim+1]; - } -} - -inline void CEulerVariable::SetVelocityInc(void) { - Velocity2 = 0.0; - for (unsigned short iDim = 0; iDim < nDim; iDim++) { - Primitive[iDim+1] = Solution[iDim+1] / Primitive[nDim+1]; - Velocity2 += Primitive[iDim+1]*Primitive[iDim+1]; - } -} - -inline void CEulerVariable::SetEnthalpy(void) { Primitive[nDim+3] = (Solution[nVar-1] + Primitive[nDim+1]) / Solution[0]; } - -inline void CEulerVariable::SetBetaInc2(su2double val_betainc2) { Primitive[nDim+2] = val_betainc2; } - -inline bool CEulerVariable::SetSoundSpeed(su2double soundspeed2) { - su2double radical = soundspeed2; - if (radical < 0.0) return true; - else { - Primitive[nDim+4] = sqrt(radical); - return false; - } -} - -inline bool CEulerVariable::SetTemperature(su2double temperature) { - Primitive[0] = temperature; - if (Primitive[0] > 0.0) return false; - else return true; -} - -inline void CEulerVariable::SetdPdrho_e(su2double dPdrho_e) { - Secondary[0] = dPdrho_e; -} - -inline void CEulerVariable::SetdPde_rho(su2double dPde_rho) { - Secondary[1] = dPde_rho; -} - -inline su2double CEulerVariable::GetPrimitive(unsigned short val_var) { return Primitive[val_var]; } - -inline void CEulerVariable::SetPrimitive(unsigned short val_var, su2double val_prim) { Primitive[val_var] = val_prim; } - -inline void CEulerVariable::SetPrimitive(su2double *val_prim) { - for (unsigned short iVar = 0; iVar < nPrimVar; iVar++) - Primitive[iVar] = val_prim[iVar]; -} - -inline su2double *CEulerVariable::GetPrimitive(void) { return Primitive; } - -inline su2double CEulerVariable::GetSecondary(unsigned short val_var) { return Secondary[val_var]; } - -inline void CEulerVariable::SetSecondary(unsigned short val_var, su2double val_secondary) { Secondary[val_var] = val_secondary; } - -inline void CEulerVariable::SetSecondary(su2double *val_secondary) { - for (unsigned short iVar = 0; iVar < nSecondaryVar; iVar++) - Secondary[iVar] = val_secondary[iVar]; -} - -inline su2double *CEulerVariable::GetSecondary(void) { return Secondary; } - -inline void CEulerVariable::SetVelocity_Old(su2double *val_velocity) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Solution_Old[iDim+1] = val_velocity[iDim]*Solution[0]; -} - -inline void CEulerVariable::SetVelocityInc_Old(su2double *val_velocity) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Solution_Old[iDim+1] = val_velocity[iDim]*Primitive[nDim+1]; -} - -inline void CEulerVariable::AddGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient_Primitive[val_var][val_dim] += val_value; } - -inline void CEulerVariable::SubtractGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient_Primitive[val_var][val_dim] -= val_value; } - -inline su2double CEulerVariable::GetGradient_Primitive(unsigned short val_var, unsigned short val_dim) { return Gradient_Primitive[val_var][val_dim]; } - -inline su2double CEulerVariable::GetLimiter_Primitive(unsigned short val_var) { return Limiter_Primitive[val_var]; } - -inline void CEulerVariable::SetGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient_Primitive[val_var][val_dim] = val_value; } - -inline void CEulerVariable::SetLimiter_Primitive(unsigned short val_var, su2double val_value) { Limiter_Primitive[val_var] = val_value; } - -inline su2double **CEulerVariable::GetGradient_Primitive(void) { return Gradient_Primitive; } - -inline su2double *CEulerVariable::GetLimiter_Primitive(void) { return Limiter_Primitive; } - -inline void CEulerVariable::AddGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient_Secondary[val_var][val_dim] += val_value; } - -inline void CEulerVariable::SubtractGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient_Secondary[val_var][val_dim] -= val_value; } - -inline su2double CEulerVariable::GetGradient_Secondary(unsigned short val_var, unsigned short val_dim) { return Gradient_Secondary[val_var][val_dim]; } - -inline su2double CEulerVariable::GetLimiter_Secondary(unsigned short val_var) { return Limiter_Secondary[val_var]; } - -inline void CEulerVariable::SetGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient_Secondary[val_var][val_dim] = val_value; } - -inline void CEulerVariable::SetLimiter_Secondary(unsigned short val_var, su2double val_value) { Limiter_Secondary[val_var] = val_value; } - -inline su2double **CEulerVariable::GetGradient_Secondary(void) { return Gradient_Secondary; } - -inline su2double *CEulerVariable::GetLimiter_Secondary(void) { return Limiter_Secondary; } - -inline void CEulerVariable::SetTimeSpectral_Source(unsigned short val_var, su2double val_source) { TS_Source[val_var] = val_source; } - -inline su2double CEulerVariable::GetTimeSpectral_Source(unsigned short val_var) { return TS_Source[val_var]; } - -inline su2double CEulerVariable::GetPreconditioner_Beta() { return Precond_Beta; } - -inline void CEulerVariable::SetPreconditioner_Beta(su2double val_Beta) { Precond_Beta = val_Beta; } - -inline void CEulerVariable::SetWindGust( su2double* val_WindGust) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - WindGust[iDim] = val_WindGust[iDim];} - -inline su2double* CEulerVariable::GetWindGust() { return WindGust;} - -inline void CEulerVariable::SetWindGustDer( su2double* val_WindGustDer) { - for (unsigned short iDim = 0; iDim < nDim+1; iDim++) - WindGustDer[iDim] = val_WindGustDer[iDim];} - -inline su2double* CEulerVariable::GetWindGustDer() { return WindGustDer;} - -inline su2double CNSVariable::GetEddyViscosity(void) { return Primitive[nDim+6]; } - -inline su2double CNSVariable::GetEddyViscosityInc(void) { return Primitive[nDim+4]; } - -inline su2double CNSVariable::GetLaminarViscosity(void) { return Primitive[nDim+5]; } - -inline su2double CNSVariable::GetLaminarViscosityInc(void) { return Primitive[nDim+3]; } - -inline su2double CNSVariable::GetThermalConductivity(void) { return Primitive[nDim+7]; } - -inline su2double CNSVariable::GetSpecificHeatCp(void) { return Primitive[nDim+8]; } - -inline su2double* CNSVariable::GetVorticity(void) { return Vorticity; } - -inline su2double CNSVariable::GetStrainMag(void) { return StrainMag; } - -inline void CNSVariable::SetLaminarViscosity(su2double laminarViscosity) { - Primitive[nDim+5] = laminarViscosity; -} - -inline void CNSVariable::SetThermalConductivity(su2double thermalConductivity) { - Primitive[nDim+7] = thermalConductivity; -} - -inline void CNSVariable::SetSpecificHeatCp(su2double Cp) { - Primitive[nDim+8] = Cp; -} - -inline void CNSVariable::SetdTdrho_e(su2double dTdrho_e) { - Secondary[2] = dTdrho_e; -} - -inline void CNSVariable::SetdTde_rho(su2double dTde_rho) { - Secondary[3] = dTde_rho; -} - -inline void CNSVariable::Setdmudrho_T(su2double dmudrho_T) { - Secondary[4] = dmudrho_T; -} - -inline void CNSVariable::SetdmudT_rho(su2double dmudT_rho) { - Secondary[5] = dmudT_rho; -} - -inline void CNSVariable::Setdktdrho_T(su2double dktdrho_T) { - Secondary[6] = dktdrho_T; -} - -inline void CNSVariable::SetdktdT_rho(su2double dktdT_rho) { - Secondary[7] = dktdT_rho; -} - -inline void CNSVariable::SetLaminarViscosityInc(su2double val_laminar_viscosity_inc) { Primitive[nDim+3] = val_laminar_viscosity_inc; } - -inline void CNSVariable::SetEddyViscosity(su2double eddy_visc) { Primitive[nDim+6] = eddy_visc; } - -inline void CNSVariable::SetEddyViscosityInc(su2double eddy_visc) { Primitive[nDim+4] = eddy_visc; } - -inline void CNSVariable::SetWallTemperature(su2double Temperature_Wall ) { Primitive[0] = Temperature_Wall; } - -inline su2double CTransLMVariable::GetIntermittency() { return Solution[0]; } - -inline void CTransLMVariable::SetGammaSep(su2double gamma_sep_in) {gamma_sep = gamma_sep_in;} - -inline su2double *CAdjEulerVariable::GetForceProj_Vector(void) { return ForceProj_Vector; } - -inline su2double *CAdjEulerVariable::GetObjFuncSource(void) { return ObjFuncSource; } - -inline su2double *CAdjEulerVariable::GetIntBoundary_Jump(void) { return IntBoundary_Jump; } - -inline void CAdjEulerVariable::SetForceProj_Vector(su2double *val_ForceProj_Vector) { for (unsigned short iDim = 0; iDim < nDim; iDim++) ForceProj_Vector[iDim] = val_ForceProj_Vector[iDim]; } - -inline void CAdjEulerVariable::SetObjFuncSource(su2double *val_ObjFuncSource) { for (unsigned short iVar = 0; iVar < nVar; iVar++) ObjFuncSource[iVar] = val_ObjFuncSource[iVar]; } - -inline void CAdjEulerVariable::SetIntBoundary_Jump(su2double *val_IntBoundary_Jump) { for (unsigned short iVar = 0; iVar < nVar; iVar++) IntBoundary_Jump[iVar] = val_IntBoundary_Jump[iVar]; } - -inline void CAdjEulerVariable::SetPhi_Old(su2double *val_phi) { for (unsigned short iDim = 0; iDim < nDim; iDim++) Solution_Old[iDim+1]=val_phi[iDim]; }; - -inline void CAdjEulerVariable::SetTimeSpectral_Source(unsigned short val_var, su2double val_source) { TS_Source[val_var] = val_source; } - -inline su2double CAdjEulerVariable::GetTimeSpectral_Source(unsigned short val_var) { return TS_Source[val_var]; } - -inline su2double *CAdjNSVariable::GetForceProj_Vector(void) { return ForceProj_Vector; } - -inline void CAdjNSVariable::SetForceProj_Vector(su2double *val_ForceProj_Vector) { for (unsigned short iDim = 0; iDim < nDim; iDim++) ForceProj_Vector[iDim] = val_ForceProj_Vector[iDim]; } - -inline void CAdjNSVariable::SetPhi_Old(su2double *val_phi) { for (unsigned short iDim = 0; iDim < nDim; iDim++) Solution_Old[iDim+1] = val_phi[iDim]; }; - -inline void CAdjNSVariable::SetVelSolutionOldDVector(void) { for (unsigned short iDim = 0; iDim < nDim; iDim++) Solution_Old[iDim+1] = ForceProj_Vector[iDim]; }; - -inline void CAdjNSVariable::SetVelSolutionDVector(void) { for (unsigned short iDim = 0; iDim < nDim; iDim++) Solution[iDim+1] = ForceProj_Vector[iDim]; }; - -inline void CFEAVariable::SetStress(unsigned short iVar, unsigned short jVar, su2double val_stress) { Stress[iVar][jVar] = val_stress; } - -inline void CFEAVariable::AddStress(unsigned short iVar, unsigned short jVar, su2double val_stress) { Stress[iVar][jVar] += val_stress; } - -inline su2double **CFEAVariable::GetStress(void) { return Stress; } - -inline void CFEAVariable::SetVonMises_Stress(su2double val_stress) { VonMises_Stress = val_stress; } - -inline su2double CFEAVariable::GetVonMises_Stress(void) { return VonMises_Stress; } - -inline void CFEAVariable::SetFlow_Pressure(su2double val_pressure) { Flow_Pressure = val_pressure; } - -inline su2double CFEAVariable::GetFlow_Pressure(void) { return Flow_Pressure; } - -inline void CFEAVariable::Initialize_Connectivity(void) { nAttachedElements = 0; } - -inline void CFEAVariable::Upgrade_Connectivity(void) { nAttachedElements += 1; } - -inline unsigned short CFEAVariable::Get_Connectivity(void) { return nAttachedElements; } - -inline void CFEABoundVariable::SetTraction(unsigned short iVar, unsigned short jVar, su2double val_traction) { Traction[iVar][jVar] = val_traction; } - -inline void CFEABoundVariable::AddTraction(unsigned short iVar, unsigned short jVar, su2double val_traction) { Traction[iVar][jVar] += val_traction; } - -inline su2double **CFEABoundVariable::GetTraction(void) { return Traction; } - -inline void CFEAVariable::SetSolution_Vel(unsigned short val_var, su2double val_solution_vel) { Solution_Vel[val_var] = val_solution_vel; } - -inline void CFEAVariable::SetSolution_Vel_time_n(unsigned short val_var, su2double val_solution_vel_time_n) { Solution_Vel_time_n[val_var] = val_solution_vel_time_n; } - -inline su2double CFEAVariable::GetSolution_time_n(unsigned short val_var) { return Solution_time_n[val_var]; } - -inline su2double CFEAVariable::GetSolution_Vel(unsigned short val_var) { return Solution_Vel[val_var]; } - -inline su2double *CFEAVariable::GetSolution_Vel(void) { return Solution_Vel; } - -inline su2double CFEAVariable::GetSolution_Vel_time_n(unsigned short val_var) { return Solution_Vel_time_n[val_var]; } - -inline su2double *CFEAVariable::GetSolution_Vel_time_n(void) { return Solution_Vel_time_n; } - -inline void CFEAVariable::SetSolution_Accel(unsigned short val_var, su2double val_solution_accel) { Solution_Accel[val_var] = val_solution_accel; } - -inline void CFEAVariable::SetSolution_Accel_time_n(unsigned short val_var, su2double val_solution_accel_time_n) { Solution_Accel_time_n[val_var] = val_solution_accel_time_n; } - -inline su2double CFEAVariable::GetSolution_Accel(unsigned short val_var) { return Solution_Accel[val_var]; } - -inline su2double *CFEAVariable::GetSolution_Accel(void) { return Solution_Accel; } - -inline su2double CFEAVariable::GetSolution_Accel_time_n(unsigned short val_var) { return Solution_Accel_time_n[val_var]; } - -inline su2double *CFEAVariable::GetSolution_Accel_time_n(void) { return Solution_Accel_time_n; } - -inline void CFEAVariable::SetSolution_Pred(su2double *val_solution_pred){ Solution_Pred = val_solution_pred; } - -inline su2double CFEAVariable::GetSolution_Pred(unsigned short val_var){ return Solution_Pred[val_var]; } - -inline su2double *CFEAVariable::GetSolution_Pred(void){ return Solution_Pred; } - -inline void CFEAVariable::SetSolution_Pred_Old(su2double *val_solution_pred_Old){ Solution_Pred_Old = val_solution_pred_Old; } - -inline su2double CFEAVariable::GetSolution_Pred_Old(unsigned short val_var){ return Solution_Pred_Old[val_var]; } - -inline su2double *CFEAVariable::GetSolution_Pred_Old(void){ return Solution_Pred_Old; } - -inline su2double* CWaveVariable::GetSolution_Direct() { return Solution_Direct;} - -inline void CWaveVariable::SetSolution_Direct(su2double *val_solution_direct) { for (unsigned short iVar = 0; iVar < nVar; iVar++) Solution_Direct[iVar] += val_solution_direct[iVar];} - -inline su2double* CPotentialVariable::GetChargeDensity() { return Charge_Density;} - -inline void CPotentialVariable::SetChargeDensity(su2double positive_charge, su2double negative_charge) {Charge_Density[0] = positive_charge; Charge_Density[1] = negative_charge;} - -inline su2double* CHeatVariable::GetSolution_Direct() { return Solution_Direct;} - -inline void CHeatVariable::SetSolution_Direct(su2double *val_solution_direct) { for (unsigned short iVar = 0; iVar < nVar; iVar++) Solution_Direct[iVar] += val_solution_direct[iVar];} - -inline void CTurbSAVariable::SetTimeSpectral_Source(unsigned short val_var, su2double val_source) { TS_Source[val_var] = val_source; } - -inline su2double CTurbSAVariable::GetTimeSpectral_Source(unsigned short val_var) { return TS_Source[val_var]; } - - -inline void CTurbMLVariable::SetTimeSpectral_Source(unsigned short val_var, su2double val_source) { TS_Source[val_var] = val_source; } - -inline su2double CTurbMLVariable::GetTimeSpectral_Source(unsigned short val_var) { return TS_Source[val_var]; } - -inline su2double CTurbSSTVariable::GetF1blending() { return F1; } - -inline su2double CTurbSSTVariable::GetF2blending() { return F2; } - -inline su2double CTurbSSTVariable::GetCrossDiff() { return CDkw; } - -inline void CAdjTurbVariable::SetEddyViscSens(su2double *val_EddyViscSens, unsigned short numTotalVar) { - for (unsigned short iVar = 0; iVar < numTotalVar; iVar++) { - EddyViscSens[iVar] = val_EddyViscSens[iVar];} -} - -inline su2double *CAdjTurbVariable::GetEddyViscSens(void) { return EddyViscSens; } - -inline void CVariable::RegisterSolution(bool input) { - if (input) { - for (unsigned short iVar = 0; iVar < nVar; iVar++) - AD::RegisterInput(Solution[iVar]); - } - else { for (unsigned short iVar = 0; iVar < nVar; iVar++) - AD::RegisterOutput(Solution[iVar]);} -} - -inline void CVariable::RegisterSolution_time_n(){ - for (unsigned short iVar = 0; iVar < nVar; iVar++) - AD::RegisterInput(Solution_time_n[iVar]); -} - -inline void CVariable::RegisterSolution_time_n1(){ - for (unsigned short iVar = 0; iVar < nVar; iVar++) - AD::RegisterInput(Solution_time_n1[iVar]); -} - -inline void CVariable::SetAdjointSolution(su2double *adj_sol){ - for (unsigned short iVar = 0; iVar < nVar; iVar++) - SU2_TYPE::SetDerivative(Solution[iVar], SU2_TYPE::GetValue(adj_sol[iVar])); -} - - -inline void CVariable::GetAdjointSolution(su2double *adj_sol){ - for (unsigned short iVar = 0; iVar < nVar; iVar++){ - adj_sol[iVar] = SU2_TYPE::GetDerivative(Solution[iVar]); - } -} - -inline void CVariable::SetAdjointSolution_time_n(su2double *adj_sol){ - for (unsigned short iVar = 0; iVar < nVar; iVar++) - SU2_TYPE::SetDerivative(Solution_time_n[iVar], SU2_TYPE::GetValue(adj_sol[iVar])); -} - - -inline void CVariable::GetAdjointSolution_time_n(su2double *adj_sol){ - for (unsigned short iVar = 0; iVar < nVar; iVar++){ - adj_sol[iVar] = SU2_TYPE::GetDerivative(Solution_time_n[iVar]); - } -} - -inline void CVariable::SetAdjointSolution_time_n1(su2double *adj_sol){ - for (unsigned short iVar = 0; iVar < nVar; iVar++) - SU2_TYPE::SetDerivative(Solution_time_n1[iVar], SU2_TYPE::GetValue(adj_sol[iVar])); -} - - -inline void CVariable::GetAdjointSolution_time_n1(su2double *adj_sol){ - for (unsigned short iVar = 0; iVar < nVar; iVar++){ - adj_sol[iVar] = SU2_TYPE::GetDerivative(Solution_time_n1[iVar]); - } -} -inline void CVariable::SetDual_Time_Derivative(unsigned short iVar, su2double der){} - -inline void CDiscAdjVariable::SetDual_Time_Derivative(unsigned short iVar, su2double der){DualTime_Derivative[iVar] = der;} - -inline void CVariable::SetDual_Time_Derivative_n(unsigned short iVar, su2double der){} - -inline void CDiscAdjVariable::SetDual_Time_Derivative_n(unsigned short iVar, su2double der){DualTime_Derivative_n[iVar] = der;} - -inline su2double CVariable::GetDual_Time_Derivative(unsigned short iVar){return 0.0;} - -inline su2double CDiscAdjVariable::GetDual_Time_Derivative(unsigned short iVar){return DualTime_Derivative[iVar];} - -inline su2double CVariable::GetDual_Time_Derivative_n(unsigned short iVar){return 0.0;} - -inline su2double CDiscAdjVariable::GetDual_Time_Derivative_n(unsigned short iVar){return DualTime_Derivative_n[iVar];} - -inline void CVariable::SetSensitivity(unsigned short iDim, su2double val){} - -inline su2double CVariable::GetSensitivity(unsigned short iDim){ return 0.0; } - -inline void CDiscAdjVariable::SetSensitivity(unsigned short iDim, su2double val){Sensitivity[iDim] = val;} - -inline su2double CDiscAdjVariable::GetSensitivity(unsigned short iDim){return Sensitivity[iDim];} - -inline su2double* CDiscAdjVariable::GetSolution_Direct() { return Solution_Direct; } - -inline void CDiscAdjVariable::SetSolution_Direct(su2double *val_solution_direct) { - for (unsigned short iVar = 0; iVar < nVar; iVar++){ - Solution_Direct[iVar] = val_solution_direct[iVar]; - } -} +/*! + * \file variable_structure.inl + * \brief In-Line subroutines of the variable_structure.hpp file. + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +inline bool CVariable::SetDensity(void) { return 0; } + +inline void CVariable::SetVelSolutionOldDVector(void) { } + +inline void CVariable::SetVelSolutionDVector(void) { } + +inline void CVariable::SetTraction(unsigned short iVar, unsigned short jVar, su2double val_traction) { } + +inline void CVariable::AddTraction(unsigned short iVar, unsigned short jVar, su2double val_traction) { } + +inline su2double **CVariable::GetTraction(void) { return NULL; } + +inline void CVariable::SetStress(unsigned short iVar, unsigned short jVar, su2double val_stress) { } + +inline void CVariable::AddStress(unsigned short iVar, unsigned short jVar, su2double val_stress) { } + +inline su2double **CVariable::GetStress(void) { return 0; } + +inline void CVariable::SetVonMises_Stress(su2double val_stress) { } + +inline su2double CVariable::GetVonMises_Stress(void) { return 0; } + +inline void CVariable::SetFlow_Pressure(su2double val_pressure) { } + +inline su2double CVariable::GetFlow_Pressure(void) { return 0; } + +inline void CVariable::Initialize_Connectivity(void) { } + +inline void CVariable::Upgrade_Connectivity(void) { } + +inline unsigned short CVariable::Get_Connectivity(void) { return 0; } + +inline su2double CVariable::GetBetaInc2(void) { return 0; } + +inline su2double CVariable::GetDiffLevelSet(void) { return 0; } + +inline su2double CVariable::GetDensityInc(void) { return 0; } + +inline su2double CVariable::GetLevelSet(void) { return 0; } + +inline su2double CVariable::GetDistance(void) { return 0; } + +inline su2double CVariable::GetMassFraction(unsigned short val_Species) { return 0; } + +inline void CVariable::SetNon_Physical(bool val_value) { Non_Physical = !val_value; } + +inline su2double CVariable::GetNon_Physical(void) { return su2double(Non_Physical); } + +inline void CVariable::SetSolution(unsigned short val_var, su2double val_solution) { Solution[val_var] = val_solution; } + +inline void CVariable::SetUndivided_Laplacian(unsigned short val_var, su2double val_undivided_laplacian) { Undivided_Laplacian[val_var] = val_undivided_laplacian; } + +inline void CVariable::SetAuxVar(su2double val_auxvar) { AuxVar = val_auxvar; } + +inline void CVariable::SetSolution_Old(unsigned short val_var, su2double val_solution_old) { Solution_Old[val_var] = val_solution_old; } + +inline void CVariable::SetLimiter(unsigned short val_var, su2double val_limiter) { Limiter[val_var] = val_limiter; } + +inline void CVariable::SetLimiterPrimitive(unsigned short val_species, unsigned short val_var, su2double val_limiter) { } + +inline su2double CVariable::GetLimiterPrimitive(unsigned short val_species, unsigned short val_var) { return 0.0; } + +inline void CVariable::SetSolution_Max(unsigned short val_var, su2double val_solution) { Solution_Max[val_var] = val_solution; } + +inline void CVariable::SetSolution_Min(unsigned short val_var, su2double val_solution) { Solution_Min[val_var] = val_solution; } + +inline void CVariable::SetAuxVarGradient(unsigned short iDim, su2double val_gradient) { Grad_AuxVar[iDim] = val_gradient; } + +inline su2double *CVariable::GetSolution(void) { return Solution; } + +inline su2double *CVariable::GetSolution_Old(void) { return Solution_Old; } + +inline su2double *CVariable::GetSolution_time_n(void) { return Solution_time_n; } + +inline su2double *CVariable::GetSolution_time_n1(void) { return Solution_time_n1; } + +inline su2double CVariable::GetAuxVar(void) { return AuxVar; } + +inline su2double *CVariable::GetUndivided_Laplacian(void) { return Undivided_Laplacian; } + +inline su2double CVariable::GetUndivided_Laplacian(unsigned short val_var) { return Undivided_Laplacian[val_var]; } + +inline su2double CVariable::GetSolution(unsigned short val_var) { return Solution[val_var]; } + +inline su2double CVariable::GetSolution_Old(unsigned short val_var) { return Solution_Old[val_var]; } + +inline su2double *CVariable::GetResidual_Sum(void) { return Residual_Sum; } + +inline su2double *CVariable::GetResidual_Old(void) { return Residual_Old; } + +inline void CVariable::SetGradient(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient[val_var][val_dim] = val_value; } + +inline void CVariable::AddGradient(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient[val_var][val_dim] += val_value; } + +inline void CVariable::SubtractGradient(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient[val_var][val_dim] -= val_value; } + +inline void CVariable::AddAuxVarGradient(unsigned short val_dim, su2double val_value) { Grad_AuxVar[val_dim] += val_value; } + +inline void CVariable::SubtractAuxVarGradient(unsigned short val_dim, su2double val_value) { Grad_AuxVar[val_dim] -= val_value; } + +inline su2double CVariable::GetGradient(unsigned short val_var, unsigned short val_dim) { return Gradient[val_var][val_dim]; } + +inline su2double CVariable::GetLimiter(unsigned short val_var) { return Limiter[val_var]; } + +inline su2double CVariable::GetSolution_Max(unsigned short val_var) { return Solution_Max[val_var]; } + +inline su2double CVariable::GetSolution_Min(unsigned short val_var) { return Solution_Min[val_var]; } + +inline su2double CVariable::GetPreconditioner_Beta() { return 0; } + +inline void CVariable::SetPreconditioner_Beta( su2double val_Beta) { } + +inline su2double* CVariable::GetWindGust() { return 0; } + +inline void CVariable::SetWindGust( su2double* val_WindGust) {} + +inline su2double* CVariable::GetWindGustDer() { return 0; } + +inline void CVariable::SetWindGustDer( su2double* val_WindGustDer) {} + +inline su2double **CVariable::GetGradient(void) { return Gradient; } + +inline su2double *CVariable::GetLimiter(void) { return Limiter; } + +inline su2double *CVariable::GetAuxVarGradient(void) { return Grad_AuxVar; } + +inline su2double CVariable::GetAuxVarGradient(unsigned short val_dim) { return Grad_AuxVar[val_dim]; } + +inline su2double *CVariable::GetResTruncError(void) { return Res_TruncError; } + +inline void CVariable::SetDelta_Time(su2double val_delta_time) { Delta_Time = val_delta_time; } + +inline void CVariable::SetDelta_Time(su2double val_delta_time, unsigned short iSpecies) { } + +inline su2double CVariable::GetDelta_Time(void) { return Delta_Time; } + +inline su2double CVariable::GetDelta_Time(unsigned short iSpecies) { return 0;} + +inline void CVariable::SetMax_Lambda(su2double val_max_lambda) { Max_Lambda = val_max_lambda; } + +inline void CVariable::SetMax_Lambda_Inv(su2double val_max_lambda) { Max_Lambda_Inv = val_max_lambda; } + +inline void CVariable::SetMax_Lambda_Inv(su2double val_max_lambda, unsigned short val_species) { } + +inline void CVariable::SetMax_Lambda_Visc(su2double val_max_lambda) { Max_Lambda_Visc = val_max_lambda; } + +inline void CVariable::SetMax_Lambda_Visc(su2double val_max_lambda, unsigned short val_species) { } + +inline void CVariable::SetLambda(su2double val_lambda) { Lambda = val_lambda; } + +inline void CVariable::SetLambda(su2double val_lambda, unsigned short iSpecies) {} + +inline void CVariable::AddMax_Lambda(su2double val_max_lambda) { Max_Lambda += val_max_lambda; } + +inline void CVariable::AddMax_Lambda_Inv(su2double val_max_lambda) { Max_Lambda_Inv += val_max_lambda; } + +inline void CVariable::AddMax_Lambda_Visc(su2double val_max_lambda) { Max_Lambda_Visc += val_max_lambda; } + +inline void CVariable::AddLambda(su2double val_lambda) { Lambda += val_lambda; } + +inline void CVariable::AddLambda(su2double val_lambda, unsigned short iSpecies) {} + +inline su2double CVariable::GetMax_Lambda(void) { return Max_Lambda; } + +inline su2double CVariable::GetMax_Lambda_Inv(void) { return Max_Lambda_Inv; } + +inline su2double CVariable::GetMax_Lambda_Visc(void) { return Max_Lambda_Visc; } + +inline su2double CVariable::GetLambda(void) { return Lambda; } + +inline su2double CVariable::GetLambda(unsigned short iSpecies) { return 0; } + +inline su2double CVariable::GetSensor(void) { return Sensor; } + +inline su2double CVariable::GetSensor(unsigned short iSpecies) { return 0;} + +inline void CVariable::AddMax_Lambda_Inv(su2double val_max_lambda, unsigned short iSpecies) { } + +inline void CVariable::AddMax_Lambda_Visc(su2double val_max_lambda, unsigned short iSpecies) { } + +inline void CVariable::SetSensor(su2double val_sensor) { Sensor = val_sensor; } + +inline void CVariable::SetSensor(su2double val_sensor, unsigned short val_iSpecies) {} + +inline su2double CVariable::GetDensity(void) { return 0; } + +inline su2double CVariable::GetDensity(unsigned short val_iSpecies) { return 0; } + +inline su2double CVariable::GetEnergy(void) { return 0; } + +inline su2double *CVariable::GetForceProj_Vector(void) { return NULL; } + +inline su2double *CVariable::GetObjFuncSource(void) { return NULL; } + +inline su2double *CVariable::GetIntBoundary_Jump(void) { return NULL; } + +inline su2double CVariable::GetEddyViscosity(void) { return 0; } + +inline su2double CVariable::GetEddyViscosityInc(void) { return 0; } + +inline void CVariable::SetGammaEff(void) { } + +inline void CVariable::SetGammaSep(su2double gamma_sep) { } + +inline su2double CVariable::GetIntermittency(void) { return 0; } + +inline su2double CVariable::GetEnthalpy(void) { return 0; } + +inline su2double CVariable::GetPressure(void) { return 0; } + +inline su2double CVariable::GetPressureInc(void) { return 0; } + +inline su2double CVariable::GetProjVel(su2double *val_vector) { return 0; } + +inline su2double CVariable::GetProjVel(su2double *val_vector, unsigned short val_species) { return 0; } + +inline su2double CVariable::GetSoundSpeed(void) { return 0; } + +inline su2double CVariable::GetTemperature(void) { return 0; } + +inline su2double CVariable::GetTemperature_ve(void) { return 0; } + +inline su2double CVariable::GetRhoCv_tr(void) { return 0; } + +inline su2double CVariable::GetRhoCv_ve(void) { return 0; } + +inline su2double CVariable::GetVelocity(unsigned short val_dim) { return 0; } + +inline su2double CVariable::GetVelocity2(void) { return 0; } + +inline su2double CVariable::GetVelocity2(unsigned short val_species) { return 0;} + +inline su2double CVariable::GetLaminarViscosity(void) { return 0; } + +inline su2double CVariable::GetLaminarViscosityInc(void) { return 0; } + +inline su2double CVariable::GetLaminarViscosity(unsigned short iSpecies) { return 0; } + +inline su2double* CVariable::GetDiffusionCoeff(void) { return NULL; } + +inline su2double CVariable::GetThermalConductivity(void) { return 0; } + +inline su2double CVariable::GetSpecificHeatCp(void) { return 0; } + +inline su2double CVariable::GetThermalConductivity_ve(void) { return 0; } + +inline su2double* CVariable::GetVorticity(void) { return 0; } + +inline su2double CVariable::GetStrainMag(void) { return 0; } + +inline void CVariable::SetForceProj_Vector(su2double *val_ForceProj_Vector) { } + +inline void CVariable::SetObjFuncSource(su2double *val_ObjFuncSource) { } + +inline void CVariable::SetIntBoundary_Jump(su2double *val_IntBoundary_Jump) { } + +inline void CVariable::SetEnthalpy(void) { } + +inline bool CVariable::SetPrimVar_Compressible(su2double SharpEdge_Distance, bool check, CConfig *config) { return true; } + +inline bool CVariable::SetPrimVar_Incompressible(su2double SharpEdge_Distance, bool check, CConfig *config) { return true; } + +inline bool CVariable::SetPrimVar_FreeSurface(su2double SharpEdge_Distance, bool check, CConfig *config) { return true; } + +inline bool CVariable::SetPrimVar_Compressible(CConfig *config) { return true; } + +inline bool CVariable::SetPrimVar_Compressible(CFluidModel *FluidModel) { return true; } + +inline void CVariable::SetSecondaryVar_Compressible(CFluidModel *FluidModel) { } + +inline bool CVariable::SetPrimVar_Compressible(su2double eddy_visc, su2double turb_ke, CConfig *config) { return true; } + +inline bool CVariable::SetPrimVar_Compressible(su2double eddy_visc, su2double turb_ke, CFluidModel *FluidModel) { return true; } + +inline bool CVariable::SetPrimVar_Incompressible(su2double Density_Inf, CConfig *config) { return true; } + +inline bool CVariable::SetPrimVar_FreeSurface(CConfig *config) { return true; } + +inline bool CVariable::SetPrimVar_Incompressible(su2double Density_Inf, su2double Viscosity_Inf, su2double eddy_visc, su2double turb_ke, CConfig *config) { return true; } + +inline bool CVariable::SetPrimVar_FreeSurface(su2double eddy_visc, su2double turb_ke, CConfig *config) { return true; } + +inline su2double CVariable::GetPrimitive(unsigned short val_var) { return 0; } + +inline su2double *CVariable::GetPrimitive(void) { return NULL; } + +inline void CVariable::SetPrimitive(unsigned short val_var, su2double val_prim) { } + +inline void CVariable::SetPrimitive(su2double *val_prim) { } + +inline su2double CVariable::GetSecondary(unsigned short val_var) { return 0; } + +inline su2double *CVariable::GetSecondary(void) { return NULL; } + +inline void CVariable::SetSecondary(unsigned short val_var, su2double val_secondary) { } + +inline void CVariable::SetSecondary(su2double *val_prim) { } + +inline bool CVariable::Cons2PrimVar(CConfig *config, su2double *U, su2double *V, + su2double *val_dPdU, su2double *val_dTdU, + su2double *val_dTvedU) { return false; } + +inline void CVariable::Prim2ConsVar(CConfig *config, su2double *V, su2double *U) { return; } + +inline void CVariable::SetBetaInc2(su2double val_betainc2) { } + +inline void CVariable::SetDensityInc(su2double val_density) { } + +inline void CVariable::SetPressureInc(void) { } + +inline void CVariable::SetVelocityInc(void) { } + +inline void CVariable::SetPhi_Old(su2double *val_phi) { } + +inline void CVariable::SetDiffLevelSet(su2double val_difflevelset) { } + +inline void CVariable::SetdPdrho_e(su2double dPdrho_e) { } + +inline void CVariable::SetdPde_rho(su2double dPde_rho) { } + +inline void CVariable::SetdTdrho_e(su2double dTdrho_e) { } + +inline void CVariable::SetdTde_rho(su2double dTde_rho) { } + +inline void CVariable::Setdmudrho_T(su2double dmudrho_T) { } + +inline void CVariable::SetdmudT_rho(su2double dmudT_rho) { } + +inline void CVariable::Setdktdrho_T(su2double dktdrho_T) { } + +inline void CVariable::SetdktdT_rho(su2double dktdT_rho) { } + +inline bool CVariable::SetPressure(su2double Gamma) { return false; } + +inline bool CVariable::SetPressure(CConfig *config) { return false; } + +inline bool CVariable::SetPressure(su2double Gamma, su2double turb_ke) { return false; } + +inline void CVariable::SetPressure() { } + +inline su2double *CVariable::GetdPdU() { return NULL; } + +inline su2double *CVariable::GetdTdU() { return NULL; } + +inline su2double *CVariable::GetdTvedU() { return NULL; } + +inline su2double CVariable::CalcEve(su2double *V, CConfig *config, unsigned short val_Species) { return 0; } + +inline su2double CVariable::CalcHs(su2double *V, CConfig *config, unsigned short val_Species) { return 0; } + +inline su2double CVariable::CalcCvve(su2double val_Tve, CConfig *config, unsigned short val_Species) { return 0; } + +inline void CVariable::CalcdPdU(su2double *V, CConfig *config, su2double *dPdU) { } + +inline void CVariable::CalcdTdU(su2double *V, CConfig *config, su2double *dTdU) { } + +inline void CVariable::CalcdTvedU(su2double *V, CConfig *config, su2double *dTvedU) { } + +inline void CVariable::SetDeltaPressure(su2double *val_velocity, su2double Gamma) { } + +inline bool CVariable::SetSoundSpeed(CConfig *config) { return false; } + +inline bool CVariable::SetSoundSpeed() { return false; } + +inline bool CVariable::SetSoundSpeed(su2double Gamma) { return false; } + +inline bool CVariable::SetTemperature(su2double Gas_Constant) { return false; } + +inline bool CVariable::SetTemperature_ve(su2double val_Tve) {return false; } + +inline bool CVariable::SetTemperature(CConfig *config) { return false; } + +inline void CVariable::SetPrimitive(CConfig *config) { } + +inline void CVariable::SetPrimitive(CConfig *config, su2double *Coord) { } + +inline void CVariable::SetWallTemperature(su2double Temperature_Wall) { } + +inline void CVariable::SetWallTemperature(su2double* Temperature_Wall) { } + +inline void CVariable::SetThermalCoeff(CConfig *config) { } + +inline void CVariable::SetVelocity(void) { } + +inline void CVariable::SetVelocity2(void) { } + +inline void CVariable::SetVelocity_Old(su2double *val_velocity) { } + +inline void CVariable::SetVelocityInc_Old(su2double *val_velocity) { } + +inline void CVariable::SetVel_ResTruncError_Zero(unsigned short iSpecies) { } + +inline void CVariable::SetLaminarViscosity(su2double laminarViscosity) { } + +inline void CVariable::SetLaminarViscosity(CConfig *config) { } + +inline void CVariable::SetLaminarViscosityInc(su2double val_laminar_viscosity_inc) { } + +inline void CVariable::SetEddyViscosity(su2double eddy_visc) { } + +inline void CVariable::SetEddyViscosityInc(su2double eddy_visc) { } + +inline void CVariable::SetThermalConductivity(su2double thermalConductivity) { } + +inline void CVariable::SetThermalConductivity(CConfig *config) { } + +inline void CVariable::SetSpecificHeatCp(su2double Cp) { } + +inline bool CVariable::SetVorticity(bool val_limiter) { return false; } + +inline bool CVariable::SetStrainMag(bool val_limiter) { return false; } + +inline void CVariable::SetGradient_PrimitiveZero(unsigned short val_primvar) { } + +inline void CVariable::AddGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value) { } + +inline void CVariable::SubtractGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value) { } + +inline su2double CVariable::GetGradient_Primitive(unsigned short val_var, unsigned short val_dim) { return 0; } + +inline su2double CVariable::GetLimiter_Primitive(unsigned short val_var) { return 0; } + +inline void CVariable::SetGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value) { } + +inline void CVariable::SetLimiter_Primitive(unsigned short val_var, su2double val_value) { } + +inline su2double **CVariable::GetGradient_Primitive(void) { return NULL; } + +inline su2double *CVariable::GetLimiter_Primitive(void) { return NULL; } + +inline void CVariable::SetGradient_SecondaryZero(unsigned short val_secondaryvar) { } + +inline void CVariable::AddGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value) { } + +inline void CVariable::SubtractGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value) { } + +inline su2double CVariable::GetGradient_Secondary(unsigned short val_var, unsigned short val_dim) { return 0; } + +inline su2double CVariable::GetLimiter_Secondary(unsigned short val_var) { return 0; } + +inline void CVariable::SetGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value) { } + +inline void CVariable::SetLimiter_Secondary(unsigned short val_var, su2double val_value) { } + +inline su2double **CVariable::GetGradient_Secondary(void) { return NULL; } + +inline su2double *CVariable::GetLimiter_Secondary(void) { return NULL; } + +inline void CVariable::SetBlendingFunc(su2double val_viscosity, su2double val_dist, su2double val_density) { } + +inline su2double CVariable::GetF1blending(void) { return 0; } + +inline su2double CVariable::GetF2blending(void) { return 0; } + +inline su2double CVariable::GetmuT() { return 0;} + +inline void CVariable::SetmuT(su2double val_muT) { } + +inline su2double* CVariable::GetSolution_Direct() { return NULL; } + +inline void CVariable::SetSolution_Direct(su2double *val_solution_direct) { } + +inline void CVariable::SetTimeSpectral_Source(unsigned short val_var, su2double val_source) { } + +inline su2double CVariable::GetTimeSpectral_Source(unsigned short val_var) { return 0; } + +inline void CVariable::SetEddyViscSens(su2double *val_EddyViscSens, unsigned short numTotalVar) { } + +inline su2double *CVariable::GetEddyViscSens(void) { return NULL; } + +inline void CVariable::SetSolution_time_n(void) { } + +inline void CVariable::SetSolution_Vel(su2double *val_solution_vel) { } + +inline void CVariable::SetSolution_Vel(unsigned short val_var, su2double val_solution_vel) { } + +inline void CVariable::SetSolution_Vel_time_n(su2double *val_solution_vel_time_n) { } + +inline void CVariable::SetSolution_Vel_time_n(void) { } + +inline void CVariable::SetSolution_Vel_time_n(unsigned short val_var, su2double val_solution_vel_time_n) { } + +inline su2double CVariable::GetSolution_time_n(unsigned short val_var) { return 0; } + +inline su2double CVariable::GetSolution_Vel(unsigned short val_var) { return 0; } + +inline su2double *CVariable::GetSolution_Vel(void) { return NULL; } + +inline su2double CVariable::GetSolution_Vel_time_n(unsigned short val_var) { return 0; } + +inline su2double *CVariable::GetSolution_Vel_time_n(void) { return NULL; } + +inline void CVariable::SetSolution_Accel(su2double *val_solution_accel) { } + +inline void CVariable::SetSolution_Accel(unsigned short val_var, su2double val_solution_accel) { } + +inline void CVariable::SetSolution_Accel_time_n(su2double *val_solution_accel_time_n) { } + +inline void CVariable::SetSolution_Accel_time_n(void) { } + +inline void CVariable::SetSolution_Accel_time_n(unsigned short val_var, su2double val_solution_accel_time_n) { } + +inline su2double CVariable::GetSolution_Accel(unsigned short val_var) { return 0; } + +inline su2double *CVariable::GetSolution_Accel(void) { return NULL; } + +inline su2double CVariable::GetSolution_Accel_time_n(unsigned short val_var) { return 0; } + +inline su2double *CVariable::GetSolution_Accel_time_n(void) { return NULL; } + +inline void CVariable::SetSolution_Pred(su2double *val_solution_pred){ } + +inline void CVariable::SetSolution_Pred(void){ } + +inline su2double CVariable::GetSolution_Pred(unsigned short val_var){ return 0.0; } + +inline su2double *CVariable::GetSolution_Pred(void){ return NULL; } + +inline void CVariable::SetSolution_Pred_Old(su2double *val_solution_pred_Old){ } + +inline void CVariable::SetSolution_Pred_Old(void){ } + +inline su2double CVariable::GetSolution_Pred_Old(unsigned short val_var){ return 0.0; } + +inline su2double *CVariable::GetSolution_Pred_Old(void){ return NULL; } + +inline su2double CEulerVariable::GetDensity(void) { return Solution[0]; } + +inline su2double CEulerVariable::GetDensityInc(void) { return Primitive[nDim+1]; } + +inline su2double CEulerVariable::GetLevelSet(void) { return Primitive[nDim+5]; } + +inline su2double CEulerVariable::GetDistance(void) { return Primitive[nDim+6]; } + +inline su2double CEulerVariable::GetBetaInc2(void) { return Primitive[nDim+2]; } + +inline su2double CEulerVariable::GetEnergy(void) { return Solution[nVar-1]/Solution[0]; }; + +inline su2double CEulerVariable::GetEnthalpy(void) { return Primitive[nDim+3]; } + +inline su2double CEulerVariable::GetPressure(void) { return Primitive[nDim+1]; } + +inline su2double CEulerVariable::GetPressureInc(void) { return Primitive[0]; } + +inline su2double CEulerVariable::GetSoundSpeed(void) { return Primitive[nDim+4]; } + +inline su2double CEulerVariable::GetTemperature(void) { return Primitive[0]; } + +inline su2double CEulerVariable::GetVelocity(unsigned short val_dim) { return Primitive[val_dim+1]; } + +inline su2double CEulerVariable::GetVelocity2(void) { return Velocity2; } + +inline bool CEulerVariable::SetDensity(void) { + Primitive[nDim+2] = Solution[0]; + if (Primitive[nDim+2] > 0.0) return false; + else return true; +} + +inline void CEulerVariable::SetDensityInc(su2double val_density) { Primitive[nDim+1] = val_density; } + +inline bool CEulerVariable::SetPressure(su2double pressure) { + Primitive[nDim+1] = pressure; + if (Primitive[nDim+1] > 0.0) return false; + else return true; +} + +inline void CEulerVariable::SetPressureInc(void) { Primitive[0] = Solution[0]; } + +inline void CEulerVariable::SetVelocity(void) { + Velocity2 = 0.0; + for (unsigned short iDim = 0; iDim < nDim; iDim++) { + Primitive[iDim+1] = Solution[iDim+1] / Solution[0]; + Velocity2 += Primitive[iDim+1]*Primitive[iDim+1]; + } +} + +inline void CEulerVariable::SetVelocityInc(void) { + Velocity2 = 0.0; + for (unsigned short iDim = 0; iDim < nDim; iDim++) { + Primitive[iDim+1] = Solution[iDim+1] / Primitive[nDim+1]; + Velocity2 += Primitive[iDim+1]*Primitive[iDim+1]; + } +} + +inline void CEulerVariable::SetEnthalpy(void) { Primitive[nDim+3] = (Solution[nVar-1] + Primitive[nDim+1]) / Solution[0]; } + +inline void CEulerVariable::SetBetaInc2(su2double val_betainc2) { Primitive[nDim+2] = val_betainc2; } + +inline bool CEulerVariable::SetSoundSpeed(su2double soundspeed2) { + su2double radical = soundspeed2; + if (radical < 0.0) return true; + else { + Primitive[nDim+4] = sqrt(radical); + return false; + } +} + +inline bool CEulerVariable::SetTemperature(su2double temperature) { + Primitive[0] = temperature; + if (Primitive[0] > 0.0) return false; + else return true; +} + +inline void CEulerVariable::SetdPdrho_e(su2double dPdrho_e) { + Secondary[0] = dPdrho_e; +} + +inline void CEulerVariable::SetdPde_rho(su2double dPde_rho) { + Secondary[1] = dPde_rho; +} + +inline su2double CEulerVariable::GetPrimitive(unsigned short val_var) { return Primitive[val_var]; } + +inline void CEulerVariable::SetPrimitive(unsigned short val_var, su2double val_prim) { Primitive[val_var] = val_prim; } + +inline void CEulerVariable::SetPrimitive(su2double *val_prim) { + for (unsigned short iVar = 0; iVar < nPrimVar; iVar++) + Primitive[iVar] = val_prim[iVar]; +} + +inline su2double *CEulerVariable::GetPrimitive(void) { return Primitive; } + +inline su2double CEulerVariable::GetSecondary(unsigned short val_var) { return Secondary[val_var]; } + +inline void CEulerVariable::SetSecondary(unsigned short val_var, su2double val_secondary) { Secondary[val_var] = val_secondary; } + +inline void CEulerVariable::SetSecondary(su2double *val_secondary) { + for (unsigned short iVar = 0; iVar < nSecondaryVar; iVar++) + Secondary[iVar] = val_secondary[iVar]; +} + +inline su2double *CEulerVariable::GetSecondary(void) { return Secondary; } + +inline void CEulerVariable::SetVelocity_Old(su2double *val_velocity) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Solution_Old[iDim+1] = val_velocity[iDim]*Solution[0]; +} + +inline void CEulerVariable::SetVelocityInc_Old(su2double *val_velocity) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Solution_Old[iDim+1] = val_velocity[iDim]*Primitive[nDim+1]; +} + +inline void CEulerVariable::AddGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient_Primitive[val_var][val_dim] += val_value; } + +inline void CEulerVariable::SubtractGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient_Primitive[val_var][val_dim] -= val_value; } + +inline su2double CEulerVariable::GetGradient_Primitive(unsigned short val_var, unsigned short val_dim) { return Gradient_Primitive[val_var][val_dim]; } + +inline su2double CEulerVariable::GetLimiter_Primitive(unsigned short val_var) { return Limiter_Primitive[val_var]; } + +inline void CEulerVariable::SetGradient_Primitive(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient_Primitive[val_var][val_dim] = val_value; } + +inline void CEulerVariable::SetLimiter_Primitive(unsigned short val_var, su2double val_value) { Limiter_Primitive[val_var] = val_value; } + +inline su2double **CEulerVariable::GetGradient_Primitive(void) { return Gradient_Primitive; } + +inline su2double *CEulerVariable::GetLimiter_Primitive(void) { return Limiter_Primitive; } + +inline void CEulerVariable::AddGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient_Secondary[val_var][val_dim] += val_value; } + +inline void CEulerVariable::SubtractGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient_Secondary[val_var][val_dim] -= val_value; } + +inline su2double CEulerVariable::GetGradient_Secondary(unsigned short val_var, unsigned short val_dim) { return Gradient_Secondary[val_var][val_dim]; } + +inline su2double CEulerVariable::GetLimiter_Secondary(unsigned short val_var) { return Limiter_Secondary[val_var]; } + +inline void CEulerVariable::SetGradient_Secondary(unsigned short val_var, unsigned short val_dim, su2double val_value) { Gradient_Secondary[val_var][val_dim] = val_value; } + +inline void CEulerVariable::SetLimiter_Secondary(unsigned short val_var, su2double val_value) { Limiter_Secondary[val_var] = val_value; } + +inline su2double **CEulerVariable::GetGradient_Secondary(void) { return Gradient_Secondary; } + +inline su2double *CEulerVariable::GetLimiter_Secondary(void) { return Limiter_Secondary; } + +inline void CEulerVariable::SetTimeSpectral_Source(unsigned short val_var, su2double val_source) { TS_Source[val_var] = val_source; } + +inline su2double CEulerVariable::GetTimeSpectral_Source(unsigned short val_var) { return TS_Source[val_var]; } + +inline su2double CEulerVariable::GetPreconditioner_Beta() { return Precond_Beta; } + +inline void CEulerVariable::SetPreconditioner_Beta(su2double val_Beta) { Precond_Beta = val_Beta; } + +inline void CEulerVariable::SetWindGust( su2double* val_WindGust) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + WindGust[iDim] = val_WindGust[iDim];} + +inline su2double* CEulerVariable::GetWindGust() { return WindGust;} + +inline void CEulerVariable::SetWindGustDer( su2double* val_WindGustDer) { + for (unsigned short iDim = 0; iDim < nDim+1; iDim++) + WindGustDer[iDim] = val_WindGustDer[iDim];} + +inline su2double* CEulerVariable::GetWindGustDer() { return WindGustDer;} + +inline su2double CNSVariable::GetEddyViscosity(void) { return Primitive[nDim+6]; } + +inline su2double CNSVariable::GetEddyViscosityInc(void) { return Primitive[nDim+4]; } + +inline su2double CNSVariable::GetLaminarViscosity(void) { return Primitive[nDim+5]; } + +inline su2double CNSVariable::GetLaminarViscosityInc(void) { return Primitive[nDim+3]; } + +inline su2double CNSVariable::GetThermalConductivity(void) { return Primitive[nDim+7]; } + +inline su2double CNSVariable::GetSpecificHeatCp(void) { return Primitive[nDim+8]; } + +inline su2double* CNSVariable::GetVorticity(void) { return Vorticity; } + +inline su2double CNSVariable::GetStrainMag(void) { return StrainMag; } + +inline void CNSVariable::SetLaminarViscosity(su2double laminarViscosity) { + Primitive[nDim+5] = laminarViscosity; +} + +inline void CNSVariable::SetThermalConductivity(su2double thermalConductivity) { + Primitive[nDim+7] = thermalConductivity; +} + +inline void CNSVariable::SetSpecificHeatCp(su2double Cp) { + Primitive[nDim+8] = Cp; +} + +inline void CNSVariable::SetdTdrho_e(su2double dTdrho_e) { + Secondary[2] = dTdrho_e; +} + +inline void CNSVariable::SetdTde_rho(su2double dTde_rho) { + Secondary[3] = dTde_rho; +} + +inline void CNSVariable::Setdmudrho_T(su2double dmudrho_T) { + Secondary[4] = dmudrho_T; +} + +inline void CNSVariable::SetdmudT_rho(su2double dmudT_rho) { + Secondary[5] = dmudT_rho; +} + +inline void CNSVariable::Setdktdrho_T(su2double dktdrho_T) { + Secondary[6] = dktdrho_T; +} + +inline void CNSVariable::SetdktdT_rho(su2double dktdT_rho) { + Secondary[7] = dktdT_rho; +} + +inline void CNSVariable::SetLaminarViscosityInc(su2double val_laminar_viscosity_inc) { Primitive[nDim+3] = val_laminar_viscosity_inc; } + +inline void CNSVariable::SetEddyViscosity(su2double eddy_visc) { Primitive[nDim+6] = eddy_visc; } + +inline void CNSVariable::SetEddyViscosityInc(su2double eddy_visc) { Primitive[nDim+4] = eddy_visc; } + +inline void CNSVariable::SetWallTemperature(su2double Temperature_Wall ) { Primitive[0] = Temperature_Wall; } + +inline su2double CTransLMVariable::GetIntermittency() { return Solution[0]; } + +inline void CTransLMVariable::SetGammaSep(su2double gamma_sep_in) {gamma_sep = gamma_sep_in;} + +inline su2double *CAdjEulerVariable::GetForceProj_Vector(void) { return ForceProj_Vector; } + +inline su2double *CAdjEulerVariable::GetObjFuncSource(void) { return ObjFuncSource; } + +inline su2double *CAdjEulerVariable::GetIntBoundary_Jump(void) { return IntBoundary_Jump; } + +inline void CAdjEulerVariable::SetForceProj_Vector(su2double *val_ForceProj_Vector) { for (unsigned short iDim = 0; iDim < nDim; iDim++) ForceProj_Vector[iDim] = val_ForceProj_Vector[iDim]; } + +inline void CAdjEulerVariable::SetObjFuncSource(su2double *val_ObjFuncSource) { for (unsigned short iVar = 0; iVar < nVar; iVar++) ObjFuncSource[iVar] = val_ObjFuncSource[iVar]; } + +inline void CAdjEulerVariable::SetIntBoundary_Jump(su2double *val_IntBoundary_Jump) { for (unsigned short iVar = 0; iVar < nVar; iVar++) IntBoundary_Jump[iVar] = val_IntBoundary_Jump[iVar]; } + +inline void CAdjEulerVariable::SetPhi_Old(su2double *val_phi) { for (unsigned short iDim = 0; iDim < nDim; iDim++) Solution_Old[iDim+1]=val_phi[iDim]; }; + +inline void CAdjEulerVariable::SetTimeSpectral_Source(unsigned short val_var, su2double val_source) { TS_Source[val_var] = val_source; } + +inline su2double CAdjEulerVariable::GetTimeSpectral_Source(unsigned short val_var) { return TS_Source[val_var]; } + +inline su2double *CAdjNSVariable::GetForceProj_Vector(void) { return ForceProj_Vector; } + +inline void CAdjNSVariable::SetForceProj_Vector(su2double *val_ForceProj_Vector) { for (unsigned short iDim = 0; iDim < nDim; iDim++) ForceProj_Vector[iDim] = val_ForceProj_Vector[iDim]; } + +inline void CAdjNSVariable::SetPhi_Old(su2double *val_phi) { for (unsigned short iDim = 0; iDim < nDim; iDim++) Solution_Old[iDim+1] = val_phi[iDim]; }; + +inline void CAdjNSVariable::SetVelSolutionOldDVector(void) { for (unsigned short iDim = 0; iDim < nDim; iDim++) Solution_Old[iDim+1] = ForceProj_Vector[iDim]; }; + +inline void CAdjNSVariable::SetVelSolutionDVector(void) { for (unsigned short iDim = 0; iDim < nDim; iDim++) Solution[iDim+1] = ForceProj_Vector[iDim]; }; + +inline void CFEAVariable::SetStress(unsigned short iVar, unsigned short jVar, su2double val_stress) { Stress[iVar][jVar] = val_stress; } + +inline void CFEAVariable::AddStress(unsigned short iVar, unsigned short jVar, su2double val_stress) { Stress[iVar][jVar] += val_stress; } + +inline su2double **CFEAVariable::GetStress(void) { return Stress; } + +inline void CFEAVariable::SetVonMises_Stress(su2double val_stress) { VonMises_Stress = val_stress; } + +inline su2double CFEAVariable::GetVonMises_Stress(void) { return VonMises_Stress; } + +inline void CFEAVariable::SetFlow_Pressure(su2double val_pressure) { Flow_Pressure = val_pressure; } + +inline su2double CFEAVariable::GetFlow_Pressure(void) { return Flow_Pressure; } + +inline void CFEAVariable::Initialize_Connectivity(void) { nAttachedElements = 0; } + +inline void CFEAVariable::Upgrade_Connectivity(void) { nAttachedElements += 1; } + +inline unsigned short CFEAVariable::Get_Connectivity(void) { return nAttachedElements; } + +inline void CFEABoundVariable::SetTraction(unsigned short iVar, unsigned short jVar, su2double val_traction) { Traction[iVar][jVar] = val_traction; } + +inline void CFEABoundVariable::AddTraction(unsigned short iVar, unsigned short jVar, su2double val_traction) { Traction[iVar][jVar] += val_traction; } + +inline su2double **CFEABoundVariable::GetTraction(void) { return Traction; } + +inline void CFEAVariable::SetSolution_Vel(unsigned short val_var, su2double val_solution_vel) { Solution_Vel[val_var] = val_solution_vel; } + +inline void CFEAVariable::SetSolution_Vel_time_n(unsigned short val_var, su2double val_solution_vel_time_n) { Solution_Vel_time_n[val_var] = val_solution_vel_time_n; } + +inline su2double CFEAVariable::GetSolution_time_n(unsigned short val_var) { return Solution_time_n[val_var]; } + +inline su2double CFEAVariable::GetSolution_Vel(unsigned short val_var) { return Solution_Vel[val_var]; } + +inline su2double *CFEAVariable::GetSolution_Vel(void) { return Solution_Vel; } + +inline su2double CFEAVariable::GetSolution_Vel_time_n(unsigned short val_var) { return Solution_Vel_time_n[val_var]; } + +inline su2double *CFEAVariable::GetSolution_Vel_time_n(void) { return Solution_Vel_time_n; } + +inline void CFEAVariable::SetSolution_Accel(unsigned short val_var, su2double val_solution_accel) { Solution_Accel[val_var] = val_solution_accel; } + +inline void CFEAVariable::SetSolution_Accel_time_n(unsigned short val_var, su2double val_solution_accel_time_n) { Solution_Accel_time_n[val_var] = val_solution_accel_time_n; } + +inline su2double CFEAVariable::GetSolution_Accel(unsigned short val_var) { return Solution_Accel[val_var]; } + +inline su2double *CFEAVariable::GetSolution_Accel(void) { return Solution_Accel; } + +inline su2double CFEAVariable::GetSolution_Accel_time_n(unsigned short val_var) { return Solution_Accel_time_n[val_var]; } + +inline su2double *CFEAVariable::GetSolution_Accel_time_n(void) { return Solution_Accel_time_n; } + +inline void CFEAVariable::SetSolution_Pred(su2double *val_solution_pred){ Solution_Pred = val_solution_pred; } + +inline su2double CFEAVariable::GetSolution_Pred(unsigned short val_var){ return Solution_Pred[val_var]; } + +inline su2double *CFEAVariable::GetSolution_Pred(void){ return Solution_Pred; } + +inline void CFEAVariable::SetSolution_Pred_Old(su2double *val_solution_pred_Old){ Solution_Pred_Old = val_solution_pred_Old; } + +inline su2double CFEAVariable::GetSolution_Pred_Old(unsigned short val_var){ return Solution_Pred_Old[val_var]; } + +inline su2double *CFEAVariable::GetSolution_Pred_Old(void){ return Solution_Pred_Old; } + +inline su2double* CWaveVariable::GetSolution_Direct() { return Solution_Direct;} + +inline void CWaveVariable::SetSolution_Direct(su2double *val_solution_direct) { for (unsigned short iVar = 0; iVar < nVar; iVar++) Solution_Direct[iVar] += val_solution_direct[iVar];} + +inline su2double* CPotentialVariable::GetChargeDensity() { return Charge_Density;} + +inline void CPotentialVariable::SetChargeDensity(su2double positive_charge, su2double negative_charge) {Charge_Density[0] = positive_charge; Charge_Density[1] = negative_charge;} + +inline su2double* CHeatVariable::GetSolution_Direct() { return Solution_Direct;} + +inline void CHeatVariable::SetSolution_Direct(su2double *val_solution_direct) { for (unsigned short iVar = 0; iVar < nVar; iVar++) Solution_Direct[iVar] += val_solution_direct[iVar];} + +inline void CTurbSAVariable::SetTimeSpectral_Source(unsigned short val_var, su2double val_source) { TS_Source[val_var] = val_source; } + +inline su2double CTurbSAVariable::GetTimeSpectral_Source(unsigned short val_var) { return TS_Source[val_var]; } + + +inline void CTurbMLVariable::SetTimeSpectral_Source(unsigned short val_var, su2double val_source) { TS_Source[val_var] = val_source; } + +inline su2double CTurbMLVariable::GetTimeSpectral_Source(unsigned short val_var) { return TS_Source[val_var]; } + +inline su2double CTurbSSTVariable::GetF1blending() { return F1; } + +inline su2double CTurbSSTVariable::GetF2blending() { return F2; } + +inline su2double CTurbSSTVariable::GetCrossDiff() { return CDkw; } + +inline void CAdjTurbVariable::SetEddyViscSens(su2double *val_EddyViscSens, unsigned short numTotalVar) { + for (unsigned short iVar = 0; iVar < numTotalVar; iVar++) { + EddyViscSens[iVar] = val_EddyViscSens[iVar];} +} + +inline su2double *CAdjTurbVariable::GetEddyViscSens(void) { return EddyViscSens; } + +inline void CVariable::RegisterSolution(bool input) { + if (input) { + for (unsigned short iVar = 0; iVar < nVar; iVar++) + AD::RegisterInput(Solution[iVar]); + } + else { for (unsigned short iVar = 0; iVar < nVar; iVar++) + AD::RegisterOutput(Solution[iVar]);} +} + +inline void CVariable::RegisterSolution_time_n(){ + for (unsigned short iVar = 0; iVar < nVar; iVar++) + AD::RegisterInput(Solution_time_n[iVar]); +} + +inline void CVariable::RegisterSolution_time_n1(){ + for (unsigned short iVar = 0; iVar < nVar; iVar++) + AD::RegisterInput(Solution_time_n1[iVar]); +} + +inline void CVariable::SetAdjointSolution(su2double *adj_sol){ + for (unsigned short iVar = 0; iVar < nVar; iVar++) + SU2_TYPE::SetDerivative(Solution[iVar], SU2_TYPE::GetValue(adj_sol[iVar])); +} + + +inline void CVariable::GetAdjointSolution(su2double *adj_sol){ + for (unsigned short iVar = 0; iVar < nVar; iVar++){ + adj_sol[iVar] = SU2_TYPE::GetDerivative(Solution[iVar]); + } +} + +inline void CVariable::SetAdjointSolution_time_n(su2double *adj_sol){ + for (unsigned short iVar = 0; iVar < nVar; iVar++) + SU2_TYPE::SetDerivative(Solution_time_n[iVar], SU2_TYPE::GetValue(adj_sol[iVar])); +} + + +inline void CVariable::GetAdjointSolution_time_n(su2double *adj_sol){ + for (unsigned short iVar = 0; iVar < nVar; iVar++){ + adj_sol[iVar] = SU2_TYPE::GetDerivative(Solution_time_n[iVar]); + } +} + +inline void CVariable::SetAdjointSolution_time_n1(su2double *adj_sol){ + for (unsigned short iVar = 0; iVar < nVar; iVar++) + SU2_TYPE::SetDerivative(Solution_time_n1[iVar], SU2_TYPE::GetValue(adj_sol[iVar])); +} + + +inline void CVariable::GetAdjointSolution_time_n1(su2double *adj_sol){ + for (unsigned short iVar = 0; iVar < nVar; iVar++){ + adj_sol[iVar] = SU2_TYPE::GetDerivative(Solution_time_n1[iVar]); + } +} +inline void CVariable::SetDual_Time_Derivative(unsigned short iVar, su2double der){} + +inline void CDiscAdjVariable::SetDual_Time_Derivative(unsigned short iVar, su2double der){DualTime_Derivative[iVar] = der;} + +inline void CVariable::SetDual_Time_Derivative_n(unsigned short iVar, su2double der){} + +inline void CDiscAdjVariable::SetDual_Time_Derivative_n(unsigned short iVar, su2double der){DualTime_Derivative_n[iVar] = der;} + +inline su2double CVariable::GetDual_Time_Derivative(unsigned short iVar){return 0.0;} + +inline su2double CDiscAdjVariable::GetDual_Time_Derivative(unsigned short iVar){return DualTime_Derivative[iVar];} + +inline su2double CVariable::GetDual_Time_Derivative_n(unsigned short iVar){return 0.0;} + +inline su2double CDiscAdjVariable::GetDual_Time_Derivative_n(unsigned short iVar){return DualTime_Derivative_n[iVar];} + +inline void CVariable::SetSensitivity(unsigned short iDim, su2double val){} + +inline su2double CVariable::GetSensitivity(unsigned short iDim){ return 0.0; } + +inline void CDiscAdjVariable::SetSensitivity(unsigned short iDim, su2double val){Sensitivity[iDim] = val;} + +inline su2double CDiscAdjVariable::GetSensitivity(unsigned short iDim){return Sensitivity[iDim];} + +inline su2double* CDiscAdjVariable::GetSolution_Direct() { return Solution_Direct; } + +inline void CDiscAdjVariable::SetSolution_Direct(su2double *val_solution_direct) { + for (unsigned short iVar = 0; iVar < nVar; iVar++){ + Solution_Direct[iVar] = val_solution_direct[iVar]; + } +} diff --git a/SU2_CFD/src/definition_structure.cpp b/SU2_CFD/src/definition_structure.cpp index c96012187e7..5de7036f0ea 100644 --- a/SU2_CFD/src/definition_structure.cpp +++ b/SU2_CFD/src/definition_structure.cpp @@ -1,370 +1,370 @@ -/*! - * \file definition_structure.cpp - * \brief Main subroutines used by SU2_CFD - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/definition_structure.hpp" - -unsigned short GetnZone(string val_mesh_filename, unsigned short val_format, CConfig *config) { - string text_line, Marker_Tag; - ifstream mesh_file; - short nZone = 1; // Default value - unsigned short iLine, nLine = 10; - char cstr[200]; - string::size_type position; - - /*--- Search the mesh file for the 'NZONE' keyword. ---*/ - - switch (val_format) { - case SU2: - - /*--- Open grid file ---*/ - - strcpy (cstr, val_mesh_filename.c_str()); - mesh_file.open(cstr, ios::in); - if (mesh_file.fail()) { - cout << "cstr=" << cstr << endl; - cout << "There is no geometry file (GetnZone))!" << endl; - -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - } - - /*--- Read the SU2 mesh file ---*/ - - for (iLine = 0; iLine < nLine ; iLine++) { - - getline (mesh_file, text_line); - - /*--- Search for the "NZONE" keyword to see if there are multiple Zones ---*/ - - position = text_line.find ("NZONE=",0); - if (position != string::npos) { - text_line.erase (0,6); nZone = atoi(text_line.c_str()); - } - } - - break; - - } - - /*--- For time spectral integration, nZones = nTimeInstances. ---*/ - - if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { - nZone = config->GetnTimeInstances(); - } - - return (unsigned short) nZone; -} - -unsigned short GetnDim(string val_mesh_filename, unsigned short val_format) { - - string text_line, Marker_Tag; - ifstream mesh_file; - short nDim = 3; - unsigned short iLine, nLine = 10; - char cstr[200]; - string::size_type position; - - /*--- Open grid file ---*/ - - strcpy (cstr, val_mesh_filename.c_str()); - mesh_file.open(cstr, ios::in); - - switch (val_format) { - case SU2: - - /*--- Read SU2 mesh file ---*/ - - for (iLine = 0; iLine < nLine ; iLine++) { - - getline (mesh_file, text_line); - - /*--- Search for the "NDIM" keyword to see if there are multiple Zones ---*/ - - position = text_line.find ("NDIME=",0); - if (position != string::npos) { - text_line.erase (0,6); nDim = atoi(text_line.c_str()); - } - } - break; - - case CGNS: - -#ifdef HAVE_CGNS - - /*--- Local variables which are needed when calling the CGNS mid-level API. ---*/ - - int fn, nbases = 0, nzones = 0, file_type; - int cell_dim = 0, phys_dim = 0; - char basename[CGNS_STRING_SIZE]; - - /*--- Check whether the supplied file is truly a CGNS file. ---*/ - - if ( cg_is_cgns(val_mesh_filename.c_str(), &file_type) != CG_OK ) { - printf( "\n\n !!! Error !!!\n" ); - printf( " %s is not a CGNS file.\n", val_mesh_filename.c_str()); - printf( " Now exiting...\n\n"); - exit(EXIT_FAILURE); - } - - /*--- Open the CGNS file for reading. The value of fn returned - is the specific index number for this file and will be - repeatedly used in the function calls. ---*/ - - if (cg_open(val_mesh_filename.c_str(), CG_MODE_READ, &fn)) cg_error_exit(); - - /*--- Get the number of databases. This is the highest node - in the CGNS heirarchy. ---*/ - - if (cg_nbases(fn, &nbases)) cg_error_exit(); - - /*--- Check if there is more than one database. Throw an - error if there is because this reader can currently - only handle one database. ---*/ - - if ( nbases > 1 ) { - printf("\n\n !!! Error !!!\n" ); - printf("CGNS reader currently incapable of handling more than 1 database."); - printf("Now exiting...\n\n"); - exit(EXIT_FAILURE); - } - - /*--- Read the databases. Note that the indexing starts at 1. ---*/ - - for ( int i = 1; i <= nbases; i++ ) { - - if (cg_base_read(fn, i, basename, &cell_dim, &phys_dim)) cg_error_exit(); - - /*--- Get the number of zones for this base. ---*/ - - if (cg_nzones(fn, i, &nzones)) cg_error_exit(); - - } - - /*--- Set the problem dimension as read from the CGNS file ---*/ - - nDim = cell_dim; - -#endif - - break; - - } - - mesh_file.close(); - - return (unsigned short) nDim; -} - -void Driver_Preprocessing(CDriver **driver, - CIteration **iteration_container, - CSolver ****solver_container, - CGeometry ***geometry_container, - CIntegration ***integration_container, - CNumerics *****numerics_container, - CConfig **config_container, - unsigned short val_nZone) { - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - if (val_nZone == SINGLE_ZONE) { - - /*--- Single zone problem: instantiate the single zone driver class. ---*/ - if (rank == MASTER_NODE) cout << "Instantiating a single zone driver for the problem. " << endl; - - *driver = new CSingleZoneDriver(iteration_container, solver_container, geometry_container, - integration_container, numerics_container, config_container, val_nZone); - - } else if (config_container[ZONE_0]->GetUnsteady_Simulation() == TIME_SPECTRAL) { - - /*--- Use the spectral method driver. ---*/ - - if (rank == MASTER_NODE) cout << "Instantiating a spectral method driver for the problem. " << endl; - *driver = new CSpectralDriver(iteration_container, solver_container, geometry_container, - integration_container, numerics_container, config_container, val_nZone); - - } else { - - /*--- Multi-zone problem: instantiate the multi-zone driver class by default - or a specialized driver class for a particular multi-physics problem. ---*/ - - if (rank == MASTER_NODE) cout << "Instantiating a multi-zone driver for the problem. " << endl; - *driver = new CMultiZoneDriver(iteration_container, solver_container, geometry_container, - integration_container, numerics_container, config_container, val_nZone); - - /*--- Future multi-zone drivers instatiated here. ---*/ - - } - -} - - -void Geometrical_Preprocessing(CGeometry ***geometry, CConfig **config, unsigned short val_nZone) { - - unsigned short iMGlevel, iZone; - unsigned long iPoint; - int rank = MASTER_NODE; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - for (iZone = 0; iZone < val_nZone; iZone++) { - - /*--- Compute elements surrounding points, points surrounding points ---*/ - - if (rank == MASTER_NODE) cout << "Setting point connectivity." << endl; - geometry[iZone][MESH_0]->SetPoint_Connectivity(); - - /*--- Renumbering points using Reverse Cuthill McKee ordering ---*/ - - if (rank == MASTER_NODE) cout << "Renumbering points (Reverse Cuthill McKee Ordering)." << endl; - geometry[iZone][MESH_0]->SetRCM_Ordering(config[iZone]); - - /*--- recompute elements surrounding points, points surrounding points ---*/ - - if (rank == MASTER_NODE) cout << "Recomputing point connectivity." << endl; - geometry[iZone][MESH_0]->SetPoint_Connectivity(); - - /*--- Compute elements surrounding elements ---*/ - - if (rank == MASTER_NODE) cout << "Setting element connectivity." << endl; - geometry[iZone][MESH_0]->SetElement_Connectivity(); - - /*--- Check the orientation before computing geometrical quantities ---*/ - - if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation." << endl; - geometry[iZone][MESH_0]->SetBoundVolume(); - geometry[iZone][MESH_0]->Check_IntElem_Orientation(config[iZone]); - geometry[iZone][MESH_0]->Check_BoundElem_Orientation(config[iZone]); - - /*--- Create the edge structure ---*/ - - if (rank == MASTER_NODE) cout << "Identifying edges and vertices." << endl; - geometry[iZone][MESH_0]->SetEdges(); - geometry[iZone][MESH_0]->SetVertex(config[iZone]); - - /*--- Compute cell center of gravity ---*/ - - if (rank == MASTER_NODE) cout << "Computing centers of gravity." << endl; - geometry[iZone][MESH_0]->SetCoord_CG(); - - /*--- Create the control volume structures ---*/ - - if (rank == MASTER_NODE) cout << "Setting the control volume structure." << endl; - geometry[iZone][MESH_0]->SetControlVolume(config[iZone], ALLOCATE); - geometry[iZone][MESH_0]->SetBoundControlVolume(config[iZone], ALLOCATE); - - /*--- Visualize a dual control volume if requested ---*/ - - if ((config[iZone]->GetVisualize_CV() >= 0) && - (config[iZone]->GetVisualize_CV() < (long)geometry[iZone][MESH_0]->GetnPointDomain())) - geometry[iZone][MESH_0]->VisualizeControlVolume(config[iZone], UPDATE); - - /*--- Identify closest normal neighbor ---*/ - - if (rank == MASTER_NODE) cout << "Searching for the closest normal neighbors to the surfaces." << endl; - geometry[iZone][MESH_0]->FindNormal_Neighbor(config[iZone]); - - /*--- Compute the surface curvature ---*/ - - if (rank == MASTER_NODE) cout << "Compute the surface curvature." << endl; - geometry[iZone][MESH_0]->ComputeSurf_Curvature(config[iZone]); - - if ((config[iZone]->GetnMGLevels() != 0) && (rank == MASTER_NODE)) - cout << "Setting the multigrid structure." << endl; - - } - - /*--- Loop over all the new grid ---*/ - - for (iMGlevel = 1; iMGlevel <= config[ZONE_0]->GetnMGLevels(); iMGlevel++) { - - /*--- Loop over all zones at each grid level. ---*/ - - for (iZone = 0; iZone < val_nZone; iZone++) { - - /*--- Create main agglomeration structure ---*/ - - geometry[iZone][iMGlevel] = new CMultiGridGeometry(geometry, config, iMGlevel, iZone); - - /*--- Compute points surrounding points. ---*/ - - geometry[iZone][iMGlevel]->SetPoint_Connectivity(geometry[iZone][iMGlevel-1]); - - /*--- Create the edge structure ---*/ - - geometry[iZone][iMGlevel]->SetEdges(); - geometry[iZone][iMGlevel]->SetVertex(geometry[iZone][iMGlevel-1], config[iZone]); - - /*--- Create the control volume structures ---*/ - - geometry[iZone][iMGlevel]->SetControlVolume(config[iZone], geometry[iZone][iMGlevel-1], ALLOCATE); - geometry[iZone][iMGlevel]->SetBoundControlVolume(config[iZone], geometry[iZone][iMGlevel-1], ALLOCATE); - geometry[iZone][iMGlevel]->SetCoord(geometry[iZone][iMGlevel-1]); - - /*--- Find closest neighbor to a surface point ---*/ - - geometry[iZone][iMGlevel]->FindNormal_Neighbor(config[iZone]); - - } - - } - - /*--- For unsteady simulations, initialize the grid volumes - and coordinates for previous solutions. Loop over all zones/grids ---*/ - - for (iZone = 0; iZone < val_nZone; iZone++) { - if (config[iZone]->GetUnsteady_Simulation() && config[iZone]->GetGrid_Movement()) { - for (iMGlevel = 0; iMGlevel <= config[iZone]->GetnMGLevels(); iMGlevel++) { - for (iPoint = 0; iPoint < geometry[iZone][iMGlevel]->GetnPoint(); iPoint++) { - - /*--- Update cell volume ---*/ - - geometry[iZone][iMGlevel]->node[iPoint]->SetVolume_n(); - geometry[iZone][iMGlevel]->node[iPoint]->SetVolume_nM1(); - - /*--- Update point coordinates ---*/ - geometry[iZone][iMGlevel]->node[iPoint]->SetCoord_n(); - geometry[iZone][iMGlevel]->node[iPoint]->SetCoord_n1(); - - } - } - } - } - +/*! + * \file definition_structure.cpp + * \brief Main subroutines used by SU2_CFD + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/definition_structure.hpp" + +unsigned short GetnZone(string val_mesh_filename, unsigned short val_format, CConfig *config) { + string text_line, Marker_Tag; + ifstream mesh_file; + short nZone = 1; // Default value + unsigned short iLine, nLine = 10; + char cstr[200]; + string::size_type position; + + /*--- Search the mesh file for the 'NZONE' keyword. ---*/ + + switch (val_format) { + case SU2: + + /*--- Open grid file ---*/ + + strcpy (cstr, val_mesh_filename.c_str()); + mesh_file.open(cstr, ios::in); + if (mesh_file.fail()) { + cout << "cstr=" << cstr << endl; + cout << "There is no geometry file (GetnZone))!" << endl; + +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + } + + /*--- Read the SU2 mesh file ---*/ + + for (iLine = 0; iLine < nLine ; iLine++) { + + getline (mesh_file, text_line); + + /*--- Search for the "NZONE" keyword to see if there are multiple Zones ---*/ + + position = text_line.find ("NZONE=",0); + if (position != string::npos) { + text_line.erase (0,6); nZone = atoi(text_line.c_str()); + } + } + + break; + + } + + /*--- For time spectral integration, nZones = nTimeInstances. ---*/ + + if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { + nZone = config->GetnTimeInstances(); + } + + return (unsigned short) nZone; +} + +unsigned short GetnDim(string val_mesh_filename, unsigned short val_format) { + + string text_line, Marker_Tag; + ifstream mesh_file; + short nDim = 3; + unsigned short iLine, nLine = 10; + char cstr[200]; + string::size_type position; + + /*--- Open grid file ---*/ + + strcpy (cstr, val_mesh_filename.c_str()); + mesh_file.open(cstr, ios::in); + + switch (val_format) { + case SU2: + + /*--- Read SU2 mesh file ---*/ + + for (iLine = 0; iLine < nLine ; iLine++) { + + getline (mesh_file, text_line); + + /*--- Search for the "NDIM" keyword to see if there are multiple Zones ---*/ + + position = text_line.find ("NDIME=",0); + if (position != string::npos) { + text_line.erase (0,6); nDim = atoi(text_line.c_str()); + } + } + break; + + case CGNS: + +#ifdef HAVE_CGNS + + /*--- Local variables which are needed when calling the CGNS mid-level API. ---*/ + + int fn, nbases = 0, nzones = 0, file_type; + int cell_dim = 0, phys_dim = 0; + char basename[CGNS_STRING_SIZE]; + + /*--- Check whether the supplied file is truly a CGNS file. ---*/ + + if ( cg_is_cgns(val_mesh_filename.c_str(), &file_type) != CG_OK ) { + printf( "\n\n !!! Error !!!\n" ); + printf( " %s is not a CGNS file.\n", val_mesh_filename.c_str()); + printf( " Now exiting...\n\n"); + exit(EXIT_FAILURE); + } + + /*--- Open the CGNS file for reading. The value of fn returned + is the specific index number for this file and will be + repeatedly used in the function calls. ---*/ + + if (cg_open(val_mesh_filename.c_str(), CG_MODE_READ, &fn)) cg_error_exit(); + + /*--- Get the number of databases. This is the highest node + in the CGNS heirarchy. ---*/ + + if (cg_nbases(fn, &nbases)) cg_error_exit(); + + /*--- Check if there is more than one database. Throw an + error if there is because this reader can currently + only handle one database. ---*/ + + if ( nbases > 1 ) { + printf("\n\n !!! Error !!!\n" ); + printf("CGNS reader currently incapable of handling more than 1 database."); + printf("Now exiting...\n\n"); + exit(EXIT_FAILURE); + } + + /*--- Read the databases. Note that the indexing starts at 1. ---*/ + + for ( int i = 1; i <= nbases; i++ ) { + + if (cg_base_read(fn, i, basename, &cell_dim, &phys_dim)) cg_error_exit(); + + /*--- Get the number of zones for this base. ---*/ + + if (cg_nzones(fn, i, &nzones)) cg_error_exit(); + + } + + /*--- Set the problem dimension as read from the CGNS file ---*/ + + nDim = cell_dim; + +#endif + + break; + + } + + mesh_file.close(); + + return (unsigned short) nDim; +} + +void Driver_Preprocessing(CDriver **driver, + CIteration **iteration_container, + CSolver ****solver_container, + CGeometry ***geometry_container, + CIntegration ***integration_container, + CNumerics *****numerics_container, + CConfig **config_container, + unsigned short val_nZone) { + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + if (val_nZone == SINGLE_ZONE) { + + /*--- Single zone problem: instantiate the single zone driver class. ---*/ + if (rank == MASTER_NODE) cout << "Instantiating a single zone driver for the problem. " << endl; + + *driver = new CSingleZoneDriver(iteration_container, solver_container, geometry_container, + integration_container, numerics_container, config_container, val_nZone); + + } else if (config_container[ZONE_0]->GetUnsteady_Simulation() == TIME_SPECTRAL) { + + /*--- Use the spectral method driver. ---*/ + + if (rank == MASTER_NODE) cout << "Instantiating a spectral method driver for the problem. " << endl; + *driver = new CSpectralDriver(iteration_container, solver_container, geometry_container, + integration_container, numerics_container, config_container, val_nZone); + + } else { + + /*--- Multi-zone problem: instantiate the multi-zone driver class by default + or a specialized driver class for a particular multi-physics problem. ---*/ + + if (rank == MASTER_NODE) cout << "Instantiating a multi-zone driver for the problem. " << endl; + *driver = new CMultiZoneDriver(iteration_container, solver_container, geometry_container, + integration_container, numerics_container, config_container, val_nZone); + + /*--- Future multi-zone drivers instatiated here. ---*/ + + } + +} + + +void Geometrical_Preprocessing(CGeometry ***geometry, CConfig **config, unsigned short val_nZone) { + + unsigned short iMGlevel, iZone; + unsigned long iPoint; + int rank = MASTER_NODE; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + for (iZone = 0; iZone < val_nZone; iZone++) { + + /*--- Compute elements surrounding points, points surrounding points ---*/ + + if (rank == MASTER_NODE) cout << "Setting point connectivity." << endl; + geometry[iZone][MESH_0]->SetPoint_Connectivity(); + + /*--- Renumbering points using Reverse Cuthill McKee ordering ---*/ + + if (rank == MASTER_NODE) cout << "Renumbering points (Reverse Cuthill McKee Ordering)." << endl; + geometry[iZone][MESH_0]->SetRCM_Ordering(config[iZone]); + + /*--- recompute elements surrounding points, points surrounding points ---*/ + + if (rank == MASTER_NODE) cout << "Recomputing point connectivity." << endl; + geometry[iZone][MESH_0]->SetPoint_Connectivity(); + + /*--- Compute elements surrounding elements ---*/ + + if (rank == MASTER_NODE) cout << "Setting element connectivity." << endl; + geometry[iZone][MESH_0]->SetElement_Connectivity(); + + /*--- Check the orientation before computing geometrical quantities ---*/ + + if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation." << endl; + geometry[iZone][MESH_0]->SetBoundVolume(); + geometry[iZone][MESH_0]->Check_IntElem_Orientation(config[iZone]); + geometry[iZone][MESH_0]->Check_BoundElem_Orientation(config[iZone]); + + /*--- Create the edge structure ---*/ + + if (rank == MASTER_NODE) cout << "Identifying edges and vertices." << endl; + geometry[iZone][MESH_0]->SetEdges(); + geometry[iZone][MESH_0]->SetVertex(config[iZone]); + + /*--- Compute cell center of gravity ---*/ + + if (rank == MASTER_NODE) cout << "Computing centers of gravity." << endl; + geometry[iZone][MESH_0]->SetCoord_CG(); + + /*--- Create the control volume structures ---*/ + + if (rank == MASTER_NODE) cout << "Setting the control volume structure." << endl; + geometry[iZone][MESH_0]->SetControlVolume(config[iZone], ALLOCATE); + geometry[iZone][MESH_0]->SetBoundControlVolume(config[iZone], ALLOCATE); + + /*--- Visualize a dual control volume if requested ---*/ + + if ((config[iZone]->GetVisualize_CV() >= 0) && + (config[iZone]->GetVisualize_CV() < (long)geometry[iZone][MESH_0]->GetnPointDomain())) + geometry[iZone][MESH_0]->VisualizeControlVolume(config[iZone], UPDATE); + + /*--- Identify closest normal neighbor ---*/ + + if (rank == MASTER_NODE) cout << "Searching for the closest normal neighbors to the surfaces." << endl; + geometry[iZone][MESH_0]->FindNormal_Neighbor(config[iZone]); + + /*--- Compute the surface curvature ---*/ + + if (rank == MASTER_NODE) cout << "Compute the surface curvature." << endl; + geometry[iZone][MESH_0]->ComputeSurf_Curvature(config[iZone]); + + if ((config[iZone]->GetnMGLevels() != 0) && (rank == MASTER_NODE)) + cout << "Setting the multigrid structure." << endl; + + } + + /*--- Loop over all the new grid ---*/ + + for (iMGlevel = 1; iMGlevel <= config[ZONE_0]->GetnMGLevels(); iMGlevel++) { + + /*--- Loop over all zones at each grid level. ---*/ + + for (iZone = 0; iZone < val_nZone; iZone++) { + + /*--- Create main agglomeration structure ---*/ + + geometry[iZone][iMGlevel] = new CMultiGridGeometry(geometry, config, iMGlevel, iZone); + + /*--- Compute points surrounding points. ---*/ + + geometry[iZone][iMGlevel]->SetPoint_Connectivity(geometry[iZone][iMGlevel-1]); + + /*--- Create the edge structure ---*/ + + geometry[iZone][iMGlevel]->SetEdges(); + geometry[iZone][iMGlevel]->SetVertex(geometry[iZone][iMGlevel-1], config[iZone]); + + /*--- Create the control volume structures ---*/ + + geometry[iZone][iMGlevel]->SetControlVolume(config[iZone], geometry[iZone][iMGlevel-1], ALLOCATE); + geometry[iZone][iMGlevel]->SetBoundControlVolume(config[iZone], geometry[iZone][iMGlevel-1], ALLOCATE); + geometry[iZone][iMGlevel]->SetCoord(geometry[iZone][iMGlevel-1]); + + /*--- Find closest neighbor to a surface point ---*/ + + geometry[iZone][iMGlevel]->FindNormal_Neighbor(config[iZone]); + + } + + } + + /*--- For unsteady simulations, initialize the grid volumes + and coordinates for previous solutions. Loop over all zones/grids ---*/ + + for (iZone = 0; iZone < val_nZone; iZone++) { + if (config[iZone]->GetUnsteady_Simulation() && config[iZone]->GetGrid_Movement()) { + for (iMGlevel = 0; iMGlevel <= config[iZone]->GetnMGLevels(); iMGlevel++) { + for (iPoint = 0; iPoint < geometry[iZone][iMGlevel]->GetnPoint(); iPoint++) { + + /*--- Update cell volume ---*/ + + geometry[iZone][iMGlevel]->node[iPoint]->SetVolume_n(); + geometry[iZone][iMGlevel]->node[iPoint]->SetVolume_nM1(); + + /*--- Update point coordinates ---*/ + geometry[iZone][iMGlevel]->node[iPoint]->SetCoord_n(); + geometry[iZone][iMGlevel]->node[iPoint]->SetCoord_n1(); + + } + } + } + } + } diff --git a/SU2_CFD/src/integration_time.cpp b/SU2_CFD/src/integration_time.cpp index b6338383964..6eccc9a5760 100644 --- a/SU2_CFD/src/integration_time.cpp +++ b/SU2_CFD/src/integration_time.cpp @@ -1,937 +1,937 @@ -/*! - * \file integration_time.cpp - * \brief Time dependent numerical methods - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/integration_structure.hpp" - -CMultiGridIntegration::CMultiGridIntegration(CConfig *config) : CIntegration(config) {} - -CMultiGridIntegration::~CMultiGridIntegration(void) { } - -void CMultiGridIntegration::MultiGrid_Iteration(CGeometry ***geometry, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config, - unsigned short RunTime_EqSystem, - unsigned long Iteration, - unsigned short iZone) { - unsigned short FinestMesh, iMGLevel; - su2double monitor = 1.0; - bool FullMG = false; - - const bool restart = (config[iZone]->GetRestart() || config[iZone]->GetRestart_Flow()); - const bool startup_multigrid = ((config[iZone]->GetRestart_Flow()) && - (RunTime_EqSystem == RUNTIME_FLOW_SYS) && - (Iteration == 0)); - const bool direct = ((config[iZone]->GetKind_Solver() == EULER) || - (config[iZone]->GetKind_Solver() == NAVIER_STOKES) || - (config[iZone]->GetKind_Solver() == RANS) || - (config[iZone]->GetKind_Solver() == DISC_ADJ_EULER) || - (config[iZone]->GetKind_Solver() == DISC_ADJ_NAVIER_STOKES) || - (config[iZone]->GetKind_Solver() == DISC_ADJ_RANS)); - const unsigned short SolContainer_Position = config[iZone]->GetContainerPosition(RunTime_EqSystem); - unsigned short RecursiveParam = config[iZone]->GetMGCycle(); - - if (config[iZone]->GetMGCycle() == FULLMG_CYCLE) { - RecursiveParam = V_CYCLE; - FullMG = true; - } - - /*--- If low fidelity simulation ---*/ - - if (config[iZone]->GetLowFidelitySim()) - config[iZone]->SetFinestMesh(MESH_1); - - /*--- If restart, update multigrid levels at the first multigrid iteration ---*/ - - if ((restart && (Iteration == config[iZone]->GetnStartUpIter())) || startup_multigrid) { - for (iMGLevel = 0; iMGLevel < config[iZone]->GetnMGLevels(); iMGLevel++) { - SetRestricted_Solution(RunTime_EqSystem, solver_container[iZone][iMGLevel][SolContainer_Position], - solver_container[iZone][iMGLevel+1][SolContainer_Position], - geometry[iZone][iMGLevel], geometry[iZone][iMGLevel+1], config[iZone]); - } - } - - /*--- Full multigrid strategy and start up with fine grid only works with the direct problem ---*/ - - if (!config[iZone]->GetRestart() && FullMG && direct && ( Convergence_FullMG && (config[iZone]->GetFinestMesh() != MESH_0 ))) { - SetProlongated_Solution(RunTime_EqSystem, solver_container[iZone][config[iZone]->GetFinestMesh()-1][SolContainer_Position], - solver_container[iZone][config[iZone]->GetFinestMesh()][SolContainer_Position], - geometry[iZone][config[iZone]->GetFinestMesh()-1], geometry[iZone][config[iZone]->GetFinestMesh()], - config[iZone]); - config[iZone]->SubtractFinestMesh(); - } - - /*--- Set the current finest grid (full multigrid strategy) ---*/ - - FinestMesh = config[iZone]->GetFinestMesh(); - - /*--- Perform the Full Approximation Scheme multigrid ---*/ - - MultiGrid_Cycle(geometry, solver_container, numerics_container, config, - FinestMesh, RecursiveParam, RunTime_EqSystem, - Iteration, iZone); - - /*--- Computes primitive variables and gradients in the finest mesh (useful for the next solver (turbulence) and output ---*/ - - solver_container[iZone][MESH_0][SolContainer_Position]->Preprocessing(geometry[iZone][MESH_0], - solver_container[iZone][MESH_0], config[iZone], - MESH_0, NO_RK_ITER, RunTime_EqSystem, true); - - /*--- Compute non-dimensional parameters and the convergence monitor ---*/ - - NonDimensional_Parameters(geometry[iZone], solver_container[iZone], - numerics_container[iZone], config[iZone], - FinestMesh, RunTime_EqSystem, Iteration, &monitor); - - /*--- Convergence strategy ---*/ - - Convergence_Monitoring(geometry[iZone][FinestMesh], config[iZone], Iteration, monitor, FinestMesh); - -} - -void CMultiGridIntegration::MultiGrid_Cycle(CGeometry ***geometry, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config, - unsigned short iMesh, - unsigned short RecursiveParam, - unsigned short RunTime_EqSystem, - unsigned long Iteration, - unsigned short iZone) { - - unsigned short iPreSmooth, iPostSmooth, iRKStep, iRKLimit = 1; - - bool startup_multigrid = (config[iZone]->GetRestart_Flow() && (RunTime_EqSystem == RUNTIME_FLOW_SYS) && (Iteration == 0)); - unsigned short SolContainer_Position = config[iZone]->GetContainerPosition(RunTime_EqSystem); - - /*--- Do a presmoothing on the grid iMesh to be restricted to the grid iMesh+1 ---*/ - - for (iPreSmooth = 0; iPreSmooth < config[iZone]->GetMG_PreSmooth(iMesh); iPreSmooth++) { - - switch (config[iZone]->GetKind_TimeIntScheme()) { - case RUNGE_KUTTA_EXPLICIT: iRKLimit = config[iZone]->GetnRKStep(); break; - case EULER_EXPLICIT: case EULER_IMPLICIT: iRKLimit = 1; break; } - - /*--- Time and space integration ---*/ - - for (iRKStep = 0; iRKStep < iRKLimit; iRKStep++) { - - /*--- Send-Receive boundary conditions, and preprocessing ---*/ - - solver_container[iZone][iMesh][SolContainer_Position]->Preprocessing(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iMesh, iRKStep, RunTime_EqSystem, false); - - if (iRKStep == 0) { - - /*--- Set the old solution ---*/ - - solver_container[iZone][iMesh][SolContainer_Position]->Set_OldSolution(geometry[iZone][iMesh]); - - /*--- Compute time step, max eigenvalue, and integration scheme (steady and unsteady problems) ---*/ - - solver_container[iZone][iMesh][SolContainer_Position]->SetTime_Step(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iMesh, Iteration); - - /*--- Restrict the solution and gradient for the adjoint problem ---*/ - - Adjoint_Setup(geometry, solver_container, config, RunTime_EqSystem, Iteration, iZone); - - } - - /*--- Space integration ---*/ - - Space_Integration(geometry[iZone][iMesh], solver_container[iZone][iMesh], numerics_container[iZone][iMesh][SolContainer_Position], config[iZone], iMesh, iRKStep, RunTime_EqSystem); - - /*--- Time integration, update solution using the old solution plus the solution increment ---*/ - - Time_Integration(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iRKStep, RunTime_EqSystem, Iteration); - - /*--- Send-Receive boundary conditions, and postprocessing ---*/ - - solver_container[iZone][iMesh][SolContainer_Position]->Postprocessing(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iMesh); - - } - - } - - /*--- Compute Forcing Term $P_(k+1) = I^(k+1)_k(P_k+F_k(u_k))-F_(k+1)(I^(k+1)_k u_k)$ and update solution for multigrid ---*/ - - if ( (iMesh < config[iZone]->GetnMGLevels() && ((Iteration >= config[iZone]->GetnStartUpIter()) || startup_multigrid)) ) { - - /*--- Compute $r_k = P_k + F_k(u_k)$ ---*/ - - solver_container[iZone][iMesh][SolContainer_Position]->Preprocessing(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iMesh, NO_RK_ITER, RunTime_EqSystem, false); - Space_Integration(geometry[iZone][iMesh], solver_container[iZone][iMesh], numerics_container[iZone][iMesh][SolContainer_Position], config[iZone], iMesh, NO_RK_ITER, RunTime_EqSystem); - SetResidual_Term(geometry[iZone][iMesh], solver_container[iZone][iMesh][SolContainer_Position]); - - /*--- Compute $r_(k+1) = F_(k+1)(I^(k+1)_k u_k)$ ---*/ - - SetRestricted_Solution(RunTime_EqSystem, solver_container[iZone][iMesh][SolContainer_Position], solver_container[iZone][iMesh+1][SolContainer_Position], geometry[iZone][iMesh], geometry[iZone][iMesh+1], config[iZone]); - solver_container[iZone][iMesh+1][SolContainer_Position]->Preprocessing(geometry[iZone][iMesh+1], solver_container[iZone][iMesh+1], config[iZone], iMesh+1, NO_RK_ITER, RunTime_EqSystem, false); - Space_Integration(geometry[iZone][iMesh+1], solver_container[iZone][iMesh+1], numerics_container[iZone][iMesh+1][SolContainer_Position], config[iZone], iMesh+1, NO_RK_ITER, RunTime_EqSystem); - - /*--- Compute $P_(k+1) = I^(k+1)_k(r_k) - r_(k+1) ---*/ - - SetForcing_Term(solver_container[iZone][iMesh][SolContainer_Position], solver_container[iZone][iMesh+1][SolContainer_Position], geometry[iZone][iMesh], geometry[iZone][iMesh+1], config[iZone], iMesh+1); - - /*--- Recursive call to MultiGrid_Cycle ---*/ - - for (unsigned short imu = 0; imu <= RecursiveParam; imu++) { - if (iMesh == config[iZone]->GetnMGLevels()-2) MultiGrid_Cycle(geometry, solver_container, numerics_container, config, iMesh+1, 0, RunTime_EqSystem, Iteration, iZone); - else MultiGrid_Cycle(geometry, solver_container, numerics_container, config, iMesh+1, RecursiveParam, RunTime_EqSystem, Iteration, iZone); - } - - /*--- Compute prolongated solution, and smooth the correction $u^(new)_k = u_k + Smooth(I^k_(k+1)(u_(k+1)-I^(k+1)_k u_k))$ ---*/ - - GetProlongated_Correction(RunTime_EqSystem, solver_container[iZone][iMesh][SolContainer_Position], solver_container[iZone][iMesh+1][SolContainer_Position], - geometry[iZone][iMesh], geometry[iZone][iMesh+1], config[iZone]); - SmoothProlongated_Correction(RunTime_EqSystem, solver_container[iZone][iMesh][SolContainer_Position], geometry[iZone][iMesh], - config[iZone]->GetMG_CorrecSmooth(iMesh), 1.25, config[iZone]); - SetProlongated_Correction(solver_container[iZone][iMesh][SolContainer_Position], geometry[iZone][iMesh], config[iZone], iMesh); - - /*--- Solution postsmoothing in the prolongated grid ---*/ - - for (iPostSmooth = 0; iPostSmooth < config[iZone]->GetMG_PostSmooth(iMesh); iPostSmooth++) { - - switch (config[iZone]->GetKind_TimeIntScheme()) { - case RUNGE_KUTTA_EXPLICIT: iRKLimit = config[iZone]->GetnRKStep(); break; - case EULER_EXPLICIT: case EULER_IMPLICIT: iRKLimit = 1; break; } - - for (iRKStep = 0; iRKStep < iRKLimit; iRKStep++) { - - solver_container[iZone][iMesh][SolContainer_Position]->Preprocessing(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iMesh, iRKStep, RunTime_EqSystem, false); - - if (iRKStep == 0) { - solver_container[iZone][iMesh][SolContainer_Position]->Set_OldSolution(geometry[iZone][iMesh]); - solver_container[iZone][iMesh][SolContainer_Position]->SetTime_Step(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iMesh, Iteration); - } - - Space_Integration(geometry[iZone][iMesh], solver_container[iZone][iMesh], numerics_container[iZone][iMesh][SolContainer_Position], config[iZone], iMesh, iRKStep, RunTime_EqSystem); - Time_Integration(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iRKStep, RunTime_EqSystem, Iteration); - - solver_container[iZone][iMesh][SolContainer_Position]->Postprocessing(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iMesh); - - } - } - } - -} - -void CMultiGridIntegration::GetProlongated_Correction(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, - CGeometry *geo_coarse, CConfig *config) { - unsigned long Point_Fine, Point_Coarse, iVertex; - unsigned short Boundary, iMarker, iChildren, iVar; - su2double Area_Parent, Area_Children, *Solution_Fine, *Solution_Coarse; - - const unsigned short nVar = sol_coarse->GetnVar(); - - su2double *Solution = new su2double[nVar]; - - for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { - - Area_Parent = geo_coarse->node[Point_Coarse]->GetVolume(); - - for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; - - for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { - Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); - Area_Children = geo_fine->node[Point_Fine]->GetVolume(); - Solution_Fine = sol_fine->node[Point_Fine]->GetSolution(); - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] -= Solution_Fine[iVar]*Area_Children/Area_Parent; - } - - Solution_Coarse = sol_coarse->node[Point_Coarse]->GetSolution(); - - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] += Solution_Coarse[iVar]; - - for (iVar = 0; iVar < nVar; iVar++) - sol_coarse->node[Point_Coarse]->SetSolution_Old(Solution); - - } - - /*--- Remove any contributions from no-slip walls. ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Boundary = config->GetMarker_All_KindBC(iMarker); - if ((Boundary == HEAT_FLUX ) || - (Boundary == ISOTHERMAL )) { - - for (iVertex = 0; iVertex < geo_coarse->nVertex[iMarker]; iVertex++) { - - Point_Coarse = geo_coarse->vertex[iMarker][iVertex]->GetNode(); - - /*--- For dirichlet boundary condtions, set the correction to zero. - Note that Solution_Old stores the correction not the actual value ---*/ - - sol_coarse->node[Point_Coarse]->SetVelSolutionOldZero(); - - } - - } - } - - /*--- MPI the set solution old ---*/ - - sol_coarse->Set_MPI_Solution_Old(geo_coarse, config); - - for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { - for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { - Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); - sol_fine->LinSysRes.SetBlock(Point_Fine, sol_coarse->node[Point_Coarse]->GetSolution_Old()); - } - } - - delete [] Solution; - -} - -void CMultiGridIntegration::SmoothProlongated_Correction (unsigned short RunTime_EqSystem, CSolver *solver, CGeometry *geometry, - unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config) { - su2double *Residual_Old, *Residual_Sum, *Residual, *Residual_i, *Residual_j; - unsigned short iVar, iSmooth, iMarker, nneigh; - unsigned long iEdge, iPoint, jPoint, iVertex; - - const unsigned short nVar = solver->GetnVar(); - - if (val_nSmooth > 0) { - - Residual = new su2double [nVar]; - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - Residual_Old = solver->LinSysRes.GetBlock(iPoint); - solver->node[iPoint]->SetResidual_Old(Residual_Old); - } - - /*--- Jacobi iterations ---*/ - - for (iSmooth = 0; iSmooth < val_nSmooth; iSmooth++) { - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - solver->node[iPoint]->SetResidualSumZero(); - - /*--- Loop over Interior edges ---*/ - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - - Residual_i = solver->LinSysRes.GetBlock(iPoint); - Residual_j = solver->LinSysRes.GetBlock(jPoint); - - /*--- Accumulate nearest neighbor Residual to Res_sum for each variable ---*/ - - solver->node[iPoint]->AddResidual_Sum(Residual_j); - solver->node[jPoint]->AddResidual_Sum(Residual_i); - } - - /*--- Loop over all mesh points (Update Residuals with averaged sum) ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - nneigh = geometry->node[iPoint]->GetnPoint(); - Residual_Sum = solver->node[iPoint]->GetResidual_Sum(); - Residual_Old = solver->node[iPoint]->GetResidual_Old(); - for (iVar = 0; iVar < nVar; iVar++) { - Residual[iVar] =(Residual_Old[iVar] + val_smooth_coeff*Residual_Sum[iVar]) - /(1.0 + val_smooth_coeff*su2double(nneigh)); - } - solver->LinSysRes.SetBlock(iPoint, Residual); - } - - /*--- Copy boundary values ---*/ - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Residual_Old = solver->node[iPoint]->GetResidual_Old(); - solver->LinSysRes.SetBlock(iPoint, Residual_Old); - } - } - - delete [] Residual; - - } -} - -void CMultiGridIntegration::Smooth_Solution(unsigned short RunTime_EqSystem, CSolver *solver, CGeometry *geometry, - unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config) { - su2double *Solution_Old, *Solution_Sum, *Solution, *Solution_i, *Solution_j; - unsigned short iVar, iSmooth, iMarker, nneigh; - unsigned long iEdge, iPoint, jPoint, iVertex; - - const unsigned short nVar = solver->GetnVar(); - - if (val_nSmooth > 0) { - - Solution = new su2double [nVar]; - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - Solution_Old = solver->node[iPoint]->GetSolution(); - solver->node[iPoint]->SetResidual_Old(Solution_Old); - } - - /*--- Jacobi iterations ---*/ - - for (iSmooth = 0; iSmooth < val_nSmooth; iSmooth++) { - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - solver->node[iPoint]->SetResidualSumZero(); - - /*--- Loop over Interior edges ---*/ - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - - Solution_i = solver->node[iPoint]->GetSolution(); - Solution_j = solver->node[jPoint]->GetSolution(); - - /*--- Accumulate nearest neighbor Residual to Res_sum for each variable ---*/ - - solver->node[iPoint]->AddResidual_Sum(Solution_j); - solver->node[jPoint]->AddResidual_Sum(Solution_i); - } - - /*--- Loop over all mesh points (Update Residuals with averaged sum) ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - nneigh = geometry->node[iPoint]->GetnPoint(); - Solution_Sum = solver->node[iPoint]->GetResidual_Sum(); - Solution_Old = solver->node[iPoint]->GetResidual_Old(); - for (iVar = 0; iVar < nVar; iVar++) { - Solution[iVar] =(Solution_Old[iVar] + val_smooth_coeff*Solution_Sum[iVar]) - /(1.0 + val_smooth_coeff*su2double(nneigh)); - } - solver->node[iPoint]->SetSolution(Solution); - } - - /*--- Copy boundary values ---*/ - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Solution_Old = solver->node[iPoint]->GetResidual_Old(); - solver->node[iPoint]->SetSolution(Solution_Old); - } - } - - delete [] Solution; - - } - -} - -void CMultiGridIntegration::SetProlongated_Correction(CSolver *sol_fine, CGeometry *geo_fine, CConfig *config, unsigned short iMesh) { - unsigned long Point_Fine; - unsigned short iVar; - su2double *Solution_Fine, *Residual_Fine; - - const unsigned short nVar = sol_fine->GetnVar(); - su2double factor = config->GetDamp_Correc_Prolong(); //pow(config->GetDamp_Correc_Prolong(), iMesh+1); - - su2double *Solution = new su2double [nVar]; - - for (Point_Fine = 0; Point_Fine < geo_fine->GetnPointDomain(); Point_Fine++) { - Residual_Fine = sol_fine->LinSysRes.GetBlock(Point_Fine); - Solution_Fine = sol_fine->node[Point_Fine]->GetSolution(); - for (iVar = 0; iVar < nVar; iVar++) { - /*--- Prevent a fine grid divergence due to a coarse grid divergence ---*/ - if (Residual_Fine[iVar] != Residual_Fine[iVar]) Residual_Fine[iVar] = 0.0; - Solution[iVar] = Solution_Fine[iVar]+factor*Residual_Fine[iVar]; - } - sol_fine->node[Point_Fine]->SetSolution(Solution); - } - - /*--- MPI the new interpolated solution ---*/ - sol_fine->Set_MPI_Solution(geo_fine, config); - - delete [] Solution; -} - - -void CMultiGridIntegration::SetProlongated_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { - unsigned long Point_Fine, Point_Coarse; - unsigned short iChildren; - - for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { - for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { - Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); - sol_fine->node[Point_Fine]->SetSolution(sol_coarse->node[Point_Coarse]->GetSolution()); - } - } -} - -void CMultiGridIntegration::SetForcing_Term(CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config, unsigned short iMesh) { - unsigned long Point_Fine, Point_Coarse, iVertex; - unsigned short iMarker, iVar, iChildren; - su2double *Residual_Fine; - - const unsigned short nVar = sol_coarse->GetnVar(); - su2double factor = config->GetDamp_Res_Restric(); //pow(config->GetDamp_Res_Restric(), iMesh); - - su2double *Residual = new su2double[nVar]; - - for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { - sol_coarse->node[Point_Coarse]->SetRes_TruncErrorZero(); - - for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; - for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { - Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); - Residual_Fine = sol_fine->LinSysRes.GetBlock(Point_Fine); - for (iVar = 0; iVar < nVar; iVar++) - Residual[iVar] += factor*Residual_Fine[iVar]; - } - sol_coarse->node[Point_Coarse]->AddRes_TruncError(Residual); - } - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX ) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL )) { - for (iVertex = 0; iVertex < geo_coarse->nVertex[iMarker]; iVertex++) { - Point_Coarse = geo_coarse->vertex[iMarker][iVertex]->GetNode(); - sol_coarse->node[Point_Coarse]->SetVel_ResTruncError_Zero(); - } - } - } - - for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { - sol_coarse->node[Point_Coarse]->SubtractRes_TruncError(sol_coarse->LinSysRes.GetBlock(Point_Coarse)); - } - - delete [] Residual; -} - -void CMultiGridIntegration::SetResidual_Term(CGeometry *geometry, CSolver *solver) { - unsigned long iPoint; - - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) - solver->LinSysRes.AddBlock(iPoint, solver->node[iPoint]->GetResTruncError()); - -} - -void CMultiGridIntegration::SetRestricted_Residual(CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { - unsigned long iVertex, Point_Fine, Point_Coarse; - unsigned short iMarker, iVar, iChildren; - su2double *Residual_Fine; - - const unsigned short nVar = sol_coarse->GetnVar(); - - su2double *Residual = new su2double[nVar]; - - for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { - sol_coarse->node[Point_Coarse]->SetRes_TruncErrorZero(); - - for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; - for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { - Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); - Residual_Fine = sol_fine->LinSysRes.GetBlock(Point_Fine); - for (iVar = 0; iVar < nVar; iVar++) - Residual[iVar] += Residual_Fine[iVar]; - } - sol_coarse->node[Point_Coarse]->AddRes_TruncError(Residual); - } - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX ) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL )) { - for (iVertex = 0; iVertexnVertex[iMarker]; iVertex++) { - Point_Coarse = geo_coarse->vertex[iMarker][iVertex]->GetNode(); - sol_coarse->node[Point_Coarse]->SetVel_ResTruncError_Zero(); - } - } - } - - delete [] Residual; -} - -void CMultiGridIntegration::SetRestricted_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { - unsigned long iVertex, Point_Fine, Point_Coarse; - unsigned short iMarker, iVar, iChildren, iDim; - su2double Area_Parent, Area_Children, *Solution_Fine, *Grid_Vel, Vector[3]; - - const unsigned short SolContainer_Position = config->GetContainerPosition(RunTime_EqSystem); - const unsigned short nVar = sol_coarse->GetnVar(); - const unsigned short nDim = geo_fine->GetnDim(); - const bool grid_movement = config->GetGrid_Movement(); - - su2double *Solution = new su2double[nVar]; - - /*--- Compute coarse solution from fine solution ---*/ - - for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { - Area_Parent = geo_coarse->node[Point_Coarse]->GetVolume(); - - for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; - - for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { - - Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); - Area_Children = geo_fine->node[Point_Fine]->GetVolume(); - Solution_Fine = sol_fine->node[Point_Fine]->GetSolution(); - for (iVar = 0; iVar < nVar; iVar++) { - Solution[iVar] += Solution_Fine[iVar]*Area_Children/Area_Parent; - } - } - - sol_coarse->node[Point_Coarse]->SetSolution(Solution); - - } - - /*--- Update the solution at the no-slip walls ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX ) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL )) { - - for (iVertex = 0; iVertex < geo_coarse->nVertex[iMarker]; iVertex++) { - Point_Coarse = geo_coarse->vertex[iMarker][iVertex]->GetNode(); - - if (SolContainer_Position == FLOW_SOL) { - - /*--- At moving walls, set the solution based on the new density and wall velocity ---*/ - - if (grid_movement) { - Grid_Vel = geo_coarse->node[Point_Coarse]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - Vector[iDim] = sol_coarse->node[Point_Coarse]->GetSolution(0)*Grid_Vel[iDim]; - sol_coarse->node[Point_Coarse]->SetVelSolutionVector(Vector); - } else { - - /*--- For stationary no-slip walls, set the velocity to zero. ---*/ - - sol_coarse->node[Point_Coarse]->SetVelSolutionZero(); - } - - } - - if (SolContainer_Position == ADJFLOW_SOL) { - sol_coarse->node[Point_Coarse]->SetVelSolutionDVector(); - } - - } - } - } - - /*--- MPI the new interpolated solution ---*/ - - sol_coarse->Set_MPI_Solution(geo_coarse, config); - - delete [] Solution; - -} - -void CMultiGridIntegration::SetRestricted_Gradient(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, - CGeometry *geo_coarse, CConfig *config) { - unsigned long Point_Fine, Point_Coarse; - unsigned short iVar, iDim, iChildren; - su2double Area_Parent, Area_Children, **Gradient_fine; - - const unsigned short nDim = geo_coarse->GetnDim(); - const unsigned short nVar = sol_coarse->GetnVar(); - - su2double **Gradient = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - Gradient[iVar] = new su2double [nDim]; - - for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPoint(); Point_Coarse++) { - Area_Parent = geo_coarse->node[Point_Coarse]->GetVolume(); - - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Gradient[iVar][iDim] = 0.0; - - for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { - Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); - Area_Children = geo_fine->node[Point_Fine]->GetVolume(); - Gradient_fine = sol_fine->node[Point_Fine]->GetGradient(); - - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Gradient[iVar][iDim] += Gradient_fine[iVar][iDim]*Area_Children/Area_Parent; - } - sol_coarse->node[Point_Coarse]->SetGradient(Gradient); - } - - for (iVar = 0; iVar < nVar; iVar++) - delete [] Gradient[iVar]; - delete [] Gradient; - -} - -void CMultiGridIntegration::NonDimensional_Parameters(CGeometry **geometry, CSolver ***solver_container, CNumerics ****numerics_container, - CConfig *config, unsigned short FinestMesh, unsigned short RunTime_EqSystem, unsigned long Iteration, - su2double *monitor) { - - const unsigned short nDim = geometry[FinestMesh]->GetnDim(); - - switch (RunTime_EqSystem) { - - case RUNTIME_FLOW_SYS: - - /*--- Calculate the inviscid and viscous forces ---*/ - - solver_container[FinestMesh][FLOW_SOL]->Inviscid_Forces(geometry[FinestMesh], config); - solver_container[FinestMesh][FLOW_SOL]->Viscous_Forces(geometry[FinestMesh], config); - - /*--- Evaluate convergence monitor ---*/ - - if (config->GetConvCriteria() == CAUCHY) { - if (config->GetCauchy_Func_Flow() == DRAG_COEFFICIENT) (*monitor) = solver_container[FinestMesh][FLOW_SOL]->GetTotal_CDrag(); - if (config->GetCauchy_Func_Flow() == LIFT_COEFFICIENT) (*monitor) = solver_container[FinestMesh][FLOW_SOL]->GetTotal_CLift(); - if (config->GetCauchy_Func_Flow() == NEARFIELD_PRESSURE) (*monitor) = solver_container[FinestMesh][FLOW_SOL]->GetTotal_CNearFieldOF(); - if (config->GetCauchy_Func_Flow() == MASS_FLOW_RATE) (*monitor) = solver_container[FinestMesh][FLOW_SOL]->GetOneD_MassFlowRate(); - } - - if (config->GetConvCriteria() == RESIDUAL) { - if (config->GetResidual_Func_Flow() == RHO_RESIDUAL) (*monitor) = log10(solver_container[FinestMesh][FLOW_SOL]->GetRes_RMS(0)); - else if (config->GetResidual_Func_Flow() == RHO_ENERGY_RESIDUAL) { - if (nDim == 2) (*monitor) = log10(solver_container[FinestMesh][FLOW_SOL]->GetRes_RMS(3)); - else (*monitor) = log10(solver_container[FinestMesh][FLOW_SOL]->GetRes_RMS(4)); - } - } - - break; - - case RUNTIME_ADJFLOW_SYS: - - /*--- Calculate the inviscid and viscous sensitivities ---*/ - - solver_container[FinestMesh][ADJFLOW_SOL]->Inviscid_Sensitivity(geometry[FinestMesh], solver_container[FinestMesh], numerics_container[FinestMesh][ADJFLOW_SOL][CONV_BOUND_TERM], config); - solver_container[FinestMesh][ADJFLOW_SOL]->Viscous_Sensitivity(geometry[FinestMesh], solver_container[FinestMesh], numerics_container[FinestMesh][ADJFLOW_SOL][CONV_BOUND_TERM], config); - - /*--- Smooth the inviscid and viscous sensitivities ---*/ - - if (config->GetKind_SensSmooth() != NONE) solver_container[FinestMesh][ADJFLOW_SOL]->Smooth_Sensitivity(geometry[FinestMesh], solver_container[FinestMesh], numerics_container[FinestMesh][ADJFLOW_SOL][CONV_BOUND_TERM], config); - - /*--- Evaluate convergence monitor ---*/ - - if (config->GetConvCriteria() == CAUCHY) { - if (config->GetCauchy_Func_AdjFlow() == SENS_GEOMETRY) (*monitor) = solver_container[FinestMesh][ADJFLOW_SOL]->GetTotal_Sens_Geo(); - if (config->GetCauchy_Func_AdjFlow() == SENS_MACH) (*monitor) = solver_container[FinestMesh][ADJFLOW_SOL]->GetTotal_Sens_Mach(); - } - - if (config->GetConvCriteria() == RESIDUAL) { - if (config->GetResidual_Func_Flow() == RHO_RESIDUAL) (*monitor) = log10(solver_container[FinestMesh][ADJFLOW_SOL]->GetRes_RMS(0)); - else if (config->GetResidual_Func_Flow() == RHO_ENERGY_RESIDUAL) { - if (nDim == 2) (*monitor) = log10(solver_container[FinestMesh][ADJFLOW_SOL]->GetRes_RMS(3)); - else (*monitor) = log10(solver_container[FinestMesh][ADJFLOW_SOL]->GetRes_RMS(4)); - } - } - - break; - - } - -} - -CSingleGridIntegration::CSingleGridIntegration(CConfig *config) : CIntegration(config) { } - -CSingleGridIntegration::~CSingleGridIntegration(void) { } - -void CSingleGridIntegration::SingleGrid_Iteration(CGeometry ***geometry, CSolver ****solver_container, - CNumerics *****numerics_container, CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone) { - unsigned short iMesh; - su2double monitor = 0.0; - - unsigned short SolContainer_Position = config[iZone]->GetContainerPosition(RunTime_EqSystem); - - unsigned short FinestMesh = config[iZone]->GetFinestMesh(); - - /*--- Preprocessing ---*/ - - solver_container[iZone][FinestMesh][SolContainer_Position]->Preprocessing(geometry[iZone][FinestMesh], solver_container[iZone][FinestMesh], config[iZone], FinestMesh, 0, RunTime_EqSystem, false); - - /*--- Set the old solution ---*/ - - solver_container[iZone][FinestMesh][SolContainer_Position]->Set_OldSolution(geometry[iZone][FinestMesh]); - - /*--- Time step evaluation ---*/ - - solver_container[iZone][FinestMesh][SolContainer_Position]->SetTime_Step(geometry[iZone][FinestMesh], solver_container[iZone][FinestMesh], config[iZone], FinestMesh, 0); - - /*--- Space integration ---*/ - - Space_Integration(geometry[iZone][FinestMesh], solver_container[iZone][FinestMesh], numerics_container[iZone][FinestMesh][SolContainer_Position], - config[iZone], FinestMesh, NO_RK_ITER, RunTime_EqSystem); - - /*--- Time integration ---*/ - - Time_Integration(geometry[iZone][FinestMesh], solver_container[iZone][FinestMesh], config[iZone], NO_RK_ITER, - RunTime_EqSystem, Iteration); - - /*--- Postprocessing ---*/ - - solver_container[iZone][FinestMesh][SolContainer_Position]->Postprocessing(geometry[iZone][FinestMesh], solver_container[iZone][FinestMesh], config[iZone], FinestMesh); - - /*--- Compute adimensional parameters and the convergence monitor ---*/ - - switch (RunTime_EqSystem) { - case RUNTIME_WAVE_SYS: monitor = log10(solver_container[iZone][FinestMesh][WAVE_SOL]->GetRes_RMS(0)); break; - case RUNTIME_FEA_SYS: monitor = log10(solver_container[iZone][FinestMesh][FEA_SOL]->GetRes_RMS(0)); break; - case RUNTIME_HEAT_SYS: monitor = log10(solver_container[iZone][FinestMesh][HEAT_SOL]->GetRes_RMS(0)); break; - case RUNTIME_POISSON_SYS: monitor = log10(solver_container[iZone][FinestMesh][POISSON_SOL]->GetRes_RMS(0)); break; - } - - /*--- Convergence strategy ---*/ - - Convergence_Monitoring(geometry[iZone][FinestMesh], config[iZone], Iteration, monitor, FinestMesh); - - /*--- If turbulence model, copy the eddy viscosity to the coarse levels ---*/ - - if (RunTime_EqSystem == RUNTIME_TURB_SYS) { - for (iMesh = FinestMesh; iMesh < config[iZone]->GetnMGLevels(); iMesh++) { - if ((config[iZone]->GetMGCycle() == FULLMG_CYCLE) || config[iZone]->GetLowFidelitySim()){ - SetRestricted_Solution(RunTime_EqSystem, solver_container[iZone][iMesh][SolContainer_Position], solver_container[iZone][iMesh+1][SolContainer_Position], geometry[iZone][iMesh], geometry[iZone][iMesh+1], config[iZone]); - } - SetRestricted_EddyVisc(RunTime_EqSystem, solver_container[iZone][iMesh][SolContainer_Position], solver_container[iZone][iMesh+1][SolContainer_Position], geometry[iZone][iMesh], geometry[iZone][iMesh+1], config[iZone]); - } - } - -} - -void CSingleGridIntegration::SetRestricted_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { - unsigned long Point_Fine, Point_Coarse; - unsigned short iVar, iChildren; - su2double Area_Parent, Area_Children, *Solution_Fine, *Solution; - - unsigned short nVar = sol_coarse->GetnVar(); - - Solution = new su2double[nVar]; - - /*--- Compute coarse solution from fine solution ---*/ - - for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { - Area_Parent = geo_coarse->node[Point_Coarse]->GetVolume(); - - for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; - - for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { - - Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); - Area_Children = geo_fine->node[Point_Fine]->GetVolume(); - Solution_Fine = sol_fine->node[Point_Fine]->GetSolution(); - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] += Solution_Fine[iVar]*Area_Children/Area_Parent; - } - - sol_coarse->node[Point_Coarse]->SetSolution(Solution); - - } - - /*--- MPI the new interpolated solution ---*/ - - sol_coarse->Set_MPI_Solution(geo_coarse, config); - - delete [] Solution; - -} - -void CSingleGridIntegration::SetRestricted_EddyVisc(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { - - unsigned long iVertex, Point_Fine, Point_Coarse; - unsigned short iMarker, iChildren; - su2double Area_Parent, Area_Children, EddyVisc_Fine, EddyVisc; - - /*--- Compute coarse Eddy Viscosity from fine solution ---*/ - - for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { - Area_Parent = geo_coarse->node[Point_Coarse]->GetVolume(); - - EddyVisc = 0.0; - - for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { - Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); - Area_Children = geo_fine->node[Point_Fine]->GetVolume(); - EddyVisc_Fine = sol_fine->node[Point_Fine]->GetmuT(); - EddyVisc += EddyVisc_Fine*Area_Children/Area_Parent; - } - - sol_coarse->node[Point_Coarse]->SetmuT(EddyVisc); - - } - - /*--- Update solution at the no slip wall boundary, only the first - variable (nu_tilde -in SA and SA_NEG- and k -in SST-), to guarantee that the eddy viscoisty - is zero on the surface ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX ) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL )) { - for (iVertex = 0; iVertex < geo_coarse->nVertex[iMarker]; iVertex++) { - Point_Coarse = geo_coarse->vertex[iMarker][iVertex]->GetNode(); - sol_coarse->node[Point_Coarse]->SetmuT(0); - } - } - } - - /*--- MPI the new interpolated solution (this also includes the eddy viscosity) ---*/ - - sol_coarse->Set_MPI_Solution(geo_coarse, config); - -} - - -CStructuralIntegration::CStructuralIntegration(CConfig *config) : CIntegration(config) { } - -CStructuralIntegration::~CStructuralIntegration(void) { } - -void CStructuralIntegration::Structural_Iteration(CGeometry ***geometry, CSolver ****solver_container, - CNumerics *****numerics_container, CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone) { - su2double monitor = 0.0; - - unsigned short SolContainer_Position = config[iZone]->GetContainerPosition(RunTime_EqSystem); - - /*--- Preprocessing ---*/ - - solver_container[iZone][MESH_0][SolContainer_Position]->Preprocessing(geometry[iZone][MESH_0], solver_container[iZone][MESH_0], - config[iZone], numerics_container[iZone][MESH_0][SolContainer_Position], MESH_0, Iteration, RunTime_EqSystem, false); - - /*--- Space integration ---*/ - - Space_Integration(geometry[iZone][MESH_0], solver_container[iZone][MESH_0], numerics_container[iZone][MESH_0][SolContainer_Position], - config[iZone], MESH_0, NO_RK_ITER, RunTime_EqSystem); - - /*--- Time integration ---*/ - - Time_Integration(geometry[iZone][MESH_0], solver_container[iZone][MESH_0], config[iZone], NO_RK_ITER, - RunTime_EqSystem, Iteration); - - /*--- Postprocessing ---*/ - - solver_container[iZone][MESH_0][SolContainer_Position]->Postprocessing(geometry[iZone][MESH_0], solver_container[iZone][MESH_0], - config[iZone], numerics_container[iZone][MESH_0][SolContainer_Position], MESH_0); - - /*--- Compute adimensional parameters and the convergence monitor ---*/ - - monitor = log10(solver_container[iZone][MESH_0][FEA_SOL]->GetRes_RMS(0)); - - /*--- Convergence strategy ---*/ - Convergence_Monitoring(geometry[iZone][MESH_0], config[iZone], Iteration, monitor, MESH_0); - - -} +/*! + * \file integration_time.cpp + * \brief Time dependent numerical methods + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/integration_structure.hpp" + +CMultiGridIntegration::CMultiGridIntegration(CConfig *config) : CIntegration(config) {} + +CMultiGridIntegration::~CMultiGridIntegration(void) { } + +void CMultiGridIntegration::MultiGrid_Iteration(CGeometry ***geometry, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config, + unsigned short RunTime_EqSystem, + unsigned long Iteration, + unsigned short iZone) { + unsigned short FinestMesh, iMGLevel; + su2double monitor = 1.0; + bool FullMG = false; + + const bool restart = (config[iZone]->GetRestart() || config[iZone]->GetRestart_Flow()); + const bool startup_multigrid = ((config[iZone]->GetRestart_Flow()) && + (RunTime_EqSystem == RUNTIME_FLOW_SYS) && + (Iteration == 0)); + const bool direct = ((config[iZone]->GetKind_Solver() == EULER) || + (config[iZone]->GetKind_Solver() == NAVIER_STOKES) || + (config[iZone]->GetKind_Solver() == RANS) || + (config[iZone]->GetKind_Solver() == DISC_ADJ_EULER) || + (config[iZone]->GetKind_Solver() == DISC_ADJ_NAVIER_STOKES) || + (config[iZone]->GetKind_Solver() == DISC_ADJ_RANS)); + const unsigned short SolContainer_Position = config[iZone]->GetContainerPosition(RunTime_EqSystem); + unsigned short RecursiveParam = config[iZone]->GetMGCycle(); + + if (config[iZone]->GetMGCycle() == FULLMG_CYCLE) { + RecursiveParam = V_CYCLE; + FullMG = true; + } + + /*--- If low fidelity simulation ---*/ + + if (config[iZone]->GetLowFidelitySim()) + config[iZone]->SetFinestMesh(MESH_1); + + /*--- If restart, update multigrid levels at the first multigrid iteration ---*/ + + if ((restart && (Iteration == config[iZone]->GetnStartUpIter())) || startup_multigrid) { + for (iMGLevel = 0; iMGLevel < config[iZone]->GetnMGLevels(); iMGLevel++) { + SetRestricted_Solution(RunTime_EqSystem, solver_container[iZone][iMGLevel][SolContainer_Position], + solver_container[iZone][iMGLevel+1][SolContainer_Position], + geometry[iZone][iMGLevel], geometry[iZone][iMGLevel+1], config[iZone]); + } + } + + /*--- Full multigrid strategy and start up with fine grid only works with the direct problem ---*/ + + if (!config[iZone]->GetRestart() && FullMG && direct && ( Convergence_FullMG && (config[iZone]->GetFinestMesh() != MESH_0 ))) { + SetProlongated_Solution(RunTime_EqSystem, solver_container[iZone][config[iZone]->GetFinestMesh()-1][SolContainer_Position], + solver_container[iZone][config[iZone]->GetFinestMesh()][SolContainer_Position], + geometry[iZone][config[iZone]->GetFinestMesh()-1], geometry[iZone][config[iZone]->GetFinestMesh()], + config[iZone]); + config[iZone]->SubtractFinestMesh(); + } + + /*--- Set the current finest grid (full multigrid strategy) ---*/ + + FinestMesh = config[iZone]->GetFinestMesh(); + + /*--- Perform the Full Approximation Scheme multigrid ---*/ + + MultiGrid_Cycle(geometry, solver_container, numerics_container, config, + FinestMesh, RecursiveParam, RunTime_EqSystem, + Iteration, iZone); + + /*--- Computes primitive variables and gradients in the finest mesh (useful for the next solver (turbulence) and output ---*/ + + solver_container[iZone][MESH_0][SolContainer_Position]->Preprocessing(geometry[iZone][MESH_0], + solver_container[iZone][MESH_0], config[iZone], + MESH_0, NO_RK_ITER, RunTime_EqSystem, true); + + /*--- Compute non-dimensional parameters and the convergence monitor ---*/ + + NonDimensional_Parameters(geometry[iZone], solver_container[iZone], + numerics_container[iZone], config[iZone], + FinestMesh, RunTime_EqSystem, Iteration, &monitor); + + /*--- Convergence strategy ---*/ + + Convergence_Monitoring(geometry[iZone][FinestMesh], config[iZone], Iteration, monitor, FinestMesh); + +} + +void CMultiGridIntegration::MultiGrid_Cycle(CGeometry ***geometry, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config, + unsigned short iMesh, + unsigned short RecursiveParam, + unsigned short RunTime_EqSystem, + unsigned long Iteration, + unsigned short iZone) { + + unsigned short iPreSmooth, iPostSmooth, iRKStep, iRKLimit = 1; + + bool startup_multigrid = (config[iZone]->GetRestart_Flow() && (RunTime_EqSystem == RUNTIME_FLOW_SYS) && (Iteration == 0)); + unsigned short SolContainer_Position = config[iZone]->GetContainerPosition(RunTime_EqSystem); + + /*--- Do a presmoothing on the grid iMesh to be restricted to the grid iMesh+1 ---*/ + + for (iPreSmooth = 0; iPreSmooth < config[iZone]->GetMG_PreSmooth(iMesh); iPreSmooth++) { + + switch (config[iZone]->GetKind_TimeIntScheme()) { + case RUNGE_KUTTA_EXPLICIT: iRKLimit = config[iZone]->GetnRKStep(); break; + case EULER_EXPLICIT: case EULER_IMPLICIT: iRKLimit = 1; break; } + + /*--- Time and space integration ---*/ + + for (iRKStep = 0; iRKStep < iRKLimit; iRKStep++) { + + /*--- Send-Receive boundary conditions, and preprocessing ---*/ + + solver_container[iZone][iMesh][SolContainer_Position]->Preprocessing(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iMesh, iRKStep, RunTime_EqSystem, false); + + if (iRKStep == 0) { + + /*--- Set the old solution ---*/ + + solver_container[iZone][iMesh][SolContainer_Position]->Set_OldSolution(geometry[iZone][iMesh]); + + /*--- Compute time step, max eigenvalue, and integration scheme (steady and unsteady problems) ---*/ + + solver_container[iZone][iMesh][SolContainer_Position]->SetTime_Step(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iMesh, Iteration); + + /*--- Restrict the solution and gradient for the adjoint problem ---*/ + + Adjoint_Setup(geometry, solver_container, config, RunTime_EqSystem, Iteration, iZone); + + } + + /*--- Space integration ---*/ + + Space_Integration(geometry[iZone][iMesh], solver_container[iZone][iMesh], numerics_container[iZone][iMesh][SolContainer_Position], config[iZone], iMesh, iRKStep, RunTime_EqSystem); + + /*--- Time integration, update solution using the old solution plus the solution increment ---*/ + + Time_Integration(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iRKStep, RunTime_EqSystem, Iteration); + + /*--- Send-Receive boundary conditions, and postprocessing ---*/ + + solver_container[iZone][iMesh][SolContainer_Position]->Postprocessing(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iMesh); + + } + + } + + /*--- Compute Forcing Term $P_(k+1) = I^(k+1)_k(P_k+F_k(u_k))-F_(k+1)(I^(k+1)_k u_k)$ and update solution for multigrid ---*/ + + if ( (iMesh < config[iZone]->GetnMGLevels() && ((Iteration >= config[iZone]->GetnStartUpIter()) || startup_multigrid)) ) { + + /*--- Compute $r_k = P_k + F_k(u_k)$ ---*/ + + solver_container[iZone][iMesh][SolContainer_Position]->Preprocessing(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iMesh, NO_RK_ITER, RunTime_EqSystem, false); + Space_Integration(geometry[iZone][iMesh], solver_container[iZone][iMesh], numerics_container[iZone][iMesh][SolContainer_Position], config[iZone], iMesh, NO_RK_ITER, RunTime_EqSystem); + SetResidual_Term(geometry[iZone][iMesh], solver_container[iZone][iMesh][SolContainer_Position]); + + /*--- Compute $r_(k+1) = F_(k+1)(I^(k+1)_k u_k)$ ---*/ + + SetRestricted_Solution(RunTime_EqSystem, solver_container[iZone][iMesh][SolContainer_Position], solver_container[iZone][iMesh+1][SolContainer_Position], geometry[iZone][iMesh], geometry[iZone][iMesh+1], config[iZone]); + solver_container[iZone][iMesh+1][SolContainer_Position]->Preprocessing(geometry[iZone][iMesh+1], solver_container[iZone][iMesh+1], config[iZone], iMesh+1, NO_RK_ITER, RunTime_EqSystem, false); + Space_Integration(geometry[iZone][iMesh+1], solver_container[iZone][iMesh+1], numerics_container[iZone][iMesh+1][SolContainer_Position], config[iZone], iMesh+1, NO_RK_ITER, RunTime_EqSystem); + + /*--- Compute $P_(k+1) = I^(k+1)_k(r_k) - r_(k+1) ---*/ + + SetForcing_Term(solver_container[iZone][iMesh][SolContainer_Position], solver_container[iZone][iMesh+1][SolContainer_Position], geometry[iZone][iMesh], geometry[iZone][iMesh+1], config[iZone], iMesh+1); + + /*--- Recursive call to MultiGrid_Cycle ---*/ + + for (unsigned short imu = 0; imu <= RecursiveParam; imu++) { + if (iMesh == config[iZone]->GetnMGLevels()-2) MultiGrid_Cycle(geometry, solver_container, numerics_container, config, iMesh+1, 0, RunTime_EqSystem, Iteration, iZone); + else MultiGrid_Cycle(geometry, solver_container, numerics_container, config, iMesh+1, RecursiveParam, RunTime_EqSystem, Iteration, iZone); + } + + /*--- Compute prolongated solution, and smooth the correction $u^(new)_k = u_k + Smooth(I^k_(k+1)(u_(k+1)-I^(k+1)_k u_k))$ ---*/ + + GetProlongated_Correction(RunTime_EqSystem, solver_container[iZone][iMesh][SolContainer_Position], solver_container[iZone][iMesh+1][SolContainer_Position], + geometry[iZone][iMesh], geometry[iZone][iMesh+1], config[iZone]); + SmoothProlongated_Correction(RunTime_EqSystem, solver_container[iZone][iMesh][SolContainer_Position], geometry[iZone][iMesh], + config[iZone]->GetMG_CorrecSmooth(iMesh), 1.25, config[iZone]); + SetProlongated_Correction(solver_container[iZone][iMesh][SolContainer_Position], geometry[iZone][iMesh], config[iZone], iMesh); + + /*--- Solution postsmoothing in the prolongated grid ---*/ + + for (iPostSmooth = 0; iPostSmooth < config[iZone]->GetMG_PostSmooth(iMesh); iPostSmooth++) { + + switch (config[iZone]->GetKind_TimeIntScheme()) { + case RUNGE_KUTTA_EXPLICIT: iRKLimit = config[iZone]->GetnRKStep(); break; + case EULER_EXPLICIT: case EULER_IMPLICIT: iRKLimit = 1; break; } + + for (iRKStep = 0; iRKStep < iRKLimit; iRKStep++) { + + solver_container[iZone][iMesh][SolContainer_Position]->Preprocessing(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iMesh, iRKStep, RunTime_EqSystem, false); + + if (iRKStep == 0) { + solver_container[iZone][iMesh][SolContainer_Position]->Set_OldSolution(geometry[iZone][iMesh]); + solver_container[iZone][iMesh][SolContainer_Position]->SetTime_Step(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iMesh, Iteration); + } + + Space_Integration(geometry[iZone][iMesh], solver_container[iZone][iMesh], numerics_container[iZone][iMesh][SolContainer_Position], config[iZone], iMesh, iRKStep, RunTime_EqSystem); + Time_Integration(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iRKStep, RunTime_EqSystem, Iteration); + + solver_container[iZone][iMesh][SolContainer_Position]->Postprocessing(geometry[iZone][iMesh], solver_container[iZone][iMesh], config[iZone], iMesh); + + } + } + } + +} + +void CMultiGridIntegration::GetProlongated_Correction(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, + CGeometry *geo_coarse, CConfig *config) { + unsigned long Point_Fine, Point_Coarse, iVertex; + unsigned short Boundary, iMarker, iChildren, iVar; + su2double Area_Parent, Area_Children, *Solution_Fine, *Solution_Coarse; + + const unsigned short nVar = sol_coarse->GetnVar(); + + su2double *Solution = new su2double[nVar]; + + for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { + + Area_Parent = geo_coarse->node[Point_Coarse]->GetVolume(); + + for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; + + for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { + Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); + Area_Children = geo_fine->node[Point_Fine]->GetVolume(); + Solution_Fine = sol_fine->node[Point_Fine]->GetSolution(); + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] -= Solution_Fine[iVar]*Area_Children/Area_Parent; + } + + Solution_Coarse = sol_coarse->node[Point_Coarse]->GetSolution(); + + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] += Solution_Coarse[iVar]; + + for (iVar = 0; iVar < nVar; iVar++) + sol_coarse->node[Point_Coarse]->SetSolution_Old(Solution); + + } + + /*--- Remove any contributions from no-slip walls. ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + Boundary = config->GetMarker_All_KindBC(iMarker); + if ((Boundary == HEAT_FLUX ) || + (Boundary == ISOTHERMAL )) { + + for (iVertex = 0; iVertex < geo_coarse->nVertex[iMarker]; iVertex++) { + + Point_Coarse = geo_coarse->vertex[iMarker][iVertex]->GetNode(); + + /*--- For dirichlet boundary condtions, set the correction to zero. + Note that Solution_Old stores the correction not the actual value ---*/ + + sol_coarse->node[Point_Coarse]->SetVelSolutionOldZero(); + + } + + } + } + + /*--- MPI the set solution old ---*/ + + sol_coarse->Set_MPI_Solution_Old(geo_coarse, config); + + for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { + for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { + Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); + sol_fine->LinSysRes.SetBlock(Point_Fine, sol_coarse->node[Point_Coarse]->GetSolution_Old()); + } + } + + delete [] Solution; + +} + +void CMultiGridIntegration::SmoothProlongated_Correction (unsigned short RunTime_EqSystem, CSolver *solver, CGeometry *geometry, + unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config) { + su2double *Residual_Old, *Residual_Sum, *Residual, *Residual_i, *Residual_j; + unsigned short iVar, iSmooth, iMarker, nneigh; + unsigned long iEdge, iPoint, jPoint, iVertex; + + const unsigned short nVar = solver->GetnVar(); + + if (val_nSmooth > 0) { + + Residual = new su2double [nVar]; + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + Residual_Old = solver->LinSysRes.GetBlock(iPoint); + solver->node[iPoint]->SetResidual_Old(Residual_Old); + } + + /*--- Jacobi iterations ---*/ + + for (iSmooth = 0; iSmooth < val_nSmooth; iSmooth++) { + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + solver->node[iPoint]->SetResidualSumZero(); + + /*--- Loop over Interior edges ---*/ + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + + Residual_i = solver->LinSysRes.GetBlock(iPoint); + Residual_j = solver->LinSysRes.GetBlock(jPoint); + + /*--- Accumulate nearest neighbor Residual to Res_sum for each variable ---*/ + + solver->node[iPoint]->AddResidual_Sum(Residual_j); + solver->node[jPoint]->AddResidual_Sum(Residual_i); + } + + /*--- Loop over all mesh points (Update Residuals with averaged sum) ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + nneigh = geometry->node[iPoint]->GetnPoint(); + Residual_Sum = solver->node[iPoint]->GetResidual_Sum(); + Residual_Old = solver->node[iPoint]->GetResidual_Old(); + for (iVar = 0; iVar < nVar; iVar++) { + Residual[iVar] =(Residual_Old[iVar] + val_smooth_coeff*Residual_Sum[iVar]) + /(1.0 + val_smooth_coeff*su2double(nneigh)); + } + solver->LinSysRes.SetBlock(iPoint, Residual); + } + + /*--- Copy boundary values ---*/ + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Residual_Old = solver->node[iPoint]->GetResidual_Old(); + solver->LinSysRes.SetBlock(iPoint, Residual_Old); + } + } + + delete [] Residual; + + } +} + +void CMultiGridIntegration::Smooth_Solution(unsigned short RunTime_EqSystem, CSolver *solver, CGeometry *geometry, + unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config) { + su2double *Solution_Old, *Solution_Sum, *Solution, *Solution_i, *Solution_j; + unsigned short iVar, iSmooth, iMarker, nneigh; + unsigned long iEdge, iPoint, jPoint, iVertex; + + const unsigned short nVar = solver->GetnVar(); + + if (val_nSmooth > 0) { + + Solution = new su2double [nVar]; + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + Solution_Old = solver->node[iPoint]->GetSolution(); + solver->node[iPoint]->SetResidual_Old(Solution_Old); + } + + /*--- Jacobi iterations ---*/ + + for (iSmooth = 0; iSmooth < val_nSmooth; iSmooth++) { + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + solver->node[iPoint]->SetResidualSumZero(); + + /*--- Loop over Interior edges ---*/ + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + + Solution_i = solver->node[iPoint]->GetSolution(); + Solution_j = solver->node[jPoint]->GetSolution(); + + /*--- Accumulate nearest neighbor Residual to Res_sum for each variable ---*/ + + solver->node[iPoint]->AddResidual_Sum(Solution_j); + solver->node[jPoint]->AddResidual_Sum(Solution_i); + } + + /*--- Loop over all mesh points (Update Residuals with averaged sum) ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + nneigh = geometry->node[iPoint]->GetnPoint(); + Solution_Sum = solver->node[iPoint]->GetResidual_Sum(); + Solution_Old = solver->node[iPoint]->GetResidual_Old(); + for (iVar = 0; iVar < nVar; iVar++) { + Solution[iVar] =(Solution_Old[iVar] + val_smooth_coeff*Solution_Sum[iVar]) + /(1.0 + val_smooth_coeff*su2double(nneigh)); + } + solver->node[iPoint]->SetSolution(Solution); + } + + /*--- Copy boundary values ---*/ + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Solution_Old = solver->node[iPoint]->GetResidual_Old(); + solver->node[iPoint]->SetSolution(Solution_Old); + } + } + + delete [] Solution; + + } + +} + +void CMultiGridIntegration::SetProlongated_Correction(CSolver *sol_fine, CGeometry *geo_fine, CConfig *config, unsigned short iMesh) { + unsigned long Point_Fine; + unsigned short iVar; + su2double *Solution_Fine, *Residual_Fine; + + const unsigned short nVar = sol_fine->GetnVar(); + su2double factor = config->GetDamp_Correc_Prolong(); //pow(config->GetDamp_Correc_Prolong(), iMesh+1); + + su2double *Solution = new su2double [nVar]; + + for (Point_Fine = 0; Point_Fine < geo_fine->GetnPointDomain(); Point_Fine++) { + Residual_Fine = sol_fine->LinSysRes.GetBlock(Point_Fine); + Solution_Fine = sol_fine->node[Point_Fine]->GetSolution(); + for (iVar = 0; iVar < nVar; iVar++) { + /*--- Prevent a fine grid divergence due to a coarse grid divergence ---*/ + if (Residual_Fine[iVar] != Residual_Fine[iVar]) Residual_Fine[iVar] = 0.0; + Solution[iVar] = Solution_Fine[iVar]+factor*Residual_Fine[iVar]; + } + sol_fine->node[Point_Fine]->SetSolution(Solution); + } + + /*--- MPI the new interpolated solution ---*/ + sol_fine->Set_MPI_Solution(geo_fine, config); + + delete [] Solution; +} + + +void CMultiGridIntegration::SetProlongated_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { + unsigned long Point_Fine, Point_Coarse; + unsigned short iChildren; + + for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { + for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { + Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); + sol_fine->node[Point_Fine]->SetSolution(sol_coarse->node[Point_Coarse]->GetSolution()); + } + } +} + +void CMultiGridIntegration::SetForcing_Term(CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config, unsigned short iMesh) { + unsigned long Point_Fine, Point_Coarse, iVertex; + unsigned short iMarker, iVar, iChildren; + su2double *Residual_Fine; + + const unsigned short nVar = sol_coarse->GetnVar(); + su2double factor = config->GetDamp_Res_Restric(); //pow(config->GetDamp_Res_Restric(), iMesh); + + su2double *Residual = new su2double[nVar]; + + for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { + sol_coarse->node[Point_Coarse]->SetRes_TruncErrorZero(); + + for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; + for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { + Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); + Residual_Fine = sol_fine->LinSysRes.GetBlock(Point_Fine); + for (iVar = 0; iVar < nVar; iVar++) + Residual[iVar] += factor*Residual_Fine[iVar]; + } + sol_coarse->node[Point_Coarse]->AddRes_TruncError(Residual); + } + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX ) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL )) { + for (iVertex = 0; iVertex < geo_coarse->nVertex[iMarker]; iVertex++) { + Point_Coarse = geo_coarse->vertex[iMarker][iVertex]->GetNode(); + sol_coarse->node[Point_Coarse]->SetVel_ResTruncError_Zero(); + } + } + } + + for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { + sol_coarse->node[Point_Coarse]->SubtractRes_TruncError(sol_coarse->LinSysRes.GetBlock(Point_Coarse)); + } + + delete [] Residual; +} + +void CMultiGridIntegration::SetResidual_Term(CGeometry *geometry, CSolver *solver) { + unsigned long iPoint; + + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) + solver->LinSysRes.AddBlock(iPoint, solver->node[iPoint]->GetResTruncError()); + +} + +void CMultiGridIntegration::SetRestricted_Residual(CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { + unsigned long iVertex, Point_Fine, Point_Coarse; + unsigned short iMarker, iVar, iChildren; + su2double *Residual_Fine; + + const unsigned short nVar = sol_coarse->GetnVar(); + + su2double *Residual = new su2double[nVar]; + + for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { + sol_coarse->node[Point_Coarse]->SetRes_TruncErrorZero(); + + for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; + for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { + Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); + Residual_Fine = sol_fine->LinSysRes.GetBlock(Point_Fine); + for (iVar = 0; iVar < nVar; iVar++) + Residual[iVar] += Residual_Fine[iVar]; + } + sol_coarse->node[Point_Coarse]->AddRes_TruncError(Residual); + } + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX ) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL )) { + for (iVertex = 0; iVertexnVertex[iMarker]; iVertex++) { + Point_Coarse = geo_coarse->vertex[iMarker][iVertex]->GetNode(); + sol_coarse->node[Point_Coarse]->SetVel_ResTruncError_Zero(); + } + } + } + + delete [] Residual; +} + +void CMultiGridIntegration::SetRestricted_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { + unsigned long iVertex, Point_Fine, Point_Coarse; + unsigned short iMarker, iVar, iChildren, iDim; + su2double Area_Parent, Area_Children, *Solution_Fine, *Grid_Vel, Vector[3]; + + const unsigned short SolContainer_Position = config->GetContainerPosition(RunTime_EqSystem); + const unsigned short nVar = sol_coarse->GetnVar(); + const unsigned short nDim = geo_fine->GetnDim(); + const bool grid_movement = config->GetGrid_Movement(); + + su2double *Solution = new su2double[nVar]; + + /*--- Compute coarse solution from fine solution ---*/ + + for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { + Area_Parent = geo_coarse->node[Point_Coarse]->GetVolume(); + + for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; + + for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { + + Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); + Area_Children = geo_fine->node[Point_Fine]->GetVolume(); + Solution_Fine = sol_fine->node[Point_Fine]->GetSolution(); + for (iVar = 0; iVar < nVar; iVar++) { + Solution[iVar] += Solution_Fine[iVar]*Area_Children/Area_Parent; + } + } + + sol_coarse->node[Point_Coarse]->SetSolution(Solution); + + } + + /*--- Update the solution at the no-slip walls ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX ) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL )) { + + for (iVertex = 0; iVertex < geo_coarse->nVertex[iMarker]; iVertex++) { + Point_Coarse = geo_coarse->vertex[iMarker][iVertex]->GetNode(); + + if (SolContainer_Position == FLOW_SOL) { + + /*--- At moving walls, set the solution based on the new density and wall velocity ---*/ + + if (grid_movement) { + Grid_Vel = geo_coarse->node[Point_Coarse]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + Vector[iDim] = sol_coarse->node[Point_Coarse]->GetSolution(0)*Grid_Vel[iDim]; + sol_coarse->node[Point_Coarse]->SetVelSolutionVector(Vector); + } else { + + /*--- For stationary no-slip walls, set the velocity to zero. ---*/ + + sol_coarse->node[Point_Coarse]->SetVelSolutionZero(); + } + + } + + if (SolContainer_Position == ADJFLOW_SOL) { + sol_coarse->node[Point_Coarse]->SetVelSolutionDVector(); + } + + } + } + } + + /*--- MPI the new interpolated solution ---*/ + + sol_coarse->Set_MPI_Solution(geo_coarse, config); + + delete [] Solution; + +} + +void CMultiGridIntegration::SetRestricted_Gradient(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, + CGeometry *geo_coarse, CConfig *config) { + unsigned long Point_Fine, Point_Coarse; + unsigned short iVar, iDim, iChildren; + su2double Area_Parent, Area_Children, **Gradient_fine; + + const unsigned short nDim = geo_coarse->GetnDim(); + const unsigned short nVar = sol_coarse->GetnVar(); + + su2double **Gradient = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + Gradient[iVar] = new su2double [nDim]; + + for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPoint(); Point_Coarse++) { + Area_Parent = geo_coarse->node[Point_Coarse]->GetVolume(); + + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Gradient[iVar][iDim] = 0.0; + + for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { + Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); + Area_Children = geo_fine->node[Point_Fine]->GetVolume(); + Gradient_fine = sol_fine->node[Point_Fine]->GetGradient(); + + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Gradient[iVar][iDim] += Gradient_fine[iVar][iDim]*Area_Children/Area_Parent; + } + sol_coarse->node[Point_Coarse]->SetGradient(Gradient); + } + + for (iVar = 0; iVar < nVar; iVar++) + delete [] Gradient[iVar]; + delete [] Gradient; + +} + +void CMultiGridIntegration::NonDimensional_Parameters(CGeometry **geometry, CSolver ***solver_container, CNumerics ****numerics_container, + CConfig *config, unsigned short FinestMesh, unsigned short RunTime_EqSystem, unsigned long Iteration, + su2double *monitor) { + + const unsigned short nDim = geometry[FinestMesh]->GetnDim(); + + switch (RunTime_EqSystem) { + + case RUNTIME_FLOW_SYS: + + /*--- Calculate the inviscid and viscous forces ---*/ + + solver_container[FinestMesh][FLOW_SOL]->Inviscid_Forces(geometry[FinestMesh], config); + solver_container[FinestMesh][FLOW_SOL]->Viscous_Forces(geometry[FinestMesh], config); + + /*--- Evaluate convergence monitor ---*/ + + if (config->GetConvCriteria() == CAUCHY) { + if (config->GetCauchy_Func_Flow() == DRAG_COEFFICIENT) (*monitor) = solver_container[FinestMesh][FLOW_SOL]->GetTotal_CDrag(); + if (config->GetCauchy_Func_Flow() == LIFT_COEFFICIENT) (*monitor) = solver_container[FinestMesh][FLOW_SOL]->GetTotal_CLift(); + if (config->GetCauchy_Func_Flow() == NEARFIELD_PRESSURE) (*monitor) = solver_container[FinestMesh][FLOW_SOL]->GetTotal_CNearFieldOF(); + if (config->GetCauchy_Func_Flow() == MASS_FLOW_RATE) (*monitor) = solver_container[FinestMesh][FLOW_SOL]->GetOneD_MassFlowRate(); + } + + if (config->GetConvCriteria() == RESIDUAL) { + if (config->GetResidual_Func_Flow() == RHO_RESIDUAL) (*monitor) = log10(solver_container[FinestMesh][FLOW_SOL]->GetRes_RMS(0)); + else if (config->GetResidual_Func_Flow() == RHO_ENERGY_RESIDUAL) { + if (nDim == 2) (*monitor) = log10(solver_container[FinestMesh][FLOW_SOL]->GetRes_RMS(3)); + else (*monitor) = log10(solver_container[FinestMesh][FLOW_SOL]->GetRes_RMS(4)); + } + } + + break; + + case RUNTIME_ADJFLOW_SYS: + + /*--- Calculate the inviscid and viscous sensitivities ---*/ + + solver_container[FinestMesh][ADJFLOW_SOL]->Inviscid_Sensitivity(geometry[FinestMesh], solver_container[FinestMesh], numerics_container[FinestMesh][ADJFLOW_SOL][CONV_BOUND_TERM], config); + solver_container[FinestMesh][ADJFLOW_SOL]->Viscous_Sensitivity(geometry[FinestMesh], solver_container[FinestMesh], numerics_container[FinestMesh][ADJFLOW_SOL][CONV_BOUND_TERM], config); + + /*--- Smooth the inviscid and viscous sensitivities ---*/ + + if (config->GetKind_SensSmooth() != NONE) solver_container[FinestMesh][ADJFLOW_SOL]->Smooth_Sensitivity(geometry[FinestMesh], solver_container[FinestMesh], numerics_container[FinestMesh][ADJFLOW_SOL][CONV_BOUND_TERM], config); + + /*--- Evaluate convergence monitor ---*/ + + if (config->GetConvCriteria() == CAUCHY) { + if (config->GetCauchy_Func_AdjFlow() == SENS_GEOMETRY) (*monitor) = solver_container[FinestMesh][ADJFLOW_SOL]->GetTotal_Sens_Geo(); + if (config->GetCauchy_Func_AdjFlow() == SENS_MACH) (*monitor) = solver_container[FinestMesh][ADJFLOW_SOL]->GetTotal_Sens_Mach(); + } + + if (config->GetConvCriteria() == RESIDUAL) { + if (config->GetResidual_Func_Flow() == RHO_RESIDUAL) (*monitor) = log10(solver_container[FinestMesh][ADJFLOW_SOL]->GetRes_RMS(0)); + else if (config->GetResidual_Func_Flow() == RHO_ENERGY_RESIDUAL) { + if (nDim == 2) (*monitor) = log10(solver_container[FinestMesh][ADJFLOW_SOL]->GetRes_RMS(3)); + else (*monitor) = log10(solver_container[FinestMesh][ADJFLOW_SOL]->GetRes_RMS(4)); + } + } + + break; + + } + +} + +CSingleGridIntegration::CSingleGridIntegration(CConfig *config) : CIntegration(config) { } + +CSingleGridIntegration::~CSingleGridIntegration(void) { } + +void CSingleGridIntegration::SingleGrid_Iteration(CGeometry ***geometry, CSolver ****solver_container, + CNumerics *****numerics_container, CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone) { + unsigned short iMesh; + su2double monitor = 0.0; + + unsigned short SolContainer_Position = config[iZone]->GetContainerPosition(RunTime_EqSystem); + + unsigned short FinestMesh = config[iZone]->GetFinestMesh(); + + /*--- Preprocessing ---*/ + + solver_container[iZone][FinestMesh][SolContainer_Position]->Preprocessing(geometry[iZone][FinestMesh], solver_container[iZone][FinestMesh], config[iZone], FinestMesh, 0, RunTime_EqSystem, false); + + /*--- Set the old solution ---*/ + + solver_container[iZone][FinestMesh][SolContainer_Position]->Set_OldSolution(geometry[iZone][FinestMesh]); + + /*--- Time step evaluation ---*/ + + solver_container[iZone][FinestMesh][SolContainer_Position]->SetTime_Step(geometry[iZone][FinestMesh], solver_container[iZone][FinestMesh], config[iZone], FinestMesh, 0); + + /*--- Space integration ---*/ + + Space_Integration(geometry[iZone][FinestMesh], solver_container[iZone][FinestMesh], numerics_container[iZone][FinestMesh][SolContainer_Position], + config[iZone], FinestMesh, NO_RK_ITER, RunTime_EqSystem); + + /*--- Time integration ---*/ + + Time_Integration(geometry[iZone][FinestMesh], solver_container[iZone][FinestMesh], config[iZone], NO_RK_ITER, + RunTime_EqSystem, Iteration); + + /*--- Postprocessing ---*/ + + solver_container[iZone][FinestMesh][SolContainer_Position]->Postprocessing(geometry[iZone][FinestMesh], solver_container[iZone][FinestMesh], config[iZone], FinestMesh); + + /*--- Compute adimensional parameters and the convergence monitor ---*/ + + switch (RunTime_EqSystem) { + case RUNTIME_WAVE_SYS: monitor = log10(solver_container[iZone][FinestMesh][WAVE_SOL]->GetRes_RMS(0)); break; + case RUNTIME_FEA_SYS: monitor = log10(solver_container[iZone][FinestMesh][FEA_SOL]->GetRes_RMS(0)); break; + case RUNTIME_HEAT_SYS: monitor = log10(solver_container[iZone][FinestMesh][HEAT_SOL]->GetRes_RMS(0)); break; + case RUNTIME_POISSON_SYS: monitor = log10(solver_container[iZone][FinestMesh][POISSON_SOL]->GetRes_RMS(0)); break; + } + + /*--- Convergence strategy ---*/ + + Convergence_Monitoring(geometry[iZone][FinestMesh], config[iZone], Iteration, monitor, FinestMesh); + + /*--- If turbulence model, copy the eddy viscosity to the coarse levels ---*/ + + if (RunTime_EqSystem == RUNTIME_TURB_SYS) { + for (iMesh = FinestMesh; iMesh < config[iZone]->GetnMGLevels(); iMesh++) { + if ((config[iZone]->GetMGCycle() == FULLMG_CYCLE) || config[iZone]->GetLowFidelitySim()){ + SetRestricted_Solution(RunTime_EqSystem, solver_container[iZone][iMesh][SolContainer_Position], solver_container[iZone][iMesh+1][SolContainer_Position], geometry[iZone][iMesh], geometry[iZone][iMesh+1], config[iZone]); + } + SetRestricted_EddyVisc(RunTime_EqSystem, solver_container[iZone][iMesh][SolContainer_Position], solver_container[iZone][iMesh+1][SolContainer_Position], geometry[iZone][iMesh], geometry[iZone][iMesh+1], config[iZone]); + } + } + +} + +void CSingleGridIntegration::SetRestricted_Solution(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { + unsigned long Point_Fine, Point_Coarse; + unsigned short iVar, iChildren; + su2double Area_Parent, Area_Children, *Solution_Fine, *Solution; + + unsigned short nVar = sol_coarse->GetnVar(); + + Solution = new su2double[nVar]; + + /*--- Compute coarse solution from fine solution ---*/ + + for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { + Area_Parent = geo_coarse->node[Point_Coarse]->GetVolume(); + + for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; + + for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { + + Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); + Area_Children = geo_fine->node[Point_Fine]->GetVolume(); + Solution_Fine = sol_fine->node[Point_Fine]->GetSolution(); + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] += Solution_Fine[iVar]*Area_Children/Area_Parent; + } + + sol_coarse->node[Point_Coarse]->SetSolution(Solution); + + } + + /*--- MPI the new interpolated solution ---*/ + + sol_coarse->Set_MPI_Solution(geo_coarse, config); + + delete [] Solution; + +} + +void CSingleGridIntegration::SetRestricted_EddyVisc(unsigned short RunTime_EqSystem, CSolver *sol_fine, CSolver *sol_coarse, CGeometry *geo_fine, CGeometry *geo_coarse, CConfig *config) { + + unsigned long iVertex, Point_Fine, Point_Coarse; + unsigned short iMarker, iChildren; + su2double Area_Parent, Area_Children, EddyVisc_Fine, EddyVisc; + + /*--- Compute coarse Eddy Viscosity from fine solution ---*/ + + for (Point_Coarse = 0; Point_Coarse < geo_coarse->GetnPointDomain(); Point_Coarse++) { + Area_Parent = geo_coarse->node[Point_Coarse]->GetVolume(); + + EddyVisc = 0.0; + + for (iChildren = 0; iChildren < geo_coarse->node[Point_Coarse]->GetnChildren_CV(); iChildren++) { + Point_Fine = geo_coarse->node[Point_Coarse]->GetChildren_CV(iChildren); + Area_Children = geo_fine->node[Point_Fine]->GetVolume(); + EddyVisc_Fine = sol_fine->node[Point_Fine]->GetmuT(); + EddyVisc += EddyVisc_Fine*Area_Children/Area_Parent; + } + + sol_coarse->node[Point_Coarse]->SetmuT(EddyVisc); + + } + + /*--- Update solution at the no slip wall boundary, only the first + variable (nu_tilde -in SA and SA_NEG- and k -in SST-), to guarantee that the eddy viscoisty + is zero on the surface ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX ) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL )) { + for (iVertex = 0; iVertex < geo_coarse->nVertex[iMarker]; iVertex++) { + Point_Coarse = geo_coarse->vertex[iMarker][iVertex]->GetNode(); + sol_coarse->node[Point_Coarse]->SetmuT(0); + } + } + } + + /*--- MPI the new interpolated solution (this also includes the eddy viscosity) ---*/ + + sol_coarse->Set_MPI_Solution(geo_coarse, config); + +} + + +CStructuralIntegration::CStructuralIntegration(CConfig *config) : CIntegration(config) { } + +CStructuralIntegration::~CStructuralIntegration(void) { } + +void CStructuralIntegration::Structural_Iteration(CGeometry ***geometry, CSolver ****solver_container, + CNumerics *****numerics_container, CConfig **config, unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone) { + su2double monitor = 0.0; + + unsigned short SolContainer_Position = config[iZone]->GetContainerPosition(RunTime_EqSystem); + + /*--- Preprocessing ---*/ + + solver_container[iZone][MESH_0][SolContainer_Position]->Preprocessing(geometry[iZone][MESH_0], solver_container[iZone][MESH_0], + config[iZone], numerics_container[iZone][MESH_0][SolContainer_Position], MESH_0, Iteration, RunTime_EqSystem, false); + + /*--- Space integration ---*/ + + Space_Integration(geometry[iZone][MESH_0], solver_container[iZone][MESH_0], numerics_container[iZone][MESH_0][SolContainer_Position], + config[iZone], MESH_0, NO_RK_ITER, RunTime_EqSystem); + + /*--- Time integration ---*/ + + Time_Integration(geometry[iZone][MESH_0], solver_container[iZone][MESH_0], config[iZone], NO_RK_ITER, + RunTime_EqSystem, Iteration); + + /*--- Postprocessing ---*/ + + solver_container[iZone][MESH_0][SolContainer_Position]->Postprocessing(geometry[iZone][MESH_0], solver_container[iZone][MESH_0], + config[iZone], numerics_container[iZone][MESH_0][SolContainer_Position], MESH_0); + + /*--- Compute adimensional parameters and the convergence monitor ---*/ + + monitor = log10(solver_container[iZone][MESH_0][FEA_SOL]->GetRes_RMS(0)); + + /*--- Convergence strategy ---*/ + Convergence_Monitoring(geometry[iZone][MESH_0], config[iZone], Iteration, monitor, MESH_0); + + +} diff --git a/SU2_CFD/src/iteration_structure.cpp b/SU2_CFD/src/iteration_structure.cpp index e6bba4c173a..944c57ffb54 100644 --- a/SU2_CFD/src/iteration_structure.cpp +++ b/SU2_CFD/src/iteration_structure.cpp @@ -1,1966 +1,1966 @@ -/*! - * \file iteration_structure.cpp - * \brief Main subroutines used by SU2_CFD - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/iteration_structure.hpp" - -CIteration::CIteration(CConfig *config) { } -CIteration::~CIteration(void) { } - -void CIteration::Preprocess(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { } -void CIteration::Iterate(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { } -void CIteration::Update(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { } -void CIteration::Monitor() { } -void CIteration::Output() { } -void CIteration::Postprocess() { } - - - -CMeanFlowIteration::CMeanFlowIteration(CConfig *config) : CIteration(config) { } -CMeanFlowIteration::~CMeanFlowIteration(void) { } - -void CMeanFlowIteration::Preprocess(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { - - unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); - unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); - - bool time_spectral = (config_container[ZONE_0]->GetUnsteady_Simulation() == TIME_SPECTRAL); - - /*--- Set the initial condition ---*/ - - solver_container[val_iZone][MESH_0][FLOW_SOL]->SetInitialCondition(geometry_container[val_iZone], solver_container[val_iZone], config_container[val_iZone], ExtIter); - - /*--- Dynamic mesh update ---*/ - - if ((config_container[val_iZone]->GetGrid_Movement()) && (!time_spectral)) { - SetGrid_Movement(geometry_container[val_iZone], surface_movement[val_iZone], grid_movement[val_iZone], FFDBox[val_iZone], solver_container[val_iZone], config_container[val_iZone], val_iZone, IntIter, ExtIter); - } - - /*--- Apply a Wind Gust ---*/ - - if (config_container[ZONE_0]->GetWind_Gust()) { - SetWind_GustField(config_container[val_iZone], geometry_container[val_iZone], solver_container[val_iZone]); - } - - - /*--- Calculate and set Mixing Plane averaged quantities at interfaces ---*/ - - if(config_container[val_iZone]->GetBoolMixingPlane()) - SetMixingPlane(geometry_container, solver_container, config_container, val_iZone); - - /*--- Compute turboperformance ---*/ - - if(config_container[val_iZone]->GetBoolTurboPerf()) - SetTurboPerformance(geometry_container, solver_container, config_container, output, val_iZone); -} - - - - -void CMeanFlowIteration::Iterate(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { - - unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); - unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); -#ifdef HAVE_MPI - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Set the value of the internal iteration ---*/ - - IntIter = ExtIter; - if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) IntIter = 0; - - /*--- Update global parameters ---*/ - - if ((config_container[val_iZone]->GetKind_Solver() == EULER) || - (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_EULER)) { - config_container[val_iZone]->SetGlobalParam(EULER, RUNTIME_FLOW_SYS, ExtIter); - } - if ((config_container[val_iZone]->GetKind_Solver() == NAVIER_STOKES) || - (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_NAVIER_STOKES)) { - config_container[val_iZone]->SetGlobalParam(NAVIER_STOKES, RUNTIME_FLOW_SYS, ExtIter); - } - if ((config_container[val_iZone]->GetKind_Solver() == RANS) || - (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_RANS)) { - config_container[val_iZone]->SetGlobalParam(RANS, RUNTIME_FLOW_SYS, ExtIter); - } - - /*--- Solve the Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes (RANS) equations (one iteration) ---*/ - - integration_container[val_iZone][FLOW_SOL]->MultiGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_FLOW_SYS, IntIter, val_iZone); - - if ((config_container[val_iZone]->GetKind_Solver() == RANS) || - (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_RANS)) { - - /*--- Solve the turbulence model ---*/ - - config_container[val_iZone]->SetGlobalParam(RANS, RUNTIME_TURB_SYS, ExtIter); - integration_container[val_iZone][TURB_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_TURB_SYS, IntIter, val_iZone); - - /*--- Solve transition model ---*/ - - if (config_container[val_iZone]->GetKind_Trans_Model() == LM) { - config_container[val_iZone]->SetGlobalParam(RANS, RUNTIME_TRANS_SYS, ExtIter); - integration_container[val_iZone][TRANS_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_TRANS_SYS, IntIter, val_iZone); - } - - } - - /*--- Dual time stepping strategy ---*/ - - if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { - - for (IntIter = 1; IntIter < config_container[val_iZone]->GetUnst_nIntIter(); IntIter++) { - - /*--- Write the convergence history (only screen output) ---*/ - - output->SetConvHistory_Body(NULL, geometry_container, solver_container, config_container, integration_container, true, 0.0, val_iZone); - - /*--- Set the value of the internal iteration ---*/ - - config_container[val_iZone]->SetIntIter(IntIter); - - /*--- Pseudo-timestepping for the Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes equations ---*/ - - if ((config_container[val_iZone]->GetKind_Solver() == EULER) || - (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_EULER)) { - config_container[val_iZone]->SetGlobalParam(EULER, RUNTIME_FLOW_SYS, ExtIter); - } - if ((config_container[val_iZone]->GetKind_Solver() == NAVIER_STOKES) || - (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_NAVIER_STOKES)) { - config_container[val_iZone]->SetGlobalParam(NAVIER_STOKES, RUNTIME_FLOW_SYS, ExtIter); - } - if ((config_container[val_iZone]->GetKind_Solver() == RANS) || - (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_RANS)) { - config_container[val_iZone]->SetGlobalParam(RANS, RUNTIME_FLOW_SYS, ExtIter); - } - - /*--- Solve the Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes (RANS) equations (one iteration) ---*/ - - integration_container[val_iZone][FLOW_SOL]->MultiGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_FLOW_SYS, IntIter, val_iZone); - - /*--- Pseudo-timestepping the turbulence model ---*/ - - if ((config_container[val_iZone]->GetKind_Solver() == RANS) || - (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_RANS)) { - - /*--- Solve the turbulence model ---*/ - - config_container[val_iZone]->SetGlobalParam(RANS, RUNTIME_TURB_SYS, ExtIter); - integration_container[val_iZone][TURB_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_TURB_SYS, IntIter, val_iZone); - - /*--- Solve transition model ---*/ - - if (config_container[val_iZone]->GetKind_Trans_Model() == LM) { - config_container[val_iZone]->SetGlobalParam(RANS, RUNTIME_TRANS_SYS, ExtIter); - integration_container[val_iZone][TRANS_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_TRANS_SYS, IntIter, val_iZone); - } - - } - - /*--- Call Dynamic mesh update if AEROELASTIC motion was specified ---*/ - if ((config_container[val_iZone]->GetGrid_Movement()) && (config_container[val_iZone]->GetAeroelastic_Simulation())) { - SetGrid_Movement(geometry_container[val_iZone], surface_movement[val_iZone], grid_movement[val_iZone], FFDBox[val_iZone], - solver_container[val_iZone], config_container[val_iZone], val_iZone, IntIter, ExtIter); - /*--- Apply a Wind Gust ---*/ - if (config_container[val_iZone]->GetWind_Gust()) { - if (IntIter % config_container[val_iZone]->GetAeroelasticIter() ==0) - SetWind_GustField(config_container[val_iZone], geometry_container[val_iZone], solver_container[val_iZone]); - } - } - - if (integration_container[val_iZone][FLOW_SOL]->GetConvergence()) break; - - } - - } - -} - -void CMeanFlowIteration::Update(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { - - unsigned short iMesh; - su2double Physical_dt, Physical_t; - unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); - - /*--- Dual time stepping strategy ---*/ - - if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { - - /*--- Update dual time solver on all mesh levels ---*/ - - for (iMesh = 0; iMesh <= config_container[val_iZone]->GetnMGLevels(); iMesh++) { - integration_container[val_iZone][FLOW_SOL]->SetDualTime_Solver(geometry_container[val_iZone][iMesh], solver_container[val_iZone][iMesh][FLOW_SOL], config_container[val_iZone], iMesh); - integration_container[val_iZone][FLOW_SOL]->SetConvergence(false); - } - - /*--- Update dual time solver for the turbulence model ---*/ - - if ((config_container[val_iZone]->GetKind_Solver() == RANS) || - (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_RANS)) { - integration_container[val_iZone][TURB_SOL]->SetDualTime_Solver(geometry_container[val_iZone][MESH_0], solver_container[val_iZone][MESH_0][TURB_SOL], config_container[val_iZone], MESH_0); - integration_container[val_iZone][TURB_SOL]->SetConvergence(false); - } - - /*--- Update dual time solver for the transition model ---*/ - - if (config_container[val_iZone]->GetKind_Trans_Model() == LM) { - integration_container[val_iZone][TRANS_SOL]->SetDualTime_Solver(geometry_container[val_iZone][MESH_0], solver_container[val_iZone][MESH_0][TRANS_SOL], config_container[val_iZone], MESH_0); - integration_container[val_iZone][TRANS_SOL]->SetConvergence(false); - } - - /*--- Verify convergence criteria (based on total time) ---*/ - - Physical_dt = config_container[val_iZone]->GetDelta_UnstTime(); - Physical_t = (ExtIter+1)*Physical_dt; - if (Physical_t >= config_container[val_iZone]->GetTotal_UnstTime()) - integration_container[val_iZone][FLOW_SOL]->SetConvergence(true); - - } - -} - -void CMeanFlowIteration::Monitor() { } -void CMeanFlowIteration::Output() { } -void CMeanFlowIteration::Postprocess() { } - -void CMeanFlowIteration::SetWind_GustField(CConfig *config_container, CGeometry **geometry_container, CSolver ***solver_container) { - // The gust is imposed on the flow field via the grid velocities. This method called the Field Velocity Method is described in the - // NASA TM–2012-217771 - Development, Verification and Use of Gust Modeling in the NASA Computational Fluid Dynamics Code FUN3D - // the desired gust is prescribed as the negative of the grid velocity. - - // If a source term is included to account for the gust field, the method is described by Jones et al. as the Split Velocity Method in - // Simulation of Airfoil Gust Responses Using Prescribed Velocities. - // In this routine the gust derivatives needed for the source term are calculated when applicable. - // If the gust derivatives are zero the source term is also zero. - // The source term itself is implemented in the class CSourceWindGust - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - if (rank == MASTER_NODE) - cout << endl << "Running simulation with a Wind Gust." << endl; - unsigned short iDim, nDim = geometry_container[MESH_0]->GetnDim(); //We assume nDim = 2 - if (nDim != 2) { - if (rank == MASTER_NODE) { - cout << endl << "WARNING - Wind Gust capability is only verified for 2 dimensional simulations." << endl; - } - } - - /*--- Gust Parameters from config ---*/ - unsigned short Gust_Type = config_container->GetGust_Type(); - su2double xbegin = config_container->GetGust_Begin_Loc(); // Location at which the gust begins. - su2double L = config_container->GetGust_WaveLength(); // Gust size - su2double tbegin = config_container->GetGust_Begin_Time(); // Physical time at which the gust begins. - su2double gust_amp = config_container->GetGust_Ampl(); // Gust amplitude - su2double n = config_container->GetGust_Periods(); // Number of gust periods - unsigned short GustDir = config_container->GetGust_Dir(); // Gust direction - - /*--- Variables needed to compute the gust ---*/ - unsigned short Kind_Grid_Movement = config_container->GetKind_GridMovement(ZONE_0); - unsigned long iPoint; - unsigned short iMGlevel, nMGlevel = config_container->GetnMGLevels(); - - su2double x, y, x_gust, dgust_dx, dgust_dy, dgust_dt; - su2double *Gust, *GridVel, *NewGridVel, *GustDer; - - su2double Physical_dt = config_container->GetDelta_UnstTime(); - unsigned long ExtIter = config_container->GetExtIter(); - su2double Physical_t = ExtIter*Physical_dt; - - su2double Uinf = solver_container[MESH_0][FLOW_SOL]->GetVelocity_Inf(0); // Assumption gust moves at infinity velocity - - Gust = new su2double [nDim]; - NewGridVel = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) { - Gust[iDim] = 0.0; - NewGridVel[iDim] = 0.0; - } - - GustDer = new su2double [3]; - for (unsigned short i = 0; i < 3; i++) { - GustDer[i] = 0.0; - } - - // Vortex variables - unsigned long nVortex = 0; - vector x0, y0, vort_strenth, r_core; //vortex is positive in clockwise direction. - if (Gust_Type == VORTEX) { - InitializeVortexDistribution(nVortex, x0, y0, vort_strenth, r_core); - } - - /*--- Check to make sure gust lenght is not zero or negative (vortex gust doesn't use this). ---*/ - if (L <= 0.0 && Gust_Type != VORTEX) { - if (rank == MASTER_NODE) cout << "ERROR: The gust length needs to be positive" << endl; -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - } - - /*--- Loop over all multigrid levels ---*/ - - for (iMGlevel = 0; iMGlevel <= nMGlevel; iMGlevel++) { - - /*--- Loop over each node in the volume mesh ---*/ - - for (iPoint = 0; iPoint < geometry_container[iMGlevel]->GetnPoint(); iPoint++) { - - /*--- Reset the Grid Velocity to zero if there is no grid movement ---*/ - if (Kind_Grid_Movement == GUST) { - for (iDim = 0; iDim < nDim; iDim++) - geometry_container[iMGlevel]->node[iPoint]->SetGridVel(iDim, 0.0); - } - - /*--- initialize the gust and derivatives to zero everywhere ---*/ - - for (iDim = 0; iDim < nDim; iDim++) {Gust[iDim]=0.0;} - dgust_dx = 0.0; dgust_dy = 0.0; dgust_dt = 0.0; - - /*--- Begin applying the gust ---*/ - - if (Physical_t >= tbegin) { - - x = geometry_container[iMGlevel]->node[iPoint]->GetCoord()[0]; // x-location of the node. - y = geometry_container[iMGlevel]->node[iPoint]->GetCoord()[1]; // y-location of the node. - - // Gust coordinate - x_gust = (x - xbegin - Uinf*(Physical_t-tbegin))/L; - - /*--- Calculate the specified gust ---*/ - switch (Gust_Type) { - - case TOP_HAT: - // Check if we are in the region where the gust is active - if (x_gust > 0 && x_gust < n) { - Gust[GustDir] = gust_amp; - // Still need to put the gust derivatives. Think about this. - } - break; - - case SINE: - // Check if we are in the region where the gust is active - if (x_gust > 0 && x_gust < n) { - Gust[GustDir] = gust_amp*(sin(2*PI_NUMBER*x_gust)); - - // Gust derivatives - //dgust_dx = gust_amp*2*PI_NUMBER*(cos(2*PI_NUMBER*x_gust))/L; - //dgust_dy = 0; - //dgust_dt = gust_amp*2*PI_NUMBER*(cos(2*PI_NUMBER*x_gust))*(-Uinf)/L; - } - break; - - case ONE_M_COSINE: - // Check if we are in the region where the gust is active - if (x_gust > 0 && x_gust < n) { - Gust[GustDir] = gust_amp*(1-cos(2*PI_NUMBER*x_gust)); - - // Gust derivatives - //dgust_dx = gust_amp*2*PI_NUMBER*(sin(2*PI_NUMBER*x_gust))/L; - //dgust_dy = 0; - //dgust_dt = gust_amp*2*PI_NUMBER*(sin(2*PI_NUMBER*x_gust))*(-Uinf)/L; - } - break; - - case EOG: - // Check if we are in the region where the gust is active - if (x_gust > 0 && x_gust < n) { - Gust[GustDir] = -0.37*gust_amp*sin(3*PI_NUMBER*x_gust)*(1-cos(2*PI_NUMBER*x_gust)); - } - break; - - case VORTEX: - - /*--- Use vortex distribution ---*/ - // Algebraic vortex equation. - for (unsigned long i=0; inode[iPoint]->SetWindGust(Gust); - solver_container[iMGlevel][FLOW_SOL]->node[iPoint]->SetWindGustDer(GustDer); - - GridVel = geometry_container[iMGlevel]->node[iPoint]->GetGridVel(); - - /*--- Store new grid velocity ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - NewGridVel[iDim] = GridVel[iDim] - Gust[iDim]; - geometry_container[iMGlevel]->node[iPoint]->SetGridVel(iDim, NewGridVel[iDim]); - } - - } - } - - delete [] Gust; - delete [] GustDer; - delete [] NewGridVel; - -} - -void CMeanFlowIteration::InitializeVortexDistribution(unsigned long &nVortex, vector& x0, vector& y0, vector& vort_strength, vector& r_core) { - /*--- Read in Vortex Distribution ---*/ - std::string line; - std::ifstream file; - su2double x_temp, y_temp, vort_strength_temp, r_core_temp; - file.open("vortex_distribution.txt"); - /*--- In case there is no vortex file ---*/ - if (file.fail()) { - cout << "There is no vortex data file!!" << endl; - cout << "Press any key to exit..." << endl; - cin.get(); exit(EXIT_FAILURE); - } - - // Ignore line containing the header - getline(file, line); - // Read in the information of the vortices (xloc, yloc, lambda(strength), eta(size, gradient)) - while (file.good()) - { - getline(file, line); - std::stringstream ss(line); - if (line.size() != 0) { //ignore blank lines if they exist. - ss >> x_temp; - ss >> y_temp; - ss >> vort_strength_temp; - ss >> r_core_temp; - x0.push_back(x_temp); - y0.push_back(y_temp); - vort_strength.push_back(vort_strength_temp); - r_core.push_back(r_core_temp); - } - } - file.close(); - // number of vortices - nVortex = x0.size(); - -} - -void CMeanFlowIteration::SetMixingPlane(CGeometry ***geometry_container, CSolver ****solver_container, CConfig **config_container, unsigned short iZone) { - - unsigned short jZone; - unsigned short nZone = geometry_container[ZONE_0][MESH_0]->GetnZone(); - int intMarker, extMarker, intMarkerMix; - string intMarker_Tag, extMarker_Tag; - - /*-- Loop on all the boundary to find MIXING_PLANE boundary --*/ - for (intMarker = 0; intMarker < config_container[iZone]->GetnMarker_All(); intMarker++) { - for (intMarkerMix=0; intMarkerMix < config_container[iZone]->Get_nMarkerMixingPlane(); intMarkerMix++) - if (config_container[iZone]->GetMarker_All_TagBound(intMarker) == config_container[iZone]->GetMarker_MixingPlane_Bound(intMarkerMix) ) { - solver_container[iZone][MESH_0][FLOW_SOL]->Mixing_Process(geometry_container[iZone][MESH_0], solver_container[iZone][MESH_0], config_container[iZone], intMarker); - extMarker_Tag = config_container[iZone]->GetMarker_MixingPlane_Donor(intMarkerMix); - for (jZone = 0; jZone < nZone; jZone++){ - for (extMarker = 0; extMarker < config_container[jZone]->GetnMarker_All(); extMarker++) - if (config_container[jZone]->GetMarker_All_TagBound(extMarker) == extMarker_Tag){ - solver_container[jZone][MESH_0][FLOW_SOL]->SetExtAveragedValue(solver_container[iZone][MESH_0][FLOW_SOL], intMarker, extMarker); - } - } - - } - - } - -} - -void CMeanFlowIteration::SetTurboPerformance(CGeometry ***geometry_container, CSolver ****solver_container, CConfig **config_container, COutput *output, unsigned short iZone) { - - unsigned short jZone, inMarker, outMarker, inMarkerTP, Kind_TurboPerf; - unsigned short nZone = geometry_container[iZone][MESH_0]->GetnZone(); - string inMarker_Tag, outMarker_Tag; - - - /*-- Loop on all the boundary to find MIXING_PLANE boundary --*/ - for (inMarker = 0; inMarker < config_container[iZone]->GetnMarker_All(); inMarker++) - for (inMarkerTP=0; inMarkerTP < config_container[iZone]->Get_nMarkerTurboPerf(); inMarkerTP++) - if (config_container[iZone]->GetMarker_All_TagBound(inMarker) == config_container[iZone]->GetMarker_TurboPerf_BoundIn(inMarkerTP) ) { - outMarker_Tag = config_container[iZone]->GetMarker_TurboPerf_BoundOut(inMarkerTP); - Kind_TurboPerf = config_container[iZone]->GetKind_TurboPerf(inMarkerTP); - for (jZone = 0; jZone < nZone; jZone++) - for (outMarker = 0; outMarker < config_container[jZone]->GetnMarker_All(); outMarker++) - if (config_container[jZone]->GetMarker_All_TagBound(outMarker) == outMarker_Tag){ - solver_container[iZone][MESH_0][FLOW_SOL]->Mixing_Process(geometry_container[iZone][MESH_0], solver_container[iZone][MESH_0], config_container[iZone], inMarker); - solver_container[jZone][MESH_0][FLOW_SOL]->Mixing_Process(geometry_container[jZone][MESH_0], solver_container[jZone][MESH_0], config_container[jZone], outMarker); - solver_container[iZone][MESH_0][FLOW_SOL]->TurboPerformance(solver_container[jZone][MESH_0][FLOW_SOL], config_container[iZone], inMarker, outMarker, Kind_TurboPerf, inMarkerTP); - solver_container[ZONE_0][MESH_0][FLOW_SOL]->StoreTurboPerformance(solver_container[iZone][MESH_0][FLOW_SOL], inMarkerTP); - } - } -} - - -CWaveIteration::CWaveIteration(CConfig *config) : CIteration(config) { } -CWaveIteration::~CWaveIteration(void) { } -void CWaveIteration::Preprocess(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { } -void CWaveIteration::Iterate(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { - - unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); - unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); - - /*--- Set the value of the internal iteration ---*/ - IntIter = ExtIter; - if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) IntIter = 0; - - /*--- Wave equations ---*/ - config_container[val_iZone]->SetGlobalParam(WAVE_EQUATION, RUNTIME_WAVE_SYS, ExtIter); - integration_container[val_iZone][WAVE_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_WAVE_SYS, IntIter, val_iZone); - - /*--- Dual time stepping strategy ---*/ - if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { - - for (IntIter = 1; IntIter < config_container[val_iZone]->GetUnst_nIntIter(); IntIter++) { - output->SetConvHistory_Body(NULL, geometry_container, solver_container, config_container, integration_container, true, 0.0, val_iZone); - config_container[val_iZone]->SetIntIter(IntIter); - integration_container[val_iZone][WAVE_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_WAVE_SYS, IntIter, val_iZone); - if (integration_container[val_iZone][WAVE_SOL]->GetConvergence()) break; - } - - } - -} -void CWaveIteration::Update(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { - - unsigned short iMesh; - su2double Physical_dt, Physical_t; - unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); - - /*--- Dual time stepping strategy ---*/ - if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { - - /*--- Update dual time solver ---*/ - for (iMesh = 0; iMesh <= config_container[val_iZone]->GetnMGLevels(); iMesh++) { - integration_container[val_iZone][WAVE_SOL]->SetDualTime_Solver(geometry_container[val_iZone][iMesh], solver_container[val_iZone][iMesh][WAVE_SOL], config_container[val_iZone], iMesh); - integration_container[val_iZone][WAVE_SOL]->SetConvergence(false); - } - - Physical_dt = config_container[val_iZone]->GetDelta_UnstTime(); Physical_t = (ExtIter+1)*Physical_dt; - if (Physical_t >= config_container[val_iZone]->GetTotal_UnstTime()) integration_container[val_iZone][WAVE_SOL]->SetConvergence(true); - } -} - -void CWaveIteration::Monitor() { } -void CWaveIteration::Output() { } -void CWaveIteration::Postprocess() { } - - -CHeatIteration::CHeatIteration(CConfig *config) : CIteration(config) { } -CHeatIteration::~CHeatIteration(void) { } -void CHeatIteration::Preprocess(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { } -void CHeatIteration::Iterate(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone){ - - unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); - unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); - - /*--- Set the value of the internal iteration ---*/ - IntIter = ExtIter; - if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) IntIter = 0; - - /*--- Heat equation ---*/ - config_container[val_iZone]->SetGlobalParam(HEAT_EQUATION, RUNTIME_HEAT_SYS, ExtIter); - integration_container[val_iZone][HEAT_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_HEAT_SYS, IntIter, val_iZone); - - /*--- Dual time stepping strategy ---*/ - if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { - - for (IntIter = 1; IntIter < config_container[val_iZone]->GetUnst_nIntIter(); IntIter++) { - output->SetConvHistory_Body(NULL, geometry_container, solver_container, config_container, integration_container, true, 0.0, val_iZone); - config_container[val_iZone]->SetIntIter(IntIter); - integration_container[val_iZone][HEAT_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_HEAT_SYS, IntIter, val_iZone); - if (integration_container[val_iZone][HEAT_SOL]->GetConvergence()) break; - } - } -} - -void CHeatIteration::Update(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { - - unsigned short iMesh; - su2double Physical_dt, Physical_t; - unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); - - /*--- Dual time stepping strategy ---*/ - if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { - - /*--- Update dual time solver ---*/ - for (iMesh = 0; iMesh <= config_container[val_iZone]->GetnMGLevels(); iMesh++) { - integration_container[val_iZone][HEAT_SOL]->SetDualTime_Solver(geometry_container[val_iZone][iMesh], solver_container[val_iZone][iMesh][HEAT_SOL], config_container[val_iZone], iMesh); - integration_container[val_iZone][HEAT_SOL]->SetConvergence(false); - } - - Physical_dt = config_container[val_iZone]->GetDelta_UnstTime(); Physical_t = (ExtIter+1)*Physical_dt; - if (Physical_t >= config_container[val_iZone]->GetTotal_UnstTime()) integration_container[val_iZone][HEAT_SOL]->SetConvergence(true); - } -} -void CHeatIteration::Monitor() { } -void CHeatIteration::Output() { } -void CHeatIteration::Postprocess() { } - - -CPoissonIteration::CPoissonIteration(CConfig *config) : CIteration(config) { } -CPoissonIteration::~CPoissonIteration(void) { } -void CPoissonIteration::Preprocess(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { } -void CPoissonIteration::Iterate(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { - - unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); - unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); - - /*--- Set the value of the internal iteration ---*/ - IntIter = ExtIter; - if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) IntIter = 0; - - /*--- Poisson equation ---*/ - config_container[val_iZone]->SetGlobalParam(POISSON_EQUATION, RUNTIME_POISSON_SYS, ExtIter); - integration_container[val_iZone][POISSON_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_POISSON_SYS, IntIter, val_iZone); - - -} -void CPoissonIteration::Update(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { } -void CPoissonIteration::Monitor() { } -void CPoissonIteration::Output() { } -void CPoissonIteration::Postprocess() { } - - -CFEAIteration::CFEAIteration(CConfig *config) : CIteration(config) { } -CFEAIteration::~CFEAIteration(void) { } -void CFEAIteration::Preprocess(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { - - unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); - unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); - - if (config_container[val_iZone]->GetGrid_Movement()) - SetGrid_Movement(geometry_container[val_iZone], surface_movement[val_iZone], - grid_movement[val_iZone], FFDBox[val_iZone], solver_container[val_iZone], config_container[val_iZone], val_iZone, IntIter, ExtIter); - - /*--- Set the initial condition at the first iteration ---*/ - - solver_container[val_iZone][MESH_0][FEA_SOL]->SetInitialCondition(geometry_container[val_iZone], solver_container[val_iZone], config_container[val_iZone], ExtIter); - -} -void CFEAIteration::Iterate(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { - - unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); - unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); - - /*--- Set the value of the internal iteration ---*/ - - IntIter = ExtIter; - - /*--- FEA equations ---*/ - - config_container[val_iZone]->SetGlobalParam(LINEAR_ELASTICITY, RUNTIME_FEA_SYS, ExtIter); - - /*--- Run the iteration ---*/ - - integration_container[val_iZone][FEA_SOL]->Structural_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_FEA_SYS, IntIter, val_iZone); - - -} -void CFEAIteration::Update(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { - - /*----------------- Update structural solver ----------------------*/ - - bool dynamic = (config_container[val_iZone]->GetDynamic_Analysis() == DYNAMIC); - - if (dynamic){ - integration_container[val_iZone][FEA_SOL]->SetStructural_Solver(geometry_container[val_iZone][MESH_0], solver_container[val_iZone][MESH_0][FEA_SOL], config_container[val_iZone], MESH_0); - } - -} -void CFEAIteration::Monitor() { } -void CFEAIteration::Output() { } -void CFEAIteration::Postprocess() { } - - -CAdjMeanFlowIteration::CAdjMeanFlowIteration(CConfig *config) : CIteration(config) { } -CAdjMeanFlowIteration::~CAdjMeanFlowIteration(void) { } -void CAdjMeanFlowIteration::Preprocess(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { - - unsigned short iMesh; - bool time_spectral = (config_container[ZONE_0]->GetUnsteady_Simulation() == TIME_SPECTRAL); - bool dynamic_mesh = config_container[ZONE_0]->GetGrid_Movement(); - unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); - unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- For the unsteady adjoint, load a new direct solution from a restart file. ---*/ - - if (((dynamic_mesh && ExtIter == 0) || config_container[val_iZone]->GetUnsteady_Simulation()) && !time_spectral) { - int Direct_Iter = SU2_TYPE::Int(config_container[val_iZone]->GetUnst_AdjointIter()) - SU2_TYPE::Int(ExtIter) - 1; - if (rank == MASTER_NODE && val_iZone == ZONE_0 && config_container[val_iZone]->GetUnsteady_Simulation()) - cout << endl << " Loading flow solution from direct iteration " << Direct_Iter << "." << endl; - solver_container[val_iZone][MESH_0][FLOW_SOL]->LoadRestart(geometry_container[val_iZone], solver_container[val_iZone], config_container[val_iZone], Direct_Iter); - } - - /*--- Continuous adjoint Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes (RANS) equations ---*/ - - if ((ExtIter == 0) || config_container[val_iZone]->GetUnsteady_Simulation()) { - - if (config_container[val_iZone]->GetKind_Solver() == ADJ_EULER) - config_container[val_iZone]->SetGlobalParam(ADJ_EULER, RUNTIME_FLOW_SYS, ExtIter); - if (config_container[val_iZone]->GetKind_Solver() == ADJ_NAVIER_STOKES) - config_container[val_iZone]->SetGlobalParam(ADJ_NAVIER_STOKES, RUNTIME_FLOW_SYS, ExtIter); - if (config_container[val_iZone]->GetKind_Solver() == ADJ_RANS) - config_container[val_iZone]->SetGlobalParam(ADJ_RANS, RUNTIME_FLOW_SYS, ExtIter); - - /*--- Solve the Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes (RANS) equations (one iteration) ---*/ - - if (rank == MASTER_NODE && val_iZone == ZONE_0) - cout << "Begin direct solver to store flow data (single iteration)." << endl; - - if (rank == MASTER_NODE && val_iZone == ZONE_0) - cout << "Compute residuals to check the convergence of the direct problem." << endl; - - integration_container[val_iZone][FLOW_SOL]->MultiGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_FLOW_SYS, 0, val_iZone); - - if (config_container[val_iZone]->GetKind_Solver() == ADJ_RANS) { - - /*--- Solve the turbulence model ---*/ - - config_container[val_iZone]->SetGlobalParam(ADJ_RANS, RUNTIME_TURB_SYS, ExtIter); - integration_container[val_iZone][TURB_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_TURB_SYS, IntIter, val_iZone); - - /*--- Solve transition model ---*/ - - if (config_container[val_iZone]->GetKind_Trans_Model() == LM) { - config_container[val_iZone]->SetGlobalParam(RANS, RUNTIME_TRANS_SYS, ExtIter); - integration_container[val_iZone][TRANS_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_TRANS_SYS, IntIter, val_iZone); - } - - } - - /*--- Output the residual (visualization purpouses to identify if - the direct solution is converged)---*/ - if (rank == MASTER_NODE && val_iZone == ZONE_0) - cout << "log10[Maximum residual]: " << log10(solver_container[val_iZone][MESH_0][FLOW_SOL]->GetRes_Max(0)) - <<", located at point "<< solver_container[val_iZone][MESH_0][FLOW_SOL]->GetPoint_Max(0) << "." << endl; - - /*--- Compute gradients of the flow variables, this is necessary for sensitivity computation, - note that in the direct Euler problem we are not computing the gradients of the primitive variables ---*/ - - if (config_container[val_iZone]->GetKind_Gradient_Method() == GREEN_GAUSS) - solver_container[val_iZone][MESH_0][FLOW_SOL]->SetPrimitive_Gradient_GG(geometry_container[val_iZone][MESH_0], config_container[val_iZone]); - if (config_container[val_iZone]->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) - solver_container[val_iZone][MESH_0][FLOW_SOL]->SetPrimitive_Gradient_LS(geometry_container[val_iZone][MESH_0], config_container[val_iZone]); - - /*--- Set contribution from cost function for boundary conditions ---*/ - - for (iMesh = 0; iMesh <= config_container[val_iZone]->GetnMGLevels(); iMesh++) { - - /*--- Set the value of the non-dimensional coefficients in the coarse levels, using the fine level solution ---*/ - - solver_container[val_iZone][iMesh][FLOW_SOL]->SetTotal_CDrag(solver_container[val_iZone][MESH_0][FLOW_SOL]->GetTotal_CDrag()); - solver_container[val_iZone][iMesh][FLOW_SOL]->SetTotal_CLift(solver_container[val_iZone][MESH_0][FLOW_SOL]->GetTotal_CLift()); - solver_container[val_iZone][iMesh][FLOW_SOL]->SetTotal_CT(solver_container[val_iZone][MESH_0][FLOW_SOL]->GetTotal_CT()); - solver_container[val_iZone][iMesh][FLOW_SOL]->SetTotal_CQ(solver_container[val_iZone][MESH_0][FLOW_SOL]->GetTotal_CQ()); - - /*--- Compute the adjoint boundary condition on Euler walls ---*/ - - solver_container[val_iZone][iMesh][ADJFLOW_SOL]->SetForceProj_Vector(geometry_container[val_iZone][iMesh], solver_container[val_iZone][iMesh], config_container[val_iZone]); - - /*--- Set the internal boundary condition on nearfield surfaces ---*/ - - if ((config_container[val_iZone]->GetKind_ObjFunc() == EQUIVALENT_AREA) || - (config_container[val_iZone]->GetKind_ObjFunc() == NEARFIELD_PRESSURE)) - solver_container[val_iZone][iMesh][ADJFLOW_SOL]->SetIntBoundary_Jump(geometry_container[val_iZone][iMesh], solver_container[val_iZone][iMesh], config_container[val_iZone]); - - } - - if (rank == MASTER_NODE && val_iZone == ZONE_0) - cout << "End direct solver, begin adjoint problem." << endl; - - } - -} -void CAdjMeanFlowIteration::Iterate(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { - - unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); - unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); - - /*--- Set the value of the internal iteration ---*/ - - IntIter = ExtIter; - if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { - IntIter = 0; - } - - if (config_container[val_iZone]->GetKind_Solver() == ADJ_EULER) - config_container[val_iZone]->SetGlobalParam(ADJ_EULER, RUNTIME_ADJFLOW_SYS, ExtIter); - if (config_container[val_iZone]->GetKind_Solver() == ADJ_NAVIER_STOKES) - config_container[val_iZone]->SetGlobalParam(ADJ_NAVIER_STOKES, RUNTIME_ADJFLOW_SYS, ExtIter); - if (config_container[val_iZone]->GetKind_Solver() == ADJ_RANS) - config_container[val_iZone]->SetGlobalParam(ADJ_RANS, RUNTIME_ADJFLOW_SYS, ExtIter); - - /*--- Iteration of the flow adjoint problem ---*/ - - integration_container[val_iZone][ADJFLOW_SOL]->MultiGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_ADJFLOW_SYS, IntIter, val_iZone); - - /*--- Iteration of the turbulence model adjoint ---*/ - - if ((config_container[val_iZone]->GetKind_Solver() == ADJ_RANS) && (!config_container[val_iZone]->GetFrozen_Visc())) { - - /*--- Adjoint turbulence model solution ---*/ - - config_container[val_iZone]->SetGlobalParam(ADJ_RANS, RUNTIME_ADJTURB_SYS, ExtIter); - integration_container[val_iZone][ADJTURB_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_ADJTURB_SYS, IntIter, val_iZone); - - } - - /*--- Dual time stepping strategy ---*/ - - if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { - - for (IntIter = 1; IntIter < config_container[val_iZone]->GetUnst_nIntIter(); IntIter++) { - - /*--- Write the convergence history (only screen output) ---*/ - - output->SetConvHistory_Body(NULL, geometry_container, solver_container, config_container, integration_container, true, 0.0, val_iZone); - - /*--- Set the value of the internal iteration ---*/ - - config_container[val_iZone]->SetIntIter(IntIter); - - /*--- All zones must be advanced and coupled with each pseudo timestep ---*/ - - integration_container[val_iZone][ADJFLOW_SOL]->MultiGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_ADJFLOW_SYS, IntIter, val_iZone); - - /*--- Check to see if the convergence criteria has been met ---*/ - - if (integration_container[val_iZone][ADJFLOW_SOL]->GetConvergence()) break; - } - - } - -} -void CAdjMeanFlowIteration::Update(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { - - su2double Physical_dt, Physical_t; - unsigned short iMesh; - unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); - - /*--- Dual time stepping strategy ---*/ - - if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { - - /*--- Update dual time solver ---*/ - - for (iMesh = 0; iMesh <= config_container[val_iZone]->GetnMGLevels(); iMesh++) { - integration_container[val_iZone][ADJFLOW_SOL]->SetDualTime_Solver(geometry_container[val_iZone][iMesh], solver_container[val_iZone][iMesh][ADJFLOW_SOL], config_container[val_iZone], iMesh); - integration_container[val_iZone][ADJFLOW_SOL]->SetConvergence(false); - } - - Physical_dt = config_container[val_iZone]->GetDelta_UnstTime(); Physical_t = (ExtIter+1)*Physical_dt; - if (Physical_t >= config_container[val_iZone]->GetTotal_UnstTime()) integration_container[val_iZone][ADJFLOW_SOL]->SetConvergence(true); - - } -} - -void CAdjMeanFlowIteration::Monitor() { } -void CAdjMeanFlowIteration::Output() { } -void CAdjMeanFlowIteration::Postprocess() { } - -CDiscAdjMeanFlowIteration::CDiscAdjMeanFlowIteration(CConfig *config) : CIteration(config), CurrentRecording(NONE){ - - meanflow_iteration = new CMeanFlowIteration(config); - - turbulent = config->GetKind_Solver() == DISC_ADJ_RANS; - -} - -CDiscAdjMeanFlowIteration::~CDiscAdjMeanFlowIteration(void) { } -void CDiscAdjMeanFlowIteration::Preprocess(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { - - unsigned short ExtIter = config_container[val_iZone]->GetExtIter(); - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - if (CurrentRecording != FLOW_VARIABLES){ - - if ((rank == MASTER_NODE) && (ExtIter == 0)){ - cout << "Direct iteration to store computational graph." << endl; - } - - /*--- Record one mean flow iteration with flow variables as input ---*/ - - SetRecording(output, integration_container, geometry_container, solver_container, numerics_container, - config_container, surface_movement, grid_movement, FFDBox, val_iZone, FLOW_VARIABLES); - - /*--- Print residuals in the first iteration ---*/ - - if (rank == MASTER_NODE && ExtIter == 0){ - cout << "log10[RMS Density]: "<< log10(solver_container[val_iZone][MESH_0][FLOW_SOL]->GetRes_RMS(0)) - <<", Drag: " <GetTotal_CDrag() - <<", Lift: " << solver_container[val_iZone][MESH_0][FLOW_SOL]->GetTotal_CLift() << "." << endl; - - if (turbulent){ - cout << "log10[RMS k]: " << log10(solver_container[val_iZone][MESH_0][TURB_SOL]->GetRes_RMS(0)) << endl; - } - } - } -} -void CDiscAdjMeanFlowIteration::Iterate(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **volume_grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { - - unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); - - /*--- Set the adjoint values of the flow and objective function ---*/ - - InitializeAdjoint(solver_container, geometry_container, config_container, val_iZone); - - /*--- Run the adjoint computation ---*/ - - AD::ComputeAdjoint(); - - /*--- Extract the adjoints of the conservative input variables and store them for the next iteration ---*/ - - solver_container[val_iZone][MESH_0][ADJFLOW_SOL]->ExtractAdjoint_Solution(geometry_container[val_iZone][MESH_0], - config_container[val_iZone]); - - solver_container[val_iZone][MESH_0][ADJFLOW_SOL]->ExtractAdjoint_Variables(geometry_container[val_iZone][MESH_0], - config_container[val_iZone]); - - if (config_container[ZONE_0]->GetKind_Solver() == DISC_ADJ_RANS) { - solver_container[val_iZone][MESH_0][ADJTURB_SOL]->ExtractAdjoint_Solution(geometry_container[val_iZone][MESH_0], - config_container[val_iZone]); - } - - /*--- Clear all adjoints to re-use the stored computational graph in the next iteration ---*/ - - AD::ClearAdjoints(); - - /*--- Set the convergence criteria (only residual possible) ---*/ - - integration_container[val_iZone][ADJFLOW_SOL]->Convergence_Monitoring(geometry_container[val_iZone][MESH_0],config_container[val_iZone], - ExtIter,log10(solver_container[val_iZone][MESH_0][ADJFLOW_SOL]->GetRes_RMS(0)), MESH_0); - - if (((unsigned short)(ExtIter+1) >= config_container[val_iZone]->GetnExtIter()) || - ((ExtIter % config_container[val_iZone]->GetWrt_Sol_Freq() == 0))){ - - /*--- Record one mean flow iteration with geometry variables as input ---*/ - - SetRecording(output, integration_container, geometry_container, solver_container, numerics_container, - config_container, surface_movement, volume_grid_movement, FFDBox, val_iZone, GEOMETRY_VARIABLES); - - /*--- Set the adjoint values of the flow and objective function ---*/ - - InitializeAdjoint(solver_container, geometry_container, config_container, val_iZone); - - /*--- Run the adjoint computation ---*/ - - AD::ComputeAdjoint(); - - /*--- Extract the sensitivities (adjoint of node coordinates) ---*/ - - solver_container[val_iZone][MESH_0][ADJFLOW_SOL]->SetSensitivity(geometry_container[val_iZone][MESH_0],config_container[val_iZone]); - - } - -} - -void CDiscAdjMeanFlowIteration::SetRecording(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone, - unsigned short kind_recording) { - - unsigned short iMesh; - - /*--- Reset the tape ---*/ - - AD::Reset(); - - /*--- Update geometry to set all indices to zero ---*/ - - geometry_container[val_iZone][MESH_0]->UpdateGeometry(geometry_container[val_iZone], config_container[val_iZone]); - - /*--- Run one iteration while tape is passive - this clears all indices ---*/ - - meanflow_iteration->Iterate(output,integration_container,geometry_container,solver_container,numerics_container, - config_container,surface_movement,grid_movement,FFDBox,val_iZone); - - /*--- Prepare for recording ---*/ - - for (iMesh = 0; iMesh <= config_container[val_iZone]->GetnMGLevels(); iMesh++){ - - solver_container[val_iZone][iMesh][ADJFLOW_SOL]->SetRecording(geometry_container[val_iZone][MESH_0], config_container[val_iZone], kind_recording); - - if (turbulent){ - solver_container[val_iZone][iMesh][ADJTURB_SOL]->SetRecording(geometry_container[val_iZone][MESH_0], config_container[val_iZone], kind_recording); - } - } - - /*--- Start the recording of all operations ---*/ - - AD::StartRecording(); - - /*--- Register flow variables and compute coupling or update the geometry ---*/ - - RegisterInput(solver_container, geometry_container, config_container, val_iZone, kind_recording); - - /*--- Run the direct iteration ---*/ - - meanflow_iteration->Iterate(output,integration_container,geometry_container,solver_container,numerics_container, - config_container,surface_movement,grid_movement,FFDBox, val_iZone); - - /*--- Register flow variables and objective function as output ---*/ - - /*--- For flux-avg or area-avg objective functions the 1D values must be calculated first ---*/ - if (config_container[val_iZone]->GetKind_ObjFunc()==AVG_OUTLET_PRESSURE || - config_container[val_iZone]->GetKind_ObjFunc()==AVG_TOTAL_PRESSURE || - config_container[val_iZone]->GetKind_ObjFunc()==MASS_FLOW_RATE) - output->OneDimensionalOutput(solver_container[val_iZone][MESH_0][FLOW_SOL], - geometry_container[val_iZone][MESH_0], config_container[val_iZone]); - - RegisterOutput(solver_container, geometry_container, config_container, val_iZone); - - /*--- Stop the recording ---*/ - - AD::StopRecording(); - - /*--- Set the recording status ---*/ - - CurrentRecording = kind_recording; -} - - -void CDiscAdjMeanFlowIteration::RegisterInput(CSolver ****solver_container, CGeometry ***geometry_container, CConfig **config_container, unsigned short iZone, unsigned short kind_recording){ - - - if (kind_recording == FLOW_VARIABLES){ - - /*--- Register flow and turbulent variables as input ---*/ - - solver_container[iZone][MESH_0][ADJFLOW_SOL]->RegisterSolution(geometry_container[iZone][MESH_0], config_container[iZone]); - - solver_container[iZone][MESH_0][ADJFLOW_SOL]->RegisterVariables(geometry_container[iZone][MESH_0], config_container[iZone]); - - if (turbulent){ - solver_container[iZone][MESH_0][ADJTURB_SOL]->RegisterSolution(geometry_container[iZone][MESH_0], config_container[iZone]); - } - - /*--- Compute coupling between flow and turbulent equations ---*/ - - if (turbulent){ - solver_container[iZone][MESH_0][FLOW_SOL]->SetPrimitive_Variables(solver_container[iZone][MESH_0], config_container[iZone], false); - solver_container[iZone][MESH_0][TURB_SOL]->Postprocessing(geometry_container[iZone][MESH_0],solver_container[iZone][MESH_0], config_container[iZone], MESH_0); - } - } - else if (kind_recording == GEOMETRY_VARIABLES){ - - /*--- Register node coordinates as input ---*/ - - geometry_container[iZone][MESH_0]->RegisterCoordinates(config_container[iZone]); - - /*--- Update geometry to get the influence on other geometry variables (normals, volume etc) ---*/ - - geometry_container[iZone][MESH_0]->UpdateGeometry(geometry_container[iZone], config_container[iZone]); - - } - -} - -void CDiscAdjMeanFlowIteration::RegisterOutput(CSolver ****solver_container, CGeometry ***geometry_container, CConfig **config_container, unsigned short iZone){ - - /*--- Register objective function as output of the iteration ---*/ - - solver_container[iZone][MESH_0][ADJFLOW_SOL]->RegisterObj_Func(config_container[iZone]); - - /*--- Register conservative variables as output of the iteration ---*/ - - solver_container[iZone][MESH_0][ADJFLOW_SOL]->RegisterOutput(geometry_container[iZone][MESH_0],config_container[iZone]); - - if (turbulent){ - solver_container[iZone][MESH_0][ADJTURB_SOL]->RegisterOutput(geometry_container[iZone][MESH_0], - config_container[iZone]); - } -} - -void CDiscAdjMeanFlowIteration::InitializeAdjoint(CSolver ****solver_container, CGeometry ***geometry_container, CConfig **config_container, unsigned short iZone){ - - /*--- Initialize the adjoint of the objective function (typically with 1.0) ---*/ - - solver_container[iZone][MESH_0][ADJFLOW_SOL]->SetAdj_ObjFunc(geometry_container[iZone][MESH_0], config_container[iZone]); - - /*--- Initialize the adjoints the conservative variables ---*/ - - solver_container[iZone][MESH_0][ADJFLOW_SOL]->SetAdjoint_Output(geometry_container[iZone][MESH_0], - config_container[iZone]); - - if (turbulent){ - solver_container[iZone][MESH_0][ADJTURB_SOL]->SetAdjoint_Output(geometry_container[iZone][MESH_0], - config_container[iZone]); - } -} -void CDiscAdjMeanFlowIteration::Update(COutput *output, - CIntegration ***integration_container, - CGeometry ***geometry_container, - CSolver ****solver_container, - CNumerics *****numerics_container, - CConfig **config_container, - CSurfaceMovement **surface_movement, - CVolumetricMovement **grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone) { } -void CDiscAdjMeanFlowIteration::Monitor() { } -void CDiscAdjMeanFlowIteration::Output() { } -void CDiscAdjMeanFlowIteration::Postprocess() { } - -void FluidStructureIteration(COutput *output, CIntegration ***integration_container, CGeometry ***geometry_container, - CSolver ****solver_container, CNumerics *****numerics_container, CConfig **config_container, - CSurfaceMovement **surface_movement, CVolumetricMovement **grid_movement, CFreeFormDefBox*** FFDBox, - unsigned long iFluidIt, unsigned long nFluidIt) { - - su2double Physical_dt, Physical_t; - unsigned short iMesh; - unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); - unsigned long IntIter_Struct = 0; config_container[ZONE_1]->SetIntIter(IntIter_Struct); - unsigned long iFSIIter = 0; - unsigned long nFSIIter = config_container[ZONE_0]->GetnIterFSI(); - unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); - - unsigned short SolContainer_Position_fea = config_container[ZONE_1]->GetContainerPosition(RUNTIME_FEA_SYS); - - /*------------- Structural predictor for displacements ------------*/ - - /*--- Predict structural displacement --*/ - solver_container[ZONE_1][MESH_0][FEA_SOL]->PredictStruct_Displacement(geometry_container[ZONE_1], config_container[ZONE_1], - solver_container[ZONE_1]); - - - while (iFSIIterSetFlow_Displacement(geometry_container[ZONE_0], grid_movement[ZONE_0], - config_container[ZONE_0], config_container[ZONE_1], - geometry_container[ZONE_1], solver_container[ZONE_1]); - - /*---------------------- Fluid iteration --------------------------*/ - - /*--- Set the initial condition ---*/ - - solver_container[ZONE_0][MESH_0][FLOW_SOL]->SetInitialCondition(geometry_container[ZONE_0], solver_container[ZONE_0], config_container[ZONE_0], ExtIter); - - /*--- Apply a Wind Gust ---*/ - - if (config_container[ZONE_0]->GetWind_Gust()){ - //SetWind_GustField(config_container[ZONE_0],geometry_container[ZONE_0],solver_container[ZONE_0]); - } - - /*--- Set the value of the internal iteration ---*/ - - IntIter = ExtIter; - - if ((config_container[ZONE_0]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config_container[ZONE_0]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) IntIter = 0; - - /*--- Update global parameters ---*/ - - if (config_container[ZONE_0]->GetKind_Solver() == EULER){ - config_container[ZONE_0]->SetGlobalParam(EULER, RUNTIME_FLOW_SYS, ExtIter); - } - if (config_container[ZONE_0]->GetKind_Solver() == NAVIER_STOKES){ - config_container[ZONE_0]->SetGlobalParam(NAVIER_STOKES, RUNTIME_FLOW_SYS, ExtIter); - } - if (config_container[ZONE_0]->GetKind_Solver() == RANS){ - config_container[ZONE_0]->SetGlobalParam(RANS, RUNTIME_FLOW_SYS, ExtIter); - } - - /*--- Solve the Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes (RANS) equations (one iteration) ---*/ - - integration_container[ZONE_0][FLOW_SOL]->MultiGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_FLOW_SYS, IntIter, ZONE_0); - - if (config_container[ZONE_0]->GetKind_Solver() == RANS) { - - /*--- Solve the turbulence model ---*/ - - config_container[ZONE_0]->SetGlobalParam(RANS, RUNTIME_TURB_SYS, ExtIter); - integration_container[ZONE_0][TURB_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_TURB_SYS, IntIter, ZONE_0); - - /*--- Solve transition model ---*/ - - if (config_container[ZONE_0]->GetKind_Trans_Model() == LM) { - config_container[ZONE_0]->SetGlobalParam(RANS, RUNTIME_TRANS_SYS, ExtIter); - integration_container[ZONE_0][TRANS_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_TRANS_SYS, IntIter, ZONE_0); - } - - } - - /*--- Dual time stepping strategy ---*/ - - if ((config_container[ZONE_0]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config_container[ZONE_0]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { - - for(IntIter = 1; IntIter < config_container[ZONE_0]->GetUnst_nIntIter(); IntIter++) { - - /*--- Write the convergence history (only screen output) ---*/ - - output->SetConvHistory_Body(NULL, geometry_container, solver_container, config_container, integration_container, true, 0.0, ZONE_0); - - /*--- Set the value of the internal iteration ---*/ - - config_container[ZONE_0]->SetIntIter(IntIter); - - /*--- Pseudo-timestepping for the Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes equations ---*/ - - if (config_container[ZONE_0]->GetKind_Solver() == EULER) - config_container[ZONE_0]->SetGlobalParam(EULER, RUNTIME_FLOW_SYS, ExtIter); - if (config_container[ZONE_0]->GetKind_Solver() == NAVIER_STOKES) - config_container[ZONE_0]->SetGlobalParam(NAVIER_STOKES, RUNTIME_FLOW_SYS, ExtIter); - if (config_container[ZONE_0]->GetKind_Solver() == RANS) - config_container[ZONE_0]->SetGlobalParam(RANS, RUNTIME_FLOW_SYS, ExtIter); - - /*--- Solve the Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes (RANS) equations (one iteration) ---*/ - - integration_container[ZONE_0][FLOW_SOL]->MultiGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_FLOW_SYS, IntIter, ZONE_0); - - /*--- Pseudo-timestepping the turbulence model ---*/ - - if (config_container[ZONE_0]->GetKind_Solver() == RANS) { - - /*--- Solve the turbulence model ---*/ - - config_container[ZONE_0]->SetGlobalParam(RANS, RUNTIME_TURB_SYS, ExtIter); - integration_container[ZONE_0][TURB_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_TURB_SYS, IntIter, ZONE_0); - - /*--- Solve transition model ---*/ - - if (config_container[ZONE_0]->GetKind_Trans_Model() == LM) { - config_container[ZONE_0]->SetGlobalParam(RANS, RUNTIME_TRANS_SYS, ExtIter); - integration_container[ZONE_0][TRANS_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_TRANS_SYS, IntIter, ZONE_0); - } - } - - if (integration_container[ZONE_0][FLOW_SOL]->GetConvergence()) break; - - } - - } - - /*-------------------- Structural iteration -----------------------*/ - - /*--- Set the initial condition at the first iteration ---*/ - - // solver_container[ZONE_1][MESH_0][FEA_SOL]->SetInitialCondition(geometry_container[ZONE_1], solver_container[ZONE_1], config_container[ZONE_1], ExtIter); - - /*--- Set the value of the internal iteration ---*/ - - IntIter_Struct = ExtIter; - - /*--- FEA equations ---*/ - - config_container[ZONE_1]->SetGlobalParam(LINEAR_ELASTICITY, RUNTIME_FEA_SYS, ExtIter); - - /*--- Update loads for the FEA model ---*/ - - solver_container[ZONE_1][MESH_0][FEA_SOL]->SetFEA_Load(solver_container[ZONE_0], geometry_container[ZONE_1], geometry_container[ZONE_0], - config_container[ZONE_1], config_container[ZONE_0], numerics_container[ZONE_1][MESH_0][SolContainer_Position_fea][VISC_TERM]); - - /*--- Run the iteration ---*/ - - integration_container[ZONE_1][FEA_SOL]->Structural_Iteration(geometry_container, solver_container, numerics_container, - config_container, RUNTIME_FEA_SYS, IntIter_Struct, ZONE_1); - - /*-------------------- Aitken's relaxation ------------------------*/ - - solver_container[ZONE_1][MESH_0][FEA_SOL]->ComputeAitken_Coefficient(geometry_container[ZONE_1], config_container[ZONE_1], - solver_container[ZONE_1], iFSIIter); - - - solver_container[ZONE_1][MESH_0][FEA_SOL]->SetAitken_Relaxation(geometry_container[ZONE_1], config_container[ZONE_1], - solver_container[ZONE_1]); - - /*-------------------- Check convergence --------------------------*/ - - integration_container[ZONE_1][FEA_SOL]->Convergence_Monitoring_FSI(geometry_container[ZONE_1][MESH_0], config_container[ZONE_1], - solver_container[ZONE_1][MESH_0][FEA_SOL], iFSIIter); - - if (integration_container[ZONE_1][FEA_SOL]->GetConvergence_FSI()) break; - - /*--------------------- Update iFSIIter ---------------------------*/ - - iFSIIter++; - - } - - if ((config_container[ZONE_0]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config_container[ZONE_0]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { - - /*-------------------- Update fluid solver ------------------------*/ - - /*--- Update dual time solver on all mesh levels ---*/ - - for (iMesh = 0; iMesh <= config_container[ZONE_0]->GetnMGLevels(); iMesh++) { - integration_container[ZONE_0][FLOW_SOL]->SetDualTime_Solver(geometry_container[ZONE_0][iMesh], solver_container[ZONE_0][iMesh][FLOW_SOL], config_container[ZONE_0], iMesh); - integration_container[ZONE_0][FLOW_SOL]->SetConvergence(false); - } - - /*--- Update dual time solver for the turbulence model ---*/ - - if (config_container[ZONE_0]->GetKind_Solver() == RANS) { - integration_container[ZONE_0][TURB_SOL]->SetDualTime_Solver(geometry_container[ZONE_0][MESH_0], solver_container[ZONE_0][MESH_0][TURB_SOL], config_container[ZONE_0], MESH_0); - integration_container[ZONE_0][TURB_SOL]->SetConvergence(false); - } - - /*--- Update dual time solver for the transition model ---*/ - - if (config_container[ZONE_0]->GetKind_Trans_Model() == LM) { - integration_container[ZONE_0][TRANS_SOL]->SetDualTime_Solver(geometry_container[ZONE_0][MESH_0], solver_container[ZONE_0][MESH_0][TRANS_SOL], config_container[ZONE_0], MESH_0); - integration_container[ZONE_0][TRANS_SOL]->SetConvergence(false); - } - - /*--- Verify convergence criteria (based on total time) ---*/ - - Physical_dt = config_container[ZONE_0]->GetDelta_UnstTime(); - Physical_t = (ExtIter+1)*Physical_dt; - if (Physical_t >= config_container[ZONE_0]->GetTotal_UnstTime()) - integration_container[ZONE_0][FLOW_SOL]->SetConvergence(true); - - } - - /*----------------- Update structural solver ----------------------*/ - - integration_container[ZONE_1][FEA_SOL]->SetStructural_Solver(geometry_container[ZONE_1][MESH_0], solver_container[ZONE_1][MESH_0][FEA_SOL], config_container[ZONE_1], MESH_0); - - /*-----------------------------------------------------------------*/ - /*--------------- Update convergence parameter --------------------*/ - /*-----------------------------------------------------------------*/ - - integration_container[ZONE_1][FEA_SOL]->SetConvergence_FSI(false); - - -} - -void SetGrid_Movement(CGeometry **geometry_container, CSurfaceMovement *surface_movement, - CVolumetricMovement *grid_movement, CFreeFormDefBox **FFDBox, - CSolver ***solver_container, CConfig *config_container, - unsigned short iZone, unsigned long IntIter, unsigned long ExtIter) { - - unsigned short iDim, iMGlevel, nMGlevels = config_container->GetnMGLevels(); - unsigned short Kind_Grid_Movement = config_container->GetKind_GridMovement(iZone); - unsigned long iPoint; - bool adjoint = config_container->GetAdjoint(); - bool time_spectral = (config_container->GetUnsteady_Simulation() == TIME_SPECTRAL); - - /*--- For a time-spectral case, set "iteration number" to the zone number, - so that the meshes are positioned correctly for each instance. ---*/ - if (time_spectral) { - ExtIter = iZone; - Kind_Grid_Movement = config_container->GetKind_GridMovement(ZONE_0); - } - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Perform mesh movement depending on specified type ---*/ - switch (Kind_Grid_Movement) { - - case MOVING_WALL: - - /*--- Fixed wall velocities: set the grid velocities only one time - before the first iteration flow solver. ---*/ - - if (ExtIter == 0) { - - if (rank == MASTER_NODE) - cout << endl << " Setting the moving wall velocities." << endl; - - surface_movement->Moving_Walls(geometry_container[MESH_0], - config_container, iZone, ExtIter); - - /*--- Update the grid velocities on the coarser multigrid levels after - setting the moving wall velocities for the finest mesh. ---*/ - - grid_movement->UpdateMultiGrid(geometry_container, config_container); - - } - - break; - - - case ROTATING_FRAME: - - /*--- Steadily rotating frame: set the grid velocities just once - before the first iteration flow solver. ---*/ - - if (ExtIter == 0) { - - if (rank == MASTER_NODE) { - cout << endl << " Setting rotating frame grid velocities"; - cout << " for zone " << iZone << "." << endl; - } - - /*--- Set the grid velocities on all multigrid levels for a steadily - rotating reference frame. ---*/ - - for (iMGlevel = 0; iMGlevel <= nMGlevels; iMGlevel++) - geometry_container[iMGlevel]->SetRotationalVelocity(config_container, iZone); - - } - - break; - - case STEADY_TRANSLATION: - - /*--- Set the translational velocity and hold the grid fixed during - the calculation (similar to rotating frame, but there is no extra - source term for translation). ---*/ - - if (ExtIter == 0) { - - if (rank == MASTER_NODE) - cout << endl << " Setting translational grid velocities." << endl; - - /*--- Set the translational velocity on all grid levels. ---*/ - - for (iMGlevel = 0; iMGlevel <= nMGlevels; iMGlevel++) - geometry_container[iMGlevel]->SetTranslationalVelocity(config_container); - - } - - break; - - case RIGID_MOTION: - - if (rank == MASTER_NODE) { - cout << endl << " Performing rigid mesh transformation." << endl; - } - - /*--- Move each node in the volume mesh using the specified type - of rigid mesh motion. These routines also compute analytic grid - velocities for the fine mesh. ---*/ - - grid_movement->Rigid_Translation(geometry_container[MESH_0], - config_container, iZone, ExtIter); - grid_movement->Rigid_Plunging(geometry_container[MESH_0], - config_container, iZone, ExtIter); - grid_movement->Rigid_Pitching(geometry_container[MESH_0], - config_container, iZone, ExtIter); - grid_movement->Rigid_Rotation(geometry_container[MESH_0], - config_container, iZone, ExtIter); - - /*--- Update the multigrid structure after moving the finest grid, - including computing the grid velocities on the coarser levels. ---*/ - - grid_movement->UpdateMultiGrid(geometry_container, config_container); - - break; - - case DEFORMING: - - if (rank == MASTER_NODE) - cout << endl << " Updating surface positions." << endl; - - /*--- Translating ---*/ - - /*--- Compute the new node locations for moving markers ---*/ - - surface_movement->Surface_Translating(geometry_container[MESH_0], - config_container, ExtIter, iZone); - /*--- Deform the volume grid around the new boundary locations ---*/ - - if (rank == MASTER_NODE) - cout << " Deforming the volume grid." << endl; - grid_movement->SetVolume_Deformation(geometry_container[MESH_0], - config_container, true); - - /*--- Plunging ---*/ - - /*--- Compute the new node locations for moving markers ---*/ - - surface_movement->Surface_Plunging(geometry_container[MESH_0], - config_container, ExtIter, iZone); - /*--- Deform the volume grid around the new boundary locations ---*/ - - if (rank == MASTER_NODE) - cout << " Deforming the volume grid." << endl; - grid_movement->SetVolume_Deformation(geometry_container[MESH_0], - config_container, true); - - /*--- Pitching ---*/ - - /*--- Compute the new node locations for moving markers ---*/ - - surface_movement->Surface_Pitching(geometry_container[MESH_0], - config_container, ExtIter, iZone); - /*--- Deform the volume grid around the new boundary locations ---*/ - - if (rank == MASTER_NODE) - cout << " Deforming the volume grid." << endl; - grid_movement->SetVolume_Deformation(geometry_container[MESH_0], - config_container, true); - - /*--- Rotating ---*/ - - /*--- Compute the new node locations for moving markers ---*/ - - surface_movement->Surface_Rotating(geometry_container[MESH_0], - config_container, ExtIter, iZone); - /*--- Deform the volume grid around the new boundary locations ---*/ - - if (rank == MASTER_NODE) - cout << " Deforming the volume grid." << endl; - grid_movement->SetVolume_Deformation(geometry_container[MESH_0], - config_container, true); - - /*--- Update the grid velocities on the fine mesh using finite - differencing based on node coordinates at previous times. ---*/ - - if (!adjoint) { - if (rank == MASTER_NODE) - cout << " Computing grid velocities by finite differencing." << endl; - geometry_container[MESH_0]->SetGridVelocity(config_container, ExtIter); - } - - /*--- Update the multigrid structure after moving the finest grid, - including computing the grid velocities on the coarser levels. ---*/ - - grid_movement->UpdateMultiGrid(geometry_container, config_container); - - break; - - case EXTERNAL: case EXTERNAL_ROTATION: - - /*--- Apply rigid rotation to entire grid first, if necessary ---*/ - - if (Kind_Grid_Movement == EXTERNAL_ROTATION) { - if (rank == MASTER_NODE) - cout << " Updating node locations by rigid rotation." << endl; - grid_movement->Rigid_Rotation(geometry_container[MESH_0], - config_container, iZone, ExtIter); - } - - /*--- Load new surface node locations from external files ---*/ - - if (rank == MASTER_NODE) - cout << " Updating surface locations from file." << endl; - surface_movement->SetExternal_Deformation(geometry_container[MESH_0], - config_container, iZone, ExtIter); - - /*--- Deform the volume grid around the new boundary locations ---*/ - - if (rank == MASTER_NODE) - cout << " Deforming the volume grid." << endl; - grid_movement->SetVolume_Deformation(geometry_container[MESH_0], - config_container, true); - - /*--- Update the grid velocities on the fine mesh using finite - differencing based on node coordinates at previous times. ---*/ - - if (!adjoint) { - if (rank == MASTER_NODE) - cout << " Computing grid velocities by finite differencing." << endl; - geometry_container[MESH_0]->SetGridVelocity(config_container, ExtIter); - } - - /*--- Update the multigrid structure after moving the finest grid, - including computing the grid velocities on the coarser levels. ---*/ - - grid_movement->UpdateMultiGrid(geometry_container, config_container); - - break; - - case AEROELASTIC: case AEROELASTIC_RIGID_MOTION: - - /*--- Apply rigid mesh transformation to entire grid first, if necessary ---*/ - if (IntIter == 0) { - if (Kind_Grid_Movement == AEROELASTIC_RIGID_MOTION) { - - if (rank == MASTER_NODE) { - cout << endl << " Performing rigid mesh transformation." << endl; - } - - /*--- Move each node in the volume mesh using the specified type - of rigid mesh motion. These routines also compute analytic grid - velocities for the fine mesh. ---*/ - - grid_movement->Rigid_Translation(geometry_container[MESH_0], - config_container, iZone, ExtIter); - grid_movement->Rigid_Plunging(geometry_container[MESH_0], - config_container, iZone, ExtIter); - grid_movement->Rigid_Pitching(geometry_container[MESH_0], - config_container, iZone, ExtIter); - grid_movement->Rigid_Rotation(geometry_container[MESH_0], - config_container, iZone, ExtIter); - - /*--- Update the multigrid structure after moving the finest grid, - including computing the grid velocities on the coarser levels. ---*/ - - grid_movement->UpdateMultiGrid(geometry_container, config_container); - } - - } - - /*--- Use the if statement to move the grid only at selected dual time step iterations. ---*/ - else if (IntIter % config_container->GetAeroelasticIter() ==0) { - - if (rank == MASTER_NODE) - cout << endl << " Solving aeroelastic equations and updating surface positions." << endl; - - /*--- Solve the aeroelastic equations for the new node locations of the moving markers(surfaces) ---*/ - - solver_container[MESH_0][FLOW_SOL]->Aeroelastic(surface_movement, geometry_container[MESH_0], config_container, ExtIter); - - /*--- Deform the volume grid around the new boundary locations ---*/ - - if (rank == MASTER_NODE) - cout << " Deforming the volume grid due to the aeroelastic movement." << endl; - grid_movement->SetVolume_Deformation(geometry_container[MESH_0], - config_container, true); - - /*--- Update the grid velocities on the fine mesh using finite - differencing based on node coordinates at previous times. ---*/ - - if (rank == MASTER_NODE) - cout << " Computing grid velocities by finite differencing." << endl; - geometry_container[MESH_0]->SetGridVelocity(config_container, ExtIter); - - /*--- Update the multigrid structure after moving the finest grid, - including computing the grid velocities on the coarser levels. ---*/ - - grid_movement->UpdateMultiGrid(geometry_container, config_container); - } - - break; - - case ELASTICITY: - - if (ExtIter != 0) { - - if (rank == MASTER_NODE) - cout << " Deforming the grid using the Linear Elasticity solution." << endl; - - /*--- Update the coordinates of the grid using the linear elasticity solution. ---*/ - for (iPoint = 0; iPoint < geometry_container[MESH_0]->GetnPoint(); iPoint++) { - - su2double *U_time_nM1 = solver_container[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_time_n1(); - su2double *U_time_n = solver_container[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_time_n(); - - for (iDim = 0; iDim < geometry_container[MESH_0]->GetnDim(); iDim++) - geometry_container[MESH_0]->node[iPoint]->AddCoord(iDim, U_time_n[iDim] - U_time_nM1[iDim]); - - } - - } - - break; - - case NO_MOVEMENT: case GUST: default: - - /*--- There is no mesh motion specified for this zone. ---*/ - if (rank == MASTER_NODE) - cout << "No mesh motion specified." << endl; - - break; - } - -} +/*! + * \file iteration_structure.cpp + * \brief Main subroutines used by SU2_CFD + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/iteration_structure.hpp" + +CIteration::CIteration(CConfig *config) { } +CIteration::~CIteration(void) { } + +void CIteration::Preprocess(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { } +void CIteration::Iterate(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { } +void CIteration::Update(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { } +void CIteration::Monitor() { } +void CIteration::Output() { } +void CIteration::Postprocess() { } + + + +CMeanFlowIteration::CMeanFlowIteration(CConfig *config) : CIteration(config) { } +CMeanFlowIteration::~CMeanFlowIteration(void) { } + +void CMeanFlowIteration::Preprocess(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { + + unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); + unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); + + bool time_spectral = (config_container[ZONE_0]->GetUnsteady_Simulation() == TIME_SPECTRAL); + + /*--- Set the initial condition ---*/ + + solver_container[val_iZone][MESH_0][FLOW_SOL]->SetInitialCondition(geometry_container[val_iZone], solver_container[val_iZone], config_container[val_iZone], ExtIter); + + /*--- Dynamic mesh update ---*/ + + if ((config_container[val_iZone]->GetGrid_Movement()) && (!time_spectral)) { + SetGrid_Movement(geometry_container[val_iZone], surface_movement[val_iZone], grid_movement[val_iZone], FFDBox[val_iZone], solver_container[val_iZone], config_container[val_iZone], val_iZone, IntIter, ExtIter); + } + + /*--- Apply a Wind Gust ---*/ + + if (config_container[ZONE_0]->GetWind_Gust()) { + SetWind_GustField(config_container[val_iZone], geometry_container[val_iZone], solver_container[val_iZone]); + } + + + /*--- Calculate and set Mixing Plane averaged quantities at interfaces ---*/ + + if(config_container[val_iZone]->GetBoolMixingPlane()) + SetMixingPlane(geometry_container, solver_container, config_container, val_iZone); + + /*--- Compute turboperformance ---*/ + + if(config_container[val_iZone]->GetBoolTurboPerf()) + SetTurboPerformance(geometry_container, solver_container, config_container, output, val_iZone); +} + + + + +void CMeanFlowIteration::Iterate(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { + + unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); + unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); +#ifdef HAVE_MPI + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Set the value of the internal iteration ---*/ + + IntIter = ExtIter; + if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) IntIter = 0; + + /*--- Update global parameters ---*/ + + if ((config_container[val_iZone]->GetKind_Solver() == EULER) || + (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_EULER)) { + config_container[val_iZone]->SetGlobalParam(EULER, RUNTIME_FLOW_SYS, ExtIter); + } + if ((config_container[val_iZone]->GetKind_Solver() == NAVIER_STOKES) || + (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_NAVIER_STOKES)) { + config_container[val_iZone]->SetGlobalParam(NAVIER_STOKES, RUNTIME_FLOW_SYS, ExtIter); + } + if ((config_container[val_iZone]->GetKind_Solver() == RANS) || + (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_RANS)) { + config_container[val_iZone]->SetGlobalParam(RANS, RUNTIME_FLOW_SYS, ExtIter); + } + + /*--- Solve the Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes (RANS) equations (one iteration) ---*/ + + integration_container[val_iZone][FLOW_SOL]->MultiGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_FLOW_SYS, IntIter, val_iZone); + + if ((config_container[val_iZone]->GetKind_Solver() == RANS) || + (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_RANS)) { + + /*--- Solve the turbulence model ---*/ + + config_container[val_iZone]->SetGlobalParam(RANS, RUNTIME_TURB_SYS, ExtIter); + integration_container[val_iZone][TURB_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_TURB_SYS, IntIter, val_iZone); + + /*--- Solve transition model ---*/ + + if (config_container[val_iZone]->GetKind_Trans_Model() == LM) { + config_container[val_iZone]->SetGlobalParam(RANS, RUNTIME_TRANS_SYS, ExtIter); + integration_container[val_iZone][TRANS_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_TRANS_SYS, IntIter, val_iZone); + } + + } + + /*--- Dual time stepping strategy ---*/ + + if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { + + for (IntIter = 1; IntIter < config_container[val_iZone]->GetUnst_nIntIter(); IntIter++) { + + /*--- Write the convergence history (only screen output) ---*/ + + output->SetConvHistory_Body(NULL, geometry_container, solver_container, config_container, integration_container, true, 0.0, val_iZone); + + /*--- Set the value of the internal iteration ---*/ + + config_container[val_iZone]->SetIntIter(IntIter); + + /*--- Pseudo-timestepping for the Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes equations ---*/ + + if ((config_container[val_iZone]->GetKind_Solver() == EULER) || + (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_EULER)) { + config_container[val_iZone]->SetGlobalParam(EULER, RUNTIME_FLOW_SYS, ExtIter); + } + if ((config_container[val_iZone]->GetKind_Solver() == NAVIER_STOKES) || + (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_NAVIER_STOKES)) { + config_container[val_iZone]->SetGlobalParam(NAVIER_STOKES, RUNTIME_FLOW_SYS, ExtIter); + } + if ((config_container[val_iZone]->GetKind_Solver() == RANS) || + (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_RANS)) { + config_container[val_iZone]->SetGlobalParam(RANS, RUNTIME_FLOW_SYS, ExtIter); + } + + /*--- Solve the Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes (RANS) equations (one iteration) ---*/ + + integration_container[val_iZone][FLOW_SOL]->MultiGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_FLOW_SYS, IntIter, val_iZone); + + /*--- Pseudo-timestepping the turbulence model ---*/ + + if ((config_container[val_iZone]->GetKind_Solver() == RANS) || + (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_RANS)) { + + /*--- Solve the turbulence model ---*/ + + config_container[val_iZone]->SetGlobalParam(RANS, RUNTIME_TURB_SYS, ExtIter); + integration_container[val_iZone][TURB_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_TURB_SYS, IntIter, val_iZone); + + /*--- Solve transition model ---*/ + + if (config_container[val_iZone]->GetKind_Trans_Model() == LM) { + config_container[val_iZone]->SetGlobalParam(RANS, RUNTIME_TRANS_SYS, ExtIter); + integration_container[val_iZone][TRANS_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_TRANS_SYS, IntIter, val_iZone); + } + + } + + /*--- Call Dynamic mesh update if AEROELASTIC motion was specified ---*/ + if ((config_container[val_iZone]->GetGrid_Movement()) && (config_container[val_iZone]->GetAeroelastic_Simulation())) { + SetGrid_Movement(geometry_container[val_iZone], surface_movement[val_iZone], grid_movement[val_iZone], FFDBox[val_iZone], + solver_container[val_iZone], config_container[val_iZone], val_iZone, IntIter, ExtIter); + /*--- Apply a Wind Gust ---*/ + if (config_container[val_iZone]->GetWind_Gust()) { + if (IntIter % config_container[val_iZone]->GetAeroelasticIter() ==0) + SetWind_GustField(config_container[val_iZone], geometry_container[val_iZone], solver_container[val_iZone]); + } + } + + if (integration_container[val_iZone][FLOW_SOL]->GetConvergence()) break; + + } + + } + +} + +void CMeanFlowIteration::Update(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { + + unsigned short iMesh; + su2double Physical_dt, Physical_t; + unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); + + /*--- Dual time stepping strategy ---*/ + + if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { + + /*--- Update dual time solver on all mesh levels ---*/ + + for (iMesh = 0; iMesh <= config_container[val_iZone]->GetnMGLevels(); iMesh++) { + integration_container[val_iZone][FLOW_SOL]->SetDualTime_Solver(geometry_container[val_iZone][iMesh], solver_container[val_iZone][iMesh][FLOW_SOL], config_container[val_iZone], iMesh); + integration_container[val_iZone][FLOW_SOL]->SetConvergence(false); + } + + /*--- Update dual time solver for the turbulence model ---*/ + + if ((config_container[val_iZone]->GetKind_Solver() == RANS) || + (config_container[val_iZone]->GetKind_Solver() == DISC_ADJ_RANS)) { + integration_container[val_iZone][TURB_SOL]->SetDualTime_Solver(geometry_container[val_iZone][MESH_0], solver_container[val_iZone][MESH_0][TURB_SOL], config_container[val_iZone], MESH_0); + integration_container[val_iZone][TURB_SOL]->SetConvergence(false); + } + + /*--- Update dual time solver for the transition model ---*/ + + if (config_container[val_iZone]->GetKind_Trans_Model() == LM) { + integration_container[val_iZone][TRANS_SOL]->SetDualTime_Solver(geometry_container[val_iZone][MESH_0], solver_container[val_iZone][MESH_0][TRANS_SOL], config_container[val_iZone], MESH_0); + integration_container[val_iZone][TRANS_SOL]->SetConvergence(false); + } + + /*--- Verify convergence criteria (based on total time) ---*/ + + Physical_dt = config_container[val_iZone]->GetDelta_UnstTime(); + Physical_t = (ExtIter+1)*Physical_dt; + if (Physical_t >= config_container[val_iZone]->GetTotal_UnstTime()) + integration_container[val_iZone][FLOW_SOL]->SetConvergence(true); + + } + +} + +void CMeanFlowIteration::Monitor() { } +void CMeanFlowIteration::Output() { } +void CMeanFlowIteration::Postprocess() { } + +void CMeanFlowIteration::SetWind_GustField(CConfig *config_container, CGeometry **geometry_container, CSolver ***solver_container) { + // The gust is imposed on the flow field via the grid velocities. This method called the Field Velocity Method is described in the + // NASA TM–2012-217771 - Development, Verification and Use of Gust Modeling in the NASA Computational Fluid Dynamics Code FUN3D + // the desired gust is prescribed as the negative of the grid velocity. + + // If a source term is included to account for the gust field, the method is described by Jones et al. as the Split Velocity Method in + // Simulation of Airfoil Gust Responses Using Prescribed Velocities. + // In this routine the gust derivatives needed for the source term are calculated when applicable. + // If the gust derivatives are zero the source term is also zero. + // The source term itself is implemented in the class CSourceWindGust + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + if (rank == MASTER_NODE) + cout << endl << "Running simulation with a Wind Gust." << endl; + unsigned short iDim, nDim = geometry_container[MESH_0]->GetnDim(); //We assume nDim = 2 + if (nDim != 2) { + if (rank == MASTER_NODE) { + cout << endl << "WARNING - Wind Gust capability is only verified for 2 dimensional simulations." << endl; + } + } + + /*--- Gust Parameters from config ---*/ + unsigned short Gust_Type = config_container->GetGust_Type(); + su2double xbegin = config_container->GetGust_Begin_Loc(); // Location at which the gust begins. + su2double L = config_container->GetGust_WaveLength(); // Gust size + su2double tbegin = config_container->GetGust_Begin_Time(); // Physical time at which the gust begins. + su2double gust_amp = config_container->GetGust_Ampl(); // Gust amplitude + su2double n = config_container->GetGust_Periods(); // Number of gust periods + unsigned short GustDir = config_container->GetGust_Dir(); // Gust direction + + /*--- Variables needed to compute the gust ---*/ + unsigned short Kind_Grid_Movement = config_container->GetKind_GridMovement(ZONE_0); + unsigned long iPoint; + unsigned short iMGlevel, nMGlevel = config_container->GetnMGLevels(); + + su2double x, y, x_gust, dgust_dx, dgust_dy, dgust_dt; + su2double *Gust, *GridVel, *NewGridVel, *GustDer; + + su2double Physical_dt = config_container->GetDelta_UnstTime(); + unsigned long ExtIter = config_container->GetExtIter(); + su2double Physical_t = ExtIter*Physical_dt; + + su2double Uinf = solver_container[MESH_0][FLOW_SOL]->GetVelocity_Inf(0); // Assumption gust moves at infinity velocity + + Gust = new su2double [nDim]; + NewGridVel = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) { + Gust[iDim] = 0.0; + NewGridVel[iDim] = 0.0; + } + + GustDer = new su2double [3]; + for (unsigned short i = 0; i < 3; i++) { + GustDer[i] = 0.0; + } + + // Vortex variables + unsigned long nVortex = 0; + vector x0, y0, vort_strenth, r_core; //vortex is positive in clockwise direction. + if (Gust_Type == VORTEX) { + InitializeVortexDistribution(nVortex, x0, y0, vort_strenth, r_core); + } + + /*--- Check to make sure gust lenght is not zero or negative (vortex gust doesn't use this). ---*/ + if (L <= 0.0 && Gust_Type != VORTEX) { + if (rank == MASTER_NODE) cout << "ERROR: The gust length needs to be positive" << endl; +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + } + + /*--- Loop over all multigrid levels ---*/ + + for (iMGlevel = 0; iMGlevel <= nMGlevel; iMGlevel++) { + + /*--- Loop over each node in the volume mesh ---*/ + + for (iPoint = 0; iPoint < geometry_container[iMGlevel]->GetnPoint(); iPoint++) { + + /*--- Reset the Grid Velocity to zero if there is no grid movement ---*/ + if (Kind_Grid_Movement == GUST) { + for (iDim = 0; iDim < nDim; iDim++) + geometry_container[iMGlevel]->node[iPoint]->SetGridVel(iDim, 0.0); + } + + /*--- initialize the gust and derivatives to zero everywhere ---*/ + + for (iDim = 0; iDim < nDim; iDim++) {Gust[iDim]=0.0;} + dgust_dx = 0.0; dgust_dy = 0.0; dgust_dt = 0.0; + + /*--- Begin applying the gust ---*/ + + if (Physical_t >= tbegin) { + + x = geometry_container[iMGlevel]->node[iPoint]->GetCoord()[0]; // x-location of the node. + y = geometry_container[iMGlevel]->node[iPoint]->GetCoord()[1]; // y-location of the node. + + // Gust coordinate + x_gust = (x - xbegin - Uinf*(Physical_t-tbegin))/L; + + /*--- Calculate the specified gust ---*/ + switch (Gust_Type) { + + case TOP_HAT: + // Check if we are in the region where the gust is active + if (x_gust > 0 && x_gust < n) { + Gust[GustDir] = gust_amp; + // Still need to put the gust derivatives. Think about this. + } + break; + + case SINE: + // Check if we are in the region where the gust is active + if (x_gust > 0 && x_gust < n) { + Gust[GustDir] = gust_amp*(sin(2*PI_NUMBER*x_gust)); + + // Gust derivatives + //dgust_dx = gust_amp*2*PI_NUMBER*(cos(2*PI_NUMBER*x_gust))/L; + //dgust_dy = 0; + //dgust_dt = gust_amp*2*PI_NUMBER*(cos(2*PI_NUMBER*x_gust))*(-Uinf)/L; + } + break; + + case ONE_M_COSINE: + // Check if we are in the region where the gust is active + if (x_gust > 0 && x_gust < n) { + Gust[GustDir] = gust_amp*(1-cos(2*PI_NUMBER*x_gust)); + + // Gust derivatives + //dgust_dx = gust_amp*2*PI_NUMBER*(sin(2*PI_NUMBER*x_gust))/L; + //dgust_dy = 0; + //dgust_dt = gust_amp*2*PI_NUMBER*(sin(2*PI_NUMBER*x_gust))*(-Uinf)/L; + } + break; + + case EOG: + // Check if we are in the region where the gust is active + if (x_gust > 0 && x_gust < n) { + Gust[GustDir] = -0.37*gust_amp*sin(3*PI_NUMBER*x_gust)*(1-cos(2*PI_NUMBER*x_gust)); + } + break; + + case VORTEX: + + /*--- Use vortex distribution ---*/ + // Algebraic vortex equation. + for (unsigned long i=0; inode[iPoint]->SetWindGust(Gust); + solver_container[iMGlevel][FLOW_SOL]->node[iPoint]->SetWindGustDer(GustDer); + + GridVel = geometry_container[iMGlevel]->node[iPoint]->GetGridVel(); + + /*--- Store new grid velocity ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + NewGridVel[iDim] = GridVel[iDim] - Gust[iDim]; + geometry_container[iMGlevel]->node[iPoint]->SetGridVel(iDim, NewGridVel[iDim]); + } + + } + } + + delete [] Gust; + delete [] GustDer; + delete [] NewGridVel; + +} + +void CMeanFlowIteration::InitializeVortexDistribution(unsigned long &nVortex, vector& x0, vector& y0, vector& vort_strength, vector& r_core) { + /*--- Read in Vortex Distribution ---*/ + std::string line; + std::ifstream file; + su2double x_temp, y_temp, vort_strength_temp, r_core_temp; + file.open("vortex_distribution.txt"); + /*--- In case there is no vortex file ---*/ + if (file.fail()) { + cout << "There is no vortex data file!!" << endl; + cout << "Press any key to exit..." << endl; + cin.get(); exit(EXIT_FAILURE); + } + + // Ignore line containing the header + getline(file, line); + // Read in the information of the vortices (xloc, yloc, lambda(strength), eta(size, gradient)) + while (file.good()) + { + getline(file, line); + std::stringstream ss(line); + if (line.size() != 0) { //ignore blank lines if they exist. + ss >> x_temp; + ss >> y_temp; + ss >> vort_strength_temp; + ss >> r_core_temp; + x0.push_back(x_temp); + y0.push_back(y_temp); + vort_strength.push_back(vort_strength_temp); + r_core.push_back(r_core_temp); + } + } + file.close(); + // number of vortices + nVortex = x0.size(); + +} + +void CMeanFlowIteration::SetMixingPlane(CGeometry ***geometry_container, CSolver ****solver_container, CConfig **config_container, unsigned short iZone) { + + unsigned short jZone; + unsigned short nZone = geometry_container[ZONE_0][MESH_0]->GetnZone(); + int intMarker, extMarker, intMarkerMix; + string intMarker_Tag, extMarker_Tag; + + /*-- Loop on all the boundary to find MIXING_PLANE boundary --*/ + for (intMarker = 0; intMarker < config_container[iZone]->GetnMarker_All(); intMarker++) { + for (intMarkerMix=0; intMarkerMix < config_container[iZone]->Get_nMarkerMixingPlane(); intMarkerMix++) + if (config_container[iZone]->GetMarker_All_TagBound(intMarker) == config_container[iZone]->GetMarker_MixingPlane_Bound(intMarkerMix) ) { + solver_container[iZone][MESH_0][FLOW_SOL]->Mixing_Process(geometry_container[iZone][MESH_0], solver_container[iZone][MESH_0], config_container[iZone], intMarker); + extMarker_Tag = config_container[iZone]->GetMarker_MixingPlane_Donor(intMarkerMix); + for (jZone = 0; jZone < nZone; jZone++){ + for (extMarker = 0; extMarker < config_container[jZone]->GetnMarker_All(); extMarker++) + if (config_container[jZone]->GetMarker_All_TagBound(extMarker) == extMarker_Tag){ + solver_container[jZone][MESH_0][FLOW_SOL]->SetExtAveragedValue(solver_container[iZone][MESH_0][FLOW_SOL], intMarker, extMarker); + } + } + + } + + } + +} + +void CMeanFlowIteration::SetTurboPerformance(CGeometry ***geometry_container, CSolver ****solver_container, CConfig **config_container, COutput *output, unsigned short iZone) { + + unsigned short jZone, inMarker, outMarker, inMarkerTP, Kind_TurboPerf; + unsigned short nZone = geometry_container[iZone][MESH_0]->GetnZone(); + string inMarker_Tag, outMarker_Tag; + + + /*-- Loop on all the boundary to find MIXING_PLANE boundary --*/ + for (inMarker = 0; inMarker < config_container[iZone]->GetnMarker_All(); inMarker++) + for (inMarkerTP=0; inMarkerTP < config_container[iZone]->Get_nMarkerTurboPerf(); inMarkerTP++) + if (config_container[iZone]->GetMarker_All_TagBound(inMarker) == config_container[iZone]->GetMarker_TurboPerf_BoundIn(inMarkerTP) ) { + outMarker_Tag = config_container[iZone]->GetMarker_TurboPerf_BoundOut(inMarkerTP); + Kind_TurboPerf = config_container[iZone]->GetKind_TurboPerf(inMarkerTP); + for (jZone = 0; jZone < nZone; jZone++) + for (outMarker = 0; outMarker < config_container[jZone]->GetnMarker_All(); outMarker++) + if (config_container[jZone]->GetMarker_All_TagBound(outMarker) == outMarker_Tag){ + solver_container[iZone][MESH_0][FLOW_SOL]->Mixing_Process(geometry_container[iZone][MESH_0], solver_container[iZone][MESH_0], config_container[iZone], inMarker); + solver_container[jZone][MESH_0][FLOW_SOL]->Mixing_Process(geometry_container[jZone][MESH_0], solver_container[jZone][MESH_0], config_container[jZone], outMarker); + solver_container[iZone][MESH_0][FLOW_SOL]->TurboPerformance(solver_container[jZone][MESH_0][FLOW_SOL], config_container[iZone], inMarker, outMarker, Kind_TurboPerf, inMarkerTP); + solver_container[ZONE_0][MESH_0][FLOW_SOL]->StoreTurboPerformance(solver_container[iZone][MESH_0][FLOW_SOL], inMarkerTP); + } + } +} + + +CWaveIteration::CWaveIteration(CConfig *config) : CIteration(config) { } +CWaveIteration::~CWaveIteration(void) { } +void CWaveIteration::Preprocess(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { } +void CWaveIteration::Iterate(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { + + unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); + unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); + + /*--- Set the value of the internal iteration ---*/ + IntIter = ExtIter; + if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) IntIter = 0; + + /*--- Wave equations ---*/ + config_container[val_iZone]->SetGlobalParam(WAVE_EQUATION, RUNTIME_WAVE_SYS, ExtIter); + integration_container[val_iZone][WAVE_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_WAVE_SYS, IntIter, val_iZone); + + /*--- Dual time stepping strategy ---*/ + if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { + + for (IntIter = 1; IntIter < config_container[val_iZone]->GetUnst_nIntIter(); IntIter++) { + output->SetConvHistory_Body(NULL, geometry_container, solver_container, config_container, integration_container, true, 0.0, val_iZone); + config_container[val_iZone]->SetIntIter(IntIter); + integration_container[val_iZone][WAVE_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_WAVE_SYS, IntIter, val_iZone); + if (integration_container[val_iZone][WAVE_SOL]->GetConvergence()) break; + } + + } + +} +void CWaveIteration::Update(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { + + unsigned short iMesh; + su2double Physical_dt, Physical_t; + unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); + + /*--- Dual time stepping strategy ---*/ + if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { + + /*--- Update dual time solver ---*/ + for (iMesh = 0; iMesh <= config_container[val_iZone]->GetnMGLevels(); iMesh++) { + integration_container[val_iZone][WAVE_SOL]->SetDualTime_Solver(geometry_container[val_iZone][iMesh], solver_container[val_iZone][iMesh][WAVE_SOL], config_container[val_iZone], iMesh); + integration_container[val_iZone][WAVE_SOL]->SetConvergence(false); + } + + Physical_dt = config_container[val_iZone]->GetDelta_UnstTime(); Physical_t = (ExtIter+1)*Physical_dt; + if (Physical_t >= config_container[val_iZone]->GetTotal_UnstTime()) integration_container[val_iZone][WAVE_SOL]->SetConvergence(true); + } +} + +void CWaveIteration::Monitor() { } +void CWaveIteration::Output() { } +void CWaveIteration::Postprocess() { } + + +CHeatIteration::CHeatIteration(CConfig *config) : CIteration(config) { } +CHeatIteration::~CHeatIteration(void) { } +void CHeatIteration::Preprocess(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { } +void CHeatIteration::Iterate(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone){ + + unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); + unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); + + /*--- Set the value of the internal iteration ---*/ + IntIter = ExtIter; + if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) IntIter = 0; + + /*--- Heat equation ---*/ + config_container[val_iZone]->SetGlobalParam(HEAT_EQUATION, RUNTIME_HEAT_SYS, ExtIter); + integration_container[val_iZone][HEAT_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_HEAT_SYS, IntIter, val_iZone); + + /*--- Dual time stepping strategy ---*/ + if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { + + for (IntIter = 1; IntIter < config_container[val_iZone]->GetUnst_nIntIter(); IntIter++) { + output->SetConvHistory_Body(NULL, geometry_container, solver_container, config_container, integration_container, true, 0.0, val_iZone); + config_container[val_iZone]->SetIntIter(IntIter); + integration_container[val_iZone][HEAT_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_HEAT_SYS, IntIter, val_iZone); + if (integration_container[val_iZone][HEAT_SOL]->GetConvergence()) break; + } + } +} + +void CHeatIteration::Update(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { + + unsigned short iMesh; + su2double Physical_dt, Physical_t; + unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); + + /*--- Dual time stepping strategy ---*/ + if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { + + /*--- Update dual time solver ---*/ + for (iMesh = 0; iMesh <= config_container[val_iZone]->GetnMGLevels(); iMesh++) { + integration_container[val_iZone][HEAT_SOL]->SetDualTime_Solver(geometry_container[val_iZone][iMesh], solver_container[val_iZone][iMesh][HEAT_SOL], config_container[val_iZone], iMesh); + integration_container[val_iZone][HEAT_SOL]->SetConvergence(false); + } + + Physical_dt = config_container[val_iZone]->GetDelta_UnstTime(); Physical_t = (ExtIter+1)*Physical_dt; + if (Physical_t >= config_container[val_iZone]->GetTotal_UnstTime()) integration_container[val_iZone][HEAT_SOL]->SetConvergence(true); + } +} +void CHeatIteration::Monitor() { } +void CHeatIteration::Output() { } +void CHeatIteration::Postprocess() { } + + +CPoissonIteration::CPoissonIteration(CConfig *config) : CIteration(config) { } +CPoissonIteration::~CPoissonIteration(void) { } +void CPoissonIteration::Preprocess(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { } +void CPoissonIteration::Iterate(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { + + unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); + unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); + + /*--- Set the value of the internal iteration ---*/ + IntIter = ExtIter; + if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) IntIter = 0; + + /*--- Poisson equation ---*/ + config_container[val_iZone]->SetGlobalParam(POISSON_EQUATION, RUNTIME_POISSON_SYS, ExtIter); + integration_container[val_iZone][POISSON_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_POISSON_SYS, IntIter, val_iZone); + + +} +void CPoissonIteration::Update(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { } +void CPoissonIteration::Monitor() { } +void CPoissonIteration::Output() { } +void CPoissonIteration::Postprocess() { } + + +CFEAIteration::CFEAIteration(CConfig *config) : CIteration(config) { } +CFEAIteration::~CFEAIteration(void) { } +void CFEAIteration::Preprocess(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { + + unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); + unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); + + if (config_container[val_iZone]->GetGrid_Movement()) + SetGrid_Movement(geometry_container[val_iZone], surface_movement[val_iZone], + grid_movement[val_iZone], FFDBox[val_iZone], solver_container[val_iZone], config_container[val_iZone], val_iZone, IntIter, ExtIter); + + /*--- Set the initial condition at the first iteration ---*/ + + solver_container[val_iZone][MESH_0][FEA_SOL]->SetInitialCondition(geometry_container[val_iZone], solver_container[val_iZone], config_container[val_iZone], ExtIter); + +} +void CFEAIteration::Iterate(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { + + unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); + unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); + + /*--- Set the value of the internal iteration ---*/ + + IntIter = ExtIter; + + /*--- FEA equations ---*/ + + config_container[val_iZone]->SetGlobalParam(LINEAR_ELASTICITY, RUNTIME_FEA_SYS, ExtIter); + + /*--- Run the iteration ---*/ + + integration_container[val_iZone][FEA_SOL]->Structural_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_FEA_SYS, IntIter, val_iZone); + + +} +void CFEAIteration::Update(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { + + /*----------------- Update structural solver ----------------------*/ + + bool dynamic = (config_container[val_iZone]->GetDynamic_Analysis() == DYNAMIC); + + if (dynamic){ + integration_container[val_iZone][FEA_SOL]->SetStructural_Solver(geometry_container[val_iZone][MESH_0], solver_container[val_iZone][MESH_0][FEA_SOL], config_container[val_iZone], MESH_0); + } + +} +void CFEAIteration::Monitor() { } +void CFEAIteration::Output() { } +void CFEAIteration::Postprocess() { } + + +CAdjMeanFlowIteration::CAdjMeanFlowIteration(CConfig *config) : CIteration(config) { } +CAdjMeanFlowIteration::~CAdjMeanFlowIteration(void) { } +void CAdjMeanFlowIteration::Preprocess(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { + + unsigned short iMesh; + bool time_spectral = (config_container[ZONE_0]->GetUnsteady_Simulation() == TIME_SPECTRAL); + bool dynamic_mesh = config_container[ZONE_0]->GetGrid_Movement(); + unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); + unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- For the unsteady adjoint, load a new direct solution from a restart file. ---*/ + + if (((dynamic_mesh && ExtIter == 0) || config_container[val_iZone]->GetUnsteady_Simulation()) && !time_spectral) { + int Direct_Iter = SU2_TYPE::Int(config_container[val_iZone]->GetUnst_AdjointIter()) - SU2_TYPE::Int(ExtIter) - 1; + if (rank == MASTER_NODE && val_iZone == ZONE_0 && config_container[val_iZone]->GetUnsteady_Simulation()) + cout << endl << " Loading flow solution from direct iteration " << Direct_Iter << "." << endl; + solver_container[val_iZone][MESH_0][FLOW_SOL]->LoadRestart(geometry_container[val_iZone], solver_container[val_iZone], config_container[val_iZone], Direct_Iter); + } + + /*--- Continuous adjoint Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes (RANS) equations ---*/ + + if ((ExtIter == 0) || config_container[val_iZone]->GetUnsteady_Simulation()) { + + if (config_container[val_iZone]->GetKind_Solver() == ADJ_EULER) + config_container[val_iZone]->SetGlobalParam(ADJ_EULER, RUNTIME_FLOW_SYS, ExtIter); + if (config_container[val_iZone]->GetKind_Solver() == ADJ_NAVIER_STOKES) + config_container[val_iZone]->SetGlobalParam(ADJ_NAVIER_STOKES, RUNTIME_FLOW_SYS, ExtIter); + if (config_container[val_iZone]->GetKind_Solver() == ADJ_RANS) + config_container[val_iZone]->SetGlobalParam(ADJ_RANS, RUNTIME_FLOW_SYS, ExtIter); + + /*--- Solve the Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes (RANS) equations (one iteration) ---*/ + + if (rank == MASTER_NODE && val_iZone == ZONE_0) + cout << "Begin direct solver to store flow data (single iteration)." << endl; + + if (rank == MASTER_NODE && val_iZone == ZONE_0) + cout << "Compute residuals to check the convergence of the direct problem." << endl; + + integration_container[val_iZone][FLOW_SOL]->MultiGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_FLOW_SYS, 0, val_iZone); + + if (config_container[val_iZone]->GetKind_Solver() == ADJ_RANS) { + + /*--- Solve the turbulence model ---*/ + + config_container[val_iZone]->SetGlobalParam(ADJ_RANS, RUNTIME_TURB_SYS, ExtIter); + integration_container[val_iZone][TURB_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_TURB_SYS, IntIter, val_iZone); + + /*--- Solve transition model ---*/ + + if (config_container[val_iZone]->GetKind_Trans_Model() == LM) { + config_container[val_iZone]->SetGlobalParam(RANS, RUNTIME_TRANS_SYS, ExtIter); + integration_container[val_iZone][TRANS_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_TRANS_SYS, IntIter, val_iZone); + } + + } + + /*--- Output the residual (visualization purpouses to identify if + the direct solution is converged)---*/ + if (rank == MASTER_NODE && val_iZone == ZONE_0) + cout << "log10[Maximum residual]: " << log10(solver_container[val_iZone][MESH_0][FLOW_SOL]->GetRes_Max(0)) + <<", located at point "<< solver_container[val_iZone][MESH_0][FLOW_SOL]->GetPoint_Max(0) << "." << endl; + + /*--- Compute gradients of the flow variables, this is necessary for sensitivity computation, + note that in the direct Euler problem we are not computing the gradients of the primitive variables ---*/ + + if (config_container[val_iZone]->GetKind_Gradient_Method() == GREEN_GAUSS) + solver_container[val_iZone][MESH_0][FLOW_SOL]->SetPrimitive_Gradient_GG(geometry_container[val_iZone][MESH_0], config_container[val_iZone]); + if (config_container[val_iZone]->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) + solver_container[val_iZone][MESH_0][FLOW_SOL]->SetPrimitive_Gradient_LS(geometry_container[val_iZone][MESH_0], config_container[val_iZone]); + + /*--- Set contribution from cost function for boundary conditions ---*/ + + for (iMesh = 0; iMesh <= config_container[val_iZone]->GetnMGLevels(); iMesh++) { + + /*--- Set the value of the non-dimensional coefficients in the coarse levels, using the fine level solution ---*/ + + solver_container[val_iZone][iMesh][FLOW_SOL]->SetTotal_CDrag(solver_container[val_iZone][MESH_0][FLOW_SOL]->GetTotal_CDrag()); + solver_container[val_iZone][iMesh][FLOW_SOL]->SetTotal_CLift(solver_container[val_iZone][MESH_0][FLOW_SOL]->GetTotal_CLift()); + solver_container[val_iZone][iMesh][FLOW_SOL]->SetTotal_CT(solver_container[val_iZone][MESH_0][FLOW_SOL]->GetTotal_CT()); + solver_container[val_iZone][iMesh][FLOW_SOL]->SetTotal_CQ(solver_container[val_iZone][MESH_0][FLOW_SOL]->GetTotal_CQ()); + + /*--- Compute the adjoint boundary condition on Euler walls ---*/ + + solver_container[val_iZone][iMesh][ADJFLOW_SOL]->SetForceProj_Vector(geometry_container[val_iZone][iMesh], solver_container[val_iZone][iMesh], config_container[val_iZone]); + + /*--- Set the internal boundary condition on nearfield surfaces ---*/ + + if ((config_container[val_iZone]->GetKind_ObjFunc() == EQUIVALENT_AREA) || + (config_container[val_iZone]->GetKind_ObjFunc() == NEARFIELD_PRESSURE)) + solver_container[val_iZone][iMesh][ADJFLOW_SOL]->SetIntBoundary_Jump(geometry_container[val_iZone][iMesh], solver_container[val_iZone][iMesh], config_container[val_iZone]); + + } + + if (rank == MASTER_NODE && val_iZone == ZONE_0) + cout << "End direct solver, begin adjoint problem." << endl; + + } + +} +void CAdjMeanFlowIteration::Iterate(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { + + unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); + unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); + + /*--- Set the value of the internal iteration ---*/ + + IntIter = ExtIter; + if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { + IntIter = 0; + } + + if (config_container[val_iZone]->GetKind_Solver() == ADJ_EULER) + config_container[val_iZone]->SetGlobalParam(ADJ_EULER, RUNTIME_ADJFLOW_SYS, ExtIter); + if (config_container[val_iZone]->GetKind_Solver() == ADJ_NAVIER_STOKES) + config_container[val_iZone]->SetGlobalParam(ADJ_NAVIER_STOKES, RUNTIME_ADJFLOW_SYS, ExtIter); + if (config_container[val_iZone]->GetKind_Solver() == ADJ_RANS) + config_container[val_iZone]->SetGlobalParam(ADJ_RANS, RUNTIME_ADJFLOW_SYS, ExtIter); + + /*--- Iteration of the flow adjoint problem ---*/ + + integration_container[val_iZone][ADJFLOW_SOL]->MultiGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_ADJFLOW_SYS, IntIter, val_iZone); + + /*--- Iteration of the turbulence model adjoint ---*/ + + if ((config_container[val_iZone]->GetKind_Solver() == ADJ_RANS) && (!config_container[val_iZone]->GetFrozen_Visc())) { + + /*--- Adjoint turbulence model solution ---*/ + + config_container[val_iZone]->SetGlobalParam(ADJ_RANS, RUNTIME_ADJTURB_SYS, ExtIter); + integration_container[val_iZone][ADJTURB_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_ADJTURB_SYS, IntIter, val_iZone); + + } + + /*--- Dual time stepping strategy ---*/ + + if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { + + for (IntIter = 1; IntIter < config_container[val_iZone]->GetUnst_nIntIter(); IntIter++) { + + /*--- Write the convergence history (only screen output) ---*/ + + output->SetConvHistory_Body(NULL, geometry_container, solver_container, config_container, integration_container, true, 0.0, val_iZone); + + /*--- Set the value of the internal iteration ---*/ + + config_container[val_iZone]->SetIntIter(IntIter); + + /*--- All zones must be advanced and coupled with each pseudo timestep ---*/ + + integration_container[val_iZone][ADJFLOW_SOL]->MultiGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_ADJFLOW_SYS, IntIter, val_iZone); + + /*--- Check to see if the convergence criteria has been met ---*/ + + if (integration_container[val_iZone][ADJFLOW_SOL]->GetConvergence()) break; + } + + } + +} +void CAdjMeanFlowIteration::Update(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { + + su2double Physical_dt, Physical_t; + unsigned short iMesh; + unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); + + /*--- Dual time stepping strategy ---*/ + + if ((config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config_container[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { + + /*--- Update dual time solver ---*/ + + for (iMesh = 0; iMesh <= config_container[val_iZone]->GetnMGLevels(); iMesh++) { + integration_container[val_iZone][ADJFLOW_SOL]->SetDualTime_Solver(geometry_container[val_iZone][iMesh], solver_container[val_iZone][iMesh][ADJFLOW_SOL], config_container[val_iZone], iMesh); + integration_container[val_iZone][ADJFLOW_SOL]->SetConvergence(false); + } + + Physical_dt = config_container[val_iZone]->GetDelta_UnstTime(); Physical_t = (ExtIter+1)*Physical_dt; + if (Physical_t >= config_container[val_iZone]->GetTotal_UnstTime()) integration_container[val_iZone][ADJFLOW_SOL]->SetConvergence(true); + + } +} + +void CAdjMeanFlowIteration::Monitor() { } +void CAdjMeanFlowIteration::Output() { } +void CAdjMeanFlowIteration::Postprocess() { } + +CDiscAdjMeanFlowIteration::CDiscAdjMeanFlowIteration(CConfig *config) : CIteration(config), CurrentRecording(NONE){ + + meanflow_iteration = new CMeanFlowIteration(config); + + turbulent = config->GetKind_Solver() == DISC_ADJ_RANS; + +} + +CDiscAdjMeanFlowIteration::~CDiscAdjMeanFlowIteration(void) { } +void CDiscAdjMeanFlowIteration::Preprocess(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { + + unsigned short ExtIter = config_container[val_iZone]->GetExtIter(); + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + if (CurrentRecording != FLOW_VARIABLES){ + + if ((rank == MASTER_NODE) && (ExtIter == 0)){ + cout << "Direct iteration to store computational graph." << endl; + } + + /*--- Record one mean flow iteration with flow variables as input ---*/ + + SetRecording(output, integration_container, geometry_container, solver_container, numerics_container, + config_container, surface_movement, grid_movement, FFDBox, val_iZone, FLOW_VARIABLES); + + /*--- Print residuals in the first iteration ---*/ + + if (rank == MASTER_NODE && ExtIter == 0){ + cout << "log10[RMS Density]: "<< log10(solver_container[val_iZone][MESH_0][FLOW_SOL]->GetRes_RMS(0)) + <<", Drag: " <GetTotal_CDrag() + <<", Lift: " << solver_container[val_iZone][MESH_0][FLOW_SOL]->GetTotal_CLift() << "." << endl; + + if (turbulent){ + cout << "log10[RMS k]: " << log10(solver_container[val_iZone][MESH_0][TURB_SOL]->GetRes_RMS(0)) << endl; + } + } + } +} +void CDiscAdjMeanFlowIteration::Iterate(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **volume_grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { + + unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); + + /*--- Set the adjoint values of the flow and objective function ---*/ + + InitializeAdjoint(solver_container, geometry_container, config_container, val_iZone); + + /*--- Run the adjoint computation ---*/ + + AD::ComputeAdjoint(); + + /*--- Extract the adjoints of the conservative input variables and store them for the next iteration ---*/ + + solver_container[val_iZone][MESH_0][ADJFLOW_SOL]->ExtractAdjoint_Solution(geometry_container[val_iZone][MESH_0], + config_container[val_iZone]); + + solver_container[val_iZone][MESH_0][ADJFLOW_SOL]->ExtractAdjoint_Variables(geometry_container[val_iZone][MESH_0], + config_container[val_iZone]); + + if (config_container[ZONE_0]->GetKind_Solver() == DISC_ADJ_RANS) { + solver_container[val_iZone][MESH_0][ADJTURB_SOL]->ExtractAdjoint_Solution(geometry_container[val_iZone][MESH_0], + config_container[val_iZone]); + } + + /*--- Clear all adjoints to re-use the stored computational graph in the next iteration ---*/ + + AD::ClearAdjoints(); + + /*--- Set the convergence criteria (only residual possible) ---*/ + + integration_container[val_iZone][ADJFLOW_SOL]->Convergence_Monitoring(geometry_container[val_iZone][MESH_0],config_container[val_iZone], + ExtIter,log10(solver_container[val_iZone][MESH_0][ADJFLOW_SOL]->GetRes_RMS(0)), MESH_0); + + if (((unsigned short)(ExtIter+1) >= config_container[val_iZone]->GetnExtIter()) || + ((ExtIter % config_container[val_iZone]->GetWrt_Sol_Freq() == 0))){ + + /*--- Record one mean flow iteration with geometry variables as input ---*/ + + SetRecording(output, integration_container, geometry_container, solver_container, numerics_container, + config_container, surface_movement, volume_grid_movement, FFDBox, val_iZone, GEOMETRY_VARIABLES); + + /*--- Set the adjoint values of the flow and objective function ---*/ + + InitializeAdjoint(solver_container, geometry_container, config_container, val_iZone); + + /*--- Run the adjoint computation ---*/ + + AD::ComputeAdjoint(); + + /*--- Extract the sensitivities (adjoint of node coordinates) ---*/ + + solver_container[val_iZone][MESH_0][ADJFLOW_SOL]->SetSensitivity(geometry_container[val_iZone][MESH_0],config_container[val_iZone]); + + } + +} + +void CDiscAdjMeanFlowIteration::SetRecording(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short kind_recording) { + + unsigned short iMesh; + + /*--- Reset the tape ---*/ + + AD::Reset(); + + /*--- Update geometry to set all indices to zero ---*/ + + geometry_container[val_iZone][MESH_0]->UpdateGeometry(geometry_container[val_iZone], config_container[val_iZone]); + + /*--- Run one iteration while tape is passive - this clears all indices ---*/ + + meanflow_iteration->Iterate(output,integration_container,geometry_container,solver_container,numerics_container, + config_container,surface_movement,grid_movement,FFDBox,val_iZone); + + /*--- Prepare for recording ---*/ + + for (iMesh = 0; iMesh <= config_container[val_iZone]->GetnMGLevels(); iMesh++){ + + solver_container[val_iZone][iMesh][ADJFLOW_SOL]->SetRecording(geometry_container[val_iZone][MESH_0], config_container[val_iZone], kind_recording); + + if (turbulent){ + solver_container[val_iZone][iMesh][ADJTURB_SOL]->SetRecording(geometry_container[val_iZone][MESH_0], config_container[val_iZone], kind_recording); + } + } + + /*--- Start the recording of all operations ---*/ + + AD::StartRecording(); + + /*--- Register flow variables and compute coupling or update the geometry ---*/ + + RegisterInput(solver_container, geometry_container, config_container, val_iZone, kind_recording); + + /*--- Run the direct iteration ---*/ + + meanflow_iteration->Iterate(output,integration_container,geometry_container,solver_container,numerics_container, + config_container,surface_movement,grid_movement,FFDBox, val_iZone); + + /*--- Register flow variables and objective function as output ---*/ + + /*--- For flux-avg or area-avg objective functions the 1D values must be calculated first ---*/ + if (config_container[val_iZone]->GetKind_ObjFunc()==AVG_OUTLET_PRESSURE || + config_container[val_iZone]->GetKind_ObjFunc()==AVG_TOTAL_PRESSURE || + config_container[val_iZone]->GetKind_ObjFunc()==MASS_FLOW_RATE) + output->OneDimensionalOutput(solver_container[val_iZone][MESH_0][FLOW_SOL], + geometry_container[val_iZone][MESH_0], config_container[val_iZone]); + + RegisterOutput(solver_container, geometry_container, config_container, val_iZone); + + /*--- Stop the recording ---*/ + + AD::StopRecording(); + + /*--- Set the recording status ---*/ + + CurrentRecording = kind_recording; +} + + +void CDiscAdjMeanFlowIteration::RegisterInput(CSolver ****solver_container, CGeometry ***geometry_container, CConfig **config_container, unsigned short iZone, unsigned short kind_recording){ + + + if (kind_recording == FLOW_VARIABLES){ + + /*--- Register flow and turbulent variables as input ---*/ + + solver_container[iZone][MESH_0][ADJFLOW_SOL]->RegisterSolution(geometry_container[iZone][MESH_0], config_container[iZone]); + + solver_container[iZone][MESH_0][ADJFLOW_SOL]->RegisterVariables(geometry_container[iZone][MESH_0], config_container[iZone]); + + if (turbulent){ + solver_container[iZone][MESH_0][ADJTURB_SOL]->RegisterSolution(geometry_container[iZone][MESH_0], config_container[iZone]); + } + + /*--- Compute coupling between flow and turbulent equations ---*/ + + if (turbulent){ + solver_container[iZone][MESH_0][FLOW_SOL]->SetPrimitive_Variables(solver_container[iZone][MESH_0], config_container[iZone], false); + solver_container[iZone][MESH_0][TURB_SOL]->Postprocessing(geometry_container[iZone][MESH_0],solver_container[iZone][MESH_0], config_container[iZone], MESH_0); + } + } + else if (kind_recording == GEOMETRY_VARIABLES){ + + /*--- Register node coordinates as input ---*/ + + geometry_container[iZone][MESH_0]->RegisterCoordinates(config_container[iZone]); + + /*--- Update geometry to get the influence on other geometry variables (normals, volume etc) ---*/ + + geometry_container[iZone][MESH_0]->UpdateGeometry(geometry_container[iZone], config_container[iZone]); + + } + +} + +void CDiscAdjMeanFlowIteration::RegisterOutput(CSolver ****solver_container, CGeometry ***geometry_container, CConfig **config_container, unsigned short iZone){ + + /*--- Register objective function as output of the iteration ---*/ + + solver_container[iZone][MESH_0][ADJFLOW_SOL]->RegisterObj_Func(config_container[iZone]); + + /*--- Register conservative variables as output of the iteration ---*/ + + solver_container[iZone][MESH_0][ADJFLOW_SOL]->RegisterOutput(geometry_container[iZone][MESH_0],config_container[iZone]); + + if (turbulent){ + solver_container[iZone][MESH_0][ADJTURB_SOL]->RegisterOutput(geometry_container[iZone][MESH_0], + config_container[iZone]); + } +} + +void CDiscAdjMeanFlowIteration::InitializeAdjoint(CSolver ****solver_container, CGeometry ***geometry_container, CConfig **config_container, unsigned short iZone){ + + /*--- Initialize the adjoint of the objective function (typically with 1.0) ---*/ + + solver_container[iZone][MESH_0][ADJFLOW_SOL]->SetAdj_ObjFunc(geometry_container[iZone][MESH_0], config_container[iZone]); + + /*--- Initialize the adjoints the conservative variables ---*/ + + solver_container[iZone][MESH_0][ADJFLOW_SOL]->SetAdjoint_Output(geometry_container[iZone][MESH_0], + config_container[iZone]); + + if (turbulent){ + solver_container[iZone][MESH_0][ADJTURB_SOL]->SetAdjoint_Output(geometry_container[iZone][MESH_0], + config_container[iZone]); + } +} +void CDiscAdjMeanFlowIteration::Update(COutput *output, + CIntegration ***integration_container, + CGeometry ***geometry_container, + CSolver ****solver_container, + CNumerics *****numerics_container, + CConfig **config_container, + CSurfaceMovement **surface_movement, + CVolumetricMovement **grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone) { } +void CDiscAdjMeanFlowIteration::Monitor() { } +void CDiscAdjMeanFlowIteration::Output() { } +void CDiscAdjMeanFlowIteration::Postprocess() { } + +void FluidStructureIteration(COutput *output, CIntegration ***integration_container, CGeometry ***geometry_container, + CSolver ****solver_container, CNumerics *****numerics_container, CConfig **config_container, + CSurfaceMovement **surface_movement, CVolumetricMovement **grid_movement, CFreeFormDefBox*** FFDBox, + unsigned long iFluidIt, unsigned long nFluidIt) { + + su2double Physical_dt, Physical_t; + unsigned short iMesh; + unsigned long IntIter = 0; config_container[ZONE_0]->SetIntIter(IntIter); + unsigned long IntIter_Struct = 0; config_container[ZONE_1]->SetIntIter(IntIter_Struct); + unsigned long iFSIIter = 0; + unsigned long nFSIIter = config_container[ZONE_0]->GetnIterFSI(); + unsigned long ExtIter = config_container[ZONE_0]->GetExtIter(); + + unsigned short SolContainer_Position_fea = config_container[ZONE_1]->GetContainerPosition(RUNTIME_FEA_SYS); + + /*------------- Structural predictor for displacements ------------*/ + + /*--- Predict structural displacement --*/ + solver_container[ZONE_1][MESH_0][FEA_SOL]->PredictStruct_Displacement(geometry_container[ZONE_1], config_container[ZONE_1], + solver_container[ZONE_1]); + + + while (iFSIIterSetFlow_Displacement(geometry_container[ZONE_0], grid_movement[ZONE_0], + config_container[ZONE_0], config_container[ZONE_1], + geometry_container[ZONE_1], solver_container[ZONE_1]); + + /*---------------------- Fluid iteration --------------------------*/ + + /*--- Set the initial condition ---*/ + + solver_container[ZONE_0][MESH_0][FLOW_SOL]->SetInitialCondition(geometry_container[ZONE_0], solver_container[ZONE_0], config_container[ZONE_0], ExtIter); + + /*--- Apply a Wind Gust ---*/ + + if (config_container[ZONE_0]->GetWind_Gust()){ + //SetWind_GustField(config_container[ZONE_0],geometry_container[ZONE_0],solver_container[ZONE_0]); + } + + /*--- Set the value of the internal iteration ---*/ + + IntIter = ExtIter; + + if ((config_container[ZONE_0]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config_container[ZONE_0]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) IntIter = 0; + + /*--- Update global parameters ---*/ + + if (config_container[ZONE_0]->GetKind_Solver() == EULER){ + config_container[ZONE_0]->SetGlobalParam(EULER, RUNTIME_FLOW_SYS, ExtIter); + } + if (config_container[ZONE_0]->GetKind_Solver() == NAVIER_STOKES){ + config_container[ZONE_0]->SetGlobalParam(NAVIER_STOKES, RUNTIME_FLOW_SYS, ExtIter); + } + if (config_container[ZONE_0]->GetKind_Solver() == RANS){ + config_container[ZONE_0]->SetGlobalParam(RANS, RUNTIME_FLOW_SYS, ExtIter); + } + + /*--- Solve the Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes (RANS) equations (one iteration) ---*/ + + integration_container[ZONE_0][FLOW_SOL]->MultiGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_FLOW_SYS, IntIter, ZONE_0); + + if (config_container[ZONE_0]->GetKind_Solver() == RANS) { + + /*--- Solve the turbulence model ---*/ + + config_container[ZONE_0]->SetGlobalParam(RANS, RUNTIME_TURB_SYS, ExtIter); + integration_container[ZONE_0][TURB_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_TURB_SYS, IntIter, ZONE_0); + + /*--- Solve transition model ---*/ + + if (config_container[ZONE_0]->GetKind_Trans_Model() == LM) { + config_container[ZONE_0]->SetGlobalParam(RANS, RUNTIME_TRANS_SYS, ExtIter); + integration_container[ZONE_0][TRANS_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_TRANS_SYS, IntIter, ZONE_0); + } + + } + + /*--- Dual time stepping strategy ---*/ + + if ((config_container[ZONE_0]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config_container[ZONE_0]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { + + for(IntIter = 1; IntIter < config_container[ZONE_0]->GetUnst_nIntIter(); IntIter++) { + + /*--- Write the convergence history (only screen output) ---*/ + + output->SetConvHistory_Body(NULL, geometry_container, solver_container, config_container, integration_container, true, 0.0, ZONE_0); + + /*--- Set the value of the internal iteration ---*/ + + config_container[ZONE_0]->SetIntIter(IntIter); + + /*--- Pseudo-timestepping for the Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes equations ---*/ + + if (config_container[ZONE_0]->GetKind_Solver() == EULER) + config_container[ZONE_0]->SetGlobalParam(EULER, RUNTIME_FLOW_SYS, ExtIter); + if (config_container[ZONE_0]->GetKind_Solver() == NAVIER_STOKES) + config_container[ZONE_0]->SetGlobalParam(NAVIER_STOKES, RUNTIME_FLOW_SYS, ExtIter); + if (config_container[ZONE_0]->GetKind_Solver() == RANS) + config_container[ZONE_0]->SetGlobalParam(RANS, RUNTIME_FLOW_SYS, ExtIter); + + /*--- Solve the Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes (RANS) equations (one iteration) ---*/ + + integration_container[ZONE_0][FLOW_SOL]->MultiGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_FLOW_SYS, IntIter, ZONE_0); + + /*--- Pseudo-timestepping the turbulence model ---*/ + + if (config_container[ZONE_0]->GetKind_Solver() == RANS) { + + /*--- Solve the turbulence model ---*/ + + config_container[ZONE_0]->SetGlobalParam(RANS, RUNTIME_TURB_SYS, ExtIter); + integration_container[ZONE_0][TURB_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_TURB_SYS, IntIter, ZONE_0); + + /*--- Solve transition model ---*/ + + if (config_container[ZONE_0]->GetKind_Trans_Model() == LM) { + config_container[ZONE_0]->SetGlobalParam(RANS, RUNTIME_TRANS_SYS, ExtIter); + integration_container[ZONE_0][TRANS_SOL]->SingleGrid_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_TRANS_SYS, IntIter, ZONE_0); + } + } + + if (integration_container[ZONE_0][FLOW_SOL]->GetConvergence()) break; + + } + + } + + /*-------------------- Structural iteration -----------------------*/ + + /*--- Set the initial condition at the first iteration ---*/ + + // solver_container[ZONE_1][MESH_0][FEA_SOL]->SetInitialCondition(geometry_container[ZONE_1], solver_container[ZONE_1], config_container[ZONE_1], ExtIter); + + /*--- Set the value of the internal iteration ---*/ + + IntIter_Struct = ExtIter; + + /*--- FEA equations ---*/ + + config_container[ZONE_1]->SetGlobalParam(LINEAR_ELASTICITY, RUNTIME_FEA_SYS, ExtIter); + + /*--- Update loads for the FEA model ---*/ + + solver_container[ZONE_1][MESH_0][FEA_SOL]->SetFEA_Load(solver_container[ZONE_0], geometry_container[ZONE_1], geometry_container[ZONE_0], + config_container[ZONE_1], config_container[ZONE_0], numerics_container[ZONE_1][MESH_0][SolContainer_Position_fea][VISC_TERM]); + + /*--- Run the iteration ---*/ + + integration_container[ZONE_1][FEA_SOL]->Structural_Iteration(geometry_container, solver_container, numerics_container, + config_container, RUNTIME_FEA_SYS, IntIter_Struct, ZONE_1); + + /*-------------------- Aitken's relaxation ------------------------*/ + + solver_container[ZONE_1][MESH_0][FEA_SOL]->ComputeAitken_Coefficient(geometry_container[ZONE_1], config_container[ZONE_1], + solver_container[ZONE_1], iFSIIter); + + + solver_container[ZONE_1][MESH_0][FEA_SOL]->SetAitken_Relaxation(geometry_container[ZONE_1], config_container[ZONE_1], + solver_container[ZONE_1]); + + /*-------------------- Check convergence --------------------------*/ + + integration_container[ZONE_1][FEA_SOL]->Convergence_Monitoring_FSI(geometry_container[ZONE_1][MESH_0], config_container[ZONE_1], + solver_container[ZONE_1][MESH_0][FEA_SOL], iFSIIter); + + if (integration_container[ZONE_1][FEA_SOL]->GetConvergence_FSI()) break; + + /*--------------------- Update iFSIIter ---------------------------*/ + + iFSIIter++; + + } + + if ((config_container[ZONE_0]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config_container[ZONE_0]->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { + + /*-------------------- Update fluid solver ------------------------*/ + + /*--- Update dual time solver on all mesh levels ---*/ + + for (iMesh = 0; iMesh <= config_container[ZONE_0]->GetnMGLevels(); iMesh++) { + integration_container[ZONE_0][FLOW_SOL]->SetDualTime_Solver(geometry_container[ZONE_0][iMesh], solver_container[ZONE_0][iMesh][FLOW_SOL], config_container[ZONE_0], iMesh); + integration_container[ZONE_0][FLOW_SOL]->SetConvergence(false); + } + + /*--- Update dual time solver for the turbulence model ---*/ + + if (config_container[ZONE_0]->GetKind_Solver() == RANS) { + integration_container[ZONE_0][TURB_SOL]->SetDualTime_Solver(geometry_container[ZONE_0][MESH_0], solver_container[ZONE_0][MESH_0][TURB_SOL], config_container[ZONE_0], MESH_0); + integration_container[ZONE_0][TURB_SOL]->SetConvergence(false); + } + + /*--- Update dual time solver for the transition model ---*/ + + if (config_container[ZONE_0]->GetKind_Trans_Model() == LM) { + integration_container[ZONE_0][TRANS_SOL]->SetDualTime_Solver(geometry_container[ZONE_0][MESH_0], solver_container[ZONE_0][MESH_0][TRANS_SOL], config_container[ZONE_0], MESH_0); + integration_container[ZONE_0][TRANS_SOL]->SetConvergence(false); + } + + /*--- Verify convergence criteria (based on total time) ---*/ + + Physical_dt = config_container[ZONE_0]->GetDelta_UnstTime(); + Physical_t = (ExtIter+1)*Physical_dt; + if (Physical_t >= config_container[ZONE_0]->GetTotal_UnstTime()) + integration_container[ZONE_0][FLOW_SOL]->SetConvergence(true); + + } + + /*----------------- Update structural solver ----------------------*/ + + integration_container[ZONE_1][FEA_SOL]->SetStructural_Solver(geometry_container[ZONE_1][MESH_0], solver_container[ZONE_1][MESH_0][FEA_SOL], config_container[ZONE_1], MESH_0); + + /*-----------------------------------------------------------------*/ + /*--------------- Update convergence parameter --------------------*/ + /*-----------------------------------------------------------------*/ + + integration_container[ZONE_1][FEA_SOL]->SetConvergence_FSI(false); + + +} + +void SetGrid_Movement(CGeometry **geometry_container, CSurfaceMovement *surface_movement, + CVolumetricMovement *grid_movement, CFreeFormDefBox **FFDBox, + CSolver ***solver_container, CConfig *config_container, + unsigned short iZone, unsigned long IntIter, unsigned long ExtIter) { + + unsigned short iDim, iMGlevel, nMGlevels = config_container->GetnMGLevels(); + unsigned short Kind_Grid_Movement = config_container->GetKind_GridMovement(iZone); + unsigned long iPoint; + bool adjoint = config_container->GetAdjoint(); + bool time_spectral = (config_container->GetUnsteady_Simulation() == TIME_SPECTRAL); + + /*--- For a time-spectral case, set "iteration number" to the zone number, + so that the meshes are positioned correctly for each instance. ---*/ + if (time_spectral) { + ExtIter = iZone; + Kind_Grid_Movement = config_container->GetKind_GridMovement(ZONE_0); + } + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Perform mesh movement depending on specified type ---*/ + switch (Kind_Grid_Movement) { + + case MOVING_WALL: + + /*--- Fixed wall velocities: set the grid velocities only one time + before the first iteration flow solver. ---*/ + + if (ExtIter == 0) { + + if (rank == MASTER_NODE) + cout << endl << " Setting the moving wall velocities." << endl; + + surface_movement->Moving_Walls(geometry_container[MESH_0], + config_container, iZone, ExtIter); + + /*--- Update the grid velocities on the coarser multigrid levels after + setting the moving wall velocities for the finest mesh. ---*/ + + grid_movement->UpdateMultiGrid(geometry_container, config_container); + + } + + break; + + + case ROTATING_FRAME: + + /*--- Steadily rotating frame: set the grid velocities just once + before the first iteration flow solver. ---*/ + + if (ExtIter == 0) { + + if (rank == MASTER_NODE) { + cout << endl << " Setting rotating frame grid velocities"; + cout << " for zone " << iZone << "." << endl; + } + + /*--- Set the grid velocities on all multigrid levels for a steadily + rotating reference frame. ---*/ + + for (iMGlevel = 0; iMGlevel <= nMGlevels; iMGlevel++) + geometry_container[iMGlevel]->SetRotationalVelocity(config_container, iZone); + + } + + break; + + case STEADY_TRANSLATION: + + /*--- Set the translational velocity and hold the grid fixed during + the calculation (similar to rotating frame, but there is no extra + source term for translation). ---*/ + + if (ExtIter == 0) { + + if (rank == MASTER_NODE) + cout << endl << " Setting translational grid velocities." << endl; + + /*--- Set the translational velocity on all grid levels. ---*/ + + for (iMGlevel = 0; iMGlevel <= nMGlevels; iMGlevel++) + geometry_container[iMGlevel]->SetTranslationalVelocity(config_container); + + } + + break; + + case RIGID_MOTION: + + if (rank == MASTER_NODE) { + cout << endl << " Performing rigid mesh transformation." << endl; + } + + /*--- Move each node in the volume mesh using the specified type + of rigid mesh motion. These routines also compute analytic grid + velocities for the fine mesh. ---*/ + + grid_movement->Rigid_Translation(geometry_container[MESH_0], + config_container, iZone, ExtIter); + grid_movement->Rigid_Plunging(geometry_container[MESH_0], + config_container, iZone, ExtIter); + grid_movement->Rigid_Pitching(geometry_container[MESH_0], + config_container, iZone, ExtIter); + grid_movement->Rigid_Rotation(geometry_container[MESH_0], + config_container, iZone, ExtIter); + + /*--- Update the multigrid structure after moving the finest grid, + including computing the grid velocities on the coarser levels. ---*/ + + grid_movement->UpdateMultiGrid(geometry_container, config_container); + + break; + + case DEFORMING: + + if (rank == MASTER_NODE) + cout << endl << " Updating surface positions." << endl; + + /*--- Translating ---*/ + + /*--- Compute the new node locations for moving markers ---*/ + + surface_movement->Surface_Translating(geometry_container[MESH_0], + config_container, ExtIter, iZone); + /*--- Deform the volume grid around the new boundary locations ---*/ + + if (rank == MASTER_NODE) + cout << " Deforming the volume grid." << endl; + grid_movement->SetVolume_Deformation(geometry_container[MESH_0], + config_container, true); + + /*--- Plunging ---*/ + + /*--- Compute the new node locations for moving markers ---*/ + + surface_movement->Surface_Plunging(geometry_container[MESH_0], + config_container, ExtIter, iZone); + /*--- Deform the volume grid around the new boundary locations ---*/ + + if (rank == MASTER_NODE) + cout << " Deforming the volume grid." << endl; + grid_movement->SetVolume_Deformation(geometry_container[MESH_0], + config_container, true); + + /*--- Pitching ---*/ + + /*--- Compute the new node locations for moving markers ---*/ + + surface_movement->Surface_Pitching(geometry_container[MESH_0], + config_container, ExtIter, iZone); + /*--- Deform the volume grid around the new boundary locations ---*/ + + if (rank == MASTER_NODE) + cout << " Deforming the volume grid." << endl; + grid_movement->SetVolume_Deformation(geometry_container[MESH_0], + config_container, true); + + /*--- Rotating ---*/ + + /*--- Compute the new node locations for moving markers ---*/ + + surface_movement->Surface_Rotating(geometry_container[MESH_0], + config_container, ExtIter, iZone); + /*--- Deform the volume grid around the new boundary locations ---*/ + + if (rank == MASTER_NODE) + cout << " Deforming the volume grid." << endl; + grid_movement->SetVolume_Deformation(geometry_container[MESH_0], + config_container, true); + + /*--- Update the grid velocities on the fine mesh using finite + differencing based on node coordinates at previous times. ---*/ + + if (!adjoint) { + if (rank == MASTER_NODE) + cout << " Computing grid velocities by finite differencing." << endl; + geometry_container[MESH_0]->SetGridVelocity(config_container, ExtIter); + } + + /*--- Update the multigrid structure after moving the finest grid, + including computing the grid velocities on the coarser levels. ---*/ + + grid_movement->UpdateMultiGrid(geometry_container, config_container); + + break; + + case EXTERNAL: case EXTERNAL_ROTATION: + + /*--- Apply rigid rotation to entire grid first, if necessary ---*/ + + if (Kind_Grid_Movement == EXTERNAL_ROTATION) { + if (rank == MASTER_NODE) + cout << " Updating node locations by rigid rotation." << endl; + grid_movement->Rigid_Rotation(geometry_container[MESH_0], + config_container, iZone, ExtIter); + } + + /*--- Load new surface node locations from external files ---*/ + + if (rank == MASTER_NODE) + cout << " Updating surface locations from file." << endl; + surface_movement->SetExternal_Deformation(geometry_container[MESH_0], + config_container, iZone, ExtIter); + + /*--- Deform the volume grid around the new boundary locations ---*/ + + if (rank == MASTER_NODE) + cout << " Deforming the volume grid." << endl; + grid_movement->SetVolume_Deformation(geometry_container[MESH_0], + config_container, true); + + /*--- Update the grid velocities on the fine mesh using finite + differencing based on node coordinates at previous times. ---*/ + + if (!adjoint) { + if (rank == MASTER_NODE) + cout << " Computing grid velocities by finite differencing." << endl; + geometry_container[MESH_0]->SetGridVelocity(config_container, ExtIter); + } + + /*--- Update the multigrid structure after moving the finest grid, + including computing the grid velocities on the coarser levels. ---*/ + + grid_movement->UpdateMultiGrid(geometry_container, config_container); + + break; + + case AEROELASTIC: case AEROELASTIC_RIGID_MOTION: + + /*--- Apply rigid mesh transformation to entire grid first, if necessary ---*/ + if (IntIter == 0) { + if (Kind_Grid_Movement == AEROELASTIC_RIGID_MOTION) { + + if (rank == MASTER_NODE) { + cout << endl << " Performing rigid mesh transformation." << endl; + } + + /*--- Move each node in the volume mesh using the specified type + of rigid mesh motion. These routines also compute analytic grid + velocities for the fine mesh. ---*/ + + grid_movement->Rigid_Translation(geometry_container[MESH_0], + config_container, iZone, ExtIter); + grid_movement->Rigid_Plunging(geometry_container[MESH_0], + config_container, iZone, ExtIter); + grid_movement->Rigid_Pitching(geometry_container[MESH_0], + config_container, iZone, ExtIter); + grid_movement->Rigid_Rotation(geometry_container[MESH_0], + config_container, iZone, ExtIter); + + /*--- Update the multigrid structure after moving the finest grid, + including computing the grid velocities on the coarser levels. ---*/ + + grid_movement->UpdateMultiGrid(geometry_container, config_container); + } + + } + + /*--- Use the if statement to move the grid only at selected dual time step iterations. ---*/ + else if (IntIter % config_container->GetAeroelasticIter() ==0) { + + if (rank == MASTER_NODE) + cout << endl << " Solving aeroelastic equations and updating surface positions." << endl; + + /*--- Solve the aeroelastic equations for the new node locations of the moving markers(surfaces) ---*/ + + solver_container[MESH_0][FLOW_SOL]->Aeroelastic(surface_movement, geometry_container[MESH_0], config_container, ExtIter); + + /*--- Deform the volume grid around the new boundary locations ---*/ + + if (rank == MASTER_NODE) + cout << " Deforming the volume grid due to the aeroelastic movement." << endl; + grid_movement->SetVolume_Deformation(geometry_container[MESH_0], + config_container, true); + + /*--- Update the grid velocities on the fine mesh using finite + differencing based on node coordinates at previous times. ---*/ + + if (rank == MASTER_NODE) + cout << " Computing grid velocities by finite differencing." << endl; + geometry_container[MESH_0]->SetGridVelocity(config_container, ExtIter); + + /*--- Update the multigrid structure after moving the finest grid, + including computing the grid velocities on the coarser levels. ---*/ + + grid_movement->UpdateMultiGrid(geometry_container, config_container); + } + + break; + + case ELASTICITY: + + if (ExtIter != 0) { + + if (rank == MASTER_NODE) + cout << " Deforming the grid using the Linear Elasticity solution." << endl; + + /*--- Update the coordinates of the grid using the linear elasticity solution. ---*/ + for (iPoint = 0; iPoint < geometry_container[MESH_0]->GetnPoint(); iPoint++) { + + su2double *U_time_nM1 = solver_container[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_time_n1(); + su2double *U_time_n = solver_container[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_time_n(); + + for (iDim = 0; iDim < geometry_container[MESH_0]->GetnDim(); iDim++) + geometry_container[MESH_0]->node[iPoint]->AddCoord(iDim, U_time_n[iDim] - U_time_nM1[iDim]); + + } + + } + + break; + + case NO_MOVEMENT: case GUST: default: + + /*--- There is no mesh motion specified for this zone. ---*/ + if (rank == MASTER_NODE) + cout << "No mesh motion specified." << endl; + + break; + } + +} diff --git a/SU2_CFD/src/numerics_structure.cpp b/SU2_CFD/src/numerics_structure.cpp index 7badaa4309c..19a436305ec 100644 --- a/SU2_CFD/src/numerics_structure.cpp +++ b/SU2_CFD/src/numerics_structure.cpp @@ -1,2747 +1,2747 @@ -/*! - * \file numerics_structure.cpp - * \brief This file contains all the numerical methods. - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/numerics_structure.hpp" - -CNumerics::CNumerics(void) { } - -CNumerics::CNumerics(unsigned short val_nDim, unsigned short val_nVar, - CConfig *config) { - - unsigned short iVar, iDim, jDim; - - nDim = val_nDim; - nVar = val_nVar; - Gamma = config->GetGamma(); - Gamma_Minus_One = Gamma - 1.0; - Prandtl_Lam = config->GetPrandtl_Lam(); - Prandtl_Turb = config->GetPrandtl_Turb(); - Gas_Constant = config->GetGas_ConstantND(); - - UnitNormal = new su2double [nDim]; - UnitNormald = new su2double [nDim]; - - Normal = new su2double [nDim]; - Flux_Tensor = new su2double* [nVar]; - for (iVar = 0; iVar < (nVar); iVar++) - Flux_Tensor[iVar] = new su2double [nDim]; - - tau = new su2double* [nDim]; - delta = new su2double* [nDim]; - for (iDim = 0; iDim < nDim; iDim++) { - tau[iDim] = new su2double [nDim]; - delta[iDim] = new su2double [nDim]; - } - - for (iDim = 0; iDim < nDim; iDim++) { - for (jDim = 0; jDim < nDim; jDim++) { - if (iDim == jDim) delta[iDim][jDim]=1.0; - else delta[iDim][jDim]=0.0; - } - } - - U_n = new su2double [nVar]; - U_nM1 = new su2double [nVar]; - U_nP1 = new su2double [nVar]; - - Proj_Flux_Tensor = new su2double [nVar]; - - turb_ke_i = 0.0; - turb_ke_j = 0.0; - - Diffusion_Coeff_i = NULL; - Diffusion_Coeff_j = NULL; - - Ys = NULL; - dFdYj = NULL; - dFdYi = NULL; - sumdFdYih = NULL; - sumdFdYjh = NULL; - sumdFdYieve = NULL; - sumdFdYjeve = NULL; - - Vector = new su2double[nDim]; - - l = new su2double [nDim]; - m = new su2double [nDim]; - -} - -CNumerics::~CNumerics(void) { - - delete [] Normal; - delete [] UnitNormal; - - delete [] U_n; - delete [] U_nM1; - delete [] U_nP1; - - // visc - delete [] Proj_Flux_Tensor; - - for (unsigned short iVar = 0; iVar < nDim+3; iVar++) { - delete [] Flux_Tensor[iVar]; - } - delete [] Flux_Tensor; - - for (unsigned short iDim = 0; iDim < nDim; iDim++) { - delete [] tau[iDim]; - delete [] delta[iDim]; - } - delete [] tau; - delete [] delta; - delete [] Enthalpy_formation; - delete [] Theta_v; - if (Ys != NULL) delete [] Ys; - if (sumdFdYih != NULL) delete [] sumdFdYih; - if (sumdFdYjh != NULL) delete [] sumdFdYjh; - if (sumdFdYieve != NULL) delete [] sumdFdYieve; - if (sumdFdYjeve != NULL) delete [] sumdFdYjeve; - if (Diffusion_Coeff_i != NULL) delete [] Diffusion_Coeff_i; - if (Diffusion_Coeff_j != NULL) delete [] Diffusion_Coeff_j; - if (Vector != NULL) delete [] Vector; - if (var != NULL) delete [] var; - - unsigned short iVar; - for (iVar = 0; iVar < nVar; iVar++) { - delete [] dVdU[iVar]; - } - delete [] dVdU; - -} - -void CNumerics::GetInviscidFlux(su2double val_density, su2double *val_velocity, - su2double val_pressure, su2double val_enthalpy) { - if (nDim == 3) { - Flux_Tensor[0][0] = val_density*val_velocity[0]; - Flux_Tensor[1][0] = Flux_Tensor[0][0]*val_velocity[0]+val_pressure; - Flux_Tensor[2][0] = Flux_Tensor[0][0]*val_velocity[1]; - Flux_Tensor[3][0] = Flux_Tensor[0][0]*val_velocity[2]; - Flux_Tensor[4][0] = Flux_Tensor[0][0]*val_enthalpy; - - Flux_Tensor[0][1] = val_density*val_velocity[1]; - Flux_Tensor[1][1] = Flux_Tensor[0][1]*val_velocity[0]; - Flux_Tensor[2][1] = Flux_Tensor[0][1]*val_velocity[1]+val_pressure; - Flux_Tensor[3][1] = Flux_Tensor[0][1]*val_velocity[2]; - Flux_Tensor[4][1] = Flux_Tensor[0][1]*val_enthalpy; - - Flux_Tensor[0][2] = val_density*val_velocity[2]; - Flux_Tensor[1][2] = Flux_Tensor[0][2]*val_velocity[0]; - Flux_Tensor[2][2] = Flux_Tensor[0][2]*val_velocity[1]; - Flux_Tensor[3][2] = Flux_Tensor[0][2]*val_velocity[2]+val_pressure; - Flux_Tensor[4][2] = Flux_Tensor[0][2]*val_enthalpy; - - } - if (nDim == 2) { - Flux_Tensor[0][0] = val_density*val_velocity[0]; - Flux_Tensor[1][0] = Flux_Tensor[0][0]*val_velocity[0]+val_pressure; - Flux_Tensor[2][0] = Flux_Tensor[0][0]*val_velocity[1]; - Flux_Tensor[3][0] = Flux_Tensor[0][0]*val_enthalpy; - - Flux_Tensor[0][1] = val_density*val_velocity[1]; - Flux_Tensor[1][1] = Flux_Tensor[0][1]*val_velocity[0]; - Flux_Tensor[2][1] = Flux_Tensor[0][1]*val_velocity[1]+val_pressure; - Flux_Tensor[3][1] = Flux_Tensor[0][1]*val_enthalpy; - } -} - -void CNumerics::GetInviscidProjFlux(su2double *val_density, - su2double *val_velocity, - su2double *val_pressure, - su2double *val_enthalpy, - su2double *val_normal, - su2double *val_Proj_Flux) { - - su2double rhou, rhov, rhow; - - if (nDim == 2) { - - rhou = (*val_density)*val_velocity[0]; - rhov = (*val_density)*val_velocity[1]; - - val_Proj_Flux[0] = rhou*val_normal[0]; - val_Proj_Flux[1] = (rhou*val_velocity[0]+(*val_pressure))*val_normal[0]; - val_Proj_Flux[2] = rhou*val_velocity[1]*val_normal[0]; - val_Proj_Flux[3] = rhou*(*val_enthalpy)*val_normal[0]; - - val_Proj_Flux[0] += rhov*val_normal[1]; - val_Proj_Flux[1] += rhov*val_velocity[0]*val_normal[1]; - val_Proj_Flux[2] += (rhov*val_velocity[1]+(*val_pressure))*val_normal[1]; - val_Proj_Flux[3] += rhov*(*val_enthalpy)*val_normal[1]; - - } - else { - - rhou = (*val_density)*val_velocity[0]; - rhov = (*val_density)*val_velocity[1]; - rhow = (*val_density)*val_velocity[2]; - - val_Proj_Flux[0] = rhou*val_normal[0]; - val_Proj_Flux[1] = (rhou*val_velocity[0]+(*val_pressure))*val_normal[0]; - val_Proj_Flux[2] = rhou*val_velocity[1]*val_normal[0]; - val_Proj_Flux[3] = rhou*val_velocity[2]*val_normal[0]; - val_Proj_Flux[4] = rhou*(*val_enthalpy)*val_normal[0]; - - val_Proj_Flux[0] += rhov*val_normal[1]; - val_Proj_Flux[1] += rhov*val_velocity[0]*val_normal[1]; - val_Proj_Flux[2] += (rhov*val_velocity[1]+(*val_pressure))*val_normal[1]; - val_Proj_Flux[3] += rhov*val_velocity[2]*val_normal[1]; - val_Proj_Flux[4] += rhov*(*val_enthalpy)*val_normal[1]; - - val_Proj_Flux[0] += rhow*val_normal[2]; - val_Proj_Flux[1] += rhow*val_velocity[0]*val_normal[2]; - val_Proj_Flux[2] += rhow*val_velocity[1]*val_normal[2]; - val_Proj_Flux[3] += (rhow*val_velocity[2]+(*val_pressure))*val_normal[2]; - val_Proj_Flux[4] += rhow*(*val_enthalpy)*val_normal[2]; - - } - -} - - -void CNumerics::GetInviscidArtCompProjFlux(su2double *val_density, - su2double *val_velocity, - su2double *val_pressure, - su2double *val_betainc2, - su2double *val_normal, - su2double *val_Proj_Flux) { - su2double rhou, rhov, rhow; - - if (nDim == 2) { - rhou = (*val_density)*val_velocity[0]; - rhov = (*val_density)*val_velocity[1]; - - val_Proj_Flux[0] = (*val_betainc2)*(val_velocity[0]*val_normal[0] + val_velocity[1]*val_normal[1]); - val_Proj_Flux[1] = (rhou*val_velocity[0]+(*val_pressure))*val_normal[0] + rhou*val_velocity[1]*val_normal[1]; - val_Proj_Flux[2] = rhov*val_velocity[0]*val_normal[0] + (rhov*val_velocity[1]+(*val_pressure))*val_normal[1]; - } - else { - rhou = (*val_density)*val_velocity[0]; - rhov = (*val_density)*val_velocity[1]; - rhow = (*val_density)*val_velocity[2]; - - val_Proj_Flux[0] = (*val_betainc2)*(val_velocity[0]*val_normal[0] + val_velocity[1]*val_normal[1] + val_velocity[2]*val_normal[2]); - val_Proj_Flux[1] = (rhou*val_velocity[0]+(*val_pressure))*val_normal[0] + rhou*val_velocity[1]*val_normal[1] + rhou*val_velocity[2]*val_normal[2]; - val_Proj_Flux[2] = rhov*val_velocity[0]*val_normal[0] + (rhov*val_velocity[1]+(*val_pressure))*val_normal[1] + rhov*val_velocity[2]*val_normal[2]; - val_Proj_Flux[3] = rhow*val_velocity[0]*val_normal[0] + rhow*val_velocity[1]*val_normal[1] + (rhow*val_velocity[2]+(*val_pressure))*val_normal[2]; - } - -} - -void CNumerics::GetInviscidArtComp_FreeSurf_ProjFlux(su2double *val_density, su2double *val_velocity, su2double *val_pressure, su2double *val_betainc2, - su2double *val_levelset, su2double *val_normal, su2double *val_Proj_Flux) { - - su2double rhou, rhov, rhow, ProjVel; - - if (nDim == 2) { - rhou = (*val_density)*val_velocity[0]; - rhov = (*val_density)*val_velocity[1]; - ProjVel = (val_velocity[0]*val_normal[0] + val_velocity[1]*val_normal[1]); - - val_Proj_Flux[0] = (*val_betainc2)*ProjVel; - val_Proj_Flux[1] = (rhou*val_velocity[0]+(*val_pressure))*val_normal[0] + rhou*val_velocity[1]*val_normal[1]; - val_Proj_Flux[2] = rhov*val_velocity[0]*val_normal[0] + (rhov*val_velocity[1]+(*val_pressure))*val_normal[1]; - val_Proj_Flux[3] = (*val_levelset)*ProjVel; - } - else { - rhou = (*val_density)*val_velocity[0]; - rhov = (*val_density)*val_velocity[1]; - rhow = (*val_density)*val_velocity[2]; - ProjVel = (val_velocity[0]*val_normal[0] + val_velocity[1]*val_normal[1] + val_velocity[2]*val_normal[2]); - - val_Proj_Flux[0] = (*val_betainc2)*ProjVel; - val_Proj_Flux[1] = (rhou*val_velocity[0]+(*val_pressure))*val_normal[0] + rhou*val_velocity[1]*val_normal[1] + rhou*val_velocity[2]*val_normal[2]; - val_Proj_Flux[2] = rhov*val_velocity[0]*val_normal[0] + (rhov*val_velocity[1]+(*val_pressure))*val_normal[1] + rhov*val_velocity[2]*val_normal[2]; - val_Proj_Flux[3] = rhow*val_velocity[0]*val_normal[0] + rhow*val_velocity[1]*val_normal[1] + (rhow*val_velocity[2]+(*val_pressure))*val_normal[2]; - val_Proj_Flux[4] = (*val_levelset)*ProjVel; - } -} - -void CNumerics::GetInviscidProjJac(su2double *val_velocity, su2double *val_energy, - su2double *val_normal, su2double val_scale, - su2double **val_Proj_Jac_Tensor) { - AD_BEGIN_PASSIVE - unsigned short iDim, jDim; - su2double sqvel, proj_vel, phi, a1, a2; - - sqvel = 0.0, proj_vel = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - sqvel += val_velocity[iDim]*val_velocity[iDim]; - proj_vel += val_velocity[iDim]*val_normal[iDim]; - } - - phi = 0.5*Gamma_Minus_One*sqvel; - a1 = Gamma*(*val_energy)-phi; - a2 = Gamma-1.0; - - val_Proj_Jac_Tensor[0][0] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - val_Proj_Jac_Tensor[0][iDim+1] = val_scale*val_normal[iDim]; - val_Proj_Jac_Tensor[0][nDim+1] = 0.0; - - for (iDim = 0; iDim < nDim; iDim++) { - val_Proj_Jac_Tensor[iDim+1][0] = val_scale*(val_normal[iDim]*phi - val_velocity[iDim]*proj_vel); - for (jDim = 0; jDim < nDim; jDim++) - val_Proj_Jac_Tensor[iDim+1][jDim+1] = val_scale*(val_normal[jDim]*val_velocity[iDim]-a2*val_normal[iDim]*val_velocity[jDim]); - val_Proj_Jac_Tensor[iDim+1][iDim+1] += val_scale*proj_vel; - val_Proj_Jac_Tensor[iDim+1][nDim+1] = val_scale*a2*val_normal[iDim]; - } - - val_Proj_Jac_Tensor[nDim+1][0] = val_scale*proj_vel*(phi-a1); - for (iDim = 0; iDim < nDim; iDim++) - val_Proj_Jac_Tensor[nDim+1][iDim+1] = val_scale*(val_normal[iDim]*a1-a2*val_velocity[iDim]*proj_vel); - val_Proj_Jac_Tensor[nDim+1][nDim+1] = val_scale*Gamma*proj_vel; - AD_END_PASSIVE -} - - -void CNumerics::GetInviscidProjJac(su2double *val_velocity, su2double *val_enthalpy, - su2double *val_chi, su2double *val_kappa, - su2double *val_normal, su2double val_scale, - su2double **val_Proj_Jac_Tensor) { - AD_BEGIN_PASSIVE - unsigned short iDim, jDim; - su2double sqvel, proj_vel, phi, a1, a2; - - sqvel = 0.0, proj_vel = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - sqvel += val_velocity[iDim]*val_velocity[iDim]; - proj_vel += val_velocity[iDim]*val_normal[iDim]; - } - - phi = *val_chi + 0.5*sqvel*(*val_kappa); - a1 = *val_enthalpy; - a2 = *val_kappa; - - val_Proj_Jac_Tensor[0][0] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - val_Proj_Jac_Tensor[0][iDim+1] = val_scale*val_normal[iDim]; - val_Proj_Jac_Tensor[0][nDim+1] = 0.0; - - for (iDim = 0; iDim < nDim; iDim++) { - val_Proj_Jac_Tensor[iDim+1][0] = val_scale*(val_normal[iDim]*phi - val_velocity[iDim]*proj_vel); - for (jDim = 0; jDim < nDim; jDim++) - val_Proj_Jac_Tensor[iDim+1][jDim+1] = val_scale*(val_normal[jDim]*val_velocity[iDim]-a2*val_normal[iDim]*val_velocity[jDim]); - val_Proj_Jac_Tensor[iDim+1][iDim+1] += val_scale*proj_vel; - val_Proj_Jac_Tensor[iDim+1][nDim+1] = val_scale*a2*val_normal[iDim]; - } - - val_Proj_Jac_Tensor[nDim+1][0] = val_scale*proj_vel*(phi-a1); - for (iDim = 0; iDim < nDim; iDim++) - val_Proj_Jac_Tensor[nDim+1][iDim+1] = val_scale*(val_normal[iDim]*a1-a2*val_velocity[iDim]*proj_vel); - val_Proj_Jac_Tensor[nDim+1][nDim+1] = val_scale*(a2+1)*proj_vel; - AD_END_PASSIVE -} - -void CNumerics::GetInviscidArtCompProjJac(su2double *val_density, su2double *val_velocity, su2double *val_betainc2, su2double *val_normal, - su2double val_scale, su2double **val_Proj_Jac_Tensor) { - AD_BEGIN_PASSIVE - unsigned short iDim; - su2double proj_vel; - - proj_vel = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - proj_vel += val_velocity[iDim]*val_normal[iDim]; - - if (nDim == 2) { - val_Proj_Jac_Tensor[0][0] = 0.0; - val_Proj_Jac_Tensor[0][1] = val_scale*(*val_betainc2)*val_normal[0]/(*val_density); - val_Proj_Jac_Tensor[0][2] = val_scale*(*val_betainc2)*val_normal[1]/(*val_density); - - val_Proj_Jac_Tensor[1][0] = val_scale*val_normal[0]; - val_Proj_Jac_Tensor[1][1] = val_scale*(val_velocity[0]*val_normal[0] + proj_vel); - val_Proj_Jac_Tensor[1][2] = val_scale*val_velocity[0]*val_normal[1]; - - val_Proj_Jac_Tensor[2][0] = val_scale*val_normal[1]; - val_Proj_Jac_Tensor[2][1] = val_scale*val_velocity[1]*val_normal[0]; - val_Proj_Jac_Tensor[2][2] = val_scale*(val_velocity[1]*val_normal[1] + proj_vel); - } - else { - val_Proj_Jac_Tensor[0][0] = 0.0; - val_Proj_Jac_Tensor[0][1] = val_scale*(*val_betainc2)*val_normal[0]/(*val_density); - val_Proj_Jac_Tensor[0][2] = val_scale*(*val_betainc2)*val_normal[1]/(*val_density); - val_Proj_Jac_Tensor[0][3] = val_scale*(*val_betainc2)*val_normal[2]/(*val_density); - - val_Proj_Jac_Tensor[1][0] = val_scale*val_normal[0]; - val_Proj_Jac_Tensor[1][1] = val_scale*(val_velocity[0]*val_normal[0] + proj_vel); - val_Proj_Jac_Tensor[1][2] = val_scale*val_velocity[0]*val_normal[1]; - val_Proj_Jac_Tensor[1][3] = val_scale*val_velocity[0]*val_normal[2]; - - val_Proj_Jac_Tensor[2][0] = val_scale*val_normal[1]; - val_Proj_Jac_Tensor[2][1] = val_scale*val_velocity[1]*val_normal[0]; - val_Proj_Jac_Tensor[2][2] = val_scale*(val_velocity[1]*val_normal[1] + proj_vel); - val_Proj_Jac_Tensor[2][3] = val_scale*val_velocity[1]*val_normal[2]; - - val_Proj_Jac_Tensor[3][0] = val_scale*val_normal[2]; - val_Proj_Jac_Tensor[3][1] = val_scale*val_velocity[2]*val_normal[0]; - val_Proj_Jac_Tensor[3][2] = val_scale*val_velocity[2]*val_normal[1]; - val_Proj_Jac_Tensor[3][3] = val_scale*(val_velocity[2]*val_normal[2] + proj_vel); - } - AD_END_PASSIVE -} - -void CNumerics::GetInviscidArtComp_FreeSurf_ProjJac(su2double *val_density, su2double *val_ddensity, su2double *val_velocity, su2double *val_betainc2, su2double *val_levelset, su2double *val_normal, - su2double val_scale, su2double **val_Proj_Jac_Tensor) { - - su2double a = 0.0, b = 0.0, c = 0.0, d = 0.0, nx = 0.0, ny = 0.0, nz = 0.0, u = 0.0, v = 0.0, w = 0.0; - - a = (*val_betainc2)/(*val_density); - b = (*val_levelset)/(*val_density); - c = (*val_ddensity); - - if (nDim == 2) { - - nx = val_normal[0]; ny = val_normal[1]; - u = val_velocity[0]; v = val_velocity[1]; d = u*nx + v*ny; - - val_Proj_Jac_Tensor[0][0] = 0.0; - val_Proj_Jac_Tensor[0][1] = val_scale*a*nx; - val_Proj_Jac_Tensor[0][2] = val_scale*a*ny; - val_Proj_Jac_Tensor[0][3] = - val_scale*a*c*d; - - - val_Proj_Jac_Tensor[1][0] = val_scale*nx; - val_Proj_Jac_Tensor[1][1] = val_scale*(d + nx*u); - val_Proj_Jac_Tensor[1][2] = val_scale*ny*u; - val_Proj_Jac_Tensor[1][3] = -val_scale*c*d*u; - - - val_Proj_Jac_Tensor[2][0] = val_scale*ny; - val_Proj_Jac_Tensor[2][1] = val_scale*nx*v; - val_Proj_Jac_Tensor[2][2] = val_scale*(d + ny*v); - val_Proj_Jac_Tensor[2][3] = -val_scale*c*d*v; - - - val_Proj_Jac_Tensor[3][0] = 0.0; - val_Proj_Jac_Tensor[3][1] = val_scale*b*nx; - val_Proj_Jac_Tensor[3][2] = val_scale*b*ny; - val_Proj_Jac_Tensor[3][3] = val_scale*(d - b*c*d); - - } - else { - - nx = val_normal[0]; ny = val_normal[1]; nz = val_normal[2]; - u = val_velocity[0]; v = val_velocity[1]; w = val_velocity[2]; d = u*nx + v*ny + w*nz; - - val_Proj_Jac_Tensor[0][0] = 0.0; - val_Proj_Jac_Tensor[0][1] = val_scale*a*nx; - val_Proj_Jac_Tensor[0][2] = val_scale*a*ny; - val_Proj_Jac_Tensor[0][3] = val_scale*a*nz; - val_Proj_Jac_Tensor[0][4] = - val_scale*a*c*d; - - - val_Proj_Jac_Tensor[1][0] = val_scale*nx; - val_Proj_Jac_Tensor[1][1] = val_scale*(d + nx*u); - val_Proj_Jac_Tensor[1][2] = val_scale*ny*u; - val_Proj_Jac_Tensor[1][3] = val_scale*nz*u; - val_Proj_Jac_Tensor[1][4] = -val_scale*c*d*u; - - - val_Proj_Jac_Tensor[2][0] = val_scale*ny; - val_Proj_Jac_Tensor[2][1] = val_scale*nx*v; - val_Proj_Jac_Tensor[2][2] = val_scale*(d + ny*v); - val_Proj_Jac_Tensor[2][3] = val_scale*nz*v; - val_Proj_Jac_Tensor[2][4] = -val_scale*c*d*v; - - val_Proj_Jac_Tensor[3][0] = val_scale*nz; - val_Proj_Jac_Tensor[3][1] = val_scale*nx*w; - val_Proj_Jac_Tensor[3][2] = val_scale*ny*w; - val_Proj_Jac_Tensor[3][3] = val_scale*(d + nz*w); - val_Proj_Jac_Tensor[3][4] = -val_scale*c*d*w; - - val_Proj_Jac_Tensor[3][0] = 0.0; - val_Proj_Jac_Tensor[3][1] = val_scale*b*nx; - val_Proj_Jac_Tensor[3][2] = val_scale*b*ny; - val_Proj_Jac_Tensor[3][3] = val_scale*b*nz; - val_Proj_Jac_Tensor[3][4] = val_scale*(d - b*c*d); - - } - -} - -void CNumerics::SetPastSol (su2double *val_u_nM1, su2double *val_u_n, su2double *val_u_nP1) { - unsigned short iVar; - - for (iVar = 0; iVar < nVar; iVar++) { - U_nM1[iVar] = val_u_nM1[iVar]; - U_n[iVar] = val_u_n[iVar]; - U_nP1[iVar] = val_u_nP1[iVar]; - } - -} -void CNumerics::SetPastVolume (su2double val_volume_nM1, su2double val_volume_n, su2double val_volume_nP1) { - Volume_nM1 = val_volume_nM1; - Volume_n = val_volume_n; - Volume_nP1 = val_volume_nP1; -} - - -void CNumerics::GetPMatrix(su2double *val_density, su2double *val_velocity, - su2double *val_soundspeed, su2double *val_normal, su2double **val_p_tensor) { - - su2double sqvel, rhooc, rhoxc; - //su2double c2; - - rhooc = *val_density / *val_soundspeed; - rhoxc = *val_density * *val_soundspeed; - //c2 = *val_soundspeed * *val_soundspeed; - - if (nDim == 2) { - - sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]; - - val_p_tensor[0][0]=1.0; - val_p_tensor[0][1]=0.0; - val_p_tensor[0][2]=0.5*rhooc; - val_p_tensor[0][3]=0.5*rhooc; - - val_p_tensor[1][0]=val_velocity[0]; - val_p_tensor[1][1]=*val_density*val_normal[1]; - val_p_tensor[1][2]=0.5*(val_velocity[0]*rhooc+val_normal[0]**val_density); - val_p_tensor[1][3]=0.5*(val_velocity[0]*rhooc-val_normal[0]**val_density); - - val_p_tensor[2][0]=val_velocity[1]; - val_p_tensor[2][1]=-*val_density*val_normal[0]; - val_p_tensor[2][2]=0.5*(val_velocity[1]*rhooc+val_normal[1]**val_density); - val_p_tensor[2][3]=0.5*(val_velocity[1]*rhooc-val_normal[1]**val_density); - - val_p_tensor[3][0]=0.5*sqvel; - val_p_tensor[3][1]=*val_density*val_velocity[0]*val_normal[1]-*val_density*val_velocity[1]*val_normal[0]; - val_p_tensor[3][2]=0.5*(0.5*sqvel*rhooc+*val_density*val_velocity[0]*val_normal[0]+*val_density*val_velocity[1]*val_normal[1]+rhoxc/Gamma_Minus_One); - val_p_tensor[3][3]=0.5*(0.5*sqvel*rhooc-*val_density*val_velocity[0]*val_normal[0]-*val_density*val_velocity[1]*val_normal[1]+rhoxc/Gamma_Minus_One); - - } - else { - - sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]+val_velocity[2]*val_velocity[2]; - - val_p_tensor[0][0]=val_normal[0]; - val_p_tensor[0][1]=val_normal[1]; - val_p_tensor[0][2]=val_normal[2]; - val_p_tensor[0][3]=0.5*rhooc; - val_p_tensor[0][4]=0.5*rhooc; - - val_p_tensor[1][0]=val_velocity[0]*val_normal[0]; - val_p_tensor[1][1]=val_velocity[0]*val_normal[1]-*val_density*val_normal[2]; - val_p_tensor[1][2]=val_velocity[0]*val_normal[2]+*val_density*val_normal[1]; - val_p_tensor[1][3]=0.5*(val_velocity[0]*rhooc+*val_density*val_normal[0]); - val_p_tensor[1][4]=0.5*(val_velocity[0]*rhooc-*val_density*val_normal[0]); - - val_p_tensor[2][0]=val_velocity[1]*val_normal[0]+*val_density*val_normal[2]; - val_p_tensor[2][1]=val_velocity[1]*val_normal[1]; - val_p_tensor[2][2]=val_velocity[1]*val_normal[2]-*val_density*val_normal[0]; - val_p_tensor[2][3]=0.5*(val_velocity[1]*rhooc+*val_density*val_normal[1]); - val_p_tensor[2][4]=0.5*(val_velocity[1]*rhooc-*val_density*val_normal[1]); - - val_p_tensor[3][0]=val_velocity[2]*val_normal[0]-*val_density*val_normal[1]; - val_p_tensor[3][1]=val_velocity[2]*val_normal[1]+*val_density*val_normal[0]; - val_p_tensor[3][2]=val_velocity[2]*val_normal[2]; - val_p_tensor[3][3]=0.5*(val_velocity[2]*rhooc+*val_density*val_normal[2]); - val_p_tensor[3][4]=0.5*(val_velocity[2]*rhooc-*val_density*val_normal[2]); - - val_p_tensor[4][0]=0.5*sqvel*val_normal[0]+*val_density*val_velocity[1]*val_normal[2]-*val_density*val_velocity[2]*val_normal[1]; - val_p_tensor[4][1]=0.5*sqvel*val_normal[1]-*val_density*val_velocity[0]*val_normal[2]+*val_density*val_velocity[2]*val_normal[0]; - val_p_tensor[4][2]=0.5*sqvel*val_normal[2]+*val_density*val_velocity[0]*val_normal[1]-*val_density*val_velocity[1]*val_normal[0]; - val_p_tensor[4][3]=0.5*(0.5*sqvel*rhooc+*val_density*(val_velocity[0]*val_normal[0]+val_velocity[1]*val_normal[1]+val_velocity[2]*val_normal[2])+rhoxc/Gamma_Minus_One); - val_p_tensor[4][4]=0.5*(0.5*sqvel*rhooc-*val_density*(val_velocity[0]*val_normal[0]+val_velocity[1]*val_normal[1]+val_velocity[2]*val_normal[2])+rhoxc/Gamma_Minus_One); - - } - -} - -void CNumerics::GetPMatrix(su2double *val_density, su2double *val_velocity, - su2double *val_soundspeed, su2double *val_enthalpy, su2double *val_chi, su2double *val_kappa, su2double *val_normal, su2double **val_p_tensor) { - - su2double sqvel, rhooc, zeta; - //su2double rhoxc, c2; - - rhooc = *val_density / *val_soundspeed; - //rhoxc = *val_density * *val_soundspeed; - //c2 = *val_soundspeed * *val_soundspeed; - - if (nDim == 2) { - sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]; - zeta = sqvel - (*val_kappa*0.5*sqvel + *val_chi)/(*val_kappa); - - val_p_tensor[0][0]=1.0; - val_p_tensor[0][1]=0.0; - val_p_tensor[0][2]=0.5*rhooc; - val_p_tensor[0][3]=0.5*rhooc; - - val_p_tensor[1][0]=val_velocity[0]; - val_p_tensor[1][1]=*val_density*val_normal[1]; - val_p_tensor[1][2]=0.5*(val_velocity[0]*rhooc+val_normal[0]**val_density); - val_p_tensor[1][3]=0.5*(val_velocity[0]*rhooc-val_normal[0]**val_density); - - val_p_tensor[2][0]=val_velocity[1]; - val_p_tensor[2][1]=-*val_density*val_normal[0]; - val_p_tensor[2][2]=0.5*(val_velocity[1]*rhooc+val_normal[1]**val_density); - val_p_tensor[2][3]=0.5*(val_velocity[1]*rhooc-val_normal[1]**val_density); - - val_p_tensor[3][0]= zeta; - val_p_tensor[3][1]=*val_density*val_velocity[0]*val_normal[1]-*val_density*val_velocity[1]*val_normal[0]; - val_p_tensor[3][2]=0.5*(*val_enthalpy*rhooc+*val_density*val_velocity[0]*val_normal[0]+*val_density*val_velocity[1]*val_normal[1]); - val_p_tensor[3][3]=0.5*(*val_enthalpy*rhooc-*val_density*val_velocity[0]*val_normal[0]-*val_density*val_velocity[1]*val_normal[1]); - } - else { - sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]+val_velocity[2]*val_velocity[2]; - zeta = sqvel - (*val_kappa*0.5*sqvel + *val_chi)/(*val_kappa); - - val_p_tensor[0][0]=val_normal[0]; - val_p_tensor[0][1]=val_normal[1]; - val_p_tensor[0][2]=val_normal[2]; - val_p_tensor[0][3]=0.5*rhooc; - val_p_tensor[0][4]=0.5*rhooc; - - val_p_tensor[1][0]=val_velocity[0]*val_normal[0]; - val_p_tensor[1][1]=val_velocity[0]*val_normal[1]-*val_density*val_normal[2]; - val_p_tensor[1][2]=val_velocity[0]*val_normal[2]+*val_density*val_normal[1]; - val_p_tensor[1][3]=0.5*(val_velocity[0]*rhooc+*val_density*val_normal[0]); - val_p_tensor[1][4]=0.5*(val_velocity[0]*rhooc-*val_density*val_normal[0]); - - val_p_tensor[2][0]=val_velocity[1]*val_normal[0]+*val_density*val_normal[2]; - val_p_tensor[2][1]=val_velocity[1]*val_normal[1]; - val_p_tensor[2][2]=val_velocity[1]*val_normal[2]-*val_density*val_normal[0]; - val_p_tensor[2][3]=0.5*(val_velocity[1]*rhooc+*val_density*val_normal[1]); - val_p_tensor[2][4]=0.5*(val_velocity[1]*rhooc-*val_density*val_normal[1]); - - val_p_tensor[3][0]=val_velocity[2]*val_normal[0]-*val_density*val_normal[1]; - val_p_tensor[3][1]=val_velocity[2]*val_normal[1]+*val_density*val_normal[0]; - val_p_tensor[3][2]=val_velocity[2]*val_normal[2]; - val_p_tensor[3][3]=0.5*(val_velocity[2]*rhooc+*val_density*val_normal[2]); - val_p_tensor[3][4]=0.5*(val_velocity[2]*rhooc-*val_density*val_normal[2]); - - val_p_tensor[4][0]=zeta*val_normal[0]+*val_density*val_velocity[1]*val_normal[2]-*val_density*val_velocity[2]*val_normal[1]; - val_p_tensor[4][1]=zeta*val_normal[1]-*val_density*val_velocity[0]*val_normal[2]+*val_density*val_velocity[2]*val_normal[0]; - val_p_tensor[4][2]=zeta*val_normal[2]+*val_density*val_velocity[0]*val_normal[1]-*val_density*val_velocity[1]*val_normal[0]; - val_p_tensor[4][3]=0.5*(*val_enthalpy*rhooc+*val_density*(val_velocity[0]*val_normal[0]+val_velocity[1]*val_normal[1]+val_velocity[2]*val_normal[2])); - val_p_tensor[4][4]=0.5*(*val_enthalpy*rhooc-*val_density*(val_velocity[0]*val_normal[0]+val_velocity[1]*val_normal[1]+val_velocity[2]*val_normal[2])); - } - -} - -void CNumerics::GetPMatrix_inv(su2double *val_density, su2double *val_velocity, - su2double *val_soundspeed, su2double *val_normal, su2double **val_invp_tensor) { - - su2double rhoxc, c2, gm1, k0orho, k1orho, gm1_o_c2, gm1_o_rhoxc, sqvel; - - rhoxc = *val_density * *val_soundspeed; - c2 = *val_soundspeed * *val_soundspeed; - gm1 = Gamma_Minus_One; - k0orho = val_normal[0] / *val_density; - k1orho = val_normal[1] / *val_density; - gm1_o_c2 = gm1/c2; - gm1_o_rhoxc = gm1/rhoxc; - - if (nDim == 3) { - - sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]+val_velocity[2]*val_velocity[2]; - - val_invp_tensor[0][0]=val_normal[0]-val_normal[2]*val_velocity[1] / *val_density+val_normal[1]*val_velocity[2] / *val_density-val_normal[0]*0.5*gm1*sqvel/c2; - val_invp_tensor[0][1]=val_normal[0]*gm1*val_velocity[0]/c2; - val_invp_tensor[0][2]=val_normal[2] / *val_density+val_normal[0]*gm1*val_velocity[1]/c2; - val_invp_tensor[0][3]=-val_normal[1] / *val_density+val_normal[0]*gm1*val_velocity[2]/c2; - val_invp_tensor[0][4]=-val_normal[0]*gm1/c2; - - val_invp_tensor[1][0]=val_normal[1]+val_normal[2]*val_velocity[0] / *val_density-val_normal[0]*val_velocity[2] / *val_density-val_normal[1]*0.5*gm1*sqvel/c2; - val_invp_tensor[1][1]=-val_normal[2] / *val_density+val_normal[1]*gm1*val_velocity[0]/c2; - val_invp_tensor[1][2]=val_normal[1]*gm1*val_velocity[1]/c2; - val_invp_tensor[1][3]=val_normal[0] / *val_density+val_normal[1]*gm1*val_velocity[2]/c2; - val_invp_tensor[1][4]=-val_normal[1]*gm1/c2; - - val_invp_tensor[2][0]=val_normal[2]-val_normal[1]*val_velocity[0] / *val_density+val_normal[0]*val_velocity[1] / *val_density-val_normal[2]*0.5*gm1*sqvel/c2; - val_invp_tensor[2][1]=val_normal[1] / *val_density+val_normal[2]*gm1*val_velocity[0]/c2; - val_invp_tensor[2][2]=-val_normal[0] / *val_density+val_normal[2]*gm1*val_velocity[1]/c2; - val_invp_tensor[2][3]=val_normal[2]*gm1*val_velocity[2]/c2; - val_invp_tensor[2][4]=-val_normal[2]*gm1/c2; - - val_invp_tensor[3][0]=-(val_normal[0]*val_velocity[0]+val_normal[1]*val_velocity[1]+val_normal[2]*val_velocity[2]) / *val_density+0.5*gm1*sqvel/rhoxc; - val_invp_tensor[3][1]=val_normal[0] / *val_density-gm1*val_velocity[0]/rhoxc; - val_invp_tensor[3][2]=val_normal[1] / *val_density-gm1*val_velocity[1]/rhoxc; - val_invp_tensor[3][3]=val_normal[2] / *val_density-gm1*val_velocity[2]/rhoxc; - val_invp_tensor[3][4]=Gamma_Minus_One/rhoxc; - - val_invp_tensor[4][0]=(val_normal[0]*val_velocity[0]+val_normal[1]*val_velocity[1]+val_normal[2]*val_velocity[2]) / *val_density+0.5*gm1*sqvel/rhoxc; - val_invp_tensor[4][1]=-val_normal[0] / *val_density-gm1*val_velocity[0]/rhoxc; - val_invp_tensor[4][2]=-val_normal[1] / *val_density-gm1*val_velocity[1]/rhoxc; - val_invp_tensor[4][3]=-val_normal[2] / *val_density-gm1*val_velocity[2]/rhoxc; - val_invp_tensor[4][4]=Gamma_Minus_One/rhoxc; - - } - if (nDim == 2) { - - sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]; - - val_invp_tensor[0][0]=1.0-0.5*gm1_o_c2*sqvel; - val_invp_tensor[0][1]=gm1_o_c2*val_velocity[0]; - val_invp_tensor[0][2]=gm1_o_c2*val_velocity[1]; - val_invp_tensor[0][3]=-gm1_o_c2; - - val_invp_tensor[1][0]=-k1orho*val_velocity[0]+k0orho*val_velocity[1]; - val_invp_tensor[1][1]=k1orho; - val_invp_tensor[1][2]=-k0orho; - val_invp_tensor[1][3]=0.0; - - val_invp_tensor[2][0]=-k0orho*val_velocity[0]-k1orho*val_velocity[1]+0.5*gm1_o_rhoxc*sqvel; - val_invp_tensor[2][1]=k0orho-gm1_o_rhoxc*val_velocity[0]; - val_invp_tensor[2][2]=k1orho-gm1_o_rhoxc*val_velocity[1]; - val_invp_tensor[2][3]=gm1_o_rhoxc; - - val_invp_tensor[3][0]=k0orho*val_velocity[0]+k1orho*val_velocity[1]+0.5*gm1_o_rhoxc*sqvel; - val_invp_tensor[3][1]=-k0orho-gm1_o_rhoxc*val_velocity[0]; - val_invp_tensor[3][2]=-k1orho-gm1_o_rhoxc*val_velocity[1]; - val_invp_tensor[3][3]=gm1_o_rhoxc; - - } -} - -void CNumerics::GetPMatrix_inv(su2double **val_invp_tensor, su2double *val_density, su2double *val_velocity, - su2double *val_soundspeed, su2double *val_chi, su2double *val_kappa, su2double *val_normal) { - - su2double rhoxc, c2, k0orho, k1orho, sqvel, k_o_c2, k_o_rhoxc, dp_drho; - - rhoxc = *val_density * *val_soundspeed; - c2 = *val_soundspeed * *val_soundspeed; - k0orho = val_normal[0] / *val_density; - k1orho = val_normal[1] / *val_density; - k_o_c2 = (*val_kappa)/c2; - k_o_rhoxc = (*val_kappa)/rhoxc; - - - if (nDim == 3) { - sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]+val_velocity[2]*val_velocity[2]; - dp_drho = *val_chi + 0.5*sqvel*(*val_kappa); - - val_invp_tensor[0][0]=val_normal[0]-val_normal[2]*val_velocity[1] / *val_density + val_normal[1]*val_velocity[2] / *val_density - val_normal[0]*dp_drho/c2; - val_invp_tensor[0][1]=val_normal[0]*val_velocity[0]*k_o_c2; - val_invp_tensor[0][2]=val_normal[2] / *val_density + val_normal[0]*val_velocity[1]*k_o_c2; - val_invp_tensor[0][3]=-val_normal[1] / *val_density + val_normal[0]*val_velocity[2]*k_o_c2; - val_invp_tensor[0][4]=-val_normal[0]*k_o_c2; - - val_invp_tensor[1][0]=val_normal[1]+val_normal[2]*val_velocity[0] / *val_density - val_normal[0]*val_velocity[2] / *val_density - val_normal[1]*dp_drho/c2; - val_invp_tensor[1][1]=-val_normal[2] / *val_density + val_normal[1]*val_velocity[0]*k_o_c2; - val_invp_tensor[1][2]=val_normal[1]*val_velocity[1]*k_o_c2; - val_invp_tensor[1][3]=val_normal[0] / *val_density + val_normal[1]*val_velocity[2]*k_o_c2; - val_invp_tensor[1][4]=-val_normal[1]*k_o_c2; - - val_invp_tensor[2][0]=val_normal[2]-val_normal[1]*val_velocity[0] / *val_density + val_normal[0]*val_velocity[1] / *val_density - val_normal[2]*dp_drho/c2; - val_invp_tensor[2][1]=val_normal[1] / *val_density + val_normal[2]*val_velocity[0]*k_o_c2; - val_invp_tensor[2][2]=-val_normal[0] / *val_density + val_normal[2]*val_velocity[1]*k_o_c2; - val_invp_tensor[2][3]=val_normal[2]*val_velocity[2]*k_o_c2; - val_invp_tensor[2][4]=-val_normal[2]*k_o_c2; - - val_invp_tensor[3][0]=-(val_normal[0]*val_velocity[0]+val_normal[1]*val_velocity[1]+val_normal[2]*val_velocity[2]) / *val_density+ dp_drho/rhoxc; - val_invp_tensor[3][1]=val_normal[0] / *val_density - val_velocity[0]*k_o_rhoxc; - val_invp_tensor[3][2]=val_normal[1] / *val_density- val_velocity[1]*k_o_rhoxc; - val_invp_tensor[3][3]=val_normal[2] / *val_density- val_velocity[2]*k_o_rhoxc; - val_invp_tensor[3][4]= k_o_rhoxc; - - val_invp_tensor[4][0]=(val_normal[0]*val_velocity[0]+val_normal[1]*val_velocity[1]+val_normal[2]*val_velocity[2]) / *val_density+ dp_drho/rhoxc; - val_invp_tensor[4][1]=-val_normal[0] / *val_density- val_velocity[0]*k_o_rhoxc; - val_invp_tensor[4][2]=-val_normal[1] / *val_density- val_velocity[1]*k_o_rhoxc; - val_invp_tensor[4][3]=-val_normal[2] / *val_density- val_velocity[2]*k_o_rhoxc; - val_invp_tensor[4][4]= k_o_rhoxc; - } - if (nDim == 2) { - sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]; - dp_drho = *val_chi + 0.5*sqvel*(*val_kappa); - - val_invp_tensor[0][0]=1.0 - dp_drho/c2; - val_invp_tensor[0][1]= k_o_c2*val_velocity[0]; - val_invp_tensor[0][2]= k_o_c2*val_velocity[1]; - val_invp_tensor[0][3]=-k_o_c2; - - val_invp_tensor[1][0]=-k1orho*val_velocity[0]+k0orho*val_velocity[1]; - val_invp_tensor[1][1]=k1orho; - val_invp_tensor[1][2]=-k0orho; - val_invp_tensor[1][3]=0.0; - - val_invp_tensor[2][0]=-k0orho*val_velocity[0]-k1orho*val_velocity[1] + dp_drho/rhoxc; - val_invp_tensor[2][1]=k0orho - k_o_rhoxc*val_velocity[0]; - val_invp_tensor[2][2]=k1orho - k_o_rhoxc*val_velocity[1]; - val_invp_tensor[2][3]=k_o_rhoxc; - - val_invp_tensor[3][0]=k0orho*val_velocity[0]+k1orho*val_velocity[1] + dp_drho/rhoxc; - val_invp_tensor[3][1]=-k0orho - k_o_rhoxc*val_velocity[0]; - val_invp_tensor[3][2]=-k1orho - k_o_rhoxc*val_velocity[1]; - val_invp_tensor[3][3]= k_o_rhoxc; - } -} - -void CNumerics::GetinvRinvPe(su2double Beta2, su2double val_enthalpy, - su2double val_soundspeed, su2double val_density, - su2double* val_velocity, su2double **invRinvPe) { - - su2double sqvel; - su2double factor = 1.0/(val_soundspeed*val_soundspeed*Beta2); - - if (nDim == 2) { - - sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]; - - invRinvPe[0][0] = factor; - invRinvPe[0][1] = 0.0; - invRinvPe[0][2] = 0.0; - invRinvPe[0][3] = -val_density/Gamma; - - invRinvPe[1][0] = val_velocity[0]*factor; - invRinvPe[1][1] = val_density; - invRinvPe[1][2] = 0.0; - invRinvPe[1][3] = -val_density*val_velocity[0]/Gamma; - - invRinvPe[2][0] = val_velocity[1]*factor; - invRinvPe[2][1] = 0; - invRinvPe[2][2] = val_density; - invRinvPe[2][3] = -val_density*val_velocity[1]/Gamma; - - invRinvPe[3][0] = val_enthalpy*factor; - invRinvPe[3][1] = val_density*val_velocity[0]; - invRinvPe[3][2] = val_density*val_velocity[1]; - invRinvPe[3][3] = -val_density*sqvel/(2.0*Gamma); - } - else { - - sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]+val_velocity[2]*val_velocity[2]; - - invRinvPe[0][0] = factor; - invRinvPe[0][1] = 0.0; - invRinvPe[0][2] = 0.0; - invRinvPe[0][3] = 0.0; - invRinvPe[0][4] = -val_density/Gamma; - - invRinvPe[1][0] = val_velocity[0]*factor; - invRinvPe[1][1] = val_density; - invRinvPe[1][2] = 0.0; - invRinvPe[1][3] = 0.0; - invRinvPe[1][4] = -val_density*val_velocity[0]/Gamma; - - invRinvPe[2][0] = val_velocity[1]*factor; - invRinvPe[2][1] = 0; - invRinvPe[2][2] = val_density; - invRinvPe[2][3] = 0.0; - invRinvPe[2][4] = -val_density*val_velocity[1]/Gamma; - - - invRinvPe[3][0] = val_velocity[2]*factor; - invRinvPe[3][1] = 0; - invRinvPe[3][2] = 0; - invRinvPe[3][3] = val_density; - invRinvPe[3][4] = -val_density*val_velocity[2]/Gamma; - - invRinvPe[4][0] = val_enthalpy*factor; - invRinvPe[4][1] = val_density*val_velocity[0]; - invRinvPe[4][2] = val_density*val_velocity[1]; - invRinvPe[4][3] = val_density*val_velocity[2]; - invRinvPe[4][4] = -val_density*sqvel/(2.0*Gamma); - - } - -} - -void CNumerics::GetRMatrix(su2double val_pressure, su2double val_soundspeed, su2double val_density, su2double* val_velocity, su2double **R_Matrix) { - - su2double sqvel; - //su2double factor = 1.0/(val_soundspeed*val_soundspeed*1); - su2double gm1 = Gamma - 1.0; - - if (nDim == 2) { - - sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]; - - R_Matrix[0][0] = 0.5*gm1*sqvel; - R_Matrix[0][1] = -val_velocity[0]*gm1; - R_Matrix[0][2] = -val_velocity[1]*gm1; - R_Matrix[0][3] = gm1; - - R_Matrix[1][0] = -val_velocity[0]/val_density; - R_Matrix[1][1] = 1.0/val_density; - R_Matrix[1][2] = 0.0; - R_Matrix[1][3] = 0.0; - - R_Matrix[2][0] = -val_velocity[1]/val_density; - R_Matrix[2][1] = 0.0; - R_Matrix[2][2] = 1.0/val_density; - R_Matrix[2][3] = 0.0; - - R_Matrix[3][0] = 0.5*gm1*sqvel/val_pressure - Gamma/val_density; - R_Matrix[3][1] = -gm1*val_velocity[0]/val_pressure; - R_Matrix[3][2] = -gm1*val_velocity[1]/val_pressure; - R_Matrix[3][3] = gm1/val_pressure; - } - else { - - sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]+val_velocity[2]*val_velocity[2]; - - R_Matrix[0][0] = 0.5*gm1*sqvel; - R_Matrix[0][1] = -val_velocity[0]*gm1; - R_Matrix[0][2] = -val_velocity[1]*gm1; - R_Matrix[0][3] = -val_velocity[2]*gm1; - R_Matrix[0][4] = gm1; - - R_Matrix[1][0] = -val_velocity[0]/val_density; - R_Matrix[1][1] = 1.0/val_density; - R_Matrix[1][2] = 0.0; - R_Matrix[1][3] = 0.0; - R_Matrix[1][4] = 0.0; - - R_Matrix[2][0] = -val_velocity[1]/val_density; - R_Matrix[2][1] = 0.0; - R_Matrix[2][2] = 1.0/val_density; - R_Matrix[2][3] = 0.0; - R_Matrix[2][4] = 0.0; - - R_Matrix[3][0] = -val_velocity[2]/val_density; - R_Matrix[3][1] = 0.0; - R_Matrix[3][2] = 0.0; - R_Matrix[3][3] = 1.0/val_density; - R_Matrix[3][4] = 0.0; - - R_Matrix[4][0] = 0.5*gm1*sqvel/val_pressure - Gamma/val_density; - R_Matrix[4][1] = -gm1*val_velocity[0]/val_pressure; - R_Matrix[4][2] = -gm1*val_velocity[1]/val_pressure; - R_Matrix[4][3] = -gm1*val_velocity[2]/val_pressure; - R_Matrix[4][4] = gm1/val_pressure; - - } - -} - - - -void CNumerics::GetRMatrix(su2double val_soundspeed, su2double val_density, su2double* val_normal, su2double **R_Matrix) { - - if (nDim == 2) { - - - -// R_Matrix[0][0] = 1.0; -// R_Matrix[0][1] = 0.0; -// R_Matrix[0][2] = 0.5*val_density/val_soundspeed; -// R_Matrix[0][3] = 0.5*val_density/val_soundspeed; -// -// R_Matrix[1][0] = 0.0; -// R_Matrix[1][1] = val_normal[1]; -// R_Matrix[1][2] = 0.5*val_normal[0]; -// R_Matrix[1][3] = -0.5*val_normal[0]; -// -// R_Matrix[2][0] = 0.0; -// R_Matrix[2][1] = -val_normal[0]; -// R_Matrix[2][2] = 0.5*val_normal[1]; -// R_Matrix[2][3] = -0.5*val_normal[1]; -// -// R_Matrix[3][0] = 0.0; -// R_Matrix[3][1] = 0.0; -// R_Matrix[3][2] = 0.5*val_density*val_soundspeed; -// R_Matrix[3][3] = 0.5*val_density*val_soundspeed; - - su2double cc, rhoc; - cc = val_soundspeed*val_soundspeed; - rhoc = val_density/val_soundspeed; - - R_Matrix[0][0] = -1.0/cc; - R_Matrix[0][1] = 0.0; - R_Matrix[0][2] = 0.5/cc; - R_Matrix[0][3] = 0.5/cc; - - R_Matrix[1][0] = 0.0; - R_Matrix[1][1] = 0.0; - R_Matrix[1][2] = 0.5/rhoc; - R_Matrix[1][3] = -0.5/rhoc; - - R_Matrix[2][0] = 0.0; - R_Matrix[2][1] = 1.0/rhoc; - R_Matrix[2][2] = 0.0; - R_Matrix[2][3] = 0.0; - - R_Matrix[3][0] = 0.0; - R_Matrix[3][1] = 0.0; - R_Matrix[3][2] = 0.5; - R_Matrix[3][3] = 0.5; - - } - else { - -// sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]+val_velocity[2]*val_velocity[2]; -// -// R_Matrix[0][0] = 0.5*gm1*sqvel; -// R_Matrix[0][1] = -val_velocity[0]*gm1; -// R_Matrix[0][2] = -val_velocity[1]*gm1; -// R_Matrix[0][3] = -val_velocity[2]*gm1; -// R_Matrix[0][4] = gm1; -// -// R_Matrix[1][0] = -val_velocity[0]/val_density; -// R_Matrix[1][1] = 1.0/val_density; -// R_Matrix[1][2] = 0.0; -// R_Matrix[1][3] = 0.0; -// R_Matrix[1][4] = 0.0; -// -// R_Matrix[2][0] = -val_velocity[1]/val_density; -// R_Matrix[2][1] = 0.0; -// R_Matrix[2][2] = 1.0/val_density; -// R_Matrix[2][3] = 0.0; -// R_Matrix[2][4] = 0.0; -// -// R_Matrix[3][0] = -val_velocity[2]/val_density; -// R_Matrix[3][1] = 0.0; -// R_Matrix[3][2] = 0.0; -// R_Matrix[3][3] = 1.0/val_density; -// R_Matrix[3][4] = 0.0; -// -// R_Matrix[4][0] = 0.5*gm1*sqvel/val_pressure - Gamma/val_density; -// R_Matrix[4][1] = -gm1*val_velocity[0]/val_pressure; -// R_Matrix[4][2] = -gm1*val_velocity[1]/val_pressure; -// R_Matrix[4][3] = -gm1*val_velocity[2]/val_pressure; -// R_Matrix[4][4] = gm1/val_pressure; - - } - -} - -void CNumerics::GetLMatrix(su2double val_soundspeed, su2double val_density, su2double* val_normal, su2double **L_Matrix) { - - if (nDim == 2) { - - - - L_Matrix[0][0] = 1.0; - L_Matrix[0][1] = 0.0; - L_Matrix[0][2] = 0.0; - L_Matrix[0][3] = -0.5/val_soundspeed/val_soundspeed; - - L_Matrix[1][0] = 0.0; - L_Matrix[1][1] = val_normal[1]; - L_Matrix[1][2] = -val_normal[0]; - L_Matrix[1][3] = 0.0; - - L_Matrix[2][0] = 0.0; - L_Matrix[2][1] = val_normal[0]; - L_Matrix[2][2] = val_normal[1]; - L_Matrix[2][3] = 1.0/val_density/val_soundspeed; - - L_Matrix[3][0] = 0.0; - L_Matrix[3][1] = -val_normal[0]; - L_Matrix[3][2] = -val_normal[1]; - L_Matrix[3][3] = 1.0/val_density/val_soundspeed; - } - else { - -// sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]+val_velocity[2]*val_velocity[2]; -// -// R_Matrix[0][0] = 0.5*gm1*sqvel; -// R_Matrix[0][1] = -val_velocity[0]*gm1; -// R_Matrix[0][2] = -val_velocity[1]*gm1; -// R_Matrix[0][3] = -val_velocity[2]*gm1; -// R_Matrix[0][4] = gm1; -// -// R_Matrix[1][0] = -val_velocity[0]/val_density; -// R_Matrix[1][1] = 1.0/val_density; -// R_Matrix[1][2] = 0.0; -// R_Matrix[1][3] = 0.0; -// R_Matrix[1][4] = 0.0; -// -// R_Matrix[2][0] = -val_velocity[1]/val_density; -// R_Matrix[2][1] = 0.0; -// R_Matrix[2][2] = 1.0/val_density; -// R_Matrix[2][3] = 0.0; -// R_Matrix[2][4] = 0.0; -// -// R_Matrix[3][0] = -val_velocity[2]/val_density; -// R_Matrix[3][1] = 0.0; -// R_Matrix[3][2] = 0.0; -// R_Matrix[3][3] = 1.0/val_density; -// R_Matrix[3][4] = 0.0; -// -// R_Matrix[4][0] = 0.5*gm1*sqvel/val_pressure - Gamma/val_density; -// R_Matrix[4][1] = -gm1*val_velocity[0]/val_pressure; -// R_Matrix[4][2] = -gm1*val_velocity[1]/val_pressure; -// R_Matrix[4][3] = -gm1*val_velocity[2]/val_pressure; -// R_Matrix[4][4] = gm1/val_pressure; - - } - -} - -void CNumerics::GetPrecondJacobian(su2double Beta2, su2double r_hat, su2double s_hat, su2double t_hat, su2double rB2a2, su2double* Lambda, su2double *val_normal, - su2double **val_absPeJac) { - - - su2double lam1, lam2, lam3, lam4; - lam1 = Lambda[0]; lam2 = Lambda[1]; lam3 = Lambda[2]; lam4 = Lambda[3]; - - if (nDim == 2) { - - val_absPeJac[0][0] = lam3*s_hat/(2.0*t_hat) - lam4*r_hat/(2.0*t_hat); - val_absPeJac[0][1] = -lam3*rB2a2*val_normal[0]/(2.0*t_hat) + lam4*rB2a2*val_normal[0]/(2.0*t_hat); - val_absPeJac[0][2] = -lam3*rB2a2*val_normal[1]/(2.0*t_hat) + lam4*rB2a2*val_normal[1]/(2.0*t_hat); - val_absPeJac[0][3] = 0.0; - - val_absPeJac[1][0] = r_hat*val_normal[0]*lam3*s_hat/(2.0*t_hat*rB2a2) + s_hat*val_normal[0]*lam4*(-r_hat)/(2.0*t_hat*rB2a2); - val_absPeJac[1][1] = lam2*(val_normal[1]*val_normal[1]) - lam3*r_hat*val_normal[0]*val_normal[0]/(2.0*t_hat) + lam4*s_hat*val_normal[0]*val_normal[0]/(2.0*t_hat); - val_absPeJac[1][2] = -lam2*val_normal[0]*val_normal[1] - lam3*r_hat*val_normal[0]*val_normal[1]/(2.0*t_hat) + lam4*s_hat*val_normal[0]*val_normal[1]/(2.0*t_hat); - val_absPeJac[1][3] = 0.0; - - val_absPeJac[2][0] = lam3*r_hat*val_normal[1]*s_hat/(2.0*t_hat*rB2a2) - s_hat*val_normal[1]*lam4*r_hat/(2.0*t_hat*rB2a2); - val_absPeJac[2][1] = -val_normal[0]*val_normal[1]*lam2 - r_hat*val_normal[1]*val_normal[0]*lam3/(2.0*t_hat) + s_hat*val_normal[0]*val_normal[1]*lam4/(2.0*t_hat); - val_absPeJac[2][2] = val_normal[0]*val_normal[0]*lam2 -r_hat*val_normal[1]*val_normal[1]*lam3/(2.0*t_hat) + s_hat*val_normal[1]*val_normal[1]*lam4/(2.0*t_hat); - val_absPeJac[2][3] = 0.0; - - val_absPeJac[3][0] = 0.0; - val_absPeJac[3][1] = 0.0; - val_absPeJac[3][2] = 0.0; - val_absPeJac[3][3] = lam1; - - } - else { - - su2double lam5 = Lambda[4]; - - val_absPeJac[0][0] = lam4*s_hat/(2.0*t_hat) - lam5*r_hat/(2.0*t_hat); - val_absPeJac[0][1] = -lam4*rB2a2*val_normal[0]/(2.0*t_hat) + lam5*rB2a2*val_normal[0]/(2.0*t_hat); - val_absPeJac[0][2] = -lam4*rB2a2*val_normal[1]/(2.0*t_hat) + lam5*rB2a2*val_normal[1]/(2.0*t_hat); - val_absPeJac[0][3] = -lam4*rB2a2*val_normal[2]/(2.0*t_hat) + lam5*rB2a2*val_normal[2]/(2.0*t_hat); - val_absPeJac[0][4] = 0.0; - - val_absPeJac[1][0] = r_hat*val_normal[0]*lam4*s_hat/(2.0*t_hat*rB2a2) + s_hat*val_normal[0]*lam5*(-r_hat)/(2.0*t_hat*rB2a2); - val_absPeJac[1][1] = lam2*(val_normal[2]*val_normal[2] + val_normal[1]*val_normal[1]) - lam4*r_hat*val_normal[0]*val_normal[0]/(2.0*t_hat) + lam5*s_hat*val_normal[0]*val_normal[0]/(2.0*t_hat); - val_absPeJac[1][2] = -lam2*val_normal[0]*val_normal[1] - lam4*r_hat*val_normal[0]*val_normal[1]/(2.0*t_hat) + lam5*s_hat*val_normal[0]*val_normal[1]/(2.0*t_hat); - val_absPeJac[1][3] = -lam2*val_normal[0]*val_normal[2] - lam4*r_hat*val_normal[0]*val_normal[2]/(2.0*t_hat) + lam5*s_hat*val_normal[0]*val_normal[2]/(2.0*t_hat); - val_absPeJac[1][4] = 0.0; - - val_absPeJac[2][0] = lam4*r_hat*val_normal[1]*s_hat/(2.0*t_hat*rB2a2) - s_hat*val_normal[1]*lam5*r_hat/(2.0*t_hat*rB2a2); - val_absPeJac[2][1] = -val_normal[0]*val_normal[1]*lam2 - r_hat*val_normal[1]*val_normal[0]*lam4/(2.0*t_hat) + s_hat*val_normal[0]*val_normal[1]*lam5/(2.0*t_hat); - val_absPeJac[2][2] = val_normal[0]*val_normal[0]*lam2 + val_normal[2]*val_normal[2]*lam3 -r_hat*val_normal[1]*val_normal[1]*lam4/(2.0*t_hat) + s_hat*val_normal[1]*val_normal[1]*lam5/(2.0*t_hat); - val_absPeJac[2][3] = -val_normal[2]*val_normal[1]*lam2 - r_hat*val_normal[2]*val_normal[1]*lam4/(2.0*t_hat) + s_hat*lam5*val_normal[1]*val_normal[2]/(2.0*t_hat); - val_absPeJac[2][4] = 0.0; - - val_absPeJac[3][0] = r_hat*s_hat*val_normal[2]*lam4/(2.0*t_hat*rB2a2) - r_hat*s_hat*val_normal[2]*lam5/(2.0*t_hat*rB2a2); - val_absPeJac[3][1] = -val_normal[0]*val_normal[2]*lam3 - lam4*val_normal[0]*val_normal[2]*r_hat/(2.0*t_hat) + lam5*val_normal[0]*val_normal[2]*s_hat/(2.0*t_hat); - val_absPeJac[3][2] = -val_normal[1]*val_normal[2]*lam3 - lam4*val_normal[1]*val_normal[2]*r_hat/(2.0*t_hat) + lam5*val_normal[1]*val_normal[2]*s_hat/(2.0*t_hat); - val_absPeJac[3][3] = (val_normal[1]*val_normal[1] + val_normal[0]*val_normal[0])*lam3 - lam4*val_normal[2]*val_normal[2]*r_hat/(2.0*t_hat) + lam5*val_normal[2]*val_normal[2]*s_hat/(2.0*t_hat); - val_absPeJac[3][4] = 0.0; - - val_absPeJac[4][0] = 0.0; - val_absPeJac[4][1] = 0.0; - val_absPeJac[4][2] = 0.0; - val_absPeJac[4][3] = 0.0; - val_absPeJac[4][4] = lam1; - - } - -} - -void CNumerics::GetPArtCompMatrix(su2double *val_density, su2double *val_velocity, su2double *val_betainc2, - su2double *val_normal, su2double **val_p_tensor) { - su2double a, a2, Projvel, area2, sx, sy, sz = 0.0, u, v, w = 0.0, factor = 0.0; - - sx = val_normal[0]; sy = val_normal[1]; u = val_velocity[0]; v = val_velocity[1]; - if (nDim == 3) { sz = val_normal[2]; w = val_velocity[2]; } - Projvel = u*sx + v*sy; area2 = sx*sx + sy*sy; - if (nDim == 3) { Projvel += w*sz; area2 += sz*sz; } - a2 = Projvel*Projvel + ((*val_betainc2)/(*val_density))*area2; a = sqrt(a2); - factor = 1/(2.0*((*val_betainc2)/(*val_density))*a2); - - if (nDim == 2) { - val_p_tensor[0][0] = 0.0; - val_p_tensor[0][1] = factor*((*val_betainc2)/(*val_density))*a; - val_p_tensor[0][2] = -factor*((*val_betainc2)/(*val_density))*a; - - val_p_tensor[1][0] = -factor*2.0*sy*((*val_betainc2)/(*val_density)); - val_p_tensor[1][1] = factor*(u*(a+Projvel) + sx*((*val_betainc2)/(*val_density))); - val_p_tensor[1][2] = factor*(u*(Projvel-a) + sx*((*val_betainc2)/(*val_density))); - - val_p_tensor[2][0] = factor*2.0*sx*((*val_betainc2)/(*val_density)); - val_p_tensor[2][1] = factor*(v*(a+Projvel) + sy*((*val_betainc2)/(*val_density))); - val_p_tensor[2][2] = factor*(v*(Projvel-a) + sy*((*val_betainc2)/(*val_density))); - } - else { - val_p_tensor[0][0] = 0.0; - val_p_tensor[0][1] = 0.0; - val_p_tensor[0][2] = ((*val_betainc2)/(*val_density))*a; - val_p_tensor[0][3] = -((*val_betainc2)/(*val_density))*a; - - val_p_tensor[1][0] = -sz; - val_p_tensor[1][1] = -sy; - val_p_tensor[1][2] = u*(Projvel+a) + sx*((*val_betainc2)/(*val_density)); - val_p_tensor[1][3] = u*(Projvel-a) + sx*((*val_betainc2)/(*val_density)); - - val_p_tensor[2][0] = 0.0; - val_p_tensor[2][1] = sx; - val_p_tensor[2][2] = v*(Projvel+a) + sy*((*val_betainc2)/(*val_density)); - val_p_tensor[2][3] = v*(Projvel-a) + sy*((*val_betainc2)/(*val_density)); - - val_p_tensor[3][0] = sx; - val_p_tensor[3][1] = 0.0; - val_p_tensor[3][2] = w*(Projvel+a) + sz*((*val_betainc2)/(*val_density)); - val_p_tensor[3][3] = w*(Projvel-a) + sz*((*val_betainc2)/(*val_density)); - } - -} - -void CNumerics::GetPArtCompMatrix_inv(su2double *val_density, su2double *val_velocity, su2double *val_betainc2, - su2double *val_normal, su2double **val_invp_tensor) { - su2double a, a2, Projvel, area2, sx, sy, sz = 0.0, u, v, w = 0.0; - - sx = val_normal[0]; sy = val_normal[1]; u = val_velocity[0]; v = val_velocity[1]; - if (nDim == 3) { sz = val_normal[2]; w = val_velocity[2];} - Projvel = u*sx + v*sy; area2 = sx*sx + sy*sy; - if (nDim == 3) { Projvel += w*sz; area2 += sz*sz; } - a2 = Projvel*Projvel + ((*val_betainc2)/(*val_density))*area2; a = sqrt(a2); - - if (nDim == 2) { - val_invp_tensor[0][0] = (sy*u-sx*v); - val_invp_tensor[0][1] = -v*Projvel-sy*((*val_betainc2)/(*val_density)); - val_invp_tensor[0][2] = u*Projvel+sx*((*val_betainc2)/(*val_density)); - - val_invp_tensor[1][0] = (a-Projvel); - val_invp_tensor[1][1] = ((*val_betainc2)/(*val_density))*sx; - val_invp_tensor[1][2] = ((*val_betainc2)/(*val_density))*sy; - - val_invp_tensor[2][0] = (-a-Projvel); - val_invp_tensor[2][1] = ((*val_betainc2)/(*val_density))*sx; - val_invp_tensor[2][2] = ((*val_betainc2)/(*val_density))*sy; - } - else { - val_invp_tensor[0][0] = (sz*Projvel-area2*w)/(sx*a2); - val_invp_tensor[0][1] = -(w*Projvel+sz*((*val_betainc2)/(*val_density)))/a2; - val_invp_tensor[0][2] = -sy*(w*Projvel+sz*((*val_betainc2)/(*val_density)))/(sx*a2); - val_invp_tensor[0][3] = ((sx*u+sy*v)*Projvel+(sx*sx+sy*sy)*((*val_betainc2)/(*val_density)))/(sx*a2); - - val_invp_tensor[1][0] = (sy*Projvel-area2*v)/(sx*a2); - val_invp_tensor[1][1] = -(v*Projvel+sy*((*val_betainc2)/(*val_density)))/a2; - val_invp_tensor[1][2] = ((sx*u+sz*w)*Projvel+(sx*sx+sz*sz)*((*val_betainc2)/(*val_density)))/(sx*a2); - val_invp_tensor[1][3] = -sz*(v*Projvel+sy*((*val_betainc2)/(*val_density)))/(sx*a2); - - val_invp_tensor[2][0] = -(Projvel-a)/(2.0*a2*((*val_betainc2)/(*val_density))); - val_invp_tensor[2][1] = sx/(2.0*a2); - val_invp_tensor[2][2] = sy/(2.0*a2); - val_invp_tensor[2][3] = sz/(2.0*a2); - - val_invp_tensor[3][0] = -(Projvel+a)/(2.0*a2*((*val_betainc2)/(*val_density))); - val_invp_tensor[3][1] = sx/(2.0*a2); - val_invp_tensor[3][2] = sy/(2.0*a2); - val_invp_tensor[3][3] = sz/(2.0*a2); - } - -} - -void CNumerics::GetPArtComp_FreeSurf_Matrix(su2double *val_density, su2double *val_ddensity, su2double *val_velocity, su2double *val_betainc2, su2double *val_levelset, su2double *val_normal, su2double **val_p_tensor) { - - su2double a = 0.0, b = 0.0, c = 0.0, d = 0.0, area2 = 0.0, e2 = 0.0, f = 0.0, nx = 0.0, ny = 0.0, nz = 0.0, u = 0.0, v = 0.0, w = 0.0; - - a = (*val_betainc2)/(*val_density); - b = (*val_levelset)/(*val_density); - c = (*val_ddensity); - - if (nDim == 2) { - - nx = val_normal[0]; ny = val_normal[1]; area2 = nx*nx + ny*ny; - u = val_velocity[0]; v = val_velocity[1]; d = u*nx + v*ny; - e2 = (2.0*d - b*c*d)*(2.0*d - b*c*d); - f = sqrt(4.0*a*area2 + e2); - - val_p_tensor[0][0] = 0; - val_p_tensor[0][1] = 0; - val_p_tensor[0][2] = (d*d*(1.0 - b*c) + 2.0*a*area2 + d*d + d*f)/(2.0*b*area2); - val_p_tensor[0][3] = (d*d*(1.0 - b*c) + 2.0*a*area2 + d*d - d*f)/(2.0*b*area2); - - val_p_tensor[1][0] = (c*d)/nx; - val_p_tensor[1][1] = -(ny/nx); - val_p_tensor[1][2] = (d*nx*(b*c - 1.0) + nx*nx*u + 2.0*ny*ny*u - nx*ny*v - nx*f)/(2*b*area2); - val_p_tensor[1][3] = (d*nx*(b*c - 1.0) + nx*nx*u + 2.0*ny*ny*u - nx*ny*v + nx*f)/(2*b*area2); - - val_p_tensor[2][0] = 0.0; - val_p_tensor[2][1] = 1.0; - val_p_tensor[2][2] = (d*ny*(b*c - 1.0) - nx*ny*u + 2.0*nx*nx*v + ny*ny*v - ny*f)/(2*b*area2); - val_p_tensor[2][3] = (d*ny*(b*c - 1.0) - nx*ny*u + 2.0*nx*nx*v + ny*ny*v + ny*f)/(2*b*area2); - - val_p_tensor[3][0] = 1.0; - val_p_tensor[3][1] = 0.0; - val_p_tensor[3][2] = 1.0; - val_p_tensor[3][3] = 1.0; - - } - else { - - nx = val_normal[0]; ny = val_normal[1]; nz = val_normal[2]; area2 = nx*nx + ny*ny + nz*nz; - u = val_velocity[0]; v = val_velocity[1]; w = val_velocity[2]; d = u*nx + v*ny + w*nz; - e2 = (2.0*d - b*c*d)*(2.0*d - b*c*d); - f = sqrt(4.0*a*area2 + e2); - - val_p_tensor[0][0] = 0.0; - val_p_tensor[0][1] = 0.0; - val_p_tensor[0][2] = 0.0; - val_p_tensor[0][3] = -((a*(b*c*d + f))/(b*(2.0*d - b*c*d - f))); - val_p_tensor[0][4] = (a*(- b*c*d + f))/(b*(2.0*d - b*c*d + f)); - - val_p_tensor[1][0] = (c*d)/nx; - val_p_tensor[1][1] = -(nz/nx); - val_p_tensor[1][2] = -(ny/nx); - val_p_tensor[1][3] = -((-2.0*a*nx + b*c*d*u - 2.0*u*d + u*f)/(b*(2.0*d - b*c*d - f))); - val_p_tensor[1][4] = -((-2.0*a*nx + b*c*d*u - 2.0*u*d - u*f)/(b*(2.0*d - b*c*d + f))); - - val_p_tensor[2][0] = 0.0; - val_p_tensor[2][1] = 0.0; - val_p_tensor[2][2] = 1.0; - val_p_tensor[2][3] = -((-2.0*a*ny + b*c*d*v - 2.0*v*d + v*f)/(b*(2.0*d - b*c*d - f))); - val_p_tensor[2][4] = -((-2.0*a*ny + b*c*d*v - 2.0*v*d - v*f)/(b*(2.0*d - b*c*d + f))); - - val_p_tensor[3][0] = 0.0; - val_p_tensor[3][1] = 1.0; - val_p_tensor[3][2] = 0.0; - val_p_tensor[3][3] = -((-2.0*a*nz + b*c*d*w - 2.0*w*d + w*f)/(b*(2.0*d - b*c*d - f))); - val_p_tensor[3][4] = -((-2.0*a*nz + b*c*d*w - 2.0*w*d - w*f)/(b*(2.0*d - b*c*d + f))); - - val_p_tensor[4][0] = 1.0; - val_p_tensor[4][1] = 0.0; - val_p_tensor[4][2] = 0.0; - val_p_tensor[4][3] = 1.0; - val_p_tensor[4][4] = 1.0; - - } - -} - -void CNumerics::GetPArtComp_FreeSurf_Matrix_inv(su2double *val_density, su2double *val_ddensity, su2double *val_velocity, su2double *val_betainc2, su2double *val_levelset, - su2double *val_normal, su2double **val_invp_tensor) { - - su2double a = 0.0, b = 0.0, c = 0.0, d = 0.0, area2 = 0.0, e2 = 0.0, f = 0.0, nx = 0.0, ny = 0.0, nz = 0.0, u = 0.0, v = 0.0, w = 0.0; - - a = (*val_betainc2)/(*val_density); - b = (*val_levelset)/(*val_density); - c = (*val_ddensity); - - if (nDim == 2) { - - nx = val_normal[0]; ny = val_normal[1]; area2 = nx*nx + ny*ny; - u = val_velocity[0]; v = val_velocity[1]; d = u*nx + v*ny; - e2 = (2.0*d - b*c*d)*(2.0*d - b*c*d); - f = sqrt(4.0*a*area2 + e2); - - val_invp_tensor[0][0] = -((b*area2)/(a*area2 + d*d*(1.0 - b*c))); - val_invp_tensor[0][1] = -((b*d*nx)/(a*area2 + d*d*(1.0 - b*c))); - val_invp_tensor[0][2] = -((b*d*ny)/(a*area2 + d*d*(1.0 - b*c))); - val_invp_tensor[0][3] = ( a*area2 + d*d)/(a*area2 + d*d*(1.0 - b*c)); - - val_invp_tensor[1][0] = (-b*c*d*ny + nx*(ny*u - nx*v))/(a*area2 + d*d*(1.0-b*c)); - val_invp_tensor[1][1] = -((nx*(a*ny + d*v))/(a*area2 + d*d*(1.0-b*c))); - val_invp_tensor[1][2] = (-b*c*d*d + nx*(a*nx + d*u))/(a*area2 + d*d*(1.0-b*c)); - val_invp_tensor[1][3] = (c*d*(a*ny + d*v))/(a*area2 + d*d*(1.0-b*c)); - - val_invp_tensor[2][0] = (b*area2*(-b*c*d + f))/(2.0*(-b*c*d*d + a*area2 + d*d)*f); - val_invp_tensor[2][1] = -((b*nx*(-(2.0 - b*c)*d*d - 2.0*a*area2 + d*f))/(2.0*(- a*area2 - d*d*(1.0-b*c))*f)); - val_invp_tensor[2][2] = -((b*ny*(-(2.0 - b*c)*d*d - 2.0*a*area2 + d*f))/(2.0*(- a*area2 - d*d*(1.0-b*c))*f)); - val_invp_tensor[2][3] = (b*c*d*(-(2.0 - b*c)*d*d - 2.0*a*area2 + d*f))/(2.0*(- a*area2 - d*d*(1.0-b*c))*f); - - val_invp_tensor[3][0] = (b*area2*(b*c*d + f))/(2.0*(-b*c*d*d + a*area2 + d*d)*f); - val_invp_tensor[3][1] = -((b*nx*((2.0 - b*c)*d*d + 2.0*a*area2 + d*f))/(2.0*(- a*area2 - d*d*(1.0-b*c))*f)); - val_invp_tensor[3][2] = -((b*ny*((2.0 - b*c)*d*d + 2.0*a*area2 + d*f))/(2.0*(- a*area2 - d*d*(1.0-b*c))*f)); - val_invp_tensor[3][3] = (b*c*d*((2.0 - b*c)*d*d + 2.0*a*area2 + d*f))/(2.0*(- a*area2 - d*d*(1.0-b*c))*f); - - } - else { - - nx = val_normal[0]; ny = val_normal[1]; nz = val_normal[2]; area2 = nx*nx + ny*ny + nz*nz; - u = val_velocity[0]; v = val_velocity[1]; w = val_velocity[2]; d = u*nx + v*ny + w*nz; - e2 = (2.0*d - b*c*d)*(2.0*d - b*c*d); - f = sqrt(4.0*a*area2 + e2); - - val_invp_tensor[0][0] = (b*area2)/(b*c*d*d - a*area2 - d*d); - val_invp_tensor[0][1] = -((b*d*nx)/(-b*c*d*d + a*area2 + d*d)); - val_invp_tensor[0][2] = -((b*d*ny)/(-b*c*d*d + a*area2 + d*d)); - val_invp_tensor[0][3] = -((b*d*nz)/(-b*c*d*d + a*area2 + d*d)); - val_invp_tensor[0][4] = (a*area2 + d*d)/(-b*c*d*d +a*area2 + d*d); - - val_invp_tensor[1][0] = (-b*c*d*nz +nx*nz*u - nx*nx*w + ny*(nz*v - ny*w))/(-b*c*d*d +a*area2 + d*d); - val_invp_tensor[1][1] = -((nx*(a*nz + d*w))/(-b*c*d*d + a*area2 + d*d)); - val_invp_tensor[1][2] = -((ny*(a*nz + d*w))/(-b*c*d*d + a*area2 + d*d)); - val_invp_tensor[1][3] = (-b*c*d*d + a*(nx*nx + ny*ny) + d*(nx*u + ny*v))/(-b*c*d*d + a*area2 + d*d); - val_invp_tensor[1][4] = (c*d*(a*nz + d*w))/(-b*c*d*d + a*area2 + d*d); - - val_invp_tensor[2][0] = (-b*c*d*ny + nx*ny*u - nx*nx*v + nz*(-nz*v + ny*w))/(-b*c*d*d + a*area2 + d*d); - val_invp_tensor[2][1] = -((nx*(a*ny + d*v))/(-b*c*d*d + a*area2 + d*d)); - val_invp_tensor[2][2] = (-b*c*d*d + a*(nx*nx + nz*nz) + d*(nx*u + nz*w))/(-b*c*d*d + a*area2 + d*d); - val_invp_tensor[2][3] = -((nz*(a*ny + d*v))/(-b*c*d*d + a*area2 + d*d)); - val_invp_tensor[2][4] = (c*d*(a*ny + d*v))/(-b*c*d*d + a*area2 + d*(nx*u + ny*v + nz*w)); - - val_invp_tensor[3][0] = -(b*(-d + b*c*d - d + f)*(b*b*c*c*d*d + 2.0*a*area2 + d*d - 3.0*b*c*d*d + 2.0*nx*ny*u*v + 2.0*nx*nz*u*w + 2.0*ny*nz*v*w + nx*nx*u*u + ny*ny*v*v + nz*nz*w*w - b*c*d*f + d*f))/(4*a*(b*c*d*d - a*area2 - d*d)*f); - val_invp_tensor[3][1] = (b*nx*(-d + b*c*d - d + f)*(- b*c*d + f))/(4.0*(b*c*d*d - a*area2 - d*d)*f); - val_invp_tensor[3][2] = (b*ny*(-d + b*c*d - d + f)*(- b*c*d + f))/(4.0*(b*c*d*d - a*area2 - d*d)*f); - val_invp_tensor[3][3] = (b*nz*(-d + b*c*d - d + f)*(- b*c*d + f))/(4.0*(b*c*d*d - a*area2 - d*d)*f); - val_invp_tensor[3][4] = -((b*c*d*(-d + b*c*d - d + f)*(- b*c*d + f))/(4.0*(b*c*d*d - a*area2 - d*d)*f)); - - val_invp_tensor[4][0] = -(b*(2.0*d - b*c*d + f)*(b*b*c*c*d*d + 2.0*a*area2 + d*d - 3.0*b*c*d*d + 2.0*nx*ny*u*v + 2.0*nx*nz*u*w + 2.0*ny*nz*v*w + nx*nx*u*u + ny*ny*v*v + nz*nz*w*w + b*c*d*f - d*f))/(4*a*(b*c*d*d - a*area2 - d*d)*f); - val_invp_tensor[4][1] = -((b*nx*(b*c*d + f)*(2.0*d - b*c*d + f))/(4.0*(b*c*d*d - a*area2 - d*d)*f)); - val_invp_tensor[4][2] = -((b*ny*(b*c*d + f)*(2.0*d - b*c*d + f))/(4.0*(b*c*d*d - a*area2 - d*d)*f)); - val_invp_tensor[4][3] = -((b*nz*(b*c*d + f)*(2.0*d - b*c*d + f))/(4.0*(b*c*d*d - a*area2 - d*d)*f)); - val_invp_tensor[4][4] = (b*c*d*(b*c*d + f)*(2.0*d - b*c*d + f))/(4.0*(b*c*d*d - a*area2 - d*d)*f); - - } - -} - -void CNumerics::GetJacInviscidLambda_fabs(su2double *val_velocity, su2double val_soundspeed, - su2double *val_normal, su2double *val_Lambda_Vector) { - su2double ProjVelocity = 0; - - for (unsigned short iDim = 0; iDim < nDim; iDim++) - ProjVelocity += val_velocity[iDim]*val_normal[iDim]; - - if (nDim == 3) { - val_Lambda_Vector[0] = fabs(ProjVelocity); - val_Lambda_Vector[1] = fabs(ProjVelocity); - val_Lambda_Vector[2] = fabs(ProjVelocity); - val_Lambda_Vector[3] = fabs(ProjVelocity + val_soundspeed); - val_Lambda_Vector[4] = fabs(ProjVelocity - val_soundspeed); - } - - if (nDim == 2) { - val_Lambda_Vector[0] = fabs(ProjVelocity); - val_Lambda_Vector[1] = fabs(ProjVelocity); - val_Lambda_Vector[2] = fabs(ProjVelocity + val_soundspeed); - val_Lambda_Vector[3] = fabs(ProjVelocity - val_soundspeed); - } -} - -void CNumerics::GetAdjViscousFlux_Jac(su2double Pressure_i, su2double Pressure_j, su2double Density_i, su2double Density_j, - su2double ViscDens_i, su2double ViscDens_j, su2double *Velocity_i, su2double *Velocity_j, - su2double sq_vel_i, su2double sq_vel_j, - su2double XiDens_i, su2double XiDens_j, su2double **Mean_GradPhi, su2double *Mean_GradPsiE, - su2double dPhiE_dn, su2double *Normal, su2double *Edge_Vector, su2double dist_ij_2, su2double *val_residual_i, su2double *val_residual_j, - su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, - su2double **val_Jacobian_jj, bool implicit) { - - su2double Sigma_xx, Sigma_yy, Sigma_zz, Sigma_xy, Sigma_xz, Sigma_yz, - Sigma_xx5, Sigma_yy5, Sigma_zz5, Sigma_xy5, Sigma_xz5, - Sigma_yz5, Sigma_5, eta_xx, eta_yy, eta_zz, eta_xy, eta_xz, eta_yz; - su2double dSigmaxx_phi1, dSigmayy_phi1, dSigmazz_phi1, dSigmaxy_phi1, dSigmaxz_phi1, dSigmayz_phi1; - su2double dSigmaxx_phi2, dSigmayy_phi2, dSigmazz_phi2, dSigmaxy_phi2, dSigmaxz_phi2, dSigmayz_phi2; - su2double dSigmaxx_phi3, dSigmayy_phi3, dSigmazz_phi3, dSigmaxy_phi3, dSigmaxz_phi3, dSigmayz_phi3; - su2double dSigma5_psi5; - unsigned short iVar, jVar; - - if (nDim == 3) { - - /*--- Residual at iPoint ---*/ - - Sigma_xx = ViscDens_i * (FOUR3 * Mean_GradPhi[0][0] - TWO3 * Mean_GradPhi[1][1] - TWO3 * Mean_GradPhi[2][2]); - Sigma_yy = ViscDens_i * (-TWO3 * Mean_GradPhi[0][0] + FOUR3 * Mean_GradPhi[1][1] - TWO3 * Mean_GradPhi[2][2]); - Sigma_zz = ViscDens_i * (-TWO3 * Mean_GradPhi[0][0] - TWO3 * Mean_GradPhi[1][1] + FOUR3 * Mean_GradPhi[2][2]); - Sigma_xy = ViscDens_i * (Mean_GradPhi[1][0] + Mean_GradPhi[0][1]); - Sigma_xz = ViscDens_i * (Mean_GradPhi[2][0] + Mean_GradPhi[0][2]); - Sigma_yz = ViscDens_i * (Mean_GradPhi[2][1] + Mean_GradPhi[1][2]); - Sigma_xx5 = ViscDens_i * ( FOUR3 * Velocity_i[0] * Mean_GradPsiE[0] - TWO3 * Velocity_i[1] * Mean_GradPsiE[1] - TWO3 * Velocity_i[2] * Mean_GradPsiE[2]); - Sigma_yy5 = ViscDens_i * (- TWO3 * Velocity_i[0] * Mean_GradPsiE[0] + FOUR3 * Velocity_i[1] * Mean_GradPsiE[1] - TWO3 * Velocity_i[2] * Mean_GradPsiE[2]); - Sigma_zz5 = ViscDens_i * (- TWO3 * Velocity_i[0] * Mean_GradPsiE[0] - TWO3 * Velocity_i[1] * Mean_GradPsiE[1] + FOUR3 * Velocity_i[2] * Mean_GradPsiE[2]); - Sigma_xy5 = ViscDens_i * (Velocity_i[0] * Mean_GradPsiE[1] + Velocity_i[1] * Mean_GradPsiE[0]); - Sigma_xz5 = ViscDens_i * (Velocity_i[0] * Mean_GradPsiE[2] + Velocity_i[2] * Mean_GradPsiE[0]); - Sigma_yz5 = ViscDens_i * (Velocity_i[1] * Mean_GradPsiE[2] + Velocity_i[2] * Mean_GradPsiE[1]); - Sigma_5 = XiDens_i * dPhiE_dn; - eta_xx = Sigma_xx + Sigma_xx5; eta_yy = Sigma_yy + Sigma_yy5; eta_zz = Sigma_zz + Sigma_zz5; - eta_xy = Sigma_xy + Sigma_xy5; eta_xz = Sigma_xz + Sigma_xz5; eta_yz = Sigma_yz + Sigma_yz5; - - val_residual_i[0] = - (Velocity_i[0] * Normal[0] * eta_xx + Velocity_i[1] * Normal[1] * eta_yy + Velocity_i[2] * Normal[2] * eta_zz - + (Velocity_i[0] * Normal[1] + Velocity_i[1] * Normal[0]) * eta_xy - + (Velocity_i[0] * Normal[2] + Velocity_i[2] * Normal[0]) * eta_xz - + (Velocity_i[2] * Normal[1] + Velocity_i[1] * Normal[2]) * eta_yz - - (sq_vel_i - Pressure_i/(Density_i*Gamma_Minus_One)) * Sigma_5); - - val_residual_i[1] = (eta_xx * Normal[0] + eta_xy * Normal[1] + eta_xz * Normal[2] - Velocity_i[0] * Sigma_5); - val_residual_i[2] = (eta_xy * Normal[0] + eta_yy * Normal[1] + eta_yz * Normal[2] - Velocity_i[1] * Sigma_5); - val_residual_i[3] = (eta_xz * Normal[0] + eta_yz * Normal[1] + eta_zz * Normal[2] - Velocity_i[2] * Sigma_5); - val_residual_i[4] = (Sigma_5); - - /*--- Computation of the Jacobians at Point i---*/ - - if (implicit) { - - dSigmaxx_phi1 = -FOUR3 * ViscDens_i * Edge_Vector[0]/dist_ij_2; - dSigmaxx_phi2 = TWO3 * ViscDens_i * Edge_Vector[1]/dist_ij_2; - dSigmaxx_phi3 = TWO3 * ViscDens_i * Edge_Vector[2]/dist_ij_2; - dSigmayy_phi1 = TWO3 * ViscDens_i * Edge_Vector[0]/dist_ij_2; - dSigmayy_phi2 = -FOUR3 * ViscDens_i * Edge_Vector[1]/dist_ij_2; - dSigmayy_phi3 = TWO3 * ViscDens_i * Edge_Vector[2]/dist_ij_2; - dSigmazz_phi1 = TWO3 * ViscDens_i * Edge_Vector[0]/dist_ij_2; - dSigmazz_phi2 = TWO3 * ViscDens_i * Edge_Vector[1]/dist_ij_2; - dSigmazz_phi3 = -FOUR3 * ViscDens_i * Edge_Vector[2]/dist_ij_2; - dSigmaxy_phi1 = -ViscDens_i * Edge_Vector[1]/dist_ij_2; - dSigmaxy_phi2 = -ViscDens_i * Edge_Vector[0]/dist_ij_2; - dSigmaxy_phi3 = 0; - dSigmaxz_phi1 = -ViscDens_i * Edge_Vector[2]/dist_ij_2; - dSigmaxz_phi2 = 0; - dSigmaxz_phi3 = -ViscDens_i * Edge_Vector[0]/dist_ij_2; - dSigmayz_phi1 = 0; - dSigmayz_phi2 = -ViscDens_i * Edge_Vector[2]/dist_ij_2; - dSigmayz_phi3 = -ViscDens_i * Edge_Vector[1]/dist_ij_2; - - // dSigmaxx5_psi5 = -ViscDens_i * ( FOUR3*Velocity_i[0]*Edge_Vector[0] - TWO3*Velocity_i[1]*Edge_Vector[1] - TWO3*Velocity_i[2]*Edge_Vector[2])/dist_ij_2; - // dSigmayy5_psi5 = -ViscDens_i * (- TWO3*Velocity_i[0]*Edge_Vector[0] + FOUR3*Velocity_i[1]*Edge_Vector[1] - TWO3*Velocity_i[2]*Edge_Vector[2])/dist_ij_2; - // dSigmazz5_psi5 = -ViscDens_i * (- TWO3*Velocity_i[0]*Edge_Vector[0] - TWO3*Velocity_i[1]*Edge_Vector[1] + FOUR3*Velocity_i[2]*Edge_Vector[2])/dist_ij_2; - // dSigmaxy5_psi5 = -ViscDens_i * ( Velocity_i[0]*Edge_Vector[1] + Velocity_i[1]*Edge_Vector[0] )/dist_ij_2; - // dSigmaxz5_psi5 = -ViscDens_i * ( Velocity_i[0]*Edge_Vector[2] + Velocity_i[2]*Edge_Vector[0] )/dist_ij_2; - // dSigmayz5_psi5 = -ViscDens_i * ( Velocity_i[1]*Edge_Vector[2] + Velocity_i[2]*Edge_Vector[1] )/dist_ij_2; - dSigma5_psi5 = -XiDens_i * ( Edge_Vector[0]*Normal[0] + Edge_Vector[1]*Normal[1] + Edge_Vector[2]*Normal[2] )/dist_ij_2; - - val_Jacobian_ii[0][0] = 0; - val_Jacobian_ii[0][1] = -( Velocity_i[0]*Normal[0]*dSigmaxx_phi1 + Velocity_i[1]*Normal[1]*dSigmayy_phi1 + Velocity_i[2]*Normal[2]*dSigmazz_phi1 - + (Velocity_i[0]*Normal[1] + Velocity_i[1]*Normal[0])*dSigmaxy_phi1 - + (Velocity_i[0]*Normal[2] + Velocity_i[2]*Normal[0])*dSigmaxz_phi1 - + (Velocity_i[2]*Normal[1] + Velocity_i[1]*Normal[2])*dSigmayz_phi1 ); - val_Jacobian_ii[0][2] = -( Velocity_i[0]*Normal[0]*dSigmaxx_phi2 + Velocity_i[1]*Normal[1]*dSigmayy_phi2 + Velocity_i[2]*Normal[2]*dSigmazz_phi2 - + (Velocity_i[0]*Normal[1] + Velocity_i[1]*Normal[0])*dSigmaxy_phi2 - + (Velocity_i[0]*Normal[2] + Velocity_i[2]*Normal[0])*dSigmaxz_phi2 - + (Velocity_i[2]*Normal[1] + Velocity_i[1]*Normal[2])*dSigmayz_phi2 ); - val_Jacobian_ii[0][3] = -( Velocity_i[0]*Normal[0]*dSigmaxx_phi3 + Velocity_i[1]*Normal[1]*dSigmayy_phi3 + Velocity_i[2]*Normal[2]*dSigmazz_phi3 - + (Velocity_i[0]*Normal[1] + Velocity_i[1]*Normal[0])*dSigmaxy_phi3 - + (Velocity_i[0]*Normal[2] + Velocity_i[2]*Normal[0])*dSigmaxz_phi3 - + (Velocity_i[2]*Normal[1] + Velocity_i[1]*Normal[2])*dSigmayz_phi3 ); - val_Jacobian_ii[0][4] = (sq_vel_i - Pressure_i/(Density_i*Gamma_Minus_One)) * dSigma5_psi5; - - val_Jacobian_ii[1][0] = 0; - val_Jacobian_ii[1][1] = Normal[0]*dSigmaxx_phi1 + Normal[1]*dSigmaxy_phi1 + Normal[2]*dSigmaxz_phi1; - val_Jacobian_ii[1][2] = Normal[0]*dSigmaxx_phi2 + Normal[1]*dSigmaxy_phi2 + Normal[2]*dSigmaxz_phi2; - val_Jacobian_ii[1][3] = Normal[0]*dSigmaxx_phi3 + Normal[1]*dSigmaxy_phi3 + Normal[2]*dSigmaxz_phi3; - val_Jacobian_ii[1][4] = -Velocity_i[0]*dSigma5_psi5; - - val_Jacobian_ii[2][0] = 0; - val_Jacobian_ii[2][1] = Normal[0]*dSigmaxy_phi1 + Normal[1]*dSigmayy_phi1 + Normal[2]*dSigmayz_phi1; - val_Jacobian_ii[2][2] = Normal[0]*dSigmaxy_phi2 + Normal[1]*dSigmayy_phi2 + Normal[2]*dSigmayz_phi2; - val_Jacobian_ii[2][3] = Normal[0]*dSigmaxy_phi3 + Normal[1]*dSigmayy_phi3 + Normal[2]*dSigmayz_phi3; - val_Jacobian_ii[2][4] = -Velocity_i[1]*dSigma5_psi5; - - val_Jacobian_ii[3][0] = 0; - val_Jacobian_ii[3][1] = Normal[0]*dSigmaxz_phi1 + Normal[1]*dSigmayz_phi1 + Normal[2]*dSigmazz_phi1; - val_Jacobian_ii[3][2] = Normal[0]*dSigmaxz_phi2 + Normal[1]*dSigmayz_phi2 + Normal[2]*dSigmazz_phi2; - val_Jacobian_ii[3][3] = Normal[0]*dSigmaxz_phi3 + Normal[1]*dSigmayz_phi3 + Normal[2]*dSigmazz_phi3; - val_Jacobian_ii[3][4] = -Velocity_i[2]*dSigma5_psi5; - - val_Jacobian_ii[4][0] = 0; - val_Jacobian_ii[4][1] = 0; - val_Jacobian_ii[4][2] = 0; - val_Jacobian_ii[4][3] = 0; - val_Jacobian_ii[4][4] = dSigma5_psi5; - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - val_Jacobian_ij[iVar][jVar] = -val_Jacobian_ii[iVar][jVar]; - } - - /*--- Residual at jPoint ---*/ - - Sigma_xx = ViscDens_j * (FOUR3 * Mean_GradPhi[0][0] - TWO3 * Mean_GradPhi[1][1] - TWO3 * Mean_GradPhi[2][2]); - Sigma_yy = ViscDens_j * (-TWO3 * Mean_GradPhi[0][0] + FOUR3 * Mean_GradPhi[1][1] - TWO3 * Mean_GradPhi[2][2]); - Sigma_zz = ViscDens_j * (-TWO3 * Mean_GradPhi[0][0] - TWO3 * Mean_GradPhi[1][1] + FOUR3 * Mean_GradPhi[2][2]); - Sigma_xy = ViscDens_j * (Mean_GradPhi[1][0] + Mean_GradPhi[0][1]); - Sigma_xz = ViscDens_j * (Mean_GradPhi[2][0] + Mean_GradPhi[0][2]); - Sigma_yz = ViscDens_j * (Mean_GradPhi[2][1] + Mean_GradPhi[1][2]); - Sigma_xx5 = ViscDens_j * ( FOUR3 * Velocity_j[0] * Mean_GradPsiE[0] - TWO3 * Velocity_j[1] * Mean_GradPsiE[1] - TWO3 * Velocity_j[2] * Mean_GradPsiE[2]); - Sigma_yy5 = ViscDens_j * (- TWO3 * Velocity_j[0] * Mean_GradPsiE[0] + FOUR3 * Velocity_j[1] * Mean_GradPsiE[1] - TWO3 * Velocity_j[2] * Mean_GradPsiE[2]); - Sigma_zz5 = ViscDens_j * (- TWO3 * Velocity_j[0] * Mean_GradPsiE[0] - TWO3 * Velocity_j[1] * Mean_GradPsiE[1] + FOUR3 * Velocity_j[2] * Mean_GradPsiE[2]); - Sigma_xy5 = ViscDens_j * (Velocity_j[0] * Mean_GradPsiE[1] + Velocity_j[1] * Mean_GradPsiE[0]); - Sigma_xz5 = ViscDens_j * (Velocity_j[0] * Mean_GradPsiE[2] + Velocity_j[2] * Mean_GradPsiE[0]); - Sigma_yz5 = ViscDens_j * (Velocity_j[1] * Mean_GradPsiE[2] + Velocity_j[2] * Mean_GradPsiE[1]); - Sigma_5 = XiDens_j * dPhiE_dn; - eta_xx = Sigma_xx + Sigma_xx5; eta_yy = Sigma_yy + Sigma_yy5; eta_zz = Sigma_zz + Sigma_zz5; - eta_xy = Sigma_xy + Sigma_xy5; eta_xz = Sigma_xz + Sigma_xz5; eta_yz = Sigma_yz + Sigma_yz5; - - val_residual_j[0] = - (Velocity_j[0] * Normal[0] * eta_xx + Velocity_j[1] * Normal[1] * eta_yy + Velocity_j[2] * Normal[2] * eta_zz - + (Velocity_j[0] * Normal[1] + Velocity_j[1] * Normal[0]) * eta_xy - + (Velocity_j[0] * Normal[2] + Velocity_j[2] * Normal[0]) * eta_xz - + (Velocity_j[2] * Normal[1] + Velocity_j[1] * Normal[2]) * eta_yz - - (sq_vel_j - Pressure_j/(Density_j*Gamma_Minus_One)) * Sigma_5); - val_residual_j[1] = (eta_xx * Normal[0] + eta_xy * Normal[1] + eta_xz * Normal[2] - Velocity_j[0] * Sigma_5); - val_residual_j[2] = (eta_xy * Normal[0] + eta_yy * Normal[1] + eta_yz * Normal[2] - Velocity_j[1] * Sigma_5); - val_residual_j[3] = (eta_xz * Normal[0] + eta_yz * Normal[1] + eta_zz * Normal[2] - Velocity_j[2] * Sigma_5); - val_residual_j[4] = (Sigma_5); - - /*--- Computation of the Jacobians at Point j---*/ - - if (implicit) { - - dSigmaxx_phi1 = FOUR3 * ViscDens_j * Edge_Vector[0]/dist_ij_2; - dSigmaxx_phi2 = -TWO3 * ViscDens_j * Edge_Vector[1]/dist_ij_2; - dSigmaxx_phi3 = -TWO3 * ViscDens_j * Edge_Vector[2]/dist_ij_2; - dSigmayy_phi1 = -TWO3 * ViscDens_j * Edge_Vector[0]/dist_ij_2; - dSigmayy_phi2 = FOUR3 * ViscDens_j * Edge_Vector[1]/dist_ij_2; - dSigmayy_phi3 = -TWO3 * ViscDens_j * Edge_Vector[2]/dist_ij_2; - dSigmazz_phi1 = -TWO3 * ViscDens_j * Edge_Vector[0]/dist_ij_2; - dSigmazz_phi2 = -TWO3 * ViscDens_j * Edge_Vector[1]/dist_ij_2; - dSigmazz_phi3 = FOUR3 * ViscDens_j * Edge_Vector[2]/dist_ij_2; - dSigmaxy_phi1 = ViscDens_j * Edge_Vector[1]/dist_ij_2; - dSigmaxy_phi2 = ViscDens_j * Edge_Vector[0]/dist_ij_2; - dSigmaxy_phi3 = 0; - dSigmaxz_phi1 = ViscDens_j * Edge_Vector[2]/dist_ij_2; - dSigmaxz_phi2 = 0; - dSigmaxz_phi3 = ViscDens_j * Edge_Vector[0]/dist_ij_2; - dSigmayz_phi1 = 0; - dSigmayz_phi2 = ViscDens_j * Edge_Vector[2]/dist_ij_2; - dSigmayz_phi3 = ViscDens_j * Edge_Vector[1]/dist_ij_2; - - // dSigmaxx5_psi5 = ViscDens_j * ( FOUR3*Velocity_j[0]*Edge_Vector[0] - TWO3*Velocity_j[1]*Edge_Vector[1] - TWO3*Velocity_j[2]*Edge_Vector[2])/dist_ij_2; - // dSigmayy5_psi5 = ViscDens_j * (- TWO3*Velocity_j[0]*Edge_Vector[0] + FOUR3*Velocity_j[1]*Edge_Vector[1] - TWO3*Velocity_j[2]*Edge_Vector[2])/dist_ij_2; - // dSigmazz5_psi5 = ViscDens_j * (- TWO3*Velocity_j[0]*Edge_Vector[0] - TWO3*Velocity_j[1]*Edge_Vector[1] + FOUR3*Velocity_j[2]*Edge_Vector[2])/dist_ij_2; - // dSigmaxy5_psi5 = ViscDens_j * ( Velocity_j[0]*Edge_Vector[1] + Velocity_j[1]*Edge_Vector[0] )/dist_ij_2; - // dSigmaxz5_psi5 = ViscDens_j * ( Velocity_j[0]*Edge_Vector[2] + Velocity_j[2]*Edge_Vector[0] )/dist_ij_2; - // dSigmayz5_psi5 = ViscDens_j * ( Velocity_j[1]*Edge_Vector[2] + Velocity_j[2]*Edge_Vector[1] )/dist_ij_2; - dSigma5_psi5 = XiDens_j * ( Edge_Vector[0]*Normal[0] + Edge_Vector[1]*Normal[1] + Edge_Vector[2]*Normal[2] )/dist_ij_2; - - val_Jacobian_jj[0][0] = 0; - val_Jacobian_jj[0][1] = -( Velocity_j[0]*Normal[0]*dSigmaxx_phi1 + Velocity_j[1]*Normal[1]*dSigmayy_phi1 + Velocity_j[2]*Normal[2]*dSigmazz_phi1 - + (Velocity_j[0]*Normal[1] + Velocity_j[1]*Normal[0])*dSigmaxy_phi1 - + (Velocity_j[0]*Normal[2] + Velocity_j[2]*Normal[0])*dSigmaxz_phi1 - + (Velocity_j[2]*Normal[1] + Velocity_j[1]*Normal[2])*dSigmayz_phi1 ); - val_Jacobian_jj[0][2] = -( Velocity_j[0]*Normal[0]*dSigmaxx_phi2 + Velocity_j[1]*Normal[1]*dSigmayy_phi2 + Velocity_j[2]*Normal[2]*dSigmazz_phi2 - + (Velocity_j[0]*Normal[1] + Velocity_j[1]*Normal[0])*dSigmaxy_phi2 - + (Velocity_j[0]*Normal[2] + Velocity_j[2]*Normal[0])*dSigmaxz_phi2 - + (Velocity_j[2]*Normal[1] + Velocity_j[1]*Normal[2])*dSigmayz_phi2 ); - val_Jacobian_jj[0][3] = -( Velocity_j[0]*Normal[0]*dSigmaxx_phi3 + Velocity_j[1]*Normal[1]*dSigmayy_phi3 + Velocity_j[2]*Normal[2]*dSigmazz_phi3 - + (Velocity_j[0]*Normal[1] + Velocity_j[1]*Normal[0])*dSigmaxy_phi3 - + (Velocity_j[0]*Normal[2] + Velocity_j[2]*Normal[0])*dSigmaxz_phi3 - + (Velocity_j[2]*Normal[1] + Velocity_j[1]*Normal[2])*dSigmayz_phi3 ); - val_Jacobian_jj[0][4] = (sq_vel_j - Pressure_j/(Density_j*Gamma_Minus_One)) * dSigma5_psi5; - - val_Jacobian_jj[1][0] = 0; - val_Jacobian_jj[1][1] = Normal[0]*dSigmaxx_phi1 + Normal[1]*dSigmaxy_phi1 + Normal[2]*dSigmaxz_phi1; - val_Jacobian_jj[1][2] = Normal[0]*dSigmaxx_phi2 + Normal[1]*dSigmaxy_phi2 + Normal[2]*dSigmaxz_phi2; - val_Jacobian_jj[1][3] = Normal[0]*dSigmaxx_phi3 + Normal[1]*dSigmaxy_phi3 + Normal[2]*dSigmaxz_phi3; - val_Jacobian_jj[1][4] = -Velocity_j[0]*dSigma5_psi5; - - val_Jacobian_jj[2][0] = 0; - val_Jacobian_jj[2][1] = Normal[0]*dSigmaxy_phi1 + Normal[1]*dSigmayy_phi1 + Normal[2]*dSigmayz_phi1; - val_Jacobian_jj[2][2] = Normal[0]*dSigmaxy_phi2 + Normal[1]*dSigmayy_phi2 + Normal[2]*dSigmayz_phi2; - val_Jacobian_jj[2][3] = Normal[0]*dSigmaxy_phi3 + Normal[1]*dSigmayy_phi3 + Normal[2]*dSigmayz_phi3; - val_Jacobian_jj[2][4] = -Velocity_j[1]*dSigma5_psi5; - - val_Jacobian_jj[3][0] = 0; - val_Jacobian_jj[3][1] = Normal[0]*dSigmaxz_phi1 + Normal[1]*dSigmayz_phi1 + Normal[2]*dSigmazz_phi1; - val_Jacobian_jj[3][2] = Normal[0]*dSigmaxz_phi2 + Normal[1]*dSigmayz_phi2 + Normal[2]*dSigmazz_phi2; - val_Jacobian_jj[3][3] = Normal[0]*dSigmaxz_phi3 + Normal[1]*dSigmayz_phi3 + Normal[2]*dSigmazz_phi3; - val_Jacobian_jj[3][4] = -Velocity_j[2]*dSigma5_psi5; - - val_Jacobian_jj[4][0] = 0; - val_Jacobian_jj[4][1] = 0; - val_Jacobian_jj[4][2] = 0; - val_Jacobian_jj[4][3] = 0; - val_Jacobian_jj[4][4] = dSigma5_psi5; - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - val_Jacobian_ji[iVar][jVar] = -val_Jacobian_jj[iVar][jVar]; - } - - } - else if (nDim == 2) { - - /*--- Residual at iPoint ---*/ - - Sigma_xx = ViscDens_i * (FOUR3 * Mean_GradPhi[0][0] - TWO3 * Mean_GradPhi[1][1]); - Sigma_yy = ViscDens_i * (-TWO3 * Mean_GradPhi[0][0] + FOUR3 * Mean_GradPhi[1][1]); - Sigma_xy = ViscDens_i * (Mean_GradPhi[1][0] + Mean_GradPhi[0][1]); - Sigma_xx5 = ViscDens_i * ( FOUR3 * Velocity_i[0] * Mean_GradPsiE[0] - TWO3 * Velocity_i[1] * Mean_GradPsiE[1]); - Sigma_yy5 = ViscDens_i * (- TWO3 * Velocity_i[0] * Mean_GradPsiE[0] + FOUR3 * Velocity_i[1] * Mean_GradPsiE[1]); - Sigma_xy5 = ViscDens_i * (Velocity_i[0] * Mean_GradPsiE[1] + Velocity_i[1] * Mean_GradPsiE[0]); - Sigma_5 = XiDens_i * dPhiE_dn; - eta_xx = Sigma_xx + Sigma_xx5; eta_yy = Sigma_yy + Sigma_yy5; eta_xy = Sigma_xy + Sigma_xy5; - - val_residual_i[0] = - (Velocity_i[0] * Normal[0] * eta_xx + Velocity_i[1] * Normal[1] * eta_yy - + (Velocity_i[0] * Normal[1] + Velocity_i[1] * Normal[0]) * eta_xy - - (sq_vel_i - Pressure_i/(Density_i*Gamma_Minus_One)) * Sigma_5); - val_residual_i[1] = (eta_xx * Normal[0] + eta_xy * Normal[1] - Velocity_i[0] * Sigma_5); - val_residual_i[2] = (eta_xy * Normal[0] + eta_yy * Normal[1] - Velocity_i[1] * Sigma_5); - val_residual_i[3] = (Sigma_5); - - /*--- Computation of the Jacobians at Point i---*/ - - if (implicit) { - - dSigmaxx_phi1 = -FOUR3 * ViscDens_i * Edge_Vector[0]/dist_ij_2; - dSigmaxx_phi2 = TWO3 * ViscDens_i * Edge_Vector[1]/dist_ij_2; - dSigmayy_phi1 = TWO3 * ViscDens_i * Edge_Vector[0]/dist_ij_2; - dSigmayy_phi2 = -FOUR3 * ViscDens_i * Edge_Vector[1]/dist_ij_2; - dSigmaxy_phi1 = -ViscDens_i * Edge_Vector[1]/dist_ij_2; - dSigmaxy_phi2 = -ViscDens_i * Edge_Vector[0]/dist_ij_2; - - // dSigmaxx5_psi5 = -ViscDens_i * ( FOUR3*Velocity_i[0]*Edge_Vector[0] - TWO3*Velocity_i[1]*Edge_Vector[1] )/dist_ij_2; - // dSigmayy5_psi5 = -ViscDens_i * (- TWO3*Velocity_i[0]*Edge_Vector[0] + FOUR3*Velocity_i[1]*Edge_Vector[1] )/dist_ij_2; - // dSigmaxy5_psi5 = -ViscDens_i * ( Velocity_i[0]*Edge_Vector[1] + Velocity_i[1]*Edge_Vector[0] )/dist_ij_2; - dSigma5_psi5 = -XiDens_i * ( Edge_Vector[0]*Normal[0] + Edge_Vector[1]*Normal[1] )/dist_ij_2; - - val_Jacobian_ii[0][0] = 0; - - val_Jacobian_ii[0][1] = -( Velocity_i[0]*Normal[0]*dSigmaxx_phi1 + Velocity_i[1]*Normal[1]*dSigmayy_phi1 - + (Velocity_i[0]*Normal[1] + Velocity_i[1]*Normal[0])*dSigmaxy_phi1 ); - val_Jacobian_ii[0][2] = -( Velocity_i[0]*Normal[0]*dSigmaxx_phi2 + Velocity_i[1]*Normal[1]*dSigmayy_phi2 - + (Velocity_i[0]*Normal[1] + Velocity_i[1]*Normal[0])*dSigmaxy_phi2 ); - val_Jacobian_ii[0][3] = (sq_vel_i - Pressure_i/(Density_i*Gamma_Minus_One)) * dSigma5_psi5; - - val_Jacobian_ii[1][0] = 0; - val_Jacobian_ii[1][1] = Normal[0]*dSigmaxx_phi1 + Normal[1]*dSigmaxy_phi1; - val_Jacobian_ii[1][2] = Normal[0]*dSigmaxx_phi2 + Normal[1]*dSigmaxy_phi2; - val_Jacobian_ii[1][3] = -Velocity_i[0]*dSigma5_psi5; - - val_Jacobian_ii[2][0] = 0; - val_Jacobian_ii[2][1] = Normal[0]*dSigmaxy_phi1 + Normal[1]*dSigmayy_phi1; - val_Jacobian_ii[2][2] = Normal[0]*dSigmaxy_phi2 + Normal[1]*dSigmayy_phi2; - val_Jacobian_ii[2][3] = -Velocity_i[1]*dSigma5_psi5; - - val_Jacobian_ii[3][0] = 0; - val_Jacobian_ii[3][1] = 0; - val_Jacobian_ii[3][2] = 0; - val_Jacobian_ii[3][3] = dSigma5_psi5; - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - val_Jacobian_ij[iVar][jVar] = -val_Jacobian_ii[iVar][jVar]; - } - - /*--- Residual at jPoint ---*/ - Sigma_xx = ViscDens_j * (FOUR3 * Mean_GradPhi[0][0] - TWO3 * Mean_GradPhi[1][1]); - Sigma_yy = ViscDens_j * (-TWO3 * Mean_GradPhi[0][0] + FOUR3 * Mean_GradPhi[1][1]); - Sigma_xy = ViscDens_j * (Mean_GradPhi[1][0] + Mean_GradPhi[0][1]); - Sigma_xx5 = ViscDens_j * ( FOUR3 * Velocity_j[0] * Mean_GradPsiE[0] - TWO3 * Velocity_j[1] * Mean_GradPsiE[1]); - Sigma_yy5 = ViscDens_j * (- TWO3 * Velocity_j[0] * Mean_GradPsiE[0] + FOUR3 * Velocity_j[1] * Mean_GradPsiE[1]); - Sigma_xy5 = ViscDens_j * (Velocity_j[0] * Mean_GradPsiE[1] + Velocity_j[1] * Mean_GradPsiE[0]); - Sigma_5 = XiDens_j * dPhiE_dn; - eta_xx = Sigma_xx + Sigma_xx5; eta_yy = Sigma_yy + Sigma_yy5; eta_xy = Sigma_xy + Sigma_xy5; - - val_residual_j[0] = - (Velocity_j[0] * Normal[0] * eta_xx + Velocity_j[1] * Normal[1] * eta_yy - + (Velocity_j[0] * Normal[1] + Velocity_j[1] * Normal[0]) * eta_xy - - (sq_vel_j - Pressure_j/(Density_j*Gamma_Minus_One)) * Sigma_5); - val_residual_j[1] = (eta_xx * Normal[0] + eta_xy * Normal[1] - Velocity_j[0] * Sigma_5); - val_residual_j[2] = (eta_xy * Normal[0] + eta_yy * Normal[1] - Velocity_j[1] * Sigma_5); - val_residual_j[3] = (Sigma_5); - - /*--- Computation of the Jacobians at Point j---*/ - if (implicit) { - dSigmaxx_phi1 = FOUR3 * ViscDens_j * Edge_Vector[0]/dist_ij_2; - dSigmaxx_phi2 = -TWO3 * ViscDens_j * Edge_Vector[1]/dist_ij_2; - dSigmayy_phi1 = -TWO3 * ViscDens_j * Edge_Vector[0]/dist_ij_2; - dSigmayy_phi2 = FOUR3 * ViscDens_j * Edge_Vector[1]/dist_ij_2; - dSigmaxy_phi1 = ViscDens_j * Edge_Vector[1]/dist_ij_2; - dSigmaxy_phi2 = ViscDens_j * Edge_Vector[0]/dist_ij_2; - - // dSigmaxx5_psi5 = ViscDens_j * ( FOUR3*Velocity_j[0]*Edge_Vector[0] - TWO3*Velocity_j[1]*Edge_Vector[1] )/dist_ij_2; - // dSigmayy5_psi5 = ViscDens_j * (- TWO3*Velocity_j[0]*Edge_Vector[0] + FOUR3*Velocity_j[1]*Edge_Vector[1] )/dist_ij_2; - // dSigmaxy5_psi5 = ViscDens_j * ( Velocity_j[0]*Edge_Vector[1] + Velocity_j[1]*Edge_Vector[0] )/dist_ij_2; - dSigma5_psi5 = XiDens_j * ( Edge_Vector[0]*Normal[0] + Edge_Vector[1]*Normal[1] )/dist_ij_2; - - val_Jacobian_jj[0][0] = 0; - val_Jacobian_jj[0][1] = -( Velocity_j[0]*Normal[0]*dSigmaxx_phi1 + Velocity_j[1]*Normal[1]*dSigmayy_phi1 - + (Velocity_j[0]*Normal[1] + Velocity_j[1]*Normal[0])*dSigmaxy_phi1 ); - val_Jacobian_jj[0][2] = -( Velocity_j[0]*Normal[0]*dSigmaxx_phi2 + Velocity_j[1]*Normal[1]*dSigmayy_phi2 - + (Velocity_j[0]*Normal[1] + Velocity_j[1]*Normal[0])*dSigmaxy_phi2 ); - val_Jacobian_jj[0][3] = (sq_vel_j - Pressure_j/(Density_j*Gamma_Minus_One)) * dSigma5_psi5; - - val_Jacobian_jj[1][0] = 0; - val_Jacobian_jj[1][1] = Normal[0]*dSigmaxx_phi1 + Normal[1]*dSigmaxy_phi1; - val_Jacobian_jj[1][2] = Normal[0]*dSigmaxx_phi2 + Normal[1]*dSigmaxy_phi2; - val_Jacobian_jj[1][3] = -Velocity_j[0]*dSigma5_psi5; - - val_Jacobian_jj[2][0] = 0; - val_Jacobian_jj[2][1] = Normal[0]*dSigmaxy_phi1 + Normal[1]*dSigmayy_phi1; - val_Jacobian_jj[2][2] = Normal[0]*dSigmaxy_phi2 + Normal[1]*dSigmayy_phi2; - val_Jacobian_jj[2][3] = -Velocity_j[1]*dSigma5_psi5; - - val_Jacobian_jj[3][0] = 0; - val_Jacobian_jj[3][1] = 0; - val_Jacobian_jj[3][2] = 0; - val_Jacobian_jj[3][3] = dSigma5_psi5; - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - val_Jacobian_ji[iVar][jVar] = -val_Jacobian_jj[iVar][jVar]; - } - } - -} - -void CNumerics::GetViscousFlux(su2double *val_primvar, su2double **val_gradprimvar, - su2double val_laminar_viscosity, su2double val_eddy_viscosity, su2double val_mach_inf) { - - su2double total_viscosity = val_laminar_viscosity + val_eddy_viscosity; - su2double Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; - su2double heat_flux_factor = Cp * (val_laminar_viscosity/Prandtl_Lam + val_eddy_viscosity/Prandtl_Turb); - - su2double div_vel = 0.0; - for (unsigned short iDim = 0 ; iDim < nDim; iDim++) - div_vel += val_gradprimvar[iDim+1][iDim]; - - for (unsigned short iDim = 0 ; iDim < nDim; iDim++) { - for (unsigned short jDim = 0 ; jDim < nDim; jDim++) { - tau[iDim][jDim] = total_viscosity*( val_gradprimvar[jDim+1][iDim] + - val_gradprimvar[iDim+1][jDim] ) - -TWO3*total_viscosity*div_vel*delta[iDim][jDim]; - } - } - - // Gradient of primitive variables -> [Temp vel_x vel_y vel_z Pressure] - if (nDim == 3) { - Flux_Tensor[0][0] = 0.0; - Flux_Tensor[1][0] = tau[0][0]; - Flux_Tensor[2][0] = tau[0][1]; - Flux_Tensor[3][0] = tau[0][2]; - Flux_Tensor[4][0] = tau[0][0]*val_primvar[1] + tau[0][1]*val_primvar[2] + tau[0][2]*val_primvar[3] + - heat_flux_factor*val_gradprimvar[0][0]; - - Flux_Tensor[0][1] = 0.0; - Flux_Tensor[1][1] = tau[1][0]; - Flux_Tensor[2][1] = tau[1][1]; - Flux_Tensor[3][1] = tau[1][2]; - Flux_Tensor[4][1] = tau[1][0]*val_primvar[1] + tau[1][1]*val_primvar[2] + tau[1][2]*val_primvar[3] + - heat_flux_factor*val_gradprimvar[0][1]; - - Flux_Tensor[0][2] = 0.0; - Flux_Tensor[1][2] = tau[2][0]; - Flux_Tensor[2][2] = tau[2][1]; - Flux_Tensor[3][2] = tau[2][2]; - Flux_Tensor[4][2] = tau[2][0]*val_primvar[1] + tau[2][1]*val_primvar[2] + tau[2][2]*val_primvar[3] + - heat_flux_factor*val_gradprimvar[0][2]; - } - if (nDim == 2) { - Flux_Tensor[0][0] = 0.0; - Flux_Tensor[1][0] = tau[0][0]; - Flux_Tensor[2][0] = tau[0][1]; - Flux_Tensor[3][0] = tau[0][0]*val_primvar[1] + tau[0][1]*val_primvar[2]+ - heat_flux_factor*val_gradprimvar[0][0]; - - Flux_Tensor[0][1] = 0.0; - Flux_Tensor[1][1] = tau[1][0]; - Flux_Tensor[2][1] = tau[1][1]; - Flux_Tensor[3][1] = tau[1][0]*val_primvar[1] + tau[1][1]*val_primvar[2]+ - heat_flux_factor*val_gradprimvar[0][1]; - } -} - - - -void CNumerics::GetViscousProjFlux(su2double *val_primvar, - su2double **val_gradprimvar, su2double val_turb_ke, - su2double *val_normal, - su2double val_laminar_viscosity, - su2double val_eddy_viscosity) { - - - unsigned short iVar, iDim, jDim; - su2double total_viscosity, heat_flux_factor, div_vel, Cp, Density; - - Density = val_primvar[nDim+2]; - total_viscosity = val_laminar_viscosity + val_eddy_viscosity; - Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; - heat_flux_factor = Cp * (val_laminar_viscosity/Prandtl_Lam + val_eddy_viscosity/Prandtl_Turb); - - div_vel = 0.0; - for (iDim = 0 ; iDim < nDim; iDim++) - div_vel += val_gradprimvar[iDim+1][iDim]; - for (iDim = 0 ; iDim < nDim; iDim++) - for (jDim = 0 ; jDim < nDim; jDim++) - tau[iDim][jDim] = total_viscosity*( val_gradprimvar[jDim+1][iDim] + val_gradprimvar[iDim+1][jDim] ) - - TWO3*total_viscosity*div_vel*delta[iDim][jDim] - - TWO3*Density*val_turb_ke*delta[iDim][jDim]; - /*--- Gradient of primitive variables -> [Temp vel_x vel_y vel_z Pressure] ---*/ - if (nDim == 2) { - Flux_Tensor[0][0] = 0.0; - Flux_Tensor[1][0] = tau[0][0]; - Flux_Tensor[2][0] = tau[0][1]; - Flux_Tensor[3][0] = tau[0][0]*val_primvar[1] + tau[0][1]*val_primvar[2]+ - heat_flux_factor*val_gradprimvar[0][0]; - Flux_Tensor[0][1] = 0.0; - Flux_Tensor[1][1] = tau[1][0]; - Flux_Tensor[2][1] = tau[1][1]; - Flux_Tensor[3][1] = tau[1][0]*val_primvar[1] + tau[1][1]*val_primvar[2]+ - heat_flux_factor*val_gradprimvar[0][1]; - } else { - Flux_Tensor[0][0] = 0.0; - Flux_Tensor[1][0] = tau[0][0]; - Flux_Tensor[2][0] = tau[0][1]; - Flux_Tensor[3][0] = tau[0][2]; - Flux_Tensor[4][0] = tau[0][0]*val_primvar[1] + tau[0][1]*val_primvar[2] + tau[0][2]*val_primvar[3] + - heat_flux_factor*val_gradprimvar[0][0]; - Flux_Tensor[0][1] = 0.0; - Flux_Tensor[1][1] = tau[1][0]; - Flux_Tensor[2][1] = tau[1][1]; - Flux_Tensor[3][1] = tau[1][2]; - Flux_Tensor[4][1] = tau[1][0]*val_primvar[1] + tau[1][1]*val_primvar[2] + tau[1][2]*val_primvar[3] + - heat_flux_factor*val_gradprimvar[0][1]; - Flux_Tensor[0][2] = 0.0; - Flux_Tensor[1][2] = tau[2][0]; - Flux_Tensor[2][2] = tau[2][1]; - Flux_Tensor[3][2] = tau[2][2]; - Flux_Tensor[4][2] = tau[2][0]*val_primvar[1] + tau[2][1]*val_primvar[2] + tau[2][2]*val_primvar[3] + - heat_flux_factor*val_gradprimvar[0][2]; - } - for (iVar = 0; iVar < nVar; iVar++) { - Proj_Flux_Tensor[iVar] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Proj_Flux_Tensor[iVar] += Flux_Tensor[iVar][iDim] * val_normal[iDim]; - } -} - -void CNumerics::GetViscousProjFlux(su2double *val_primvar, - su2double **val_gradprimvar, su2double val_turb_ke, - su2double *val_normal, - su2double val_laminar_viscosity, - su2double val_eddy_viscosity, - su2double val_thermal_conductivity, - su2double val_heat_capacity_cp) { - - unsigned short iVar, iDim, jDim; - su2double total_viscosity, heat_flux_factor, div_vel, Density; - Density = val_primvar[nDim+2]; - - total_viscosity = val_laminar_viscosity + val_eddy_viscosity; - heat_flux_factor = val_thermal_conductivity + val_heat_capacity_cp*val_eddy_viscosity/Prandtl_Turb; - - div_vel = 0.0; - for (iDim = 0 ; iDim < nDim; iDim++) - div_vel += val_gradprimvar[iDim+1][iDim]; - - for (iDim = 0 ; iDim < nDim; iDim++) - for (jDim = 0 ; jDim < nDim; jDim++) - tau[iDim][jDim] = total_viscosity*( val_gradprimvar[jDim+1][iDim] + val_gradprimvar[iDim+1][jDim] ) - - TWO3*total_viscosity*div_vel*delta[iDim][jDim] - - TWO3*Density*val_turb_ke*delta[iDim][jDim]; - - - /*--- Gradient of primitive variables -> [Temp vel_x vel_y vel_z Pressure] ---*/ - if (nDim == 2) { - Flux_Tensor[0][0] = 0.0; - Flux_Tensor[1][0] = tau[0][0]; - Flux_Tensor[2][0] = tau[0][1]; - Flux_Tensor[3][0] = tau[0][0]*val_primvar[1] + tau[0][1]*val_primvar[2]+ - heat_flux_factor*val_gradprimvar[0][0]; - - Flux_Tensor[0][1] = 0.0; - Flux_Tensor[1][1] = tau[1][0]; - Flux_Tensor[2][1] = tau[1][1]; - Flux_Tensor[3][1] = tau[1][0]*val_primvar[1] + tau[1][1]*val_primvar[2]+ - heat_flux_factor*val_gradprimvar[0][1]; - } else { - Flux_Tensor[0][0] = 0.0; - Flux_Tensor[1][0] = tau[0][0]; - Flux_Tensor[2][0] = tau[0][1]; - Flux_Tensor[3][0] = tau[0][2]; - Flux_Tensor[4][0] = tau[0][0]*val_primvar[1] + tau[0][1]*val_primvar[2] + tau[0][2]*val_primvar[3] + - heat_flux_factor*val_gradprimvar[0][0]; - - Flux_Tensor[0][1] = 0.0; - Flux_Tensor[1][1] = tau[1][0]; - Flux_Tensor[2][1] = tau[1][1]; - Flux_Tensor[3][1] = tau[1][2]; - Flux_Tensor[4][1] = tau[1][0]*val_primvar[1] + tau[1][1]*val_primvar[2] + tau[1][2]*val_primvar[3] + - heat_flux_factor*val_gradprimvar[0][1]; - - Flux_Tensor[0][2] = 0.0; - Flux_Tensor[1][2] = tau[2][0]; - Flux_Tensor[2][2] = tau[2][1]; - Flux_Tensor[3][2] = tau[2][2]; - Flux_Tensor[4][2] = tau[2][0]*val_primvar[1] + tau[2][1]*val_primvar[2] + tau[2][2]*val_primvar[3] + - heat_flux_factor*val_gradprimvar[0][2]; - } - - for (iVar = 0; iVar < nVar; iVar++) { - Proj_Flux_Tensor[iVar] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Proj_Flux_Tensor[iVar] += Flux_Tensor[iVar][iDim] * val_normal[iDim]; - } - -} - -void CNumerics::GetViscousArtCompProjFlux(su2double **val_gradprimvar, su2double *val_normal, su2double val_laminar_viscosity, - su2double val_eddy_viscosity) { - unsigned short iVar, iDim; - su2double total_viscosity; - - total_viscosity = (val_laminar_viscosity + val_eddy_viscosity); - - if (nDim == 3) { - Flux_Tensor[0][0] = 0.0; - Flux_Tensor[1][0] = total_viscosity * val_gradprimvar[1][0]; - Flux_Tensor[2][0] = total_viscosity * val_gradprimvar[2][0]; - Flux_Tensor[3][0] = total_viscosity * val_gradprimvar[3][0]; - - Flux_Tensor[0][1] = 0.0; - Flux_Tensor[1][1] = total_viscosity * val_gradprimvar[1][1]; - Flux_Tensor[2][1] = total_viscosity * val_gradprimvar[2][1]; - Flux_Tensor[3][1] = total_viscosity * val_gradprimvar[3][1]; - - Flux_Tensor[0][2] = 0.0; - Flux_Tensor[1][2] = total_viscosity * val_gradprimvar[1][2]; - Flux_Tensor[2][2] = total_viscosity * val_gradprimvar[2][2]; - Flux_Tensor[3][2] = total_viscosity * val_gradprimvar[3][2]; - } - - if (nDim == 2) { - Flux_Tensor[0][0] = 0.0; - Flux_Tensor[1][0] = total_viscosity * val_gradprimvar[1][0]; - Flux_Tensor[2][0] = total_viscosity * val_gradprimvar[2][0]; - - Flux_Tensor[0][1] = 0.0; - Flux_Tensor[1][1] = total_viscosity * val_gradprimvar[1][1]; - Flux_Tensor[2][1] = total_viscosity * val_gradprimvar[2][1]; - } - - for (iVar = 0; iVar < nVar; iVar++) { - Proj_Flux_Tensor[iVar] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Proj_Flux_Tensor[iVar] += Flux_Tensor[iVar][iDim] * val_normal[iDim]; - } -} - -void CNumerics::GetViscousProjJacs(su2double *val_Mean_PrimVar, su2double val_laminar_viscosity, - su2double val_eddy_viscosity, su2double val_dist_ij, su2double *val_normal, su2double val_dS, - su2double *val_Proj_Visc_Flux, su2double **val_Proj_Jac_Tensor_i, su2double **val_Proj_Jac_Tensor_j) { - unsigned short iDim, iVar, jVar; - - su2double theta = 0.0, sqvel = 0.0, proj_viscousflux_vel = 0.0; - - for (iDim = 0; iDim < nDim; iDim++) { - theta += val_normal[iDim]*val_normal[iDim]; - sqvel += val_Mean_PrimVar[iDim+1]*val_Mean_PrimVar[iDim+1]; - proj_viscousflux_vel += val_Proj_Visc_Flux[iDim+1]*val_Mean_PrimVar[iDim+1]; - } - - su2double phi = 0.5*(Gamma-1.0)*sqvel; - su2double Density = val_Mean_PrimVar[nDim+2]; - su2double Pressure = val_Mean_PrimVar[nDim+1]; - su2double total_viscosity = val_laminar_viscosity + val_eddy_viscosity; - su2double heat_flux_factor = val_laminar_viscosity/Prandtl_Lam + val_eddy_viscosity/Prandtl_Turb; - su2double cpoR = Gamma/(Gamma-1.0); // cp over R - su2double factor = total_viscosity*val_dS/(Density*val_dist_ij); - su2double phi_rho = -cpoR*heat_flux_factor*Pressure/(Density*Density); - su2double phi_p = cpoR*heat_flux_factor/(Density); - su2double rhoovisc = Density/(total_viscosity); // rho over viscosity - - for (unsigned short iVar = 0; iVar < nVar; iVar++) { - for (unsigned short jVar = 0; jVar < nVar; jVar++) { - val_Proj_Jac_Tensor_i[iVar][jVar] = 0.0; - val_Proj_Jac_Tensor_j[iVar][jVar] = 0.0; - } - } - - if (nDim == 2) { - - su2double thetax = theta + val_normal[0]*val_normal[0]/3.0; - su2double thetay = theta + val_normal[1]*val_normal[1]/3.0; - - su2double etaz = val_normal[0]*val_normal[1]/3.0; - - su2double pix = val_Mean_PrimVar[1]*thetax + val_Mean_PrimVar[2]*etaz; - su2double piy = val_Mean_PrimVar[1]*etaz + val_Mean_PrimVar[2]*thetay; - - val_Proj_Jac_Tensor_i[0][0] = 0.0; - val_Proj_Jac_Tensor_i[0][1] = 0.0; - val_Proj_Jac_Tensor_i[0][2] = 0.0; - val_Proj_Jac_Tensor_i[0][3] = 0.0; - val_Proj_Jac_Tensor_i[1][0] = factor*pix; - val_Proj_Jac_Tensor_i[1][1] = -factor*thetax; - val_Proj_Jac_Tensor_i[1][2] = -factor*etaz; - val_Proj_Jac_Tensor_i[1][3] = 0.0; - val_Proj_Jac_Tensor_i[2][0] = factor*piy; - val_Proj_Jac_Tensor_i[2][1] = -factor*etaz; - val_Proj_Jac_Tensor_i[2][2] = -factor*thetay; - val_Proj_Jac_Tensor_i[2][3] = 0.0; - - val_Proj_Jac_Tensor_i[3][0] = -factor*(rhoovisc*theta*(phi_rho+phi*phi_p)- (pix*val_Mean_PrimVar[1]+piy*val_Mean_PrimVar[2])); - val_Proj_Jac_Tensor_i[3][1] = -factor*(pix-rhoovisc*theta*phi_p*(Gamma-1.0)*val_Mean_PrimVar[1]); - val_Proj_Jac_Tensor_i[3][2] = -factor*(piy-rhoovisc*theta*phi_p*(Gamma-1.0)*val_Mean_PrimVar[2]); - val_Proj_Jac_Tensor_i[3][3] = -factor*((Gamma-1.0)*rhoovisc*theta*phi_p); - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - val_Proj_Jac_Tensor_j[iVar][jVar] = -val_Proj_Jac_Tensor_i[iVar][jVar]; - - factor = 0.5/Density; - val_Proj_Jac_Tensor_i[3][0] += factor*proj_viscousflux_vel; - val_Proj_Jac_Tensor_j[3][0] += factor*proj_viscousflux_vel; - val_Proj_Jac_Tensor_i[3][1] += factor*val_Proj_Visc_Flux[1]; - val_Proj_Jac_Tensor_j[3][1] += factor*val_Proj_Visc_Flux[1]; - val_Proj_Jac_Tensor_i[3][2] += factor*val_Proj_Visc_Flux[2]; - val_Proj_Jac_Tensor_j[3][2] += factor*val_Proj_Visc_Flux[2]; - - - } - else { - - su2double thetax = theta + val_normal[0]*val_normal[0]/3.0; - su2double thetay = theta + val_normal[1]*val_normal[1]/3.0; - su2double thetaz = theta + val_normal[2]*val_normal[2]/3.0; - - su2double etax = val_normal[1]*val_normal[2]/3.0; - su2double etay = val_normal[0]*val_normal[2]/3.0; - su2double etaz = val_normal[0]*val_normal[1]/3.0; - - su2double pix = val_Mean_PrimVar[1]*thetax + val_Mean_PrimVar[2]*etaz + val_Mean_PrimVar[3]*etay; - su2double piy = val_Mean_PrimVar[1]*etaz + val_Mean_PrimVar[2]*thetay + val_Mean_PrimVar[3]*etax; - su2double piz = val_Mean_PrimVar[1]*etay + val_Mean_PrimVar[2]*etax + val_Mean_PrimVar[3]*thetaz; - - val_Proj_Jac_Tensor_i[0][0] = 0.0; - val_Proj_Jac_Tensor_i[0][1] = 0.0; - val_Proj_Jac_Tensor_i[0][2] = 0.0; - val_Proj_Jac_Tensor_i[0][3] = 0.0; - val_Proj_Jac_Tensor_i[0][4] = 0.0; - val_Proj_Jac_Tensor_i[1][0] = factor*pix; - val_Proj_Jac_Tensor_i[1][1] = -factor*thetax; - val_Proj_Jac_Tensor_i[1][2] = -factor*etaz; - val_Proj_Jac_Tensor_i[1][3] = -factor*etay; - val_Proj_Jac_Tensor_i[1][4] = 0.0; - val_Proj_Jac_Tensor_i[2][0] = factor*piy; - val_Proj_Jac_Tensor_i[2][1] = -factor*etaz; - val_Proj_Jac_Tensor_i[2][2] = -factor*thetay; - val_Proj_Jac_Tensor_i[2][3] = -factor*etax; - val_Proj_Jac_Tensor_i[2][4] = 0.0; - val_Proj_Jac_Tensor_i[3][0] = factor*piz; - val_Proj_Jac_Tensor_i[3][1] = -factor*etay; - val_Proj_Jac_Tensor_i[3][2] = -factor*etax; - val_Proj_Jac_Tensor_i[3][3] = -factor*thetaz; - val_Proj_Jac_Tensor_i[3][4] = 0.0; - val_Proj_Jac_Tensor_i[4][0] = -factor*(rhoovisc*theta*(phi_rho+phi*phi_p) - (pix*val_Mean_PrimVar[1] + piy*val_Mean_PrimVar[2] + piz*val_Mean_PrimVar[3])); - val_Proj_Jac_Tensor_i[4][1] = -factor*(pix-rhoovisc*theta*phi_p*(Gamma-1)*val_Mean_PrimVar[1]); - val_Proj_Jac_Tensor_i[4][2] = -factor*(piy-rhoovisc*theta*phi_p*(Gamma-1)*val_Mean_PrimVar[2]); - val_Proj_Jac_Tensor_i[4][3] = -factor*(piz-rhoovisc*theta*phi_p*(Gamma-1)*val_Mean_PrimVar[3]); - val_Proj_Jac_Tensor_i[4][4] = -factor*((Gamma-1)*rhoovisc*theta*phi_p); - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - val_Proj_Jac_Tensor_j[iVar][jVar] = -val_Proj_Jac_Tensor_i[iVar][jVar]; - - factor = 0.5/Density; - val_Proj_Jac_Tensor_i[4][0] += factor*proj_viscousflux_vel; - val_Proj_Jac_Tensor_j[4][0] += factor*proj_viscousflux_vel; - val_Proj_Jac_Tensor_i[4][1] += factor*val_Proj_Visc_Flux[1]; - val_Proj_Jac_Tensor_j[4][1] += factor*val_Proj_Visc_Flux[1]; - val_Proj_Jac_Tensor_i[4][2] += factor*val_Proj_Visc_Flux[2]; - val_Proj_Jac_Tensor_j[4][2] += factor*val_Proj_Visc_Flux[2]; - val_Proj_Jac_Tensor_i[4][3] += factor*val_Proj_Visc_Flux[3]; - val_Proj_Jac_Tensor_j[4][3] += factor*val_Proj_Visc_Flux[3]; - - - - } - -// for (iVar = 0; iVar < nVar; iVar++) { -// for (jVar = 0; jVar < nVar; jVar++) { -// cout << val_Proj_Jac_Tensor_i[iVar][jVar] << " " << val_Proj_Jac_Tensor_j[iVar][jVar] << endl; -// } -// } -// getchar(); - -} - -void CNumerics::GetViscousProjJacs(su2double *val_Mean_PrimVar, - su2double **val_gradprimvar, - su2double *val_Mean_SecVar, - su2double val_laminar_viscosity, - su2double val_eddy_viscosity, - su2double val_thermal_conductivity, - su2double val_heat_capacity_cp, - su2double val_dist_ij, - su2double *val_normal, su2double val_dS, - su2double *val_Proj_Visc_Flux, - su2double **val_Proj_Jac_Tensor_i, - su2double **val_Proj_Jac_Tensor_j) { - - /* Viscous flux Jacobians for arbitrary equations of state */ - - //order of val_mean_primitives: T, vx, vy, vz, P, rho, ht - //order of secondary:dTdrho_e, dTde_rho - unsigned short iDim, iVar, jVar; - - su2double sqvel = 0.0, theta= 0.0, proj_viscousflux_vel= 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - theta += val_normal[iDim]*val_normal[iDim]; - sqvel += val_Mean_PrimVar[iDim+1]*val_Mean_PrimVar[iDim+1]; - proj_viscousflux_vel += val_Proj_Visc_Flux[iDim+1]*val_Mean_PrimVar[iDim+1]; - } - - su2double rho = val_Mean_PrimVar[nDim+2]; - su2double P= val_Mean_PrimVar[nDim+1]; - su2double h= val_Mean_PrimVar[nDim+3]; - su2double dTdrho_e= val_Mean_SecVar[0]; - su2double dTde_rho= val_Mean_SecVar[1]; - - - su2double dTdu0= dTdrho_e + dTde_rho*(-(h-P/rho) + sqvel)*(1/rho); - su2double dTdu1= dTde_rho*(-val_Mean_PrimVar[1])*(1/rho); - su2double dTdu2= dTde_rho*(-val_Mean_PrimVar[2])*(1/rho); - su2double total_viscosity = val_laminar_viscosity + val_eddy_viscosity; - su2double total_conductivity = val_thermal_conductivity + val_heat_capacity_cp*val_eddy_viscosity/Prandtl_Turb; - - - su2double factor1 = total_viscosity*val_dS/(rho*val_dist_ij); - su2double factor2 = total_conductivity*val_dS/val_dist_ij; - - - for (unsigned short iVar = 0; iVar < nVar; iVar++) { - for (unsigned short jVar = 0; jVar < nVar; jVar++) { - val_Proj_Jac_Tensor_i[iVar][jVar] = 0.0; - val_Proj_Jac_Tensor_j[iVar][jVar] = 0.0; - } - } - - if (nDim == 2) { - - /* 2D Jacobian: (Fv1, Fv2, Fv3, Fv4) --> (T, vx, vy, rho) */ - - su2double dTdu3= dTde_rho*(1/rho); - - su2double thetax = theta + val_normal[0]*val_normal[0]/3.0; - su2double thetay = theta + val_normal[1]*val_normal[1]/3.0; - - su2double etaz = val_normal[0]*val_normal[1]/3.0; - - su2double pix = val_Mean_PrimVar[1]*thetax + val_Mean_PrimVar[2]*etaz; - su2double piy = val_Mean_PrimVar[1]*etaz + val_Mean_PrimVar[2]*thetay; - - val_Proj_Jac_Tensor_i[0][0] = 0.0; - val_Proj_Jac_Tensor_i[0][1] = 0.0; - val_Proj_Jac_Tensor_i[0][2] = 0.0; - val_Proj_Jac_Tensor_i[0][3] = 0.0; - val_Proj_Jac_Tensor_i[1][0] = factor1*pix; - val_Proj_Jac_Tensor_i[1][1] = -factor1*thetax; - val_Proj_Jac_Tensor_i[1][2] = -factor1*etaz; - val_Proj_Jac_Tensor_i[1][3] = 0.0; - val_Proj_Jac_Tensor_i[2][0] = factor1*piy; - val_Proj_Jac_Tensor_i[2][1] = -factor1*etaz; - val_Proj_Jac_Tensor_i[2][2] = -factor1*thetay; - val_Proj_Jac_Tensor_i[2][3] = 0.0; - - val_Proj_Jac_Tensor_i[3][0] = val_Proj_Jac_Tensor_i[1][0]*val_Mean_PrimVar[1]+val_Proj_Jac_Tensor_i[2][0]*val_Mean_PrimVar[2]; - val_Proj_Jac_Tensor_i[3][0] += -factor2*theta*dTdu0; - val_Proj_Jac_Tensor_i[3][1] = val_Proj_Jac_Tensor_i[1][1]*val_Mean_PrimVar[1]+val_Proj_Jac_Tensor_i[2][1]*val_Mean_PrimVar[2]; - val_Proj_Jac_Tensor_i[3][1] += -factor2*theta*dTdu1; - val_Proj_Jac_Tensor_i[3][2] = val_Proj_Jac_Tensor_i[1][2]*val_Mean_PrimVar[1]+val_Proj_Jac_Tensor_i[2][2]*val_Mean_PrimVar[2]; - val_Proj_Jac_Tensor_i[3][2] += -factor2*theta*dTdu2; - val_Proj_Jac_Tensor_i[3][3] = -factor2*theta*dTdu3; - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - val_Proj_Jac_Tensor_j[iVar][jVar] = -val_Proj_Jac_Tensor_i[iVar][jVar]; - - su2double factor = 0.5/rho; - val_Proj_Jac_Tensor_i[3][0] -= factor*proj_viscousflux_vel; - val_Proj_Jac_Tensor_j[3][0] -= factor*proj_viscousflux_vel; - val_Proj_Jac_Tensor_i[3][1] += factor*val_Proj_Visc_Flux[1]; - val_Proj_Jac_Tensor_j[3][1] += factor*val_Proj_Visc_Flux[1]; - val_Proj_Jac_Tensor_i[3][2] += factor*val_Proj_Visc_Flux[2]; - val_Proj_Jac_Tensor_j[3][2] += factor*val_Proj_Visc_Flux[2]; - - - - - } else { - - - su2double dTdu3= dTde_rho*(-val_Mean_PrimVar[3])*(1/rho); - su2double dTdu4= dTde_rho*(1/rho); - - su2double thetax = theta + val_normal[0]*val_normal[0]/3.0; - su2double thetay = theta + val_normal[1]*val_normal[1]/3.0; - su2double thetaz = theta + val_normal[2]*val_normal[2]/3.0; - - su2double etax = val_normal[1]*val_normal[2]/3.0; - su2double etay = val_normal[0]*val_normal[2]/3.0; - su2double etaz = val_normal[0]*val_normal[1]/3.0; - - su2double pix = val_Mean_PrimVar[1]*thetax + val_Mean_PrimVar[2]*etaz + val_Mean_PrimVar[3]*etay; - su2double piy = val_Mean_PrimVar[1]*etaz + val_Mean_PrimVar[2]*thetay + val_Mean_PrimVar[3]*etax; - su2double piz = val_Mean_PrimVar[1]*etay + val_Mean_PrimVar[2]*etax + val_Mean_PrimVar[3]*thetaz; - - val_Proj_Jac_Tensor_i[0][0] = 0.0; - val_Proj_Jac_Tensor_i[0][1] = 0.0; - val_Proj_Jac_Tensor_i[0][2] = 0.0; - val_Proj_Jac_Tensor_i[0][3] = 0.0; - val_Proj_Jac_Tensor_i[0][4] = 0.0; - val_Proj_Jac_Tensor_i[1][0] = factor1*pix; - val_Proj_Jac_Tensor_i[1][1] = -factor1*thetax; - val_Proj_Jac_Tensor_i[1][2] = -factor1*etaz; - val_Proj_Jac_Tensor_i[1][3] = -factor1*etay; - val_Proj_Jac_Tensor_i[1][4] = 0.0; - val_Proj_Jac_Tensor_i[2][0] = factor1*piy; - val_Proj_Jac_Tensor_i[2][1] = -factor1*etaz; - val_Proj_Jac_Tensor_i[2][2] = -factor1*thetay; - val_Proj_Jac_Tensor_i[2][3] = -factor1*etax; - val_Proj_Jac_Tensor_i[2][4] = 0.0; - val_Proj_Jac_Tensor_i[3][0] = factor1*piz; - val_Proj_Jac_Tensor_i[3][1] = -factor1*etay; - val_Proj_Jac_Tensor_i[3][2] = -factor1*etax; - val_Proj_Jac_Tensor_i[3][3] = -factor1*thetaz; - val_Proj_Jac_Tensor_i[3][4] = 0.0; - val_Proj_Jac_Tensor_i[4][0] = val_Proj_Jac_Tensor_i[1][0]*val_Mean_PrimVar[1]+val_Proj_Jac_Tensor_i[2][0]*val_Mean_PrimVar[2]+val_Proj_Jac_Tensor_i[3][0]*val_Mean_PrimVar[3]; - val_Proj_Jac_Tensor_i[4][0] += -factor2*theta*dTdu0; - val_Proj_Jac_Tensor_i[4][1] = val_Proj_Jac_Tensor_i[1][1]*val_Mean_PrimVar[1]+val_Proj_Jac_Tensor_i[2][1]*val_Mean_PrimVar[2]+val_Proj_Jac_Tensor_i[3][1]*val_Mean_PrimVar[3]; - val_Proj_Jac_Tensor_i[4][1] += -factor2*theta*dTdu1; - val_Proj_Jac_Tensor_i[4][2] = val_Proj_Jac_Tensor_i[1][2]*val_Mean_PrimVar[1]+val_Proj_Jac_Tensor_i[2][2]*val_Mean_PrimVar[2]+val_Proj_Jac_Tensor_i[3][2]*val_Mean_PrimVar[3]; - val_Proj_Jac_Tensor_i[4][2] += -factor2*theta*dTdu2; - val_Proj_Jac_Tensor_i[4][3] = val_Proj_Jac_Tensor_i[1][3]*val_Mean_PrimVar[1]+val_Proj_Jac_Tensor_i[2][3]*val_Mean_PrimVar[2]+val_Proj_Jac_Tensor_i[3][3]*val_Mean_PrimVar[3]; - val_Proj_Jac_Tensor_i[4][3] += -factor2*theta*dTdu3; - val_Proj_Jac_Tensor_i[4][4] = -factor2*theta*dTdu4; - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - val_Proj_Jac_Tensor_j[iVar][jVar] = -val_Proj_Jac_Tensor_i[iVar][jVar]; - - su2double factor = 0.5/rho; - val_Proj_Jac_Tensor_i[4][0] -= factor*proj_viscousflux_vel; - val_Proj_Jac_Tensor_j[4][0] -= factor*proj_viscousflux_vel; - val_Proj_Jac_Tensor_i[4][1] += factor*val_Proj_Visc_Flux[1]; - val_Proj_Jac_Tensor_j[4][1] += factor*val_Proj_Visc_Flux[1]; - val_Proj_Jac_Tensor_i[4][2] += factor*val_Proj_Visc_Flux[2]; - val_Proj_Jac_Tensor_j[4][2] += factor*val_Proj_Visc_Flux[2]; - val_Proj_Jac_Tensor_i[4][3] += factor*val_Proj_Visc_Flux[3]; - val_Proj_Jac_Tensor_j[4][3] += factor*val_Proj_Visc_Flux[3]; - - - - - } - - - - } - - - - - -//void CNumerics::GetViscousProjJacs(su2double *val_Mean_PrimVar, -// su2double **val_gradprimvar, -// su2double *val_Mean_SecVar, -// su2double val_laminar_viscosity, -// su2double val_eddy_viscosity, -// su2double val_thermal_conductivity, -// su2double val_heat_capacity_cp, -// su2double val_dist_ij, -// su2double *val_normal, su2double val_dS, -// su2double *val_Proj_Visc_Flux, -// su2double **val_Proj_Jac_Tensor_i, -// su2double **val_Proj_Jac_Tensor_j) { -// -// /* Viscous flux Jacobians for arbitrary equations of state */ -// -// // order of primitives: T, vx, vy, vz, P, rho, h, c, MuLam, MuEddy, kt, Cp -// // order of secondary: dPdrho_e, dPde_rho, dTdrho_e, dTde_rho, dmudrho_T, dmudT_rho, dktdrho_T, dktdT_rho -// -// unsigned short iDim, iVar, jVar; -// su2double **val_Proj_Jac_Tensor_i_P, **val_Proj_Jac_Tensor_j_P; -// su2double **val_Jac_PC; -// -// su2double sqvel = 0.0; -// for (iDim = 0; iDim < nDim; iDim++) { -// sqvel += val_Mean_PrimVar[iDim+1]*val_Mean_PrimVar[iDim+1]; -// } -// -// su2double vx = val_Mean_PrimVar[1]; -// su2double vy = val_Mean_PrimVar[2]; -// su2double vz = val_Mean_PrimVar[3]; -// su2double rho = val_Mean_PrimVar[nDim+2]; -// su2double P = val_Mean_PrimVar[nDim+1]; -// su2double dmudrho_T = val_Mean_SecVar[4]; -// su2double dmudT_rho = val_Mean_SecVar[5]; -// su2double dktdrho_T = val_Mean_SecVar[6]; -// su2double dktdT_rho = val_Mean_SecVar[7]; -// -// su2double total_viscosity = val_laminar_viscosity + val_eddy_viscosity; -// su2double total_conductivity = val_thermal_conductivity + val_heat_capacity_cp*val_eddy_viscosity/Prandtl_Turb; -// -// val_Proj_Jac_Tensor_i_P = new su2double* [nVar]; -// val_Proj_Jac_Tensor_j_P = new su2double* [nVar]; -// val_Jac_PC = new su2double* [nVar]; -// -// for (unsigned short iVar = 0; iVar < nVar; iVar++) { -// val_Proj_Jac_Tensor_i_P[iVar] = new su2double [nVar]; -// val_Proj_Jac_Tensor_j_P[iVar] = new su2double [nVar]; -// val_Jac_PC[iVar] = new su2double [nVar]; -// } -// -// for (unsigned short iVar = 0; iVar < nVar; iVar++) { -// for (unsigned short jVar = 0; jVar < nVar; jVar++) { -// val_Proj_Jac_Tensor_i[iVar][jVar] = 0.0; -// val_Proj_Jac_Tensor_j[iVar][jVar] = 0.0; -// val_Proj_Jac_Tensor_i_P[iVar][jVar] = 0.0; -// val_Proj_Jac_Tensor_j_P[iVar][jVar] = 0.0; -// val_Jac_PC[iVar][jVar] = 0.0; -// } -// } -// -// if (nDim == 2) { -// -// /* 2D Jacobian: (Fv1, Fv2, Fv3, Fv4) --> (T, vx, vy, rho) */ -// -// su2double factor1 = 4.0/3.0*pow(val_normal[0],2) + pow(val_normal[1],2); -// su2double factor2 = 1.0/3.0*val_normal[0]*val_normal[1]; -// su2double factor3 = 4.0/3.0*pow(val_normal[1],2) + pow(val_normal[0],2); -// -// val_Proj_Jac_Tensor_i_P[0][0] = 0.0; -// val_Proj_Jac_Tensor_i_P[0][1] = 0.0; -// val_Proj_Jac_Tensor_i_P[0][2] = 0.0; -// val_Proj_Jac_Tensor_i_P[0][3] = 0.0; -// -// val_Proj_Jac_Tensor_i_P[1][0] = 0.5*dmudT_rho*val_Proj_Visc_Flux[1]/total_viscosity; -// val_Proj_Jac_Tensor_i_P[1][1] = -total_viscosity/val_dist_ij*factor1; -// val_Proj_Jac_Tensor_i_P[1][2] = -total_viscosity/val_dist_ij*factor2; -// val_Proj_Jac_Tensor_i_P[1][3] = 0.5*dmudrho_T*val_Proj_Visc_Flux[1]/total_viscosity; -// -// val_Proj_Jac_Tensor_i_P[2][0] = 0.5*dmudT_rho*val_Proj_Visc_Flux[2]/total_viscosity; -// val_Proj_Jac_Tensor_i_P[2][1] = -total_viscosity/val_dist_ij*factor2; -// val_Proj_Jac_Tensor_i_P[2][2] = -total_viscosity/val_dist_ij*factor3; -// val_Proj_Jac_Tensor_i_P[2][3] = 0.5*dmudrho_T*val_Proj_Visc_Flux[2]/total_viscosity; -// -// val_Proj_Jac_Tensor_i_P[3][0] = vx*val_Proj_Jac_Tensor_i_P[1][0] + vy*val_Proj_Jac_Tensor_i_P[2][0]; -// val_Proj_Jac_Tensor_i_P[3][1] = vx*val_Proj_Jac_Tensor_i_P[1][1] + vy*val_Proj_Jac_Tensor_i_P[2][1]; -// val_Proj_Jac_Tensor_i_P[3][2] = vx*val_Proj_Jac_Tensor_i_P[1][2] + vy*val_Proj_Jac_Tensor_i_P[2][2]; -// val_Proj_Jac_Tensor_i_P[3][3] = vx*val_Proj_Jac_Tensor_i_P[1][3] + vy*val_Proj_Jac_Tensor_i_P[2][3]; -// -// su2double etax = pow(val_normal[0],2)/val_dist_ij; -// su2double etay = pow(val_normal[1],2)/val_dist_ij; -// val_Proj_Jac_Tensor_i_P[3][0] += -total_conductivity*etax + 0.5*val_normal[0]*dktdT_rho*val_gradprimvar[0][0] - total_conductivity*etay + 0.5*val_normal[1]*dktdT_rho*val_gradprimvar[0][1]; -// val_Proj_Jac_Tensor_i_P[3][1] += 1.0/2.0*val_Proj_Visc_Flux[1]; -// val_Proj_Jac_Tensor_i_P[3][2] += 1.0/2.0*val_Proj_Visc_Flux[2]; -// val_Proj_Jac_Tensor_i_P[3][3] += 0.5*val_normal[0]*dktdrho_T*val_gradprimvar[0][0] +0.5*val_normal[1]*dktdrho_T*val_gradprimvar[0][1]; -// -// for (iVar = 0; iVar < nVar; iVar++) { -// for (jVar = 0; jVar < nVar; jVar++) { -// val_Proj_Jac_Tensor_i_P[iVar][jVar] *= val_dS; -// val_Proj_Jac_Tensor_j_P[iVar][jVar] = -val_Proj_Jac_Tensor_i_P[iVar][jVar]; /*Jacobian j*/ -// } -// } -// -// /* 2D Jacobian: (T, vx, vy, rho) --> (u1, u2, u3, u4) */ -// GetPrimitive2Conservative (val_Mean_PrimVar, val_Mean_SecVar, val_Jac_PC); -// -// /* 2D Jacobian: (Fv1, Fv2, Fv3, Fv4) --> (u1, u2, u3, u4) */ -// for (iVar = 0; iVar < nVar; iVar++) { -// for (jVar = 0; jVar < nVar; jVar++) { -// for (unsigned short kVar = 0; kVar < nVar; kVar++) { -// val_Proj_Jac_Tensor_i[iVar][jVar] += val_Proj_Jac_Tensor_i_P[iVar][kVar]*val_Jac_PC[kVar][jVar]; -// val_Proj_Jac_Tensor_j[iVar][jVar] += val_Proj_Jac_Tensor_j_P[iVar][kVar]*val_Jac_PC[kVar][jVar]; -// } -// } -// } -// -//// for (iVar = 0; iVar < nVar; iVar++) { -//// for (jVar = 0; jVar < nVar; jVar++) { -//// cout << val_Proj_Jac_Tensor_i[iVar][jVar] << " " << val_Proj_Jac_Tensor_j[iVar][jVar] << endl; -//// } -//// } -//// getchar(); -// -// } -// else { -// -// /* 3D Jacobian: (Fv1, Fv2, Fv3, Fv4, Fv5) --> (T, vx, vy, vz, rho) */ -// -//// su2double factor1 = 4.0/3.0*pow(val_normal[0],2) + pow(val_normal[1],2) + pow(val_normal[2],2); -//// su2double factor2 = 1.0/3.0*val_normal[0]*val_normal[1]; -//// su2double factor3 = 1.0/3.0*val_normal[0]*val_normal[2]; -//// su2double factor4 = pow(val_normal[0],2) + 4.0/3.0*pow(val_normal[1],2) + pow(val_normal[2],2); -//// su2double factor5 = 1.0/3.0*val_normal[1]*val_normal[2]; -//// su2double factor6 = pow(val_normal[0],2) + pow(val_normal[1],2) + 4.0/3.0*pow(val_normal[2],2); -// -// su2double thetax = 4.0/3.0*pow(val_normal[0],2) + pow(val_normal[1],2) + pow(val_normal[2],2); -// su2double thetay = pow(val_normal[0],2) + 4.0/3.0*pow(val_normal[1],2) + pow(val_normal[2],2); -// su2double thetaz = pow(val_normal[0],2) + pow(val_normal[1],2) + 4.0/3.0*pow(val_normal[2],2); -// su2double pix = 1.0/3.0*val_normal[0]*val_normal[1]; -// su2double piy = 1.0/3.0*val_normal[0]*val_normal[2]; -// su2double piz = 1.0/3.0*val_normal[1]*val_normal[2]; -// -// val_Proj_Jac_Tensor_i_P[0][0] = 0.0; -// val_Proj_Jac_Tensor_i_P[0][1] = 0.0; -// val_Proj_Jac_Tensor_i_P[0][2] = 0.0; -// val_Proj_Jac_Tensor_i_P[0][3] = 0.0; -// val_Proj_Jac_Tensor_i_P[0][4] = 0.0; -// -// val_Proj_Jac_Tensor_i_P[1][0] = 0.5*dmudT_rho*val_Proj_Visc_Flux[1]/total_viscosity; -// val_Proj_Jac_Tensor_i_P[1][1] = -total_viscosity/val_dist_ij*thetax; -// val_Proj_Jac_Tensor_i_P[1][2] = -total_viscosity/val_dist_ij*pix; -// val_Proj_Jac_Tensor_i_P[1][3] = -total_viscosity/val_dist_ij*piy; -// val_Proj_Jac_Tensor_i_P[1][4] = 0.5*dmudrho_T*val_Proj_Visc_Flux[1]/total_viscosity; -// -// val_Proj_Jac_Tensor_i_P[2][0] = 0.5*dmudT_rho*val_Proj_Visc_Flux[2]/total_viscosity; -// val_Proj_Jac_Tensor_i_P[2][1] = -total_viscosity/val_dist_ij*pix; -// val_Proj_Jac_Tensor_i_P[2][2] = -total_viscosity/val_dist_ij*thetay; -// val_Proj_Jac_Tensor_i_P[2][3] = -total_viscosity/val_dist_ij*piz; -// val_Proj_Jac_Tensor_i_P[2][4] = 0.5*dmudrho_T*val_Proj_Visc_Flux[2]/total_viscosity; -// -// val_Proj_Jac_Tensor_i_P[3][0] = 0.5*dmudT_rho*val_Proj_Visc_Flux[3]/total_viscosity; -// val_Proj_Jac_Tensor_i_P[3][1] = -total_viscosity/val_dist_ij*piy; -// val_Proj_Jac_Tensor_i_P[3][2] = -total_viscosity/val_dist_ij*piz; -// val_Proj_Jac_Tensor_i_P[3][3] = -total_viscosity/val_dist_ij*thetaz; -// val_Proj_Jac_Tensor_i_P[3][4] = 0.5*dmudrho_T*val_Proj_Visc_Flux[3]/total_viscosity; -// -// val_Proj_Jac_Tensor_i_P[4][0] = vx*val_Proj_Jac_Tensor_i_P[1][0] + vy*val_Proj_Jac_Tensor_i_P[2][0] + vz*val_Proj_Jac_Tensor_i_P[3][0]; -// val_Proj_Jac_Tensor_i_P[4][1] = vx*val_Proj_Jac_Tensor_i_P[1][1] + vy*val_Proj_Jac_Tensor_i_P[2][1] + vz*val_Proj_Jac_Tensor_i_P[3][1]; -// val_Proj_Jac_Tensor_i_P[4][2] = vx*val_Proj_Jac_Tensor_i_P[1][2] + vy*val_Proj_Jac_Tensor_i_P[2][2] + vz*val_Proj_Jac_Tensor_i_P[3][2]; -// val_Proj_Jac_Tensor_i_P[4][3] = vx*val_Proj_Jac_Tensor_i_P[1][3] + vy*val_Proj_Jac_Tensor_i_P[2][3] + vz*val_Proj_Jac_Tensor_i_P[3][3]; -// val_Proj_Jac_Tensor_i_P[4][4] = vx*val_Proj_Jac_Tensor_i_P[1][4] + vy*val_Proj_Jac_Tensor_i_P[2][4] + vz*val_Proj_Jac_Tensor_i_P[3][4]; -// -// su2double etax = pow(val_normal[0],2)/val_dist_ij; -// su2double etay = pow(val_normal[1],2)/val_dist_ij; -// su2double etaz = pow(val_normal[2],2)/val_dist_ij; -// val_Proj_Jac_Tensor_i_P[4][0] += -total_conductivity*etax - total_conductivity*etay - total_conductivity*etaz; -// val_Proj_Jac_Tensor_i_P[4][1] += 1.0/2.0*val_Proj_Visc_Flux[1]; -// val_Proj_Jac_Tensor_i_P[4][2] += 1.0/2.0*val_Proj_Visc_Flux[2]; -// val_Proj_Jac_Tensor_i_P[4][3] += 1.0/2.0*val_Proj_Visc_Flux[3]; -// -// val_Proj_Jac_Tensor_i_P[4][0] += 0.5*val_normal[0]*dktdT_rho*val_gradprimvar[0][0] + 0.5*val_normal[1]*dktdT_rho*val_gradprimvar[0][1] + 0.5*val_normal[2]*dktdT_rho*val_gradprimvar[0][2]; -// val_Proj_Jac_Tensor_i_P[4][4] += 0.5*val_normal[0]*dktdrho_T*val_gradprimvar[0][0] + 0.5*val_normal[1]*dktdrho_T*val_gradprimvar[0][1] + 0.5*val_normal[2]*dktdrho_T*val_gradprimvar[0][2]; -// -// for (iVar = 0; iVar < nVar; iVar++) { -// for (jVar = 0; jVar < nVar; jVar++) { -// val_Proj_Jac_Tensor_i_P[iVar][jVar] *= val_dS; -// val_Proj_Jac_Tensor_j_P[iVar][jVar] = -val_Proj_Jac_Tensor_i_P[iVar][jVar]; /*Jacobian j*/ -// } -// } -// -// /* 3D Jacobian: (T, vx, vy, vz, rho) --> (u1, u2, u3, u4, u5) */ -// GetPrimitive2Conservative (val_Mean_PrimVar, val_Mean_SecVar, val_Jac_PC); -// -// /* 3D Jacobian: (Fv1, Fv2, Fv3, Fv4, Fv5) --> (u1, u2, u3, u4, u5) */ -// for (iVar = 0; iVar < nVar; iVar++) { -// for (jVar = 0; jVar < nVar; jVar++) { -// for (unsigned short kVar = 0; kVar < nVar; kVar++) { -// val_Proj_Jac_Tensor_i[iVar][jVar] += val_Proj_Jac_Tensor_i_P[iVar][kVar]*val_Jac_PC[kVar][jVar]; -// val_Proj_Jac_Tensor_j[iVar][jVar] += val_Proj_Jac_Tensor_j_P[iVar][kVar]*val_Jac_PC[kVar][jVar]; -// } -// } -// } -// -//// for (iVar = 0; iVar < nVar; iVar++) { -//// for (jVar = 0; jVar < nVar; jVar++) { -//// cout << val_Proj_Jac_Tensor_i[iVar][jVar] << " " << val_Proj_Jac_Tensor_j[iVar][jVar] << endl; -//// } -//// } -//// getchar(); -// -// } -// -// /*--- Deallocate ---*/ -// for (unsigned short iVar = 0; iVar < nVar; iVar++) { -// delete [] val_Proj_Jac_Tensor_i_P[iVar]; -// delete [] val_Proj_Jac_Tensor_j_P[iVar]; -// delete [] val_Jac_PC[iVar]; -// } -// delete [] val_Proj_Jac_Tensor_i_P; -// delete [] val_Proj_Jac_Tensor_j_P; -// delete [] val_Jac_PC; -// -//} - -void CNumerics::GetPrimitive2Conservative (su2double *val_Mean_PrimVar, su2double *val_Mean_SecVar, su2double **val_Jac_PC) { - - unsigned short iVar, jVar, iDim; - - // order of primitives: T, vx, vy, vz, P, rho, h, c, MuLam, MuEddy, kt, Cp - // order of secondary: dPdrho_e, dPde_rho, dTdrho_e, dTde_rho, dmudrho_T, dmudT_rho, dktdrho_T, dktdT_rho - - su2double vx = val_Mean_PrimVar[1]; - su2double vy = val_Mean_PrimVar[2]; - su2double vz = val_Mean_PrimVar[3]; - su2double rho = val_Mean_PrimVar[nDim+2]; - su2double P = val_Mean_PrimVar[nDim+1]; - su2double e = val_Mean_PrimVar[nDim+3] - P/rho; - su2double dTdrho_e = val_Mean_SecVar[2]; - su2double dTde_rho = val_Mean_SecVar[3]; - - su2double sqvel = 0.0; - - for (iDim = 0; iDim < nDim; iDim++) { - sqvel += val_Mean_PrimVar[iDim+1]*val_Mean_PrimVar[iDim+1]; - } - - /*--- Initialize the Jacobian matrix ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - for (jVar = 0; jVar < nVar; jVar++) { - val_Jac_PC[iVar][jVar] = 0.0; - } - } - - /*--- Primitives to conservatives Jacobian matrix : (T, vx, vy, vz, rho) --> (u1, u2, u3, u4, u5) ---*/ - if (nDim == 2) { - - val_Jac_PC[0][0] = dTdrho_e - e/rho*dTde_rho + 0.5*dTde_rho*sqvel/rho; - val_Jac_PC[0][1] = -1/rho*dTde_rho*vx; - val_Jac_PC[0][2] = -1/rho*dTde_rho*vy; - val_Jac_PC[0][3] = 1/rho*dTde_rho; - - val_Jac_PC[1][0] = -vx/rho; - val_Jac_PC[1][1] = 1/rho; - val_Jac_PC[1][2] = 0.0; - val_Jac_PC[1][3] = 0.0; - - val_Jac_PC[2][0] = -vy/rho; - val_Jac_PC[2][1] = 0.0; - val_Jac_PC[2][2] = 1/rho; - val_Jac_PC[2][3] = 0.0; - - val_Jac_PC[3][0] = 1.0; - val_Jac_PC[3][1] = 0.0; - val_Jac_PC[3][2] = 0.0; - val_Jac_PC[3][3] = 0.0; - - } - else { - - val_Jac_PC[0][0] = dTdrho_e - e/rho*dTde_rho + 0.5*dTde_rho*sqvel/rho; - val_Jac_PC[0][1] = -1/rho*dTde_rho*vx; - val_Jac_PC[0][2] = -1/rho*dTde_rho*vy; - val_Jac_PC[0][3] = -1/rho*dTde_rho*vz; - val_Jac_PC[0][4] = 1/rho*dTde_rho; - - val_Jac_PC[1][0] = -vx/rho; - val_Jac_PC[1][1] = 1/rho; - val_Jac_PC[1][2] = 0.0; - val_Jac_PC[1][3] = 0.0; - val_Jac_PC[1][4] = 0.0; - - val_Jac_PC[2][0] = -vy/rho; - val_Jac_PC[2][1] = 0.0; - val_Jac_PC[2][2] = 1/rho; - val_Jac_PC[2][3] = 0.0; - val_Jac_PC[2][4] = 0.0; - - val_Jac_PC[3][0] = -vz/rho; - val_Jac_PC[3][1] = 0.0; - val_Jac_PC[3][2] = 0.0; - val_Jac_PC[3][3] = 1/rho; - val_Jac_PC[3][4] = 0.0; - - val_Jac_PC[4][0] = 1.0; - val_Jac_PC[4][1] = 0.0; - val_Jac_PC[4][2] = 0.0; - val_Jac_PC[4][3] = 0.0; - val_Jac_PC[4][4] = 0.0; - - } -} - -void CNumerics::GetViscousArtCompProjJacs(su2double val_laminar_viscosity, - su2double val_eddy_viscosity, su2double val_dist_ij, su2double *val_normal, su2double val_dS, - su2double **val_Proj_Jac_Tensor_i, su2double **val_Proj_Jac_Tensor_j) { - unsigned short iDim, iVar, jVar; - - su2double theta = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - theta += val_normal[iDim]*val_normal[iDim]; - - su2double total_viscosity = val_laminar_viscosity + val_eddy_viscosity; - su2double factor = total_viscosity/(val_dist_ij)*val_dS; - - if (nDim == 3) { - su2double thetax = theta + val_normal[0]*val_normal[0]/3.0; - su2double thetay = theta + val_normal[1]*val_normal[1]/3.0; - su2double thetaz = theta + val_normal[2]*val_normal[2]/3.0; - - su2double etax = val_normal[1]*val_normal[2]/3.0; - su2double etay = val_normal[0]*val_normal[2]/3.0; - su2double etaz = val_normal[0]*val_normal[1]/3.0; - - val_Proj_Jac_Tensor_i[0][0] = 0.0; - val_Proj_Jac_Tensor_i[0][1] = 0.0; - val_Proj_Jac_Tensor_i[0][2] = 0.0; - val_Proj_Jac_Tensor_i[0][3] = 0.0; - val_Proj_Jac_Tensor_i[1][0] = 0.0; - val_Proj_Jac_Tensor_i[1][1] = -factor*thetax; - val_Proj_Jac_Tensor_i[1][2] = -factor*etaz; - val_Proj_Jac_Tensor_i[1][3] = -factor*etay; - val_Proj_Jac_Tensor_i[2][0] = 0.0; - val_Proj_Jac_Tensor_i[2][1] = -factor*etaz; - val_Proj_Jac_Tensor_i[2][2] = -factor*thetay; - val_Proj_Jac_Tensor_i[2][3] = -factor*etax; - val_Proj_Jac_Tensor_i[3][0] = 0.0; - val_Proj_Jac_Tensor_i[3][1] = -factor*etay; - val_Proj_Jac_Tensor_i[3][2] = -factor*etax; - val_Proj_Jac_Tensor_i[3][3] = -factor*thetaz; - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - val_Proj_Jac_Tensor_j[iVar][jVar] = -val_Proj_Jac_Tensor_i[iVar][jVar]; - - } - - if (nDim == 2) { - su2double thetax = theta + val_normal[0]*val_normal[0]/3.0; - su2double thetay = theta + val_normal[1]*val_normal[1]/3.0; - su2double etaz = val_normal[0]*val_normal[1]/3.0; - - val_Proj_Jac_Tensor_i[0][0] = 0.0; - val_Proj_Jac_Tensor_i[0][1] = 0.0; - val_Proj_Jac_Tensor_i[0][2] = 0.0; - val_Proj_Jac_Tensor_i[1][0] = 0.0; - val_Proj_Jac_Tensor_i[1][1] = -factor*thetax; - val_Proj_Jac_Tensor_i[1][2] = -factor*etaz; - val_Proj_Jac_Tensor_i[2][0] = 0.0; - val_Proj_Jac_Tensor_i[2][1] = -factor*etaz; - val_Proj_Jac_Tensor_i[2][2] = -factor*thetay; - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - val_Proj_Jac_Tensor_j[iVar][jVar] = -val_Proj_Jac_Tensor_i[iVar][jVar]; - } - -} - -void CNumerics::CreateBasis(su2double *val_Normal) { - unsigned short iDim; - su2double modm, modl; - - /*--- Define l as a vector in the plane normal to the supplied vector ---*/ - l[0] = 0.0; - l[1] = -val_Normal[2]; - l[2] = val_Normal[1]; - - /*--- Check for the zero vector and re-assign if needed ---*/ - if (l[0] == 0.0 && l[1] == 0.0 && l[2] == 0.0) { - l[0] = -val_Normal[2]; - l[1] = 0.0; - l[2] = val_Normal[0]; - } - - /*--- Take vector product of n * l to make m ---*/ - m[0] = val_Normal[1]*l[2] - val_Normal[2]*l[1]; - m[1] = val_Normal[2]*l[0] - val_Normal[0]*l[2]; - m[2] = val_Normal[0]*l[1] - val_Normal[1]*l[0]; - - /*--- Normalize ---*/ - modm =0 ; modl = 0; - for (iDim =0 ; iDim < nDim; iDim++) { - modm += m[iDim]*m[iDim]; - modl += l[iDim]*l[iDim]; - } - modm = sqrt(modm); - modl = sqrt(modl); - for (iDim =0 ; iDim < nDim; iDim++) { - l[iDim] = l[iDim]/modl; - m[iDim] = m[iDim]/modm; - } -} - -CSourceNothing::CSourceNothing(unsigned short val_nDim, unsigned short val_nVar, CConfig *config) : CNumerics(val_nDim, val_nVar, config) { } - -CSourceNothing::~CSourceNothing(void) { } +/*! + * \file numerics_structure.cpp + * \brief This file contains all the numerical methods. + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/numerics_structure.hpp" + +CNumerics::CNumerics(void) { } + +CNumerics::CNumerics(unsigned short val_nDim, unsigned short val_nVar, + CConfig *config) { + + unsigned short iVar, iDim, jDim; + + nDim = val_nDim; + nVar = val_nVar; + Gamma = config->GetGamma(); + Gamma_Minus_One = Gamma - 1.0; + Prandtl_Lam = config->GetPrandtl_Lam(); + Prandtl_Turb = config->GetPrandtl_Turb(); + Gas_Constant = config->GetGas_ConstantND(); + + UnitNormal = new su2double [nDim]; + UnitNormald = new su2double [nDim]; + + Normal = new su2double [nDim]; + Flux_Tensor = new su2double* [nVar]; + for (iVar = 0; iVar < (nVar); iVar++) + Flux_Tensor[iVar] = new su2double [nDim]; + + tau = new su2double* [nDim]; + delta = new su2double* [nDim]; + for (iDim = 0; iDim < nDim; iDim++) { + tau[iDim] = new su2double [nDim]; + delta[iDim] = new su2double [nDim]; + } + + for (iDim = 0; iDim < nDim; iDim++) { + for (jDim = 0; jDim < nDim; jDim++) { + if (iDim == jDim) delta[iDim][jDim]=1.0; + else delta[iDim][jDim]=0.0; + } + } + + U_n = new su2double [nVar]; + U_nM1 = new su2double [nVar]; + U_nP1 = new su2double [nVar]; + + Proj_Flux_Tensor = new su2double [nVar]; + + turb_ke_i = 0.0; + turb_ke_j = 0.0; + + Diffusion_Coeff_i = NULL; + Diffusion_Coeff_j = NULL; + + Ys = NULL; + dFdYj = NULL; + dFdYi = NULL; + sumdFdYih = NULL; + sumdFdYjh = NULL; + sumdFdYieve = NULL; + sumdFdYjeve = NULL; + + Vector = new su2double[nDim]; + + l = new su2double [nDim]; + m = new su2double [nDim]; + +} + +CNumerics::~CNumerics(void) { + + delete [] Normal; + delete [] UnitNormal; + + delete [] U_n; + delete [] U_nM1; + delete [] U_nP1; + + // visc + delete [] Proj_Flux_Tensor; + + for (unsigned short iVar = 0; iVar < nDim+3; iVar++) { + delete [] Flux_Tensor[iVar]; + } + delete [] Flux_Tensor; + + for (unsigned short iDim = 0; iDim < nDim; iDim++) { + delete [] tau[iDim]; + delete [] delta[iDim]; + } + delete [] tau; + delete [] delta; + delete [] Enthalpy_formation; + delete [] Theta_v; + if (Ys != NULL) delete [] Ys; + if (sumdFdYih != NULL) delete [] sumdFdYih; + if (sumdFdYjh != NULL) delete [] sumdFdYjh; + if (sumdFdYieve != NULL) delete [] sumdFdYieve; + if (sumdFdYjeve != NULL) delete [] sumdFdYjeve; + if (Diffusion_Coeff_i != NULL) delete [] Diffusion_Coeff_i; + if (Diffusion_Coeff_j != NULL) delete [] Diffusion_Coeff_j; + if (Vector != NULL) delete [] Vector; + if (var != NULL) delete [] var; + + unsigned short iVar; + for (iVar = 0; iVar < nVar; iVar++) { + delete [] dVdU[iVar]; + } + delete [] dVdU; + +} + +void CNumerics::GetInviscidFlux(su2double val_density, su2double *val_velocity, + su2double val_pressure, su2double val_enthalpy) { + if (nDim == 3) { + Flux_Tensor[0][0] = val_density*val_velocity[0]; + Flux_Tensor[1][0] = Flux_Tensor[0][0]*val_velocity[0]+val_pressure; + Flux_Tensor[2][0] = Flux_Tensor[0][0]*val_velocity[1]; + Flux_Tensor[3][0] = Flux_Tensor[0][0]*val_velocity[2]; + Flux_Tensor[4][0] = Flux_Tensor[0][0]*val_enthalpy; + + Flux_Tensor[0][1] = val_density*val_velocity[1]; + Flux_Tensor[1][1] = Flux_Tensor[0][1]*val_velocity[0]; + Flux_Tensor[2][1] = Flux_Tensor[0][1]*val_velocity[1]+val_pressure; + Flux_Tensor[3][1] = Flux_Tensor[0][1]*val_velocity[2]; + Flux_Tensor[4][1] = Flux_Tensor[0][1]*val_enthalpy; + + Flux_Tensor[0][2] = val_density*val_velocity[2]; + Flux_Tensor[1][2] = Flux_Tensor[0][2]*val_velocity[0]; + Flux_Tensor[2][2] = Flux_Tensor[0][2]*val_velocity[1]; + Flux_Tensor[3][2] = Flux_Tensor[0][2]*val_velocity[2]+val_pressure; + Flux_Tensor[4][2] = Flux_Tensor[0][2]*val_enthalpy; + + } + if (nDim == 2) { + Flux_Tensor[0][0] = val_density*val_velocity[0]; + Flux_Tensor[1][0] = Flux_Tensor[0][0]*val_velocity[0]+val_pressure; + Flux_Tensor[2][0] = Flux_Tensor[0][0]*val_velocity[1]; + Flux_Tensor[3][0] = Flux_Tensor[0][0]*val_enthalpy; + + Flux_Tensor[0][1] = val_density*val_velocity[1]; + Flux_Tensor[1][1] = Flux_Tensor[0][1]*val_velocity[0]; + Flux_Tensor[2][1] = Flux_Tensor[0][1]*val_velocity[1]+val_pressure; + Flux_Tensor[3][1] = Flux_Tensor[0][1]*val_enthalpy; + } +} + +void CNumerics::GetInviscidProjFlux(su2double *val_density, + su2double *val_velocity, + su2double *val_pressure, + su2double *val_enthalpy, + su2double *val_normal, + su2double *val_Proj_Flux) { + + su2double rhou, rhov, rhow; + + if (nDim == 2) { + + rhou = (*val_density)*val_velocity[0]; + rhov = (*val_density)*val_velocity[1]; + + val_Proj_Flux[0] = rhou*val_normal[0]; + val_Proj_Flux[1] = (rhou*val_velocity[0]+(*val_pressure))*val_normal[0]; + val_Proj_Flux[2] = rhou*val_velocity[1]*val_normal[0]; + val_Proj_Flux[3] = rhou*(*val_enthalpy)*val_normal[0]; + + val_Proj_Flux[0] += rhov*val_normal[1]; + val_Proj_Flux[1] += rhov*val_velocity[0]*val_normal[1]; + val_Proj_Flux[2] += (rhov*val_velocity[1]+(*val_pressure))*val_normal[1]; + val_Proj_Flux[3] += rhov*(*val_enthalpy)*val_normal[1]; + + } + else { + + rhou = (*val_density)*val_velocity[0]; + rhov = (*val_density)*val_velocity[1]; + rhow = (*val_density)*val_velocity[2]; + + val_Proj_Flux[0] = rhou*val_normal[0]; + val_Proj_Flux[1] = (rhou*val_velocity[0]+(*val_pressure))*val_normal[0]; + val_Proj_Flux[2] = rhou*val_velocity[1]*val_normal[0]; + val_Proj_Flux[3] = rhou*val_velocity[2]*val_normal[0]; + val_Proj_Flux[4] = rhou*(*val_enthalpy)*val_normal[0]; + + val_Proj_Flux[0] += rhov*val_normal[1]; + val_Proj_Flux[1] += rhov*val_velocity[0]*val_normal[1]; + val_Proj_Flux[2] += (rhov*val_velocity[1]+(*val_pressure))*val_normal[1]; + val_Proj_Flux[3] += rhov*val_velocity[2]*val_normal[1]; + val_Proj_Flux[4] += rhov*(*val_enthalpy)*val_normal[1]; + + val_Proj_Flux[0] += rhow*val_normal[2]; + val_Proj_Flux[1] += rhow*val_velocity[0]*val_normal[2]; + val_Proj_Flux[2] += rhow*val_velocity[1]*val_normal[2]; + val_Proj_Flux[3] += (rhow*val_velocity[2]+(*val_pressure))*val_normal[2]; + val_Proj_Flux[4] += rhow*(*val_enthalpy)*val_normal[2]; + + } + +} + + +void CNumerics::GetInviscidArtCompProjFlux(su2double *val_density, + su2double *val_velocity, + su2double *val_pressure, + su2double *val_betainc2, + su2double *val_normal, + su2double *val_Proj_Flux) { + su2double rhou, rhov, rhow; + + if (nDim == 2) { + rhou = (*val_density)*val_velocity[0]; + rhov = (*val_density)*val_velocity[1]; + + val_Proj_Flux[0] = (*val_betainc2)*(val_velocity[0]*val_normal[0] + val_velocity[1]*val_normal[1]); + val_Proj_Flux[1] = (rhou*val_velocity[0]+(*val_pressure))*val_normal[0] + rhou*val_velocity[1]*val_normal[1]; + val_Proj_Flux[2] = rhov*val_velocity[0]*val_normal[0] + (rhov*val_velocity[1]+(*val_pressure))*val_normal[1]; + } + else { + rhou = (*val_density)*val_velocity[0]; + rhov = (*val_density)*val_velocity[1]; + rhow = (*val_density)*val_velocity[2]; + + val_Proj_Flux[0] = (*val_betainc2)*(val_velocity[0]*val_normal[0] + val_velocity[1]*val_normal[1] + val_velocity[2]*val_normal[2]); + val_Proj_Flux[1] = (rhou*val_velocity[0]+(*val_pressure))*val_normal[0] + rhou*val_velocity[1]*val_normal[1] + rhou*val_velocity[2]*val_normal[2]; + val_Proj_Flux[2] = rhov*val_velocity[0]*val_normal[0] + (rhov*val_velocity[1]+(*val_pressure))*val_normal[1] + rhov*val_velocity[2]*val_normal[2]; + val_Proj_Flux[3] = rhow*val_velocity[0]*val_normal[0] + rhow*val_velocity[1]*val_normal[1] + (rhow*val_velocity[2]+(*val_pressure))*val_normal[2]; + } + +} + +void CNumerics::GetInviscidArtComp_FreeSurf_ProjFlux(su2double *val_density, su2double *val_velocity, su2double *val_pressure, su2double *val_betainc2, + su2double *val_levelset, su2double *val_normal, su2double *val_Proj_Flux) { + + su2double rhou, rhov, rhow, ProjVel; + + if (nDim == 2) { + rhou = (*val_density)*val_velocity[0]; + rhov = (*val_density)*val_velocity[1]; + ProjVel = (val_velocity[0]*val_normal[0] + val_velocity[1]*val_normal[1]); + + val_Proj_Flux[0] = (*val_betainc2)*ProjVel; + val_Proj_Flux[1] = (rhou*val_velocity[0]+(*val_pressure))*val_normal[0] + rhou*val_velocity[1]*val_normal[1]; + val_Proj_Flux[2] = rhov*val_velocity[0]*val_normal[0] + (rhov*val_velocity[1]+(*val_pressure))*val_normal[1]; + val_Proj_Flux[3] = (*val_levelset)*ProjVel; + } + else { + rhou = (*val_density)*val_velocity[0]; + rhov = (*val_density)*val_velocity[1]; + rhow = (*val_density)*val_velocity[2]; + ProjVel = (val_velocity[0]*val_normal[0] + val_velocity[1]*val_normal[1] + val_velocity[2]*val_normal[2]); + + val_Proj_Flux[0] = (*val_betainc2)*ProjVel; + val_Proj_Flux[1] = (rhou*val_velocity[0]+(*val_pressure))*val_normal[0] + rhou*val_velocity[1]*val_normal[1] + rhou*val_velocity[2]*val_normal[2]; + val_Proj_Flux[2] = rhov*val_velocity[0]*val_normal[0] + (rhov*val_velocity[1]+(*val_pressure))*val_normal[1] + rhov*val_velocity[2]*val_normal[2]; + val_Proj_Flux[3] = rhow*val_velocity[0]*val_normal[0] + rhow*val_velocity[1]*val_normal[1] + (rhow*val_velocity[2]+(*val_pressure))*val_normal[2]; + val_Proj_Flux[4] = (*val_levelset)*ProjVel; + } +} + +void CNumerics::GetInviscidProjJac(su2double *val_velocity, su2double *val_energy, + su2double *val_normal, su2double val_scale, + su2double **val_Proj_Jac_Tensor) { + AD_BEGIN_PASSIVE + unsigned short iDim, jDim; + su2double sqvel, proj_vel, phi, a1, a2; + + sqvel = 0.0, proj_vel = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + sqvel += val_velocity[iDim]*val_velocity[iDim]; + proj_vel += val_velocity[iDim]*val_normal[iDim]; + } + + phi = 0.5*Gamma_Minus_One*sqvel; + a1 = Gamma*(*val_energy)-phi; + a2 = Gamma-1.0; + + val_Proj_Jac_Tensor[0][0] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + val_Proj_Jac_Tensor[0][iDim+1] = val_scale*val_normal[iDim]; + val_Proj_Jac_Tensor[0][nDim+1] = 0.0; + + for (iDim = 0; iDim < nDim; iDim++) { + val_Proj_Jac_Tensor[iDim+1][0] = val_scale*(val_normal[iDim]*phi - val_velocity[iDim]*proj_vel); + for (jDim = 0; jDim < nDim; jDim++) + val_Proj_Jac_Tensor[iDim+1][jDim+1] = val_scale*(val_normal[jDim]*val_velocity[iDim]-a2*val_normal[iDim]*val_velocity[jDim]); + val_Proj_Jac_Tensor[iDim+1][iDim+1] += val_scale*proj_vel; + val_Proj_Jac_Tensor[iDim+1][nDim+1] = val_scale*a2*val_normal[iDim]; + } + + val_Proj_Jac_Tensor[nDim+1][0] = val_scale*proj_vel*(phi-a1); + for (iDim = 0; iDim < nDim; iDim++) + val_Proj_Jac_Tensor[nDim+1][iDim+1] = val_scale*(val_normal[iDim]*a1-a2*val_velocity[iDim]*proj_vel); + val_Proj_Jac_Tensor[nDim+1][nDim+1] = val_scale*Gamma*proj_vel; + AD_END_PASSIVE +} + + +void CNumerics::GetInviscidProjJac(su2double *val_velocity, su2double *val_enthalpy, + su2double *val_chi, su2double *val_kappa, + su2double *val_normal, su2double val_scale, + su2double **val_Proj_Jac_Tensor) { + AD_BEGIN_PASSIVE + unsigned short iDim, jDim; + su2double sqvel, proj_vel, phi, a1, a2; + + sqvel = 0.0, proj_vel = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + sqvel += val_velocity[iDim]*val_velocity[iDim]; + proj_vel += val_velocity[iDim]*val_normal[iDim]; + } + + phi = *val_chi + 0.5*sqvel*(*val_kappa); + a1 = *val_enthalpy; + a2 = *val_kappa; + + val_Proj_Jac_Tensor[0][0] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + val_Proj_Jac_Tensor[0][iDim+1] = val_scale*val_normal[iDim]; + val_Proj_Jac_Tensor[0][nDim+1] = 0.0; + + for (iDim = 0; iDim < nDim; iDim++) { + val_Proj_Jac_Tensor[iDim+1][0] = val_scale*(val_normal[iDim]*phi - val_velocity[iDim]*proj_vel); + for (jDim = 0; jDim < nDim; jDim++) + val_Proj_Jac_Tensor[iDim+1][jDim+1] = val_scale*(val_normal[jDim]*val_velocity[iDim]-a2*val_normal[iDim]*val_velocity[jDim]); + val_Proj_Jac_Tensor[iDim+1][iDim+1] += val_scale*proj_vel; + val_Proj_Jac_Tensor[iDim+1][nDim+1] = val_scale*a2*val_normal[iDim]; + } + + val_Proj_Jac_Tensor[nDim+1][0] = val_scale*proj_vel*(phi-a1); + for (iDim = 0; iDim < nDim; iDim++) + val_Proj_Jac_Tensor[nDim+1][iDim+1] = val_scale*(val_normal[iDim]*a1-a2*val_velocity[iDim]*proj_vel); + val_Proj_Jac_Tensor[nDim+1][nDim+1] = val_scale*(a2+1)*proj_vel; + AD_END_PASSIVE +} + +void CNumerics::GetInviscidArtCompProjJac(su2double *val_density, su2double *val_velocity, su2double *val_betainc2, su2double *val_normal, + su2double val_scale, su2double **val_Proj_Jac_Tensor) { + AD_BEGIN_PASSIVE + unsigned short iDim; + su2double proj_vel; + + proj_vel = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + proj_vel += val_velocity[iDim]*val_normal[iDim]; + + if (nDim == 2) { + val_Proj_Jac_Tensor[0][0] = 0.0; + val_Proj_Jac_Tensor[0][1] = val_scale*(*val_betainc2)*val_normal[0]/(*val_density); + val_Proj_Jac_Tensor[0][2] = val_scale*(*val_betainc2)*val_normal[1]/(*val_density); + + val_Proj_Jac_Tensor[1][0] = val_scale*val_normal[0]; + val_Proj_Jac_Tensor[1][1] = val_scale*(val_velocity[0]*val_normal[0] + proj_vel); + val_Proj_Jac_Tensor[1][2] = val_scale*val_velocity[0]*val_normal[1]; + + val_Proj_Jac_Tensor[2][0] = val_scale*val_normal[1]; + val_Proj_Jac_Tensor[2][1] = val_scale*val_velocity[1]*val_normal[0]; + val_Proj_Jac_Tensor[2][2] = val_scale*(val_velocity[1]*val_normal[1] + proj_vel); + } + else { + val_Proj_Jac_Tensor[0][0] = 0.0; + val_Proj_Jac_Tensor[0][1] = val_scale*(*val_betainc2)*val_normal[0]/(*val_density); + val_Proj_Jac_Tensor[0][2] = val_scale*(*val_betainc2)*val_normal[1]/(*val_density); + val_Proj_Jac_Tensor[0][3] = val_scale*(*val_betainc2)*val_normal[2]/(*val_density); + + val_Proj_Jac_Tensor[1][0] = val_scale*val_normal[0]; + val_Proj_Jac_Tensor[1][1] = val_scale*(val_velocity[0]*val_normal[0] + proj_vel); + val_Proj_Jac_Tensor[1][2] = val_scale*val_velocity[0]*val_normal[1]; + val_Proj_Jac_Tensor[1][3] = val_scale*val_velocity[0]*val_normal[2]; + + val_Proj_Jac_Tensor[2][0] = val_scale*val_normal[1]; + val_Proj_Jac_Tensor[2][1] = val_scale*val_velocity[1]*val_normal[0]; + val_Proj_Jac_Tensor[2][2] = val_scale*(val_velocity[1]*val_normal[1] + proj_vel); + val_Proj_Jac_Tensor[2][3] = val_scale*val_velocity[1]*val_normal[2]; + + val_Proj_Jac_Tensor[3][0] = val_scale*val_normal[2]; + val_Proj_Jac_Tensor[3][1] = val_scale*val_velocity[2]*val_normal[0]; + val_Proj_Jac_Tensor[3][2] = val_scale*val_velocity[2]*val_normal[1]; + val_Proj_Jac_Tensor[3][3] = val_scale*(val_velocity[2]*val_normal[2] + proj_vel); + } + AD_END_PASSIVE +} + +void CNumerics::GetInviscidArtComp_FreeSurf_ProjJac(su2double *val_density, su2double *val_ddensity, su2double *val_velocity, su2double *val_betainc2, su2double *val_levelset, su2double *val_normal, + su2double val_scale, su2double **val_Proj_Jac_Tensor) { + + su2double a = 0.0, b = 0.0, c = 0.0, d = 0.0, nx = 0.0, ny = 0.0, nz = 0.0, u = 0.0, v = 0.0, w = 0.0; + + a = (*val_betainc2)/(*val_density); + b = (*val_levelset)/(*val_density); + c = (*val_ddensity); + + if (nDim == 2) { + + nx = val_normal[0]; ny = val_normal[1]; + u = val_velocity[0]; v = val_velocity[1]; d = u*nx + v*ny; + + val_Proj_Jac_Tensor[0][0] = 0.0; + val_Proj_Jac_Tensor[0][1] = val_scale*a*nx; + val_Proj_Jac_Tensor[0][2] = val_scale*a*ny; + val_Proj_Jac_Tensor[0][3] = - val_scale*a*c*d; + + + val_Proj_Jac_Tensor[1][0] = val_scale*nx; + val_Proj_Jac_Tensor[1][1] = val_scale*(d + nx*u); + val_Proj_Jac_Tensor[1][2] = val_scale*ny*u; + val_Proj_Jac_Tensor[1][3] = -val_scale*c*d*u; + + + val_Proj_Jac_Tensor[2][0] = val_scale*ny; + val_Proj_Jac_Tensor[2][1] = val_scale*nx*v; + val_Proj_Jac_Tensor[2][2] = val_scale*(d + ny*v); + val_Proj_Jac_Tensor[2][3] = -val_scale*c*d*v; + + + val_Proj_Jac_Tensor[3][0] = 0.0; + val_Proj_Jac_Tensor[3][1] = val_scale*b*nx; + val_Proj_Jac_Tensor[3][2] = val_scale*b*ny; + val_Proj_Jac_Tensor[3][3] = val_scale*(d - b*c*d); + + } + else { + + nx = val_normal[0]; ny = val_normal[1]; nz = val_normal[2]; + u = val_velocity[0]; v = val_velocity[1]; w = val_velocity[2]; d = u*nx + v*ny + w*nz; + + val_Proj_Jac_Tensor[0][0] = 0.0; + val_Proj_Jac_Tensor[0][1] = val_scale*a*nx; + val_Proj_Jac_Tensor[0][2] = val_scale*a*ny; + val_Proj_Jac_Tensor[0][3] = val_scale*a*nz; + val_Proj_Jac_Tensor[0][4] = - val_scale*a*c*d; + + + val_Proj_Jac_Tensor[1][0] = val_scale*nx; + val_Proj_Jac_Tensor[1][1] = val_scale*(d + nx*u); + val_Proj_Jac_Tensor[1][2] = val_scale*ny*u; + val_Proj_Jac_Tensor[1][3] = val_scale*nz*u; + val_Proj_Jac_Tensor[1][4] = -val_scale*c*d*u; + + + val_Proj_Jac_Tensor[2][0] = val_scale*ny; + val_Proj_Jac_Tensor[2][1] = val_scale*nx*v; + val_Proj_Jac_Tensor[2][2] = val_scale*(d + ny*v); + val_Proj_Jac_Tensor[2][3] = val_scale*nz*v; + val_Proj_Jac_Tensor[2][4] = -val_scale*c*d*v; + + val_Proj_Jac_Tensor[3][0] = val_scale*nz; + val_Proj_Jac_Tensor[3][1] = val_scale*nx*w; + val_Proj_Jac_Tensor[3][2] = val_scale*ny*w; + val_Proj_Jac_Tensor[3][3] = val_scale*(d + nz*w); + val_Proj_Jac_Tensor[3][4] = -val_scale*c*d*w; + + val_Proj_Jac_Tensor[3][0] = 0.0; + val_Proj_Jac_Tensor[3][1] = val_scale*b*nx; + val_Proj_Jac_Tensor[3][2] = val_scale*b*ny; + val_Proj_Jac_Tensor[3][3] = val_scale*b*nz; + val_Proj_Jac_Tensor[3][4] = val_scale*(d - b*c*d); + + } + +} + +void CNumerics::SetPastSol (su2double *val_u_nM1, su2double *val_u_n, su2double *val_u_nP1) { + unsigned short iVar; + + for (iVar = 0; iVar < nVar; iVar++) { + U_nM1[iVar] = val_u_nM1[iVar]; + U_n[iVar] = val_u_n[iVar]; + U_nP1[iVar] = val_u_nP1[iVar]; + } + +} +void CNumerics::SetPastVolume (su2double val_volume_nM1, su2double val_volume_n, su2double val_volume_nP1) { + Volume_nM1 = val_volume_nM1; + Volume_n = val_volume_n; + Volume_nP1 = val_volume_nP1; +} + + +void CNumerics::GetPMatrix(su2double *val_density, su2double *val_velocity, + su2double *val_soundspeed, su2double *val_normal, su2double **val_p_tensor) { + + su2double sqvel, rhooc, rhoxc; + //su2double c2; + + rhooc = *val_density / *val_soundspeed; + rhoxc = *val_density * *val_soundspeed; + //c2 = *val_soundspeed * *val_soundspeed; + + if (nDim == 2) { + + sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]; + + val_p_tensor[0][0]=1.0; + val_p_tensor[0][1]=0.0; + val_p_tensor[0][2]=0.5*rhooc; + val_p_tensor[0][3]=0.5*rhooc; + + val_p_tensor[1][0]=val_velocity[0]; + val_p_tensor[1][1]=*val_density*val_normal[1]; + val_p_tensor[1][2]=0.5*(val_velocity[0]*rhooc+val_normal[0]**val_density); + val_p_tensor[1][3]=0.5*(val_velocity[0]*rhooc-val_normal[0]**val_density); + + val_p_tensor[2][0]=val_velocity[1]; + val_p_tensor[2][1]=-*val_density*val_normal[0]; + val_p_tensor[2][2]=0.5*(val_velocity[1]*rhooc+val_normal[1]**val_density); + val_p_tensor[2][3]=0.5*(val_velocity[1]*rhooc-val_normal[1]**val_density); + + val_p_tensor[3][0]=0.5*sqvel; + val_p_tensor[3][1]=*val_density*val_velocity[0]*val_normal[1]-*val_density*val_velocity[1]*val_normal[0]; + val_p_tensor[3][2]=0.5*(0.5*sqvel*rhooc+*val_density*val_velocity[0]*val_normal[0]+*val_density*val_velocity[1]*val_normal[1]+rhoxc/Gamma_Minus_One); + val_p_tensor[3][3]=0.5*(0.5*sqvel*rhooc-*val_density*val_velocity[0]*val_normal[0]-*val_density*val_velocity[1]*val_normal[1]+rhoxc/Gamma_Minus_One); + + } + else { + + sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]+val_velocity[2]*val_velocity[2]; + + val_p_tensor[0][0]=val_normal[0]; + val_p_tensor[0][1]=val_normal[1]; + val_p_tensor[0][2]=val_normal[2]; + val_p_tensor[0][3]=0.5*rhooc; + val_p_tensor[0][4]=0.5*rhooc; + + val_p_tensor[1][0]=val_velocity[0]*val_normal[0]; + val_p_tensor[1][1]=val_velocity[0]*val_normal[1]-*val_density*val_normal[2]; + val_p_tensor[1][2]=val_velocity[0]*val_normal[2]+*val_density*val_normal[1]; + val_p_tensor[1][3]=0.5*(val_velocity[0]*rhooc+*val_density*val_normal[0]); + val_p_tensor[1][4]=0.5*(val_velocity[0]*rhooc-*val_density*val_normal[0]); + + val_p_tensor[2][0]=val_velocity[1]*val_normal[0]+*val_density*val_normal[2]; + val_p_tensor[2][1]=val_velocity[1]*val_normal[1]; + val_p_tensor[2][2]=val_velocity[1]*val_normal[2]-*val_density*val_normal[0]; + val_p_tensor[2][3]=0.5*(val_velocity[1]*rhooc+*val_density*val_normal[1]); + val_p_tensor[2][4]=0.5*(val_velocity[1]*rhooc-*val_density*val_normal[1]); + + val_p_tensor[3][0]=val_velocity[2]*val_normal[0]-*val_density*val_normal[1]; + val_p_tensor[3][1]=val_velocity[2]*val_normal[1]+*val_density*val_normal[0]; + val_p_tensor[3][2]=val_velocity[2]*val_normal[2]; + val_p_tensor[3][3]=0.5*(val_velocity[2]*rhooc+*val_density*val_normal[2]); + val_p_tensor[3][4]=0.5*(val_velocity[2]*rhooc-*val_density*val_normal[2]); + + val_p_tensor[4][0]=0.5*sqvel*val_normal[0]+*val_density*val_velocity[1]*val_normal[2]-*val_density*val_velocity[2]*val_normal[1]; + val_p_tensor[4][1]=0.5*sqvel*val_normal[1]-*val_density*val_velocity[0]*val_normal[2]+*val_density*val_velocity[2]*val_normal[0]; + val_p_tensor[4][2]=0.5*sqvel*val_normal[2]+*val_density*val_velocity[0]*val_normal[1]-*val_density*val_velocity[1]*val_normal[0]; + val_p_tensor[4][3]=0.5*(0.5*sqvel*rhooc+*val_density*(val_velocity[0]*val_normal[0]+val_velocity[1]*val_normal[1]+val_velocity[2]*val_normal[2])+rhoxc/Gamma_Minus_One); + val_p_tensor[4][4]=0.5*(0.5*sqvel*rhooc-*val_density*(val_velocity[0]*val_normal[0]+val_velocity[1]*val_normal[1]+val_velocity[2]*val_normal[2])+rhoxc/Gamma_Minus_One); + + } + +} + +void CNumerics::GetPMatrix(su2double *val_density, su2double *val_velocity, + su2double *val_soundspeed, su2double *val_enthalpy, su2double *val_chi, su2double *val_kappa, su2double *val_normal, su2double **val_p_tensor) { + + su2double sqvel, rhooc, zeta; + //su2double rhoxc, c2; + + rhooc = *val_density / *val_soundspeed; + //rhoxc = *val_density * *val_soundspeed; + //c2 = *val_soundspeed * *val_soundspeed; + + if (nDim == 2) { + sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]; + zeta = sqvel - (*val_kappa*0.5*sqvel + *val_chi)/(*val_kappa); + + val_p_tensor[0][0]=1.0; + val_p_tensor[0][1]=0.0; + val_p_tensor[0][2]=0.5*rhooc; + val_p_tensor[0][3]=0.5*rhooc; + + val_p_tensor[1][0]=val_velocity[0]; + val_p_tensor[1][1]=*val_density*val_normal[1]; + val_p_tensor[1][2]=0.5*(val_velocity[0]*rhooc+val_normal[0]**val_density); + val_p_tensor[1][3]=0.5*(val_velocity[0]*rhooc-val_normal[0]**val_density); + + val_p_tensor[2][0]=val_velocity[1]; + val_p_tensor[2][1]=-*val_density*val_normal[0]; + val_p_tensor[2][2]=0.5*(val_velocity[1]*rhooc+val_normal[1]**val_density); + val_p_tensor[2][3]=0.5*(val_velocity[1]*rhooc-val_normal[1]**val_density); + + val_p_tensor[3][0]= zeta; + val_p_tensor[3][1]=*val_density*val_velocity[0]*val_normal[1]-*val_density*val_velocity[1]*val_normal[0]; + val_p_tensor[3][2]=0.5*(*val_enthalpy*rhooc+*val_density*val_velocity[0]*val_normal[0]+*val_density*val_velocity[1]*val_normal[1]); + val_p_tensor[3][3]=0.5*(*val_enthalpy*rhooc-*val_density*val_velocity[0]*val_normal[0]-*val_density*val_velocity[1]*val_normal[1]); + } + else { + sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]+val_velocity[2]*val_velocity[2]; + zeta = sqvel - (*val_kappa*0.5*sqvel + *val_chi)/(*val_kappa); + + val_p_tensor[0][0]=val_normal[0]; + val_p_tensor[0][1]=val_normal[1]; + val_p_tensor[0][2]=val_normal[2]; + val_p_tensor[0][3]=0.5*rhooc; + val_p_tensor[0][4]=0.5*rhooc; + + val_p_tensor[1][0]=val_velocity[0]*val_normal[0]; + val_p_tensor[1][1]=val_velocity[0]*val_normal[1]-*val_density*val_normal[2]; + val_p_tensor[1][2]=val_velocity[0]*val_normal[2]+*val_density*val_normal[1]; + val_p_tensor[1][3]=0.5*(val_velocity[0]*rhooc+*val_density*val_normal[0]); + val_p_tensor[1][4]=0.5*(val_velocity[0]*rhooc-*val_density*val_normal[0]); + + val_p_tensor[2][0]=val_velocity[1]*val_normal[0]+*val_density*val_normal[2]; + val_p_tensor[2][1]=val_velocity[1]*val_normal[1]; + val_p_tensor[2][2]=val_velocity[1]*val_normal[2]-*val_density*val_normal[0]; + val_p_tensor[2][3]=0.5*(val_velocity[1]*rhooc+*val_density*val_normal[1]); + val_p_tensor[2][4]=0.5*(val_velocity[1]*rhooc-*val_density*val_normal[1]); + + val_p_tensor[3][0]=val_velocity[2]*val_normal[0]-*val_density*val_normal[1]; + val_p_tensor[3][1]=val_velocity[2]*val_normal[1]+*val_density*val_normal[0]; + val_p_tensor[3][2]=val_velocity[2]*val_normal[2]; + val_p_tensor[3][3]=0.5*(val_velocity[2]*rhooc+*val_density*val_normal[2]); + val_p_tensor[3][4]=0.5*(val_velocity[2]*rhooc-*val_density*val_normal[2]); + + val_p_tensor[4][0]=zeta*val_normal[0]+*val_density*val_velocity[1]*val_normal[2]-*val_density*val_velocity[2]*val_normal[1]; + val_p_tensor[4][1]=zeta*val_normal[1]-*val_density*val_velocity[0]*val_normal[2]+*val_density*val_velocity[2]*val_normal[0]; + val_p_tensor[4][2]=zeta*val_normal[2]+*val_density*val_velocity[0]*val_normal[1]-*val_density*val_velocity[1]*val_normal[0]; + val_p_tensor[4][3]=0.5*(*val_enthalpy*rhooc+*val_density*(val_velocity[0]*val_normal[0]+val_velocity[1]*val_normal[1]+val_velocity[2]*val_normal[2])); + val_p_tensor[4][4]=0.5*(*val_enthalpy*rhooc-*val_density*(val_velocity[0]*val_normal[0]+val_velocity[1]*val_normal[1]+val_velocity[2]*val_normal[2])); + } + +} + +void CNumerics::GetPMatrix_inv(su2double *val_density, su2double *val_velocity, + su2double *val_soundspeed, su2double *val_normal, su2double **val_invp_tensor) { + + su2double rhoxc, c2, gm1, k0orho, k1orho, gm1_o_c2, gm1_o_rhoxc, sqvel; + + rhoxc = *val_density * *val_soundspeed; + c2 = *val_soundspeed * *val_soundspeed; + gm1 = Gamma_Minus_One; + k0orho = val_normal[0] / *val_density; + k1orho = val_normal[1] / *val_density; + gm1_o_c2 = gm1/c2; + gm1_o_rhoxc = gm1/rhoxc; + + if (nDim == 3) { + + sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]+val_velocity[2]*val_velocity[2]; + + val_invp_tensor[0][0]=val_normal[0]-val_normal[2]*val_velocity[1] / *val_density+val_normal[1]*val_velocity[2] / *val_density-val_normal[0]*0.5*gm1*sqvel/c2; + val_invp_tensor[0][1]=val_normal[0]*gm1*val_velocity[0]/c2; + val_invp_tensor[0][2]=val_normal[2] / *val_density+val_normal[0]*gm1*val_velocity[1]/c2; + val_invp_tensor[0][3]=-val_normal[1] / *val_density+val_normal[0]*gm1*val_velocity[2]/c2; + val_invp_tensor[0][4]=-val_normal[0]*gm1/c2; + + val_invp_tensor[1][0]=val_normal[1]+val_normal[2]*val_velocity[0] / *val_density-val_normal[0]*val_velocity[2] / *val_density-val_normal[1]*0.5*gm1*sqvel/c2; + val_invp_tensor[1][1]=-val_normal[2] / *val_density+val_normal[1]*gm1*val_velocity[0]/c2; + val_invp_tensor[1][2]=val_normal[1]*gm1*val_velocity[1]/c2; + val_invp_tensor[1][3]=val_normal[0] / *val_density+val_normal[1]*gm1*val_velocity[2]/c2; + val_invp_tensor[1][4]=-val_normal[1]*gm1/c2; + + val_invp_tensor[2][0]=val_normal[2]-val_normal[1]*val_velocity[0] / *val_density+val_normal[0]*val_velocity[1] / *val_density-val_normal[2]*0.5*gm1*sqvel/c2; + val_invp_tensor[2][1]=val_normal[1] / *val_density+val_normal[2]*gm1*val_velocity[0]/c2; + val_invp_tensor[2][2]=-val_normal[0] / *val_density+val_normal[2]*gm1*val_velocity[1]/c2; + val_invp_tensor[2][3]=val_normal[2]*gm1*val_velocity[2]/c2; + val_invp_tensor[2][4]=-val_normal[2]*gm1/c2; + + val_invp_tensor[3][0]=-(val_normal[0]*val_velocity[0]+val_normal[1]*val_velocity[1]+val_normal[2]*val_velocity[2]) / *val_density+0.5*gm1*sqvel/rhoxc; + val_invp_tensor[3][1]=val_normal[0] / *val_density-gm1*val_velocity[0]/rhoxc; + val_invp_tensor[3][2]=val_normal[1] / *val_density-gm1*val_velocity[1]/rhoxc; + val_invp_tensor[3][3]=val_normal[2] / *val_density-gm1*val_velocity[2]/rhoxc; + val_invp_tensor[3][4]=Gamma_Minus_One/rhoxc; + + val_invp_tensor[4][0]=(val_normal[0]*val_velocity[0]+val_normal[1]*val_velocity[1]+val_normal[2]*val_velocity[2]) / *val_density+0.5*gm1*sqvel/rhoxc; + val_invp_tensor[4][1]=-val_normal[0] / *val_density-gm1*val_velocity[0]/rhoxc; + val_invp_tensor[4][2]=-val_normal[1] / *val_density-gm1*val_velocity[1]/rhoxc; + val_invp_tensor[4][3]=-val_normal[2] / *val_density-gm1*val_velocity[2]/rhoxc; + val_invp_tensor[4][4]=Gamma_Minus_One/rhoxc; + + } + if (nDim == 2) { + + sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]; + + val_invp_tensor[0][0]=1.0-0.5*gm1_o_c2*sqvel; + val_invp_tensor[0][1]=gm1_o_c2*val_velocity[0]; + val_invp_tensor[0][2]=gm1_o_c2*val_velocity[1]; + val_invp_tensor[0][3]=-gm1_o_c2; + + val_invp_tensor[1][0]=-k1orho*val_velocity[0]+k0orho*val_velocity[1]; + val_invp_tensor[1][1]=k1orho; + val_invp_tensor[1][2]=-k0orho; + val_invp_tensor[1][3]=0.0; + + val_invp_tensor[2][0]=-k0orho*val_velocity[0]-k1orho*val_velocity[1]+0.5*gm1_o_rhoxc*sqvel; + val_invp_tensor[2][1]=k0orho-gm1_o_rhoxc*val_velocity[0]; + val_invp_tensor[2][2]=k1orho-gm1_o_rhoxc*val_velocity[1]; + val_invp_tensor[2][3]=gm1_o_rhoxc; + + val_invp_tensor[3][0]=k0orho*val_velocity[0]+k1orho*val_velocity[1]+0.5*gm1_o_rhoxc*sqvel; + val_invp_tensor[3][1]=-k0orho-gm1_o_rhoxc*val_velocity[0]; + val_invp_tensor[3][2]=-k1orho-gm1_o_rhoxc*val_velocity[1]; + val_invp_tensor[3][3]=gm1_o_rhoxc; + + } +} + +void CNumerics::GetPMatrix_inv(su2double **val_invp_tensor, su2double *val_density, su2double *val_velocity, + su2double *val_soundspeed, su2double *val_chi, su2double *val_kappa, su2double *val_normal) { + + su2double rhoxc, c2, k0orho, k1orho, sqvel, k_o_c2, k_o_rhoxc, dp_drho; + + rhoxc = *val_density * *val_soundspeed; + c2 = *val_soundspeed * *val_soundspeed; + k0orho = val_normal[0] / *val_density; + k1orho = val_normal[1] / *val_density; + k_o_c2 = (*val_kappa)/c2; + k_o_rhoxc = (*val_kappa)/rhoxc; + + + if (nDim == 3) { + sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]+val_velocity[2]*val_velocity[2]; + dp_drho = *val_chi + 0.5*sqvel*(*val_kappa); + + val_invp_tensor[0][0]=val_normal[0]-val_normal[2]*val_velocity[1] / *val_density + val_normal[1]*val_velocity[2] / *val_density - val_normal[0]*dp_drho/c2; + val_invp_tensor[0][1]=val_normal[0]*val_velocity[0]*k_o_c2; + val_invp_tensor[0][2]=val_normal[2] / *val_density + val_normal[0]*val_velocity[1]*k_o_c2; + val_invp_tensor[0][3]=-val_normal[1] / *val_density + val_normal[0]*val_velocity[2]*k_o_c2; + val_invp_tensor[0][4]=-val_normal[0]*k_o_c2; + + val_invp_tensor[1][0]=val_normal[1]+val_normal[2]*val_velocity[0] / *val_density - val_normal[0]*val_velocity[2] / *val_density - val_normal[1]*dp_drho/c2; + val_invp_tensor[1][1]=-val_normal[2] / *val_density + val_normal[1]*val_velocity[0]*k_o_c2; + val_invp_tensor[1][2]=val_normal[1]*val_velocity[1]*k_o_c2; + val_invp_tensor[1][3]=val_normal[0] / *val_density + val_normal[1]*val_velocity[2]*k_o_c2; + val_invp_tensor[1][4]=-val_normal[1]*k_o_c2; + + val_invp_tensor[2][0]=val_normal[2]-val_normal[1]*val_velocity[0] / *val_density + val_normal[0]*val_velocity[1] / *val_density - val_normal[2]*dp_drho/c2; + val_invp_tensor[2][1]=val_normal[1] / *val_density + val_normal[2]*val_velocity[0]*k_o_c2; + val_invp_tensor[2][2]=-val_normal[0] / *val_density + val_normal[2]*val_velocity[1]*k_o_c2; + val_invp_tensor[2][3]=val_normal[2]*val_velocity[2]*k_o_c2; + val_invp_tensor[2][4]=-val_normal[2]*k_o_c2; + + val_invp_tensor[3][0]=-(val_normal[0]*val_velocity[0]+val_normal[1]*val_velocity[1]+val_normal[2]*val_velocity[2]) / *val_density+ dp_drho/rhoxc; + val_invp_tensor[3][1]=val_normal[0] / *val_density - val_velocity[0]*k_o_rhoxc; + val_invp_tensor[3][2]=val_normal[1] / *val_density- val_velocity[1]*k_o_rhoxc; + val_invp_tensor[3][3]=val_normal[2] / *val_density- val_velocity[2]*k_o_rhoxc; + val_invp_tensor[3][4]= k_o_rhoxc; + + val_invp_tensor[4][0]=(val_normal[0]*val_velocity[0]+val_normal[1]*val_velocity[1]+val_normal[2]*val_velocity[2]) / *val_density+ dp_drho/rhoxc; + val_invp_tensor[4][1]=-val_normal[0] / *val_density- val_velocity[0]*k_o_rhoxc; + val_invp_tensor[4][2]=-val_normal[1] / *val_density- val_velocity[1]*k_o_rhoxc; + val_invp_tensor[4][3]=-val_normal[2] / *val_density- val_velocity[2]*k_o_rhoxc; + val_invp_tensor[4][4]= k_o_rhoxc; + } + if (nDim == 2) { + sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]; + dp_drho = *val_chi + 0.5*sqvel*(*val_kappa); + + val_invp_tensor[0][0]=1.0 - dp_drho/c2; + val_invp_tensor[0][1]= k_o_c2*val_velocity[0]; + val_invp_tensor[0][2]= k_o_c2*val_velocity[1]; + val_invp_tensor[0][3]=-k_o_c2; + + val_invp_tensor[1][0]=-k1orho*val_velocity[0]+k0orho*val_velocity[1]; + val_invp_tensor[1][1]=k1orho; + val_invp_tensor[1][2]=-k0orho; + val_invp_tensor[1][3]=0.0; + + val_invp_tensor[2][0]=-k0orho*val_velocity[0]-k1orho*val_velocity[1] + dp_drho/rhoxc; + val_invp_tensor[2][1]=k0orho - k_o_rhoxc*val_velocity[0]; + val_invp_tensor[2][2]=k1orho - k_o_rhoxc*val_velocity[1]; + val_invp_tensor[2][3]=k_o_rhoxc; + + val_invp_tensor[3][0]=k0orho*val_velocity[0]+k1orho*val_velocity[1] + dp_drho/rhoxc; + val_invp_tensor[3][1]=-k0orho - k_o_rhoxc*val_velocity[0]; + val_invp_tensor[3][2]=-k1orho - k_o_rhoxc*val_velocity[1]; + val_invp_tensor[3][3]= k_o_rhoxc; + } +} + +void CNumerics::GetinvRinvPe(su2double Beta2, su2double val_enthalpy, + su2double val_soundspeed, su2double val_density, + su2double* val_velocity, su2double **invRinvPe) { + + su2double sqvel; + su2double factor = 1.0/(val_soundspeed*val_soundspeed*Beta2); + + if (nDim == 2) { + + sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]; + + invRinvPe[0][0] = factor; + invRinvPe[0][1] = 0.0; + invRinvPe[0][2] = 0.0; + invRinvPe[0][3] = -val_density/Gamma; + + invRinvPe[1][0] = val_velocity[0]*factor; + invRinvPe[1][1] = val_density; + invRinvPe[1][2] = 0.0; + invRinvPe[1][3] = -val_density*val_velocity[0]/Gamma; + + invRinvPe[2][0] = val_velocity[1]*factor; + invRinvPe[2][1] = 0; + invRinvPe[2][2] = val_density; + invRinvPe[2][3] = -val_density*val_velocity[1]/Gamma; + + invRinvPe[3][0] = val_enthalpy*factor; + invRinvPe[3][1] = val_density*val_velocity[0]; + invRinvPe[3][2] = val_density*val_velocity[1]; + invRinvPe[3][3] = -val_density*sqvel/(2.0*Gamma); + } + else { + + sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]+val_velocity[2]*val_velocity[2]; + + invRinvPe[0][0] = factor; + invRinvPe[0][1] = 0.0; + invRinvPe[0][2] = 0.0; + invRinvPe[0][3] = 0.0; + invRinvPe[0][4] = -val_density/Gamma; + + invRinvPe[1][0] = val_velocity[0]*factor; + invRinvPe[1][1] = val_density; + invRinvPe[1][2] = 0.0; + invRinvPe[1][3] = 0.0; + invRinvPe[1][4] = -val_density*val_velocity[0]/Gamma; + + invRinvPe[2][0] = val_velocity[1]*factor; + invRinvPe[2][1] = 0; + invRinvPe[2][2] = val_density; + invRinvPe[2][3] = 0.0; + invRinvPe[2][4] = -val_density*val_velocity[1]/Gamma; + + + invRinvPe[3][0] = val_velocity[2]*factor; + invRinvPe[3][1] = 0; + invRinvPe[3][2] = 0; + invRinvPe[3][3] = val_density; + invRinvPe[3][4] = -val_density*val_velocity[2]/Gamma; + + invRinvPe[4][0] = val_enthalpy*factor; + invRinvPe[4][1] = val_density*val_velocity[0]; + invRinvPe[4][2] = val_density*val_velocity[1]; + invRinvPe[4][3] = val_density*val_velocity[2]; + invRinvPe[4][4] = -val_density*sqvel/(2.0*Gamma); + + } + +} + +void CNumerics::GetRMatrix(su2double val_pressure, su2double val_soundspeed, su2double val_density, su2double* val_velocity, su2double **R_Matrix) { + + su2double sqvel; + //su2double factor = 1.0/(val_soundspeed*val_soundspeed*1); + su2double gm1 = Gamma - 1.0; + + if (nDim == 2) { + + sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]; + + R_Matrix[0][0] = 0.5*gm1*sqvel; + R_Matrix[0][1] = -val_velocity[0]*gm1; + R_Matrix[0][2] = -val_velocity[1]*gm1; + R_Matrix[0][3] = gm1; + + R_Matrix[1][0] = -val_velocity[0]/val_density; + R_Matrix[1][1] = 1.0/val_density; + R_Matrix[1][2] = 0.0; + R_Matrix[1][3] = 0.0; + + R_Matrix[2][0] = -val_velocity[1]/val_density; + R_Matrix[2][1] = 0.0; + R_Matrix[2][2] = 1.0/val_density; + R_Matrix[2][3] = 0.0; + + R_Matrix[3][0] = 0.5*gm1*sqvel/val_pressure - Gamma/val_density; + R_Matrix[3][1] = -gm1*val_velocity[0]/val_pressure; + R_Matrix[3][2] = -gm1*val_velocity[1]/val_pressure; + R_Matrix[3][3] = gm1/val_pressure; + } + else { + + sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]+val_velocity[2]*val_velocity[2]; + + R_Matrix[0][0] = 0.5*gm1*sqvel; + R_Matrix[0][1] = -val_velocity[0]*gm1; + R_Matrix[0][2] = -val_velocity[1]*gm1; + R_Matrix[0][3] = -val_velocity[2]*gm1; + R_Matrix[0][4] = gm1; + + R_Matrix[1][0] = -val_velocity[0]/val_density; + R_Matrix[1][1] = 1.0/val_density; + R_Matrix[1][2] = 0.0; + R_Matrix[1][3] = 0.0; + R_Matrix[1][4] = 0.0; + + R_Matrix[2][0] = -val_velocity[1]/val_density; + R_Matrix[2][1] = 0.0; + R_Matrix[2][2] = 1.0/val_density; + R_Matrix[2][3] = 0.0; + R_Matrix[2][4] = 0.0; + + R_Matrix[3][0] = -val_velocity[2]/val_density; + R_Matrix[3][1] = 0.0; + R_Matrix[3][2] = 0.0; + R_Matrix[3][3] = 1.0/val_density; + R_Matrix[3][4] = 0.0; + + R_Matrix[4][0] = 0.5*gm1*sqvel/val_pressure - Gamma/val_density; + R_Matrix[4][1] = -gm1*val_velocity[0]/val_pressure; + R_Matrix[4][2] = -gm1*val_velocity[1]/val_pressure; + R_Matrix[4][3] = -gm1*val_velocity[2]/val_pressure; + R_Matrix[4][4] = gm1/val_pressure; + + } + +} + + + +void CNumerics::GetRMatrix(su2double val_soundspeed, su2double val_density, su2double* val_normal, su2double **R_Matrix) { + + if (nDim == 2) { + + + +// R_Matrix[0][0] = 1.0; +// R_Matrix[0][1] = 0.0; +// R_Matrix[0][2] = 0.5*val_density/val_soundspeed; +// R_Matrix[0][3] = 0.5*val_density/val_soundspeed; +// +// R_Matrix[1][0] = 0.0; +// R_Matrix[1][1] = val_normal[1]; +// R_Matrix[1][2] = 0.5*val_normal[0]; +// R_Matrix[1][3] = -0.5*val_normal[0]; +// +// R_Matrix[2][0] = 0.0; +// R_Matrix[2][1] = -val_normal[0]; +// R_Matrix[2][2] = 0.5*val_normal[1]; +// R_Matrix[2][3] = -0.5*val_normal[1]; +// +// R_Matrix[3][0] = 0.0; +// R_Matrix[3][1] = 0.0; +// R_Matrix[3][2] = 0.5*val_density*val_soundspeed; +// R_Matrix[3][3] = 0.5*val_density*val_soundspeed; + + su2double cc, rhoc; + cc = val_soundspeed*val_soundspeed; + rhoc = val_density/val_soundspeed; + + R_Matrix[0][0] = -1.0/cc; + R_Matrix[0][1] = 0.0; + R_Matrix[0][2] = 0.5/cc; + R_Matrix[0][3] = 0.5/cc; + + R_Matrix[1][0] = 0.0; + R_Matrix[1][1] = 0.0; + R_Matrix[1][2] = 0.5/rhoc; + R_Matrix[1][3] = -0.5/rhoc; + + R_Matrix[2][0] = 0.0; + R_Matrix[2][1] = 1.0/rhoc; + R_Matrix[2][2] = 0.0; + R_Matrix[2][3] = 0.0; + + R_Matrix[3][0] = 0.0; + R_Matrix[3][1] = 0.0; + R_Matrix[3][2] = 0.5; + R_Matrix[3][3] = 0.5; + + } + else { + +// sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]+val_velocity[2]*val_velocity[2]; +// +// R_Matrix[0][0] = 0.5*gm1*sqvel; +// R_Matrix[0][1] = -val_velocity[0]*gm1; +// R_Matrix[0][2] = -val_velocity[1]*gm1; +// R_Matrix[0][3] = -val_velocity[2]*gm1; +// R_Matrix[0][4] = gm1; +// +// R_Matrix[1][0] = -val_velocity[0]/val_density; +// R_Matrix[1][1] = 1.0/val_density; +// R_Matrix[1][2] = 0.0; +// R_Matrix[1][3] = 0.0; +// R_Matrix[1][4] = 0.0; +// +// R_Matrix[2][0] = -val_velocity[1]/val_density; +// R_Matrix[2][1] = 0.0; +// R_Matrix[2][2] = 1.0/val_density; +// R_Matrix[2][3] = 0.0; +// R_Matrix[2][4] = 0.0; +// +// R_Matrix[3][0] = -val_velocity[2]/val_density; +// R_Matrix[3][1] = 0.0; +// R_Matrix[3][2] = 0.0; +// R_Matrix[3][3] = 1.0/val_density; +// R_Matrix[3][4] = 0.0; +// +// R_Matrix[4][0] = 0.5*gm1*sqvel/val_pressure - Gamma/val_density; +// R_Matrix[4][1] = -gm1*val_velocity[0]/val_pressure; +// R_Matrix[4][2] = -gm1*val_velocity[1]/val_pressure; +// R_Matrix[4][3] = -gm1*val_velocity[2]/val_pressure; +// R_Matrix[4][4] = gm1/val_pressure; + + } + +} + +void CNumerics::GetLMatrix(su2double val_soundspeed, su2double val_density, su2double* val_normal, su2double **L_Matrix) { + + if (nDim == 2) { + + + + L_Matrix[0][0] = 1.0; + L_Matrix[0][1] = 0.0; + L_Matrix[0][2] = 0.0; + L_Matrix[0][3] = -0.5/val_soundspeed/val_soundspeed; + + L_Matrix[1][0] = 0.0; + L_Matrix[1][1] = val_normal[1]; + L_Matrix[1][2] = -val_normal[0]; + L_Matrix[1][3] = 0.0; + + L_Matrix[2][0] = 0.0; + L_Matrix[2][1] = val_normal[0]; + L_Matrix[2][2] = val_normal[1]; + L_Matrix[2][3] = 1.0/val_density/val_soundspeed; + + L_Matrix[3][0] = 0.0; + L_Matrix[3][1] = -val_normal[0]; + L_Matrix[3][2] = -val_normal[1]; + L_Matrix[3][3] = 1.0/val_density/val_soundspeed; + } + else { + +// sqvel = val_velocity[0]*val_velocity[0]+val_velocity[1]*val_velocity[1]+val_velocity[2]*val_velocity[2]; +// +// R_Matrix[0][0] = 0.5*gm1*sqvel; +// R_Matrix[0][1] = -val_velocity[0]*gm1; +// R_Matrix[0][2] = -val_velocity[1]*gm1; +// R_Matrix[0][3] = -val_velocity[2]*gm1; +// R_Matrix[0][4] = gm1; +// +// R_Matrix[1][0] = -val_velocity[0]/val_density; +// R_Matrix[1][1] = 1.0/val_density; +// R_Matrix[1][2] = 0.0; +// R_Matrix[1][3] = 0.0; +// R_Matrix[1][4] = 0.0; +// +// R_Matrix[2][0] = -val_velocity[1]/val_density; +// R_Matrix[2][1] = 0.0; +// R_Matrix[2][2] = 1.0/val_density; +// R_Matrix[2][3] = 0.0; +// R_Matrix[2][4] = 0.0; +// +// R_Matrix[3][0] = -val_velocity[2]/val_density; +// R_Matrix[3][1] = 0.0; +// R_Matrix[3][2] = 0.0; +// R_Matrix[3][3] = 1.0/val_density; +// R_Matrix[3][4] = 0.0; +// +// R_Matrix[4][0] = 0.5*gm1*sqvel/val_pressure - Gamma/val_density; +// R_Matrix[4][1] = -gm1*val_velocity[0]/val_pressure; +// R_Matrix[4][2] = -gm1*val_velocity[1]/val_pressure; +// R_Matrix[4][3] = -gm1*val_velocity[2]/val_pressure; +// R_Matrix[4][4] = gm1/val_pressure; + + } + +} + +void CNumerics::GetPrecondJacobian(su2double Beta2, su2double r_hat, su2double s_hat, su2double t_hat, su2double rB2a2, su2double* Lambda, su2double *val_normal, + su2double **val_absPeJac) { + + + su2double lam1, lam2, lam3, lam4; + lam1 = Lambda[0]; lam2 = Lambda[1]; lam3 = Lambda[2]; lam4 = Lambda[3]; + + if (nDim == 2) { + + val_absPeJac[0][0] = lam3*s_hat/(2.0*t_hat) - lam4*r_hat/(2.0*t_hat); + val_absPeJac[0][1] = -lam3*rB2a2*val_normal[0]/(2.0*t_hat) + lam4*rB2a2*val_normal[0]/(2.0*t_hat); + val_absPeJac[0][2] = -lam3*rB2a2*val_normal[1]/(2.0*t_hat) + lam4*rB2a2*val_normal[1]/(2.0*t_hat); + val_absPeJac[0][3] = 0.0; + + val_absPeJac[1][0] = r_hat*val_normal[0]*lam3*s_hat/(2.0*t_hat*rB2a2) + s_hat*val_normal[0]*lam4*(-r_hat)/(2.0*t_hat*rB2a2); + val_absPeJac[1][1] = lam2*(val_normal[1]*val_normal[1]) - lam3*r_hat*val_normal[0]*val_normal[0]/(2.0*t_hat) + lam4*s_hat*val_normal[0]*val_normal[0]/(2.0*t_hat); + val_absPeJac[1][2] = -lam2*val_normal[0]*val_normal[1] - lam3*r_hat*val_normal[0]*val_normal[1]/(2.0*t_hat) + lam4*s_hat*val_normal[0]*val_normal[1]/(2.0*t_hat); + val_absPeJac[1][3] = 0.0; + + val_absPeJac[2][0] = lam3*r_hat*val_normal[1]*s_hat/(2.0*t_hat*rB2a2) - s_hat*val_normal[1]*lam4*r_hat/(2.0*t_hat*rB2a2); + val_absPeJac[2][1] = -val_normal[0]*val_normal[1]*lam2 - r_hat*val_normal[1]*val_normal[0]*lam3/(2.0*t_hat) + s_hat*val_normal[0]*val_normal[1]*lam4/(2.0*t_hat); + val_absPeJac[2][2] = val_normal[0]*val_normal[0]*lam2 -r_hat*val_normal[1]*val_normal[1]*lam3/(2.0*t_hat) + s_hat*val_normal[1]*val_normal[1]*lam4/(2.0*t_hat); + val_absPeJac[2][3] = 0.0; + + val_absPeJac[3][0] = 0.0; + val_absPeJac[3][1] = 0.0; + val_absPeJac[3][2] = 0.0; + val_absPeJac[3][3] = lam1; + + } + else { + + su2double lam5 = Lambda[4]; + + val_absPeJac[0][0] = lam4*s_hat/(2.0*t_hat) - lam5*r_hat/(2.0*t_hat); + val_absPeJac[0][1] = -lam4*rB2a2*val_normal[0]/(2.0*t_hat) + lam5*rB2a2*val_normal[0]/(2.0*t_hat); + val_absPeJac[0][2] = -lam4*rB2a2*val_normal[1]/(2.0*t_hat) + lam5*rB2a2*val_normal[1]/(2.0*t_hat); + val_absPeJac[0][3] = -lam4*rB2a2*val_normal[2]/(2.0*t_hat) + lam5*rB2a2*val_normal[2]/(2.0*t_hat); + val_absPeJac[0][4] = 0.0; + + val_absPeJac[1][0] = r_hat*val_normal[0]*lam4*s_hat/(2.0*t_hat*rB2a2) + s_hat*val_normal[0]*lam5*(-r_hat)/(2.0*t_hat*rB2a2); + val_absPeJac[1][1] = lam2*(val_normal[2]*val_normal[2] + val_normal[1]*val_normal[1]) - lam4*r_hat*val_normal[0]*val_normal[0]/(2.0*t_hat) + lam5*s_hat*val_normal[0]*val_normal[0]/(2.0*t_hat); + val_absPeJac[1][2] = -lam2*val_normal[0]*val_normal[1] - lam4*r_hat*val_normal[0]*val_normal[1]/(2.0*t_hat) + lam5*s_hat*val_normal[0]*val_normal[1]/(2.0*t_hat); + val_absPeJac[1][3] = -lam2*val_normal[0]*val_normal[2] - lam4*r_hat*val_normal[0]*val_normal[2]/(2.0*t_hat) + lam5*s_hat*val_normal[0]*val_normal[2]/(2.0*t_hat); + val_absPeJac[1][4] = 0.0; + + val_absPeJac[2][0] = lam4*r_hat*val_normal[1]*s_hat/(2.0*t_hat*rB2a2) - s_hat*val_normal[1]*lam5*r_hat/(2.0*t_hat*rB2a2); + val_absPeJac[2][1] = -val_normal[0]*val_normal[1]*lam2 - r_hat*val_normal[1]*val_normal[0]*lam4/(2.0*t_hat) + s_hat*val_normal[0]*val_normal[1]*lam5/(2.0*t_hat); + val_absPeJac[2][2] = val_normal[0]*val_normal[0]*lam2 + val_normal[2]*val_normal[2]*lam3 -r_hat*val_normal[1]*val_normal[1]*lam4/(2.0*t_hat) + s_hat*val_normal[1]*val_normal[1]*lam5/(2.0*t_hat); + val_absPeJac[2][3] = -val_normal[2]*val_normal[1]*lam2 - r_hat*val_normal[2]*val_normal[1]*lam4/(2.0*t_hat) + s_hat*lam5*val_normal[1]*val_normal[2]/(2.0*t_hat); + val_absPeJac[2][4] = 0.0; + + val_absPeJac[3][0] = r_hat*s_hat*val_normal[2]*lam4/(2.0*t_hat*rB2a2) - r_hat*s_hat*val_normal[2]*lam5/(2.0*t_hat*rB2a2); + val_absPeJac[3][1] = -val_normal[0]*val_normal[2]*lam3 - lam4*val_normal[0]*val_normal[2]*r_hat/(2.0*t_hat) + lam5*val_normal[0]*val_normal[2]*s_hat/(2.0*t_hat); + val_absPeJac[3][2] = -val_normal[1]*val_normal[2]*lam3 - lam4*val_normal[1]*val_normal[2]*r_hat/(2.0*t_hat) + lam5*val_normal[1]*val_normal[2]*s_hat/(2.0*t_hat); + val_absPeJac[3][3] = (val_normal[1]*val_normal[1] + val_normal[0]*val_normal[0])*lam3 - lam4*val_normal[2]*val_normal[2]*r_hat/(2.0*t_hat) + lam5*val_normal[2]*val_normal[2]*s_hat/(2.0*t_hat); + val_absPeJac[3][4] = 0.0; + + val_absPeJac[4][0] = 0.0; + val_absPeJac[4][1] = 0.0; + val_absPeJac[4][2] = 0.0; + val_absPeJac[4][3] = 0.0; + val_absPeJac[4][4] = lam1; + + } + +} + +void CNumerics::GetPArtCompMatrix(su2double *val_density, su2double *val_velocity, su2double *val_betainc2, + su2double *val_normal, su2double **val_p_tensor) { + su2double a, a2, Projvel, area2, sx, sy, sz = 0.0, u, v, w = 0.0, factor = 0.0; + + sx = val_normal[0]; sy = val_normal[1]; u = val_velocity[0]; v = val_velocity[1]; + if (nDim == 3) { sz = val_normal[2]; w = val_velocity[2]; } + Projvel = u*sx + v*sy; area2 = sx*sx + sy*sy; + if (nDim == 3) { Projvel += w*sz; area2 += sz*sz; } + a2 = Projvel*Projvel + ((*val_betainc2)/(*val_density))*area2; a = sqrt(a2); + factor = 1/(2.0*((*val_betainc2)/(*val_density))*a2); + + if (nDim == 2) { + val_p_tensor[0][0] = 0.0; + val_p_tensor[0][1] = factor*((*val_betainc2)/(*val_density))*a; + val_p_tensor[0][2] = -factor*((*val_betainc2)/(*val_density))*a; + + val_p_tensor[1][0] = -factor*2.0*sy*((*val_betainc2)/(*val_density)); + val_p_tensor[1][1] = factor*(u*(a+Projvel) + sx*((*val_betainc2)/(*val_density))); + val_p_tensor[1][2] = factor*(u*(Projvel-a) + sx*((*val_betainc2)/(*val_density))); + + val_p_tensor[2][0] = factor*2.0*sx*((*val_betainc2)/(*val_density)); + val_p_tensor[2][1] = factor*(v*(a+Projvel) + sy*((*val_betainc2)/(*val_density))); + val_p_tensor[2][2] = factor*(v*(Projvel-a) + sy*((*val_betainc2)/(*val_density))); + } + else { + val_p_tensor[0][0] = 0.0; + val_p_tensor[0][1] = 0.0; + val_p_tensor[0][2] = ((*val_betainc2)/(*val_density))*a; + val_p_tensor[0][3] = -((*val_betainc2)/(*val_density))*a; + + val_p_tensor[1][0] = -sz; + val_p_tensor[1][1] = -sy; + val_p_tensor[1][2] = u*(Projvel+a) + sx*((*val_betainc2)/(*val_density)); + val_p_tensor[1][3] = u*(Projvel-a) + sx*((*val_betainc2)/(*val_density)); + + val_p_tensor[2][0] = 0.0; + val_p_tensor[2][1] = sx; + val_p_tensor[2][2] = v*(Projvel+a) + sy*((*val_betainc2)/(*val_density)); + val_p_tensor[2][3] = v*(Projvel-a) + sy*((*val_betainc2)/(*val_density)); + + val_p_tensor[3][0] = sx; + val_p_tensor[3][1] = 0.0; + val_p_tensor[3][2] = w*(Projvel+a) + sz*((*val_betainc2)/(*val_density)); + val_p_tensor[3][3] = w*(Projvel-a) + sz*((*val_betainc2)/(*val_density)); + } + +} + +void CNumerics::GetPArtCompMatrix_inv(su2double *val_density, su2double *val_velocity, su2double *val_betainc2, + su2double *val_normal, su2double **val_invp_tensor) { + su2double a, a2, Projvel, area2, sx, sy, sz = 0.0, u, v, w = 0.0; + + sx = val_normal[0]; sy = val_normal[1]; u = val_velocity[0]; v = val_velocity[1]; + if (nDim == 3) { sz = val_normal[2]; w = val_velocity[2];} + Projvel = u*sx + v*sy; area2 = sx*sx + sy*sy; + if (nDim == 3) { Projvel += w*sz; area2 += sz*sz; } + a2 = Projvel*Projvel + ((*val_betainc2)/(*val_density))*area2; a = sqrt(a2); + + if (nDim == 2) { + val_invp_tensor[0][0] = (sy*u-sx*v); + val_invp_tensor[0][1] = -v*Projvel-sy*((*val_betainc2)/(*val_density)); + val_invp_tensor[0][2] = u*Projvel+sx*((*val_betainc2)/(*val_density)); + + val_invp_tensor[1][0] = (a-Projvel); + val_invp_tensor[1][1] = ((*val_betainc2)/(*val_density))*sx; + val_invp_tensor[1][2] = ((*val_betainc2)/(*val_density))*sy; + + val_invp_tensor[2][0] = (-a-Projvel); + val_invp_tensor[2][1] = ((*val_betainc2)/(*val_density))*sx; + val_invp_tensor[2][2] = ((*val_betainc2)/(*val_density))*sy; + } + else { + val_invp_tensor[0][0] = (sz*Projvel-area2*w)/(sx*a2); + val_invp_tensor[0][1] = -(w*Projvel+sz*((*val_betainc2)/(*val_density)))/a2; + val_invp_tensor[0][2] = -sy*(w*Projvel+sz*((*val_betainc2)/(*val_density)))/(sx*a2); + val_invp_tensor[0][3] = ((sx*u+sy*v)*Projvel+(sx*sx+sy*sy)*((*val_betainc2)/(*val_density)))/(sx*a2); + + val_invp_tensor[1][0] = (sy*Projvel-area2*v)/(sx*a2); + val_invp_tensor[1][1] = -(v*Projvel+sy*((*val_betainc2)/(*val_density)))/a2; + val_invp_tensor[1][2] = ((sx*u+sz*w)*Projvel+(sx*sx+sz*sz)*((*val_betainc2)/(*val_density)))/(sx*a2); + val_invp_tensor[1][3] = -sz*(v*Projvel+sy*((*val_betainc2)/(*val_density)))/(sx*a2); + + val_invp_tensor[2][0] = -(Projvel-a)/(2.0*a2*((*val_betainc2)/(*val_density))); + val_invp_tensor[2][1] = sx/(2.0*a2); + val_invp_tensor[2][2] = sy/(2.0*a2); + val_invp_tensor[2][3] = sz/(2.0*a2); + + val_invp_tensor[3][0] = -(Projvel+a)/(2.0*a2*((*val_betainc2)/(*val_density))); + val_invp_tensor[3][1] = sx/(2.0*a2); + val_invp_tensor[3][2] = sy/(2.0*a2); + val_invp_tensor[3][3] = sz/(2.0*a2); + } + +} + +void CNumerics::GetPArtComp_FreeSurf_Matrix(su2double *val_density, su2double *val_ddensity, su2double *val_velocity, su2double *val_betainc2, su2double *val_levelset, su2double *val_normal, su2double **val_p_tensor) { + + su2double a = 0.0, b = 0.0, c = 0.0, d = 0.0, area2 = 0.0, e2 = 0.0, f = 0.0, nx = 0.0, ny = 0.0, nz = 0.0, u = 0.0, v = 0.0, w = 0.0; + + a = (*val_betainc2)/(*val_density); + b = (*val_levelset)/(*val_density); + c = (*val_ddensity); + + if (nDim == 2) { + + nx = val_normal[0]; ny = val_normal[1]; area2 = nx*nx + ny*ny; + u = val_velocity[0]; v = val_velocity[1]; d = u*nx + v*ny; + e2 = (2.0*d - b*c*d)*(2.0*d - b*c*d); + f = sqrt(4.0*a*area2 + e2); + + val_p_tensor[0][0] = 0; + val_p_tensor[0][1] = 0; + val_p_tensor[0][2] = (d*d*(1.0 - b*c) + 2.0*a*area2 + d*d + d*f)/(2.0*b*area2); + val_p_tensor[0][3] = (d*d*(1.0 - b*c) + 2.0*a*area2 + d*d - d*f)/(2.0*b*area2); + + val_p_tensor[1][0] = (c*d)/nx; + val_p_tensor[1][1] = -(ny/nx); + val_p_tensor[1][2] = (d*nx*(b*c - 1.0) + nx*nx*u + 2.0*ny*ny*u - nx*ny*v - nx*f)/(2*b*area2); + val_p_tensor[1][3] = (d*nx*(b*c - 1.0) + nx*nx*u + 2.0*ny*ny*u - nx*ny*v + nx*f)/(2*b*area2); + + val_p_tensor[2][0] = 0.0; + val_p_tensor[2][1] = 1.0; + val_p_tensor[2][2] = (d*ny*(b*c - 1.0) - nx*ny*u + 2.0*nx*nx*v + ny*ny*v - ny*f)/(2*b*area2); + val_p_tensor[2][3] = (d*ny*(b*c - 1.0) - nx*ny*u + 2.0*nx*nx*v + ny*ny*v + ny*f)/(2*b*area2); + + val_p_tensor[3][0] = 1.0; + val_p_tensor[3][1] = 0.0; + val_p_tensor[3][2] = 1.0; + val_p_tensor[3][3] = 1.0; + + } + else { + + nx = val_normal[0]; ny = val_normal[1]; nz = val_normal[2]; area2 = nx*nx + ny*ny + nz*nz; + u = val_velocity[0]; v = val_velocity[1]; w = val_velocity[2]; d = u*nx + v*ny + w*nz; + e2 = (2.0*d - b*c*d)*(2.0*d - b*c*d); + f = sqrt(4.0*a*area2 + e2); + + val_p_tensor[0][0] = 0.0; + val_p_tensor[0][1] = 0.0; + val_p_tensor[0][2] = 0.0; + val_p_tensor[0][3] = -((a*(b*c*d + f))/(b*(2.0*d - b*c*d - f))); + val_p_tensor[0][4] = (a*(- b*c*d + f))/(b*(2.0*d - b*c*d + f)); + + val_p_tensor[1][0] = (c*d)/nx; + val_p_tensor[1][1] = -(nz/nx); + val_p_tensor[1][2] = -(ny/nx); + val_p_tensor[1][3] = -((-2.0*a*nx + b*c*d*u - 2.0*u*d + u*f)/(b*(2.0*d - b*c*d - f))); + val_p_tensor[1][4] = -((-2.0*a*nx + b*c*d*u - 2.0*u*d - u*f)/(b*(2.0*d - b*c*d + f))); + + val_p_tensor[2][0] = 0.0; + val_p_tensor[2][1] = 0.0; + val_p_tensor[2][2] = 1.0; + val_p_tensor[2][3] = -((-2.0*a*ny + b*c*d*v - 2.0*v*d + v*f)/(b*(2.0*d - b*c*d - f))); + val_p_tensor[2][4] = -((-2.0*a*ny + b*c*d*v - 2.0*v*d - v*f)/(b*(2.0*d - b*c*d + f))); + + val_p_tensor[3][0] = 0.0; + val_p_tensor[3][1] = 1.0; + val_p_tensor[3][2] = 0.0; + val_p_tensor[3][3] = -((-2.0*a*nz + b*c*d*w - 2.0*w*d + w*f)/(b*(2.0*d - b*c*d - f))); + val_p_tensor[3][4] = -((-2.0*a*nz + b*c*d*w - 2.0*w*d - w*f)/(b*(2.0*d - b*c*d + f))); + + val_p_tensor[4][0] = 1.0; + val_p_tensor[4][1] = 0.0; + val_p_tensor[4][2] = 0.0; + val_p_tensor[4][3] = 1.0; + val_p_tensor[4][4] = 1.0; + + } + +} + +void CNumerics::GetPArtComp_FreeSurf_Matrix_inv(su2double *val_density, su2double *val_ddensity, su2double *val_velocity, su2double *val_betainc2, su2double *val_levelset, + su2double *val_normal, su2double **val_invp_tensor) { + + su2double a = 0.0, b = 0.0, c = 0.0, d = 0.0, area2 = 0.0, e2 = 0.0, f = 0.0, nx = 0.0, ny = 0.0, nz = 0.0, u = 0.0, v = 0.0, w = 0.0; + + a = (*val_betainc2)/(*val_density); + b = (*val_levelset)/(*val_density); + c = (*val_ddensity); + + if (nDim == 2) { + + nx = val_normal[0]; ny = val_normal[1]; area2 = nx*nx + ny*ny; + u = val_velocity[0]; v = val_velocity[1]; d = u*nx + v*ny; + e2 = (2.0*d - b*c*d)*(2.0*d - b*c*d); + f = sqrt(4.0*a*area2 + e2); + + val_invp_tensor[0][0] = -((b*area2)/(a*area2 + d*d*(1.0 - b*c))); + val_invp_tensor[0][1] = -((b*d*nx)/(a*area2 + d*d*(1.0 - b*c))); + val_invp_tensor[0][2] = -((b*d*ny)/(a*area2 + d*d*(1.0 - b*c))); + val_invp_tensor[0][3] = ( a*area2 + d*d)/(a*area2 + d*d*(1.0 - b*c)); + + val_invp_tensor[1][0] = (-b*c*d*ny + nx*(ny*u - nx*v))/(a*area2 + d*d*(1.0-b*c)); + val_invp_tensor[1][1] = -((nx*(a*ny + d*v))/(a*area2 + d*d*(1.0-b*c))); + val_invp_tensor[1][2] = (-b*c*d*d + nx*(a*nx + d*u))/(a*area2 + d*d*(1.0-b*c)); + val_invp_tensor[1][3] = (c*d*(a*ny + d*v))/(a*area2 + d*d*(1.0-b*c)); + + val_invp_tensor[2][0] = (b*area2*(-b*c*d + f))/(2.0*(-b*c*d*d + a*area2 + d*d)*f); + val_invp_tensor[2][1] = -((b*nx*(-(2.0 - b*c)*d*d - 2.0*a*area2 + d*f))/(2.0*(- a*area2 - d*d*(1.0-b*c))*f)); + val_invp_tensor[2][2] = -((b*ny*(-(2.0 - b*c)*d*d - 2.0*a*area2 + d*f))/(2.0*(- a*area2 - d*d*(1.0-b*c))*f)); + val_invp_tensor[2][3] = (b*c*d*(-(2.0 - b*c)*d*d - 2.0*a*area2 + d*f))/(2.0*(- a*area2 - d*d*(1.0-b*c))*f); + + val_invp_tensor[3][0] = (b*area2*(b*c*d + f))/(2.0*(-b*c*d*d + a*area2 + d*d)*f); + val_invp_tensor[3][1] = -((b*nx*((2.0 - b*c)*d*d + 2.0*a*area2 + d*f))/(2.0*(- a*area2 - d*d*(1.0-b*c))*f)); + val_invp_tensor[3][2] = -((b*ny*((2.0 - b*c)*d*d + 2.0*a*area2 + d*f))/(2.0*(- a*area2 - d*d*(1.0-b*c))*f)); + val_invp_tensor[3][3] = (b*c*d*((2.0 - b*c)*d*d + 2.0*a*area2 + d*f))/(2.0*(- a*area2 - d*d*(1.0-b*c))*f); + + } + else { + + nx = val_normal[0]; ny = val_normal[1]; nz = val_normal[2]; area2 = nx*nx + ny*ny + nz*nz; + u = val_velocity[0]; v = val_velocity[1]; w = val_velocity[2]; d = u*nx + v*ny + w*nz; + e2 = (2.0*d - b*c*d)*(2.0*d - b*c*d); + f = sqrt(4.0*a*area2 + e2); + + val_invp_tensor[0][0] = (b*area2)/(b*c*d*d - a*area2 - d*d); + val_invp_tensor[0][1] = -((b*d*nx)/(-b*c*d*d + a*area2 + d*d)); + val_invp_tensor[0][2] = -((b*d*ny)/(-b*c*d*d + a*area2 + d*d)); + val_invp_tensor[0][3] = -((b*d*nz)/(-b*c*d*d + a*area2 + d*d)); + val_invp_tensor[0][4] = (a*area2 + d*d)/(-b*c*d*d +a*area2 + d*d); + + val_invp_tensor[1][0] = (-b*c*d*nz +nx*nz*u - nx*nx*w + ny*(nz*v - ny*w))/(-b*c*d*d +a*area2 + d*d); + val_invp_tensor[1][1] = -((nx*(a*nz + d*w))/(-b*c*d*d + a*area2 + d*d)); + val_invp_tensor[1][2] = -((ny*(a*nz + d*w))/(-b*c*d*d + a*area2 + d*d)); + val_invp_tensor[1][3] = (-b*c*d*d + a*(nx*nx + ny*ny) + d*(nx*u + ny*v))/(-b*c*d*d + a*area2 + d*d); + val_invp_tensor[1][4] = (c*d*(a*nz + d*w))/(-b*c*d*d + a*area2 + d*d); + + val_invp_tensor[2][0] = (-b*c*d*ny + nx*ny*u - nx*nx*v + nz*(-nz*v + ny*w))/(-b*c*d*d + a*area2 + d*d); + val_invp_tensor[2][1] = -((nx*(a*ny + d*v))/(-b*c*d*d + a*area2 + d*d)); + val_invp_tensor[2][2] = (-b*c*d*d + a*(nx*nx + nz*nz) + d*(nx*u + nz*w))/(-b*c*d*d + a*area2 + d*d); + val_invp_tensor[2][3] = -((nz*(a*ny + d*v))/(-b*c*d*d + a*area2 + d*d)); + val_invp_tensor[2][4] = (c*d*(a*ny + d*v))/(-b*c*d*d + a*area2 + d*(nx*u + ny*v + nz*w)); + + val_invp_tensor[3][0] = -(b*(-d + b*c*d - d + f)*(b*b*c*c*d*d + 2.0*a*area2 + d*d - 3.0*b*c*d*d + 2.0*nx*ny*u*v + 2.0*nx*nz*u*w + 2.0*ny*nz*v*w + nx*nx*u*u + ny*ny*v*v + nz*nz*w*w - b*c*d*f + d*f))/(4*a*(b*c*d*d - a*area2 - d*d)*f); + val_invp_tensor[3][1] = (b*nx*(-d + b*c*d - d + f)*(- b*c*d + f))/(4.0*(b*c*d*d - a*area2 - d*d)*f); + val_invp_tensor[3][2] = (b*ny*(-d + b*c*d - d + f)*(- b*c*d + f))/(4.0*(b*c*d*d - a*area2 - d*d)*f); + val_invp_tensor[3][3] = (b*nz*(-d + b*c*d - d + f)*(- b*c*d + f))/(4.0*(b*c*d*d - a*area2 - d*d)*f); + val_invp_tensor[3][4] = -((b*c*d*(-d + b*c*d - d + f)*(- b*c*d + f))/(4.0*(b*c*d*d - a*area2 - d*d)*f)); + + val_invp_tensor[4][0] = -(b*(2.0*d - b*c*d + f)*(b*b*c*c*d*d + 2.0*a*area2 + d*d - 3.0*b*c*d*d + 2.0*nx*ny*u*v + 2.0*nx*nz*u*w + 2.0*ny*nz*v*w + nx*nx*u*u + ny*ny*v*v + nz*nz*w*w + b*c*d*f - d*f))/(4*a*(b*c*d*d - a*area2 - d*d)*f); + val_invp_tensor[4][1] = -((b*nx*(b*c*d + f)*(2.0*d - b*c*d + f))/(4.0*(b*c*d*d - a*area2 - d*d)*f)); + val_invp_tensor[4][2] = -((b*ny*(b*c*d + f)*(2.0*d - b*c*d + f))/(4.0*(b*c*d*d - a*area2 - d*d)*f)); + val_invp_tensor[4][3] = -((b*nz*(b*c*d + f)*(2.0*d - b*c*d + f))/(4.0*(b*c*d*d - a*area2 - d*d)*f)); + val_invp_tensor[4][4] = (b*c*d*(b*c*d + f)*(2.0*d - b*c*d + f))/(4.0*(b*c*d*d - a*area2 - d*d)*f); + + } + +} + +void CNumerics::GetJacInviscidLambda_fabs(su2double *val_velocity, su2double val_soundspeed, + su2double *val_normal, su2double *val_Lambda_Vector) { + su2double ProjVelocity = 0; + + for (unsigned short iDim = 0; iDim < nDim; iDim++) + ProjVelocity += val_velocity[iDim]*val_normal[iDim]; + + if (nDim == 3) { + val_Lambda_Vector[0] = fabs(ProjVelocity); + val_Lambda_Vector[1] = fabs(ProjVelocity); + val_Lambda_Vector[2] = fabs(ProjVelocity); + val_Lambda_Vector[3] = fabs(ProjVelocity + val_soundspeed); + val_Lambda_Vector[4] = fabs(ProjVelocity - val_soundspeed); + } + + if (nDim == 2) { + val_Lambda_Vector[0] = fabs(ProjVelocity); + val_Lambda_Vector[1] = fabs(ProjVelocity); + val_Lambda_Vector[2] = fabs(ProjVelocity + val_soundspeed); + val_Lambda_Vector[3] = fabs(ProjVelocity - val_soundspeed); + } +} + +void CNumerics::GetAdjViscousFlux_Jac(su2double Pressure_i, su2double Pressure_j, su2double Density_i, su2double Density_j, + su2double ViscDens_i, su2double ViscDens_j, su2double *Velocity_i, su2double *Velocity_j, + su2double sq_vel_i, su2double sq_vel_j, + su2double XiDens_i, su2double XiDens_j, su2double **Mean_GradPhi, su2double *Mean_GradPsiE, + su2double dPhiE_dn, su2double *Normal, su2double *Edge_Vector, su2double dist_ij_2, su2double *val_residual_i, su2double *val_residual_j, + su2double **val_Jacobian_ii, su2double **val_Jacobian_ij, su2double **val_Jacobian_ji, + su2double **val_Jacobian_jj, bool implicit) { + + su2double Sigma_xx, Sigma_yy, Sigma_zz, Sigma_xy, Sigma_xz, Sigma_yz, + Sigma_xx5, Sigma_yy5, Sigma_zz5, Sigma_xy5, Sigma_xz5, + Sigma_yz5, Sigma_5, eta_xx, eta_yy, eta_zz, eta_xy, eta_xz, eta_yz; + su2double dSigmaxx_phi1, dSigmayy_phi1, dSigmazz_phi1, dSigmaxy_phi1, dSigmaxz_phi1, dSigmayz_phi1; + su2double dSigmaxx_phi2, dSigmayy_phi2, dSigmazz_phi2, dSigmaxy_phi2, dSigmaxz_phi2, dSigmayz_phi2; + su2double dSigmaxx_phi3, dSigmayy_phi3, dSigmazz_phi3, dSigmaxy_phi3, dSigmaxz_phi3, dSigmayz_phi3; + su2double dSigma5_psi5; + unsigned short iVar, jVar; + + if (nDim == 3) { + + /*--- Residual at iPoint ---*/ + + Sigma_xx = ViscDens_i * (FOUR3 * Mean_GradPhi[0][0] - TWO3 * Mean_GradPhi[1][1] - TWO3 * Mean_GradPhi[2][2]); + Sigma_yy = ViscDens_i * (-TWO3 * Mean_GradPhi[0][0] + FOUR3 * Mean_GradPhi[1][1] - TWO3 * Mean_GradPhi[2][2]); + Sigma_zz = ViscDens_i * (-TWO3 * Mean_GradPhi[0][0] - TWO3 * Mean_GradPhi[1][1] + FOUR3 * Mean_GradPhi[2][2]); + Sigma_xy = ViscDens_i * (Mean_GradPhi[1][0] + Mean_GradPhi[0][1]); + Sigma_xz = ViscDens_i * (Mean_GradPhi[2][0] + Mean_GradPhi[0][2]); + Sigma_yz = ViscDens_i * (Mean_GradPhi[2][1] + Mean_GradPhi[1][2]); + Sigma_xx5 = ViscDens_i * ( FOUR3 * Velocity_i[0] * Mean_GradPsiE[0] - TWO3 * Velocity_i[1] * Mean_GradPsiE[1] - TWO3 * Velocity_i[2] * Mean_GradPsiE[2]); + Sigma_yy5 = ViscDens_i * (- TWO3 * Velocity_i[0] * Mean_GradPsiE[0] + FOUR3 * Velocity_i[1] * Mean_GradPsiE[1] - TWO3 * Velocity_i[2] * Mean_GradPsiE[2]); + Sigma_zz5 = ViscDens_i * (- TWO3 * Velocity_i[0] * Mean_GradPsiE[0] - TWO3 * Velocity_i[1] * Mean_GradPsiE[1] + FOUR3 * Velocity_i[2] * Mean_GradPsiE[2]); + Sigma_xy5 = ViscDens_i * (Velocity_i[0] * Mean_GradPsiE[1] + Velocity_i[1] * Mean_GradPsiE[0]); + Sigma_xz5 = ViscDens_i * (Velocity_i[0] * Mean_GradPsiE[2] + Velocity_i[2] * Mean_GradPsiE[0]); + Sigma_yz5 = ViscDens_i * (Velocity_i[1] * Mean_GradPsiE[2] + Velocity_i[2] * Mean_GradPsiE[1]); + Sigma_5 = XiDens_i * dPhiE_dn; + eta_xx = Sigma_xx + Sigma_xx5; eta_yy = Sigma_yy + Sigma_yy5; eta_zz = Sigma_zz + Sigma_zz5; + eta_xy = Sigma_xy + Sigma_xy5; eta_xz = Sigma_xz + Sigma_xz5; eta_yz = Sigma_yz + Sigma_yz5; + + val_residual_i[0] = - (Velocity_i[0] * Normal[0] * eta_xx + Velocity_i[1] * Normal[1] * eta_yy + Velocity_i[2] * Normal[2] * eta_zz + + (Velocity_i[0] * Normal[1] + Velocity_i[1] * Normal[0]) * eta_xy + + (Velocity_i[0] * Normal[2] + Velocity_i[2] * Normal[0]) * eta_xz + + (Velocity_i[2] * Normal[1] + Velocity_i[1] * Normal[2]) * eta_yz + - (sq_vel_i - Pressure_i/(Density_i*Gamma_Minus_One)) * Sigma_5); + + val_residual_i[1] = (eta_xx * Normal[0] + eta_xy * Normal[1] + eta_xz * Normal[2] - Velocity_i[0] * Sigma_5); + val_residual_i[2] = (eta_xy * Normal[0] + eta_yy * Normal[1] + eta_yz * Normal[2] - Velocity_i[1] * Sigma_5); + val_residual_i[3] = (eta_xz * Normal[0] + eta_yz * Normal[1] + eta_zz * Normal[2] - Velocity_i[2] * Sigma_5); + val_residual_i[4] = (Sigma_5); + + /*--- Computation of the Jacobians at Point i---*/ + + if (implicit) { + + dSigmaxx_phi1 = -FOUR3 * ViscDens_i * Edge_Vector[0]/dist_ij_2; + dSigmaxx_phi2 = TWO3 * ViscDens_i * Edge_Vector[1]/dist_ij_2; + dSigmaxx_phi3 = TWO3 * ViscDens_i * Edge_Vector[2]/dist_ij_2; + dSigmayy_phi1 = TWO3 * ViscDens_i * Edge_Vector[0]/dist_ij_2; + dSigmayy_phi2 = -FOUR3 * ViscDens_i * Edge_Vector[1]/dist_ij_2; + dSigmayy_phi3 = TWO3 * ViscDens_i * Edge_Vector[2]/dist_ij_2; + dSigmazz_phi1 = TWO3 * ViscDens_i * Edge_Vector[0]/dist_ij_2; + dSigmazz_phi2 = TWO3 * ViscDens_i * Edge_Vector[1]/dist_ij_2; + dSigmazz_phi3 = -FOUR3 * ViscDens_i * Edge_Vector[2]/dist_ij_2; + dSigmaxy_phi1 = -ViscDens_i * Edge_Vector[1]/dist_ij_2; + dSigmaxy_phi2 = -ViscDens_i * Edge_Vector[0]/dist_ij_2; + dSigmaxy_phi3 = 0; + dSigmaxz_phi1 = -ViscDens_i * Edge_Vector[2]/dist_ij_2; + dSigmaxz_phi2 = 0; + dSigmaxz_phi3 = -ViscDens_i * Edge_Vector[0]/dist_ij_2; + dSigmayz_phi1 = 0; + dSigmayz_phi2 = -ViscDens_i * Edge_Vector[2]/dist_ij_2; + dSigmayz_phi3 = -ViscDens_i * Edge_Vector[1]/dist_ij_2; + + // dSigmaxx5_psi5 = -ViscDens_i * ( FOUR3*Velocity_i[0]*Edge_Vector[0] - TWO3*Velocity_i[1]*Edge_Vector[1] - TWO3*Velocity_i[2]*Edge_Vector[2])/dist_ij_2; + // dSigmayy5_psi5 = -ViscDens_i * (- TWO3*Velocity_i[0]*Edge_Vector[0] + FOUR3*Velocity_i[1]*Edge_Vector[1] - TWO3*Velocity_i[2]*Edge_Vector[2])/dist_ij_2; + // dSigmazz5_psi5 = -ViscDens_i * (- TWO3*Velocity_i[0]*Edge_Vector[0] - TWO3*Velocity_i[1]*Edge_Vector[1] + FOUR3*Velocity_i[2]*Edge_Vector[2])/dist_ij_2; + // dSigmaxy5_psi5 = -ViscDens_i * ( Velocity_i[0]*Edge_Vector[1] + Velocity_i[1]*Edge_Vector[0] )/dist_ij_2; + // dSigmaxz5_psi5 = -ViscDens_i * ( Velocity_i[0]*Edge_Vector[2] + Velocity_i[2]*Edge_Vector[0] )/dist_ij_2; + // dSigmayz5_psi5 = -ViscDens_i * ( Velocity_i[1]*Edge_Vector[2] + Velocity_i[2]*Edge_Vector[1] )/dist_ij_2; + dSigma5_psi5 = -XiDens_i * ( Edge_Vector[0]*Normal[0] + Edge_Vector[1]*Normal[1] + Edge_Vector[2]*Normal[2] )/dist_ij_2; + + val_Jacobian_ii[0][0] = 0; + val_Jacobian_ii[0][1] = -( Velocity_i[0]*Normal[0]*dSigmaxx_phi1 + Velocity_i[1]*Normal[1]*dSigmayy_phi1 + Velocity_i[2]*Normal[2]*dSigmazz_phi1 + + (Velocity_i[0]*Normal[1] + Velocity_i[1]*Normal[0])*dSigmaxy_phi1 + + (Velocity_i[0]*Normal[2] + Velocity_i[2]*Normal[0])*dSigmaxz_phi1 + + (Velocity_i[2]*Normal[1] + Velocity_i[1]*Normal[2])*dSigmayz_phi1 ); + val_Jacobian_ii[0][2] = -( Velocity_i[0]*Normal[0]*dSigmaxx_phi2 + Velocity_i[1]*Normal[1]*dSigmayy_phi2 + Velocity_i[2]*Normal[2]*dSigmazz_phi2 + + (Velocity_i[0]*Normal[1] + Velocity_i[1]*Normal[0])*dSigmaxy_phi2 + + (Velocity_i[0]*Normal[2] + Velocity_i[2]*Normal[0])*dSigmaxz_phi2 + + (Velocity_i[2]*Normal[1] + Velocity_i[1]*Normal[2])*dSigmayz_phi2 ); + val_Jacobian_ii[0][3] = -( Velocity_i[0]*Normal[0]*dSigmaxx_phi3 + Velocity_i[1]*Normal[1]*dSigmayy_phi3 + Velocity_i[2]*Normal[2]*dSigmazz_phi3 + + (Velocity_i[0]*Normal[1] + Velocity_i[1]*Normal[0])*dSigmaxy_phi3 + + (Velocity_i[0]*Normal[2] + Velocity_i[2]*Normal[0])*dSigmaxz_phi3 + + (Velocity_i[2]*Normal[1] + Velocity_i[1]*Normal[2])*dSigmayz_phi3 ); + val_Jacobian_ii[0][4] = (sq_vel_i - Pressure_i/(Density_i*Gamma_Minus_One)) * dSigma5_psi5; + + val_Jacobian_ii[1][0] = 0; + val_Jacobian_ii[1][1] = Normal[0]*dSigmaxx_phi1 + Normal[1]*dSigmaxy_phi1 + Normal[2]*dSigmaxz_phi1; + val_Jacobian_ii[1][2] = Normal[0]*dSigmaxx_phi2 + Normal[1]*dSigmaxy_phi2 + Normal[2]*dSigmaxz_phi2; + val_Jacobian_ii[1][3] = Normal[0]*dSigmaxx_phi3 + Normal[1]*dSigmaxy_phi3 + Normal[2]*dSigmaxz_phi3; + val_Jacobian_ii[1][4] = -Velocity_i[0]*dSigma5_psi5; + + val_Jacobian_ii[2][0] = 0; + val_Jacobian_ii[2][1] = Normal[0]*dSigmaxy_phi1 + Normal[1]*dSigmayy_phi1 + Normal[2]*dSigmayz_phi1; + val_Jacobian_ii[2][2] = Normal[0]*dSigmaxy_phi2 + Normal[1]*dSigmayy_phi2 + Normal[2]*dSigmayz_phi2; + val_Jacobian_ii[2][3] = Normal[0]*dSigmaxy_phi3 + Normal[1]*dSigmayy_phi3 + Normal[2]*dSigmayz_phi3; + val_Jacobian_ii[2][4] = -Velocity_i[1]*dSigma5_psi5; + + val_Jacobian_ii[3][0] = 0; + val_Jacobian_ii[3][1] = Normal[0]*dSigmaxz_phi1 + Normal[1]*dSigmayz_phi1 + Normal[2]*dSigmazz_phi1; + val_Jacobian_ii[3][2] = Normal[0]*dSigmaxz_phi2 + Normal[1]*dSigmayz_phi2 + Normal[2]*dSigmazz_phi2; + val_Jacobian_ii[3][3] = Normal[0]*dSigmaxz_phi3 + Normal[1]*dSigmayz_phi3 + Normal[2]*dSigmazz_phi3; + val_Jacobian_ii[3][4] = -Velocity_i[2]*dSigma5_psi5; + + val_Jacobian_ii[4][0] = 0; + val_Jacobian_ii[4][1] = 0; + val_Jacobian_ii[4][2] = 0; + val_Jacobian_ii[4][3] = 0; + val_Jacobian_ii[4][4] = dSigma5_psi5; + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + val_Jacobian_ij[iVar][jVar] = -val_Jacobian_ii[iVar][jVar]; + } + + /*--- Residual at jPoint ---*/ + + Sigma_xx = ViscDens_j * (FOUR3 * Mean_GradPhi[0][0] - TWO3 * Mean_GradPhi[1][1] - TWO3 * Mean_GradPhi[2][2]); + Sigma_yy = ViscDens_j * (-TWO3 * Mean_GradPhi[0][0] + FOUR3 * Mean_GradPhi[1][1] - TWO3 * Mean_GradPhi[2][2]); + Sigma_zz = ViscDens_j * (-TWO3 * Mean_GradPhi[0][0] - TWO3 * Mean_GradPhi[1][1] + FOUR3 * Mean_GradPhi[2][2]); + Sigma_xy = ViscDens_j * (Mean_GradPhi[1][0] + Mean_GradPhi[0][1]); + Sigma_xz = ViscDens_j * (Mean_GradPhi[2][0] + Mean_GradPhi[0][2]); + Sigma_yz = ViscDens_j * (Mean_GradPhi[2][1] + Mean_GradPhi[1][2]); + Sigma_xx5 = ViscDens_j * ( FOUR3 * Velocity_j[0] * Mean_GradPsiE[0] - TWO3 * Velocity_j[1] * Mean_GradPsiE[1] - TWO3 * Velocity_j[2] * Mean_GradPsiE[2]); + Sigma_yy5 = ViscDens_j * (- TWO3 * Velocity_j[0] * Mean_GradPsiE[0] + FOUR3 * Velocity_j[1] * Mean_GradPsiE[1] - TWO3 * Velocity_j[2] * Mean_GradPsiE[2]); + Sigma_zz5 = ViscDens_j * (- TWO3 * Velocity_j[0] * Mean_GradPsiE[0] - TWO3 * Velocity_j[1] * Mean_GradPsiE[1] + FOUR3 * Velocity_j[2] * Mean_GradPsiE[2]); + Sigma_xy5 = ViscDens_j * (Velocity_j[0] * Mean_GradPsiE[1] + Velocity_j[1] * Mean_GradPsiE[0]); + Sigma_xz5 = ViscDens_j * (Velocity_j[0] * Mean_GradPsiE[2] + Velocity_j[2] * Mean_GradPsiE[0]); + Sigma_yz5 = ViscDens_j * (Velocity_j[1] * Mean_GradPsiE[2] + Velocity_j[2] * Mean_GradPsiE[1]); + Sigma_5 = XiDens_j * dPhiE_dn; + eta_xx = Sigma_xx + Sigma_xx5; eta_yy = Sigma_yy + Sigma_yy5; eta_zz = Sigma_zz + Sigma_zz5; + eta_xy = Sigma_xy + Sigma_xy5; eta_xz = Sigma_xz + Sigma_xz5; eta_yz = Sigma_yz + Sigma_yz5; + + val_residual_j[0] = - (Velocity_j[0] * Normal[0] * eta_xx + Velocity_j[1] * Normal[1] * eta_yy + Velocity_j[2] * Normal[2] * eta_zz + + (Velocity_j[0] * Normal[1] + Velocity_j[1] * Normal[0]) * eta_xy + + (Velocity_j[0] * Normal[2] + Velocity_j[2] * Normal[0]) * eta_xz + + (Velocity_j[2] * Normal[1] + Velocity_j[1] * Normal[2]) * eta_yz + - (sq_vel_j - Pressure_j/(Density_j*Gamma_Minus_One)) * Sigma_5); + val_residual_j[1] = (eta_xx * Normal[0] + eta_xy * Normal[1] + eta_xz * Normal[2] - Velocity_j[0] * Sigma_5); + val_residual_j[2] = (eta_xy * Normal[0] + eta_yy * Normal[1] + eta_yz * Normal[2] - Velocity_j[1] * Sigma_5); + val_residual_j[3] = (eta_xz * Normal[0] + eta_yz * Normal[1] + eta_zz * Normal[2] - Velocity_j[2] * Sigma_5); + val_residual_j[4] = (Sigma_5); + + /*--- Computation of the Jacobians at Point j---*/ + + if (implicit) { + + dSigmaxx_phi1 = FOUR3 * ViscDens_j * Edge_Vector[0]/dist_ij_2; + dSigmaxx_phi2 = -TWO3 * ViscDens_j * Edge_Vector[1]/dist_ij_2; + dSigmaxx_phi3 = -TWO3 * ViscDens_j * Edge_Vector[2]/dist_ij_2; + dSigmayy_phi1 = -TWO3 * ViscDens_j * Edge_Vector[0]/dist_ij_2; + dSigmayy_phi2 = FOUR3 * ViscDens_j * Edge_Vector[1]/dist_ij_2; + dSigmayy_phi3 = -TWO3 * ViscDens_j * Edge_Vector[2]/dist_ij_2; + dSigmazz_phi1 = -TWO3 * ViscDens_j * Edge_Vector[0]/dist_ij_2; + dSigmazz_phi2 = -TWO3 * ViscDens_j * Edge_Vector[1]/dist_ij_2; + dSigmazz_phi3 = FOUR3 * ViscDens_j * Edge_Vector[2]/dist_ij_2; + dSigmaxy_phi1 = ViscDens_j * Edge_Vector[1]/dist_ij_2; + dSigmaxy_phi2 = ViscDens_j * Edge_Vector[0]/dist_ij_2; + dSigmaxy_phi3 = 0; + dSigmaxz_phi1 = ViscDens_j * Edge_Vector[2]/dist_ij_2; + dSigmaxz_phi2 = 0; + dSigmaxz_phi3 = ViscDens_j * Edge_Vector[0]/dist_ij_2; + dSigmayz_phi1 = 0; + dSigmayz_phi2 = ViscDens_j * Edge_Vector[2]/dist_ij_2; + dSigmayz_phi3 = ViscDens_j * Edge_Vector[1]/dist_ij_2; + + // dSigmaxx5_psi5 = ViscDens_j * ( FOUR3*Velocity_j[0]*Edge_Vector[0] - TWO3*Velocity_j[1]*Edge_Vector[1] - TWO3*Velocity_j[2]*Edge_Vector[2])/dist_ij_2; + // dSigmayy5_psi5 = ViscDens_j * (- TWO3*Velocity_j[0]*Edge_Vector[0] + FOUR3*Velocity_j[1]*Edge_Vector[1] - TWO3*Velocity_j[2]*Edge_Vector[2])/dist_ij_2; + // dSigmazz5_psi5 = ViscDens_j * (- TWO3*Velocity_j[0]*Edge_Vector[0] - TWO3*Velocity_j[1]*Edge_Vector[1] + FOUR3*Velocity_j[2]*Edge_Vector[2])/dist_ij_2; + // dSigmaxy5_psi5 = ViscDens_j * ( Velocity_j[0]*Edge_Vector[1] + Velocity_j[1]*Edge_Vector[0] )/dist_ij_2; + // dSigmaxz5_psi5 = ViscDens_j * ( Velocity_j[0]*Edge_Vector[2] + Velocity_j[2]*Edge_Vector[0] )/dist_ij_2; + // dSigmayz5_psi5 = ViscDens_j * ( Velocity_j[1]*Edge_Vector[2] + Velocity_j[2]*Edge_Vector[1] )/dist_ij_2; + dSigma5_psi5 = XiDens_j * ( Edge_Vector[0]*Normal[0] + Edge_Vector[1]*Normal[1] + Edge_Vector[2]*Normal[2] )/dist_ij_2; + + val_Jacobian_jj[0][0] = 0; + val_Jacobian_jj[0][1] = -( Velocity_j[0]*Normal[0]*dSigmaxx_phi1 + Velocity_j[1]*Normal[1]*dSigmayy_phi1 + Velocity_j[2]*Normal[2]*dSigmazz_phi1 + + (Velocity_j[0]*Normal[1] + Velocity_j[1]*Normal[0])*dSigmaxy_phi1 + + (Velocity_j[0]*Normal[2] + Velocity_j[2]*Normal[0])*dSigmaxz_phi1 + + (Velocity_j[2]*Normal[1] + Velocity_j[1]*Normal[2])*dSigmayz_phi1 ); + val_Jacobian_jj[0][2] = -( Velocity_j[0]*Normal[0]*dSigmaxx_phi2 + Velocity_j[1]*Normal[1]*dSigmayy_phi2 + Velocity_j[2]*Normal[2]*dSigmazz_phi2 + + (Velocity_j[0]*Normal[1] + Velocity_j[1]*Normal[0])*dSigmaxy_phi2 + + (Velocity_j[0]*Normal[2] + Velocity_j[2]*Normal[0])*dSigmaxz_phi2 + + (Velocity_j[2]*Normal[1] + Velocity_j[1]*Normal[2])*dSigmayz_phi2 ); + val_Jacobian_jj[0][3] = -( Velocity_j[0]*Normal[0]*dSigmaxx_phi3 + Velocity_j[1]*Normal[1]*dSigmayy_phi3 + Velocity_j[2]*Normal[2]*dSigmazz_phi3 + + (Velocity_j[0]*Normal[1] + Velocity_j[1]*Normal[0])*dSigmaxy_phi3 + + (Velocity_j[0]*Normal[2] + Velocity_j[2]*Normal[0])*dSigmaxz_phi3 + + (Velocity_j[2]*Normal[1] + Velocity_j[1]*Normal[2])*dSigmayz_phi3 ); + val_Jacobian_jj[0][4] = (sq_vel_j - Pressure_j/(Density_j*Gamma_Minus_One)) * dSigma5_psi5; + + val_Jacobian_jj[1][0] = 0; + val_Jacobian_jj[1][1] = Normal[0]*dSigmaxx_phi1 + Normal[1]*dSigmaxy_phi1 + Normal[2]*dSigmaxz_phi1; + val_Jacobian_jj[1][2] = Normal[0]*dSigmaxx_phi2 + Normal[1]*dSigmaxy_phi2 + Normal[2]*dSigmaxz_phi2; + val_Jacobian_jj[1][3] = Normal[0]*dSigmaxx_phi3 + Normal[1]*dSigmaxy_phi3 + Normal[2]*dSigmaxz_phi3; + val_Jacobian_jj[1][4] = -Velocity_j[0]*dSigma5_psi5; + + val_Jacobian_jj[2][0] = 0; + val_Jacobian_jj[2][1] = Normal[0]*dSigmaxy_phi1 + Normal[1]*dSigmayy_phi1 + Normal[2]*dSigmayz_phi1; + val_Jacobian_jj[2][2] = Normal[0]*dSigmaxy_phi2 + Normal[1]*dSigmayy_phi2 + Normal[2]*dSigmayz_phi2; + val_Jacobian_jj[2][3] = Normal[0]*dSigmaxy_phi3 + Normal[1]*dSigmayy_phi3 + Normal[2]*dSigmayz_phi3; + val_Jacobian_jj[2][4] = -Velocity_j[1]*dSigma5_psi5; + + val_Jacobian_jj[3][0] = 0; + val_Jacobian_jj[3][1] = Normal[0]*dSigmaxz_phi1 + Normal[1]*dSigmayz_phi1 + Normal[2]*dSigmazz_phi1; + val_Jacobian_jj[3][2] = Normal[0]*dSigmaxz_phi2 + Normal[1]*dSigmayz_phi2 + Normal[2]*dSigmazz_phi2; + val_Jacobian_jj[3][3] = Normal[0]*dSigmaxz_phi3 + Normal[1]*dSigmayz_phi3 + Normal[2]*dSigmazz_phi3; + val_Jacobian_jj[3][4] = -Velocity_j[2]*dSigma5_psi5; + + val_Jacobian_jj[4][0] = 0; + val_Jacobian_jj[4][1] = 0; + val_Jacobian_jj[4][2] = 0; + val_Jacobian_jj[4][3] = 0; + val_Jacobian_jj[4][4] = dSigma5_psi5; + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + val_Jacobian_ji[iVar][jVar] = -val_Jacobian_jj[iVar][jVar]; + } + + } + else if (nDim == 2) { + + /*--- Residual at iPoint ---*/ + + Sigma_xx = ViscDens_i * (FOUR3 * Mean_GradPhi[0][0] - TWO3 * Mean_GradPhi[1][1]); + Sigma_yy = ViscDens_i * (-TWO3 * Mean_GradPhi[0][0] + FOUR3 * Mean_GradPhi[1][1]); + Sigma_xy = ViscDens_i * (Mean_GradPhi[1][0] + Mean_GradPhi[0][1]); + Sigma_xx5 = ViscDens_i * ( FOUR3 * Velocity_i[0] * Mean_GradPsiE[0] - TWO3 * Velocity_i[1] * Mean_GradPsiE[1]); + Sigma_yy5 = ViscDens_i * (- TWO3 * Velocity_i[0] * Mean_GradPsiE[0] + FOUR3 * Velocity_i[1] * Mean_GradPsiE[1]); + Sigma_xy5 = ViscDens_i * (Velocity_i[0] * Mean_GradPsiE[1] + Velocity_i[1] * Mean_GradPsiE[0]); + Sigma_5 = XiDens_i * dPhiE_dn; + eta_xx = Sigma_xx + Sigma_xx5; eta_yy = Sigma_yy + Sigma_yy5; eta_xy = Sigma_xy + Sigma_xy5; + + val_residual_i[0] = - (Velocity_i[0] * Normal[0] * eta_xx + Velocity_i[1] * Normal[1] * eta_yy + + (Velocity_i[0] * Normal[1] + Velocity_i[1] * Normal[0]) * eta_xy + - (sq_vel_i - Pressure_i/(Density_i*Gamma_Minus_One)) * Sigma_5); + val_residual_i[1] = (eta_xx * Normal[0] + eta_xy * Normal[1] - Velocity_i[0] * Sigma_5); + val_residual_i[2] = (eta_xy * Normal[0] + eta_yy * Normal[1] - Velocity_i[1] * Sigma_5); + val_residual_i[3] = (Sigma_5); + + /*--- Computation of the Jacobians at Point i---*/ + + if (implicit) { + + dSigmaxx_phi1 = -FOUR3 * ViscDens_i * Edge_Vector[0]/dist_ij_2; + dSigmaxx_phi2 = TWO3 * ViscDens_i * Edge_Vector[1]/dist_ij_2; + dSigmayy_phi1 = TWO3 * ViscDens_i * Edge_Vector[0]/dist_ij_2; + dSigmayy_phi2 = -FOUR3 * ViscDens_i * Edge_Vector[1]/dist_ij_2; + dSigmaxy_phi1 = -ViscDens_i * Edge_Vector[1]/dist_ij_2; + dSigmaxy_phi2 = -ViscDens_i * Edge_Vector[0]/dist_ij_2; + + // dSigmaxx5_psi5 = -ViscDens_i * ( FOUR3*Velocity_i[0]*Edge_Vector[0] - TWO3*Velocity_i[1]*Edge_Vector[1] )/dist_ij_2; + // dSigmayy5_psi5 = -ViscDens_i * (- TWO3*Velocity_i[0]*Edge_Vector[0] + FOUR3*Velocity_i[1]*Edge_Vector[1] )/dist_ij_2; + // dSigmaxy5_psi5 = -ViscDens_i * ( Velocity_i[0]*Edge_Vector[1] + Velocity_i[1]*Edge_Vector[0] )/dist_ij_2; + dSigma5_psi5 = -XiDens_i * ( Edge_Vector[0]*Normal[0] + Edge_Vector[1]*Normal[1] )/dist_ij_2; + + val_Jacobian_ii[0][0] = 0; + + val_Jacobian_ii[0][1] = -( Velocity_i[0]*Normal[0]*dSigmaxx_phi1 + Velocity_i[1]*Normal[1]*dSigmayy_phi1 + + (Velocity_i[0]*Normal[1] + Velocity_i[1]*Normal[0])*dSigmaxy_phi1 ); + val_Jacobian_ii[0][2] = -( Velocity_i[0]*Normal[0]*dSigmaxx_phi2 + Velocity_i[1]*Normal[1]*dSigmayy_phi2 + + (Velocity_i[0]*Normal[1] + Velocity_i[1]*Normal[0])*dSigmaxy_phi2 ); + val_Jacobian_ii[0][3] = (sq_vel_i - Pressure_i/(Density_i*Gamma_Minus_One)) * dSigma5_psi5; + + val_Jacobian_ii[1][0] = 0; + val_Jacobian_ii[1][1] = Normal[0]*dSigmaxx_phi1 + Normal[1]*dSigmaxy_phi1; + val_Jacobian_ii[1][2] = Normal[0]*dSigmaxx_phi2 + Normal[1]*dSigmaxy_phi2; + val_Jacobian_ii[1][3] = -Velocity_i[0]*dSigma5_psi5; + + val_Jacobian_ii[2][0] = 0; + val_Jacobian_ii[2][1] = Normal[0]*dSigmaxy_phi1 + Normal[1]*dSigmayy_phi1; + val_Jacobian_ii[2][2] = Normal[0]*dSigmaxy_phi2 + Normal[1]*dSigmayy_phi2; + val_Jacobian_ii[2][3] = -Velocity_i[1]*dSigma5_psi5; + + val_Jacobian_ii[3][0] = 0; + val_Jacobian_ii[3][1] = 0; + val_Jacobian_ii[3][2] = 0; + val_Jacobian_ii[3][3] = dSigma5_psi5; + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + val_Jacobian_ij[iVar][jVar] = -val_Jacobian_ii[iVar][jVar]; + } + + /*--- Residual at jPoint ---*/ + Sigma_xx = ViscDens_j * (FOUR3 * Mean_GradPhi[0][0] - TWO3 * Mean_GradPhi[1][1]); + Sigma_yy = ViscDens_j * (-TWO3 * Mean_GradPhi[0][0] + FOUR3 * Mean_GradPhi[1][1]); + Sigma_xy = ViscDens_j * (Mean_GradPhi[1][0] + Mean_GradPhi[0][1]); + Sigma_xx5 = ViscDens_j * ( FOUR3 * Velocity_j[0] * Mean_GradPsiE[0] - TWO3 * Velocity_j[1] * Mean_GradPsiE[1]); + Sigma_yy5 = ViscDens_j * (- TWO3 * Velocity_j[0] * Mean_GradPsiE[0] + FOUR3 * Velocity_j[1] * Mean_GradPsiE[1]); + Sigma_xy5 = ViscDens_j * (Velocity_j[0] * Mean_GradPsiE[1] + Velocity_j[1] * Mean_GradPsiE[0]); + Sigma_5 = XiDens_j * dPhiE_dn; + eta_xx = Sigma_xx + Sigma_xx5; eta_yy = Sigma_yy + Sigma_yy5; eta_xy = Sigma_xy + Sigma_xy5; + + val_residual_j[0] = - (Velocity_j[0] * Normal[0] * eta_xx + Velocity_j[1] * Normal[1] * eta_yy + + (Velocity_j[0] * Normal[1] + Velocity_j[1] * Normal[0]) * eta_xy + - (sq_vel_j - Pressure_j/(Density_j*Gamma_Minus_One)) * Sigma_5); + val_residual_j[1] = (eta_xx * Normal[0] + eta_xy * Normal[1] - Velocity_j[0] * Sigma_5); + val_residual_j[2] = (eta_xy * Normal[0] + eta_yy * Normal[1] - Velocity_j[1] * Sigma_5); + val_residual_j[3] = (Sigma_5); + + /*--- Computation of the Jacobians at Point j---*/ + if (implicit) { + dSigmaxx_phi1 = FOUR3 * ViscDens_j * Edge_Vector[0]/dist_ij_2; + dSigmaxx_phi2 = -TWO3 * ViscDens_j * Edge_Vector[1]/dist_ij_2; + dSigmayy_phi1 = -TWO3 * ViscDens_j * Edge_Vector[0]/dist_ij_2; + dSigmayy_phi2 = FOUR3 * ViscDens_j * Edge_Vector[1]/dist_ij_2; + dSigmaxy_phi1 = ViscDens_j * Edge_Vector[1]/dist_ij_2; + dSigmaxy_phi2 = ViscDens_j * Edge_Vector[0]/dist_ij_2; + + // dSigmaxx5_psi5 = ViscDens_j * ( FOUR3*Velocity_j[0]*Edge_Vector[0] - TWO3*Velocity_j[1]*Edge_Vector[1] )/dist_ij_2; + // dSigmayy5_psi5 = ViscDens_j * (- TWO3*Velocity_j[0]*Edge_Vector[0] + FOUR3*Velocity_j[1]*Edge_Vector[1] )/dist_ij_2; + // dSigmaxy5_psi5 = ViscDens_j * ( Velocity_j[0]*Edge_Vector[1] + Velocity_j[1]*Edge_Vector[0] )/dist_ij_2; + dSigma5_psi5 = XiDens_j * ( Edge_Vector[0]*Normal[0] + Edge_Vector[1]*Normal[1] )/dist_ij_2; + + val_Jacobian_jj[0][0] = 0; + val_Jacobian_jj[0][1] = -( Velocity_j[0]*Normal[0]*dSigmaxx_phi1 + Velocity_j[1]*Normal[1]*dSigmayy_phi1 + + (Velocity_j[0]*Normal[1] + Velocity_j[1]*Normal[0])*dSigmaxy_phi1 ); + val_Jacobian_jj[0][2] = -( Velocity_j[0]*Normal[0]*dSigmaxx_phi2 + Velocity_j[1]*Normal[1]*dSigmayy_phi2 + + (Velocity_j[0]*Normal[1] + Velocity_j[1]*Normal[0])*dSigmaxy_phi2 ); + val_Jacobian_jj[0][3] = (sq_vel_j - Pressure_j/(Density_j*Gamma_Minus_One)) * dSigma5_psi5; + + val_Jacobian_jj[1][0] = 0; + val_Jacobian_jj[1][1] = Normal[0]*dSigmaxx_phi1 + Normal[1]*dSigmaxy_phi1; + val_Jacobian_jj[1][2] = Normal[0]*dSigmaxx_phi2 + Normal[1]*dSigmaxy_phi2; + val_Jacobian_jj[1][3] = -Velocity_j[0]*dSigma5_psi5; + + val_Jacobian_jj[2][0] = 0; + val_Jacobian_jj[2][1] = Normal[0]*dSigmaxy_phi1 + Normal[1]*dSigmayy_phi1; + val_Jacobian_jj[2][2] = Normal[0]*dSigmaxy_phi2 + Normal[1]*dSigmayy_phi2; + val_Jacobian_jj[2][3] = -Velocity_j[1]*dSigma5_psi5; + + val_Jacobian_jj[3][0] = 0; + val_Jacobian_jj[3][1] = 0; + val_Jacobian_jj[3][2] = 0; + val_Jacobian_jj[3][3] = dSigma5_psi5; + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + val_Jacobian_ji[iVar][jVar] = -val_Jacobian_jj[iVar][jVar]; + } + } + +} + +void CNumerics::GetViscousFlux(su2double *val_primvar, su2double **val_gradprimvar, + su2double val_laminar_viscosity, su2double val_eddy_viscosity, su2double val_mach_inf) { + + su2double total_viscosity = val_laminar_viscosity + val_eddy_viscosity; + su2double Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; + su2double heat_flux_factor = Cp * (val_laminar_viscosity/Prandtl_Lam + val_eddy_viscosity/Prandtl_Turb); + + su2double div_vel = 0.0; + for (unsigned short iDim = 0 ; iDim < nDim; iDim++) + div_vel += val_gradprimvar[iDim+1][iDim]; + + for (unsigned short iDim = 0 ; iDim < nDim; iDim++) { + for (unsigned short jDim = 0 ; jDim < nDim; jDim++) { + tau[iDim][jDim] = total_viscosity*( val_gradprimvar[jDim+1][iDim] + + val_gradprimvar[iDim+1][jDim] ) + -TWO3*total_viscosity*div_vel*delta[iDim][jDim]; + } + } + + // Gradient of primitive variables -> [Temp vel_x vel_y vel_z Pressure] + if (nDim == 3) { + Flux_Tensor[0][0] = 0.0; + Flux_Tensor[1][0] = tau[0][0]; + Flux_Tensor[2][0] = tau[0][1]; + Flux_Tensor[3][0] = tau[0][2]; + Flux_Tensor[4][0] = tau[0][0]*val_primvar[1] + tau[0][1]*val_primvar[2] + tau[0][2]*val_primvar[3] + + heat_flux_factor*val_gradprimvar[0][0]; + + Flux_Tensor[0][1] = 0.0; + Flux_Tensor[1][1] = tau[1][0]; + Flux_Tensor[2][1] = tau[1][1]; + Flux_Tensor[3][1] = tau[1][2]; + Flux_Tensor[4][1] = tau[1][0]*val_primvar[1] + tau[1][1]*val_primvar[2] + tau[1][2]*val_primvar[3] + + heat_flux_factor*val_gradprimvar[0][1]; + + Flux_Tensor[0][2] = 0.0; + Flux_Tensor[1][2] = tau[2][0]; + Flux_Tensor[2][2] = tau[2][1]; + Flux_Tensor[3][2] = tau[2][2]; + Flux_Tensor[4][2] = tau[2][0]*val_primvar[1] + tau[2][1]*val_primvar[2] + tau[2][2]*val_primvar[3] + + heat_flux_factor*val_gradprimvar[0][2]; + } + if (nDim == 2) { + Flux_Tensor[0][0] = 0.0; + Flux_Tensor[1][0] = tau[0][0]; + Flux_Tensor[2][0] = tau[0][1]; + Flux_Tensor[3][0] = tau[0][0]*val_primvar[1] + tau[0][1]*val_primvar[2]+ + heat_flux_factor*val_gradprimvar[0][0]; + + Flux_Tensor[0][1] = 0.0; + Flux_Tensor[1][1] = tau[1][0]; + Flux_Tensor[2][1] = tau[1][1]; + Flux_Tensor[3][1] = tau[1][0]*val_primvar[1] + tau[1][1]*val_primvar[2]+ + heat_flux_factor*val_gradprimvar[0][1]; + } +} + + + +void CNumerics::GetViscousProjFlux(su2double *val_primvar, + su2double **val_gradprimvar, su2double val_turb_ke, + su2double *val_normal, + su2double val_laminar_viscosity, + su2double val_eddy_viscosity) { + + + unsigned short iVar, iDim, jDim; + su2double total_viscosity, heat_flux_factor, div_vel, Cp, Density; + + Density = val_primvar[nDim+2]; + total_viscosity = val_laminar_viscosity + val_eddy_viscosity; + Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; + heat_flux_factor = Cp * (val_laminar_viscosity/Prandtl_Lam + val_eddy_viscosity/Prandtl_Turb); + + div_vel = 0.0; + for (iDim = 0 ; iDim < nDim; iDim++) + div_vel += val_gradprimvar[iDim+1][iDim]; + for (iDim = 0 ; iDim < nDim; iDim++) + for (jDim = 0 ; jDim < nDim; jDim++) + tau[iDim][jDim] = total_viscosity*( val_gradprimvar[jDim+1][iDim] + val_gradprimvar[iDim+1][jDim] ) + - TWO3*total_viscosity*div_vel*delta[iDim][jDim] + - TWO3*Density*val_turb_ke*delta[iDim][jDim]; + /*--- Gradient of primitive variables -> [Temp vel_x vel_y vel_z Pressure] ---*/ + if (nDim == 2) { + Flux_Tensor[0][0] = 0.0; + Flux_Tensor[1][0] = tau[0][0]; + Flux_Tensor[2][0] = tau[0][1]; + Flux_Tensor[3][0] = tau[0][0]*val_primvar[1] + tau[0][1]*val_primvar[2]+ + heat_flux_factor*val_gradprimvar[0][0]; + Flux_Tensor[0][1] = 0.0; + Flux_Tensor[1][1] = tau[1][0]; + Flux_Tensor[2][1] = tau[1][1]; + Flux_Tensor[3][1] = tau[1][0]*val_primvar[1] + tau[1][1]*val_primvar[2]+ + heat_flux_factor*val_gradprimvar[0][1]; + } else { + Flux_Tensor[0][0] = 0.0; + Flux_Tensor[1][0] = tau[0][0]; + Flux_Tensor[2][0] = tau[0][1]; + Flux_Tensor[3][0] = tau[0][2]; + Flux_Tensor[4][0] = tau[0][0]*val_primvar[1] + tau[0][1]*val_primvar[2] + tau[0][2]*val_primvar[3] + + heat_flux_factor*val_gradprimvar[0][0]; + Flux_Tensor[0][1] = 0.0; + Flux_Tensor[1][1] = tau[1][0]; + Flux_Tensor[2][1] = tau[1][1]; + Flux_Tensor[3][1] = tau[1][2]; + Flux_Tensor[4][1] = tau[1][0]*val_primvar[1] + tau[1][1]*val_primvar[2] + tau[1][2]*val_primvar[3] + + heat_flux_factor*val_gradprimvar[0][1]; + Flux_Tensor[0][2] = 0.0; + Flux_Tensor[1][2] = tau[2][0]; + Flux_Tensor[2][2] = tau[2][1]; + Flux_Tensor[3][2] = tau[2][2]; + Flux_Tensor[4][2] = tau[2][0]*val_primvar[1] + tau[2][1]*val_primvar[2] + tau[2][2]*val_primvar[3] + + heat_flux_factor*val_gradprimvar[0][2]; + } + for (iVar = 0; iVar < nVar; iVar++) { + Proj_Flux_Tensor[iVar] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Proj_Flux_Tensor[iVar] += Flux_Tensor[iVar][iDim] * val_normal[iDim]; + } +} + +void CNumerics::GetViscousProjFlux(su2double *val_primvar, + su2double **val_gradprimvar, su2double val_turb_ke, + su2double *val_normal, + su2double val_laminar_viscosity, + su2double val_eddy_viscosity, + su2double val_thermal_conductivity, + su2double val_heat_capacity_cp) { + + unsigned short iVar, iDim, jDim; + su2double total_viscosity, heat_flux_factor, div_vel, Density; + Density = val_primvar[nDim+2]; + + total_viscosity = val_laminar_viscosity + val_eddy_viscosity; + heat_flux_factor = val_thermal_conductivity + val_heat_capacity_cp*val_eddy_viscosity/Prandtl_Turb; + + div_vel = 0.0; + for (iDim = 0 ; iDim < nDim; iDim++) + div_vel += val_gradprimvar[iDim+1][iDim]; + + for (iDim = 0 ; iDim < nDim; iDim++) + for (jDim = 0 ; jDim < nDim; jDim++) + tau[iDim][jDim] = total_viscosity*( val_gradprimvar[jDim+1][iDim] + val_gradprimvar[iDim+1][jDim] ) + - TWO3*total_viscosity*div_vel*delta[iDim][jDim] + - TWO3*Density*val_turb_ke*delta[iDim][jDim]; + + + /*--- Gradient of primitive variables -> [Temp vel_x vel_y vel_z Pressure] ---*/ + if (nDim == 2) { + Flux_Tensor[0][0] = 0.0; + Flux_Tensor[1][0] = tau[0][0]; + Flux_Tensor[2][0] = tau[0][1]; + Flux_Tensor[3][0] = tau[0][0]*val_primvar[1] + tau[0][1]*val_primvar[2]+ + heat_flux_factor*val_gradprimvar[0][0]; + + Flux_Tensor[0][1] = 0.0; + Flux_Tensor[1][1] = tau[1][0]; + Flux_Tensor[2][1] = tau[1][1]; + Flux_Tensor[3][1] = tau[1][0]*val_primvar[1] + tau[1][1]*val_primvar[2]+ + heat_flux_factor*val_gradprimvar[0][1]; + } else { + Flux_Tensor[0][0] = 0.0; + Flux_Tensor[1][0] = tau[0][0]; + Flux_Tensor[2][0] = tau[0][1]; + Flux_Tensor[3][0] = tau[0][2]; + Flux_Tensor[4][0] = tau[0][0]*val_primvar[1] + tau[0][1]*val_primvar[2] + tau[0][2]*val_primvar[3] + + heat_flux_factor*val_gradprimvar[0][0]; + + Flux_Tensor[0][1] = 0.0; + Flux_Tensor[1][1] = tau[1][0]; + Flux_Tensor[2][1] = tau[1][1]; + Flux_Tensor[3][1] = tau[1][2]; + Flux_Tensor[4][1] = tau[1][0]*val_primvar[1] + tau[1][1]*val_primvar[2] + tau[1][2]*val_primvar[3] + + heat_flux_factor*val_gradprimvar[0][1]; + + Flux_Tensor[0][2] = 0.0; + Flux_Tensor[1][2] = tau[2][0]; + Flux_Tensor[2][2] = tau[2][1]; + Flux_Tensor[3][2] = tau[2][2]; + Flux_Tensor[4][2] = tau[2][0]*val_primvar[1] + tau[2][1]*val_primvar[2] + tau[2][2]*val_primvar[3] + + heat_flux_factor*val_gradprimvar[0][2]; + } + + for (iVar = 0; iVar < nVar; iVar++) { + Proj_Flux_Tensor[iVar] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Proj_Flux_Tensor[iVar] += Flux_Tensor[iVar][iDim] * val_normal[iDim]; + } + +} + +void CNumerics::GetViscousArtCompProjFlux(su2double **val_gradprimvar, su2double *val_normal, su2double val_laminar_viscosity, + su2double val_eddy_viscosity) { + unsigned short iVar, iDim; + su2double total_viscosity; + + total_viscosity = (val_laminar_viscosity + val_eddy_viscosity); + + if (nDim == 3) { + Flux_Tensor[0][0] = 0.0; + Flux_Tensor[1][0] = total_viscosity * val_gradprimvar[1][0]; + Flux_Tensor[2][0] = total_viscosity * val_gradprimvar[2][0]; + Flux_Tensor[3][0] = total_viscosity * val_gradprimvar[3][0]; + + Flux_Tensor[0][1] = 0.0; + Flux_Tensor[1][1] = total_viscosity * val_gradprimvar[1][1]; + Flux_Tensor[2][1] = total_viscosity * val_gradprimvar[2][1]; + Flux_Tensor[3][1] = total_viscosity * val_gradprimvar[3][1]; + + Flux_Tensor[0][2] = 0.0; + Flux_Tensor[1][2] = total_viscosity * val_gradprimvar[1][2]; + Flux_Tensor[2][2] = total_viscosity * val_gradprimvar[2][2]; + Flux_Tensor[3][2] = total_viscosity * val_gradprimvar[3][2]; + } + + if (nDim == 2) { + Flux_Tensor[0][0] = 0.0; + Flux_Tensor[1][0] = total_viscosity * val_gradprimvar[1][0]; + Flux_Tensor[2][0] = total_viscosity * val_gradprimvar[2][0]; + + Flux_Tensor[0][1] = 0.0; + Flux_Tensor[1][1] = total_viscosity * val_gradprimvar[1][1]; + Flux_Tensor[2][1] = total_viscosity * val_gradprimvar[2][1]; + } + + for (iVar = 0; iVar < nVar; iVar++) { + Proj_Flux_Tensor[iVar] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Proj_Flux_Tensor[iVar] += Flux_Tensor[iVar][iDim] * val_normal[iDim]; + } +} + +void CNumerics::GetViscousProjJacs(su2double *val_Mean_PrimVar, su2double val_laminar_viscosity, + su2double val_eddy_viscosity, su2double val_dist_ij, su2double *val_normal, su2double val_dS, + su2double *val_Proj_Visc_Flux, su2double **val_Proj_Jac_Tensor_i, su2double **val_Proj_Jac_Tensor_j) { + unsigned short iDim, iVar, jVar; + + su2double theta = 0.0, sqvel = 0.0, proj_viscousflux_vel = 0.0; + + for (iDim = 0; iDim < nDim; iDim++) { + theta += val_normal[iDim]*val_normal[iDim]; + sqvel += val_Mean_PrimVar[iDim+1]*val_Mean_PrimVar[iDim+1]; + proj_viscousflux_vel += val_Proj_Visc_Flux[iDim+1]*val_Mean_PrimVar[iDim+1]; + } + + su2double phi = 0.5*(Gamma-1.0)*sqvel; + su2double Density = val_Mean_PrimVar[nDim+2]; + su2double Pressure = val_Mean_PrimVar[nDim+1]; + su2double total_viscosity = val_laminar_viscosity + val_eddy_viscosity; + su2double heat_flux_factor = val_laminar_viscosity/Prandtl_Lam + val_eddy_viscosity/Prandtl_Turb; + su2double cpoR = Gamma/(Gamma-1.0); // cp over R + su2double factor = total_viscosity*val_dS/(Density*val_dist_ij); + su2double phi_rho = -cpoR*heat_flux_factor*Pressure/(Density*Density); + su2double phi_p = cpoR*heat_flux_factor/(Density); + su2double rhoovisc = Density/(total_viscosity); // rho over viscosity + + for (unsigned short iVar = 0; iVar < nVar; iVar++) { + for (unsigned short jVar = 0; jVar < nVar; jVar++) { + val_Proj_Jac_Tensor_i[iVar][jVar] = 0.0; + val_Proj_Jac_Tensor_j[iVar][jVar] = 0.0; + } + } + + if (nDim == 2) { + + su2double thetax = theta + val_normal[0]*val_normal[0]/3.0; + su2double thetay = theta + val_normal[1]*val_normal[1]/3.0; + + su2double etaz = val_normal[0]*val_normal[1]/3.0; + + su2double pix = val_Mean_PrimVar[1]*thetax + val_Mean_PrimVar[2]*etaz; + su2double piy = val_Mean_PrimVar[1]*etaz + val_Mean_PrimVar[2]*thetay; + + val_Proj_Jac_Tensor_i[0][0] = 0.0; + val_Proj_Jac_Tensor_i[0][1] = 0.0; + val_Proj_Jac_Tensor_i[0][2] = 0.0; + val_Proj_Jac_Tensor_i[0][3] = 0.0; + val_Proj_Jac_Tensor_i[1][0] = factor*pix; + val_Proj_Jac_Tensor_i[1][1] = -factor*thetax; + val_Proj_Jac_Tensor_i[1][2] = -factor*etaz; + val_Proj_Jac_Tensor_i[1][3] = 0.0; + val_Proj_Jac_Tensor_i[2][0] = factor*piy; + val_Proj_Jac_Tensor_i[2][1] = -factor*etaz; + val_Proj_Jac_Tensor_i[2][2] = -factor*thetay; + val_Proj_Jac_Tensor_i[2][3] = 0.0; + + val_Proj_Jac_Tensor_i[3][0] = -factor*(rhoovisc*theta*(phi_rho+phi*phi_p)- (pix*val_Mean_PrimVar[1]+piy*val_Mean_PrimVar[2])); + val_Proj_Jac_Tensor_i[3][1] = -factor*(pix-rhoovisc*theta*phi_p*(Gamma-1.0)*val_Mean_PrimVar[1]); + val_Proj_Jac_Tensor_i[3][2] = -factor*(piy-rhoovisc*theta*phi_p*(Gamma-1.0)*val_Mean_PrimVar[2]); + val_Proj_Jac_Tensor_i[3][3] = -factor*((Gamma-1.0)*rhoovisc*theta*phi_p); + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + val_Proj_Jac_Tensor_j[iVar][jVar] = -val_Proj_Jac_Tensor_i[iVar][jVar]; + + factor = 0.5/Density; + val_Proj_Jac_Tensor_i[3][0] += factor*proj_viscousflux_vel; + val_Proj_Jac_Tensor_j[3][0] += factor*proj_viscousflux_vel; + val_Proj_Jac_Tensor_i[3][1] += factor*val_Proj_Visc_Flux[1]; + val_Proj_Jac_Tensor_j[3][1] += factor*val_Proj_Visc_Flux[1]; + val_Proj_Jac_Tensor_i[3][2] += factor*val_Proj_Visc_Flux[2]; + val_Proj_Jac_Tensor_j[3][2] += factor*val_Proj_Visc_Flux[2]; + + + } + else { + + su2double thetax = theta + val_normal[0]*val_normal[0]/3.0; + su2double thetay = theta + val_normal[1]*val_normal[1]/3.0; + su2double thetaz = theta + val_normal[2]*val_normal[2]/3.0; + + su2double etax = val_normal[1]*val_normal[2]/3.0; + su2double etay = val_normal[0]*val_normal[2]/3.0; + su2double etaz = val_normal[0]*val_normal[1]/3.0; + + su2double pix = val_Mean_PrimVar[1]*thetax + val_Mean_PrimVar[2]*etaz + val_Mean_PrimVar[3]*etay; + su2double piy = val_Mean_PrimVar[1]*etaz + val_Mean_PrimVar[2]*thetay + val_Mean_PrimVar[3]*etax; + su2double piz = val_Mean_PrimVar[1]*etay + val_Mean_PrimVar[2]*etax + val_Mean_PrimVar[3]*thetaz; + + val_Proj_Jac_Tensor_i[0][0] = 0.0; + val_Proj_Jac_Tensor_i[0][1] = 0.0; + val_Proj_Jac_Tensor_i[0][2] = 0.0; + val_Proj_Jac_Tensor_i[0][3] = 0.0; + val_Proj_Jac_Tensor_i[0][4] = 0.0; + val_Proj_Jac_Tensor_i[1][0] = factor*pix; + val_Proj_Jac_Tensor_i[1][1] = -factor*thetax; + val_Proj_Jac_Tensor_i[1][2] = -factor*etaz; + val_Proj_Jac_Tensor_i[1][3] = -factor*etay; + val_Proj_Jac_Tensor_i[1][4] = 0.0; + val_Proj_Jac_Tensor_i[2][0] = factor*piy; + val_Proj_Jac_Tensor_i[2][1] = -factor*etaz; + val_Proj_Jac_Tensor_i[2][2] = -factor*thetay; + val_Proj_Jac_Tensor_i[2][3] = -factor*etax; + val_Proj_Jac_Tensor_i[2][4] = 0.0; + val_Proj_Jac_Tensor_i[3][0] = factor*piz; + val_Proj_Jac_Tensor_i[3][1] = -factor*etay; + val_Proj_Jac_Tensor_i[3][2] = -factor*etax; + val_Proj_Jac_Tensor_i[3][3] = -factor*thetaz; + val_Proj_Jac_Tensor_i[3][4] = 0.0; + val_Proj_Jac_Tensor_i[4][0] = -factor*(rhoovisc*theta*(phi_rho+phi*phi_p) - (pix*val_Mean_PrimVar[1] + piy*val_Mean_PrimVar[2] + piz*val_Mean_PrimVar[3])); + val_Proj_Jac_Tensor_i[4][1] = -factor*(pix-rhoovisc*theta*phi_p*(Gamma-1)*val_Mean_PrimVar[1]); + val_Proj_Jac_Tensor_i[4][2] = -factor*(piy-rhoovisc*theta*phi_p*(Gamma-1)*val_Mean_PrimVar[2]); + val_Proj_Jac_Tensor_i[4][3] = -factor*(piz-rhoovisc*theta*phi_p*(Gamma-1)*val_Mean_PrimVar[3]); + val_Proj_Jac_Tensor_i[4][4] = -factor*((Gamma-1)*rhoovisc*theta*phi_p); + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + val_Proj_Jac_Tensor_j[iVar][jVar] = -val_Proj_Jac_Tensor_i[iVar][jVar]; + + factor = 0.5/Density; + val_Proj_Jac_Tensor_i[4][0] += factor*proj_viscousflux_vel; + val_Proj_Jac_Tensor_j[4][0] += factor*proj_viscousflux_vel; + val_Proj_Jac_Tensor_i[4][1] += factor*val_Proj_Visc_Flux[1]; + val_Proj_Jac_Tensor_j[4][1] += factor*val_Proj_Visc_Flux[1]; + val_Proj_Jac_Tensor_i[4][2] += factor*val_Proj_Visc_Flux[2]; + val_Proj_Jac_Tensor_j[4][2] += factor*val_Proj_Visc_Flux[2]; + val_Proj_Jac_Tensor_i[4][3] += factor*val_Proj_Visc_Flux[3]; + val_Proj_Jac_Tensor_j[4][3] += factor*val_Proj_Visc_Flux[3]; + + + + } + +// for (iVar = 0; iVar < nVar; iVar++) { +// for (jVar = 0; jVar < nVar; jVar++) { +// cout << val_Proj_Jac_Tensor_i[iVar][jVar] << " " << val_Proj_Jac_Tensor_j[iVar][jVar] << endl; +// } +// } +// getchar(); + +} + +void CNumerics::GetViscousProjJacs(su2double *val_Mean_PrimVar, + su2double **val_gradprimvar, + su2double *val_Mean_SecVar, + su2double val_laminar_viscosity, + su2double val_eddy_viscosity, + su2double val_thermal_conductivity, + su2double val_heat_capacity_cp, + su2double val_dist_ij, + su2double *val_normal, su2double val_dS, + su2double *val_Proj_Visc_Flux, + su2double **val_Proj_Jac_Tensor_i, + su2double **val_Proj_Jac_Tensor_j) { + + /* Viscous flux Jacobians for arbitrary equations of state */ + + //order of val_mean_primitives: T, vx, vy, vz, P, rho, ht + //order of secondary:dTdrho_e, dTde_rho + unsigned short iDim, iVar, jVar; + + su2double sqvel = 0.0, theta= 0.0, proj_viscousflux_vel= 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + theta += val_normal[iDim]*val_normal[iDim]; + sqvel += val_Mean_PrimVar[iDim+1]*val_Mean_PrimVar[iDim+1]; + proj_viscousflux_vel += val_Proj_Visc_Flux[iDim+1]*val_Mean_PrimVar[iDim+1]; + } + + su2double rho = val_Mean_PrimVar[nDim+2]; + su2double P= val_Mean_PrimVar[nDim+1]; + su2double h= val_Mean_PrimVar[nDim+3]; + su2double dTdrho_e= val_Mean_SecVar[0]; + su2double dTde_rho= val_Mean_SecVar[1]; + + + su2double dTdu0= dTdrho_e + dTde_rho*(-(h-P/rho) + sqvel)*(1/rho); + su2double dTdu1= dTde_rho*(-val_Mean_PrimVar[1])*(1/rho); + su2double dTdu2= dTde_rho*(-val_Mean_PrimVar[2])*(1/rho); + su2double total_viscosity = val_laminar_viscosity + val_eddy_viscosity; + su2double total_conductivity = val_thermal_conductivity + val_heat_capacity_cp*val_eddy_viscosity/Prandtl_Turb; + + + su2double factor1 = total_viscosity*val_dS/(rho*val_dist_ij); + su2double factor2 = total_conductivity*val_dS/val_dist_ij; + + + for (unsigned short iVar = 0; iVar < nVar; iVar++) { + for (unsigned short jVar = 0; jVar < nVar; jVar++) { + val_Proj_Jac_Tensor_i[iVar][jVar] = 0.0; + val_Proj_Jac_Tensor_j[iVar][jVar] = 0.0; + } + } + + if (nDim == 2) { + + /* 2D Jacobian: (Fv1, Fv2, Fv3, Fv4) --> (T, vx, vy, rho) */ + + su2double dTdu3= dTde_rho*(1/rho); + + su2double thetax = theta + val_normal[0]*val_normal[0]/3.0; + su2double thetay = theta + val_normal[1]*val_normal[1]/3.0; + + su2double etaz = val_normal[0]*val_normal[1]/3.0; + + su2double pix = val_Mean_PrimVar[1]*thetax + val_Mean_PrimVar[2]*etaz; + su2double piy = val_Mean_PrimVar[1]*etaz + val_Mean_PrimVar[2]*thetay; + + val_Proj_Jac_Tensor_i[0][0] = 0.0; + val_Proj_Jac_Tensor_i[0][1] = 0.0; + val_Proj_Jac_Tensor_i[0][2] = 0.0; + val_Proj_Jac_Tensor_i[0][3] = 0.0; + val_Proj_Jac_Tensor_i[1][0] = factor1*pix; + val_Proj_Jac_Tensor_i[1][1] = -factor1*thetax; + val_Proj_Jac_Tensor_i[1][2] = -factor1*etaz; + val_Proj_Jac_Tensor_i[1][3] = 0.0; + val_Proj_Jac_Tensor_i[2][0] = factor1*piy; + val_Proj_Jac_Tensor_i[2][1] = -factor1*etaz; + val_Proj_Jac_Tensor_i[2][2] = -factor1*thetay; + val_Proj_Jac_Tensor_i[2][3] = 0.0; + + val_Proj_Jac_Tensor_i[3][0] = val_Proj_Jac_Tensor_i[1][0]*val_Mean_PrimVar[1]+val_Proj_Jac_Tensor_i[2][0]*val_Mean_PrimVar[2]; + val_Proj_Jac_Tensor_i[3][0] += -factor2*theta*dTdu0; + val_Proj_Jac_Tensor_i[3][1] = val_Proj_Jac_Tensor_i[1][1]*val_Mean_PrimVar[1]+val_Proj_Jac_Tensor_i[2][1]*val_Mean_PrimVar[2]; + val_Proj_Jac_Tensor_i[3][1] += -factor2*theta*dTdu1; + val_Proj_Jac_Tensor_i[3][2] = val_Proj_Jac_Tensor_i[1][2]*val_Mean_PrimVar[1]+val_Proj_Jac_Tensor_i[2][2]*val_Mean_PrimVar[2]; + val_Proj_Jac_Tensor_i[3][2] += -factor2*theta*dTdu2; + val_Proj_Jac_Tensor_i[3][3] = -factor2*theta*dTdu3; + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + val_Proj_Jac_Tensor_j[iVar][jVar] = -val_Proj_Jac_Tensor_i[iVar][jVar]; + + su2double factor = 0.5/rho; + val_Proj_Jac_Tensor_i[3][0] -= factor*proj_viscousflux_vel; + val_Proj_Jac_Tensor_j[3][0] -= factor*proj_viscousflux_vel; + val_Proj_Jac_Tensor_i[3][1] += factor*val_Proj_Visc_Flux[1]; + val_Proj_Jac_Tensor_j[3][1] += factor*val_Proj_Visc_Flux[1]; + val_Proj_Jac_Tensor_i[3][2] += factor*val_Proj_Visc_Flux[2]; + val_Proj_Jac_Tensor_j[3][2] += factor*val_Proj_Visc_Flux[2]; + + + + + } else { + + + su2double dTdu3= dTde_rho*(-val_Mean_PrimVar[3])*(1/rho); + su2double dTdu4= dTde_rho*(1/rho); + + su2double thetax = theta + val_normal[0]*val_normal[0]/3.0; + su2double thetay = theta + val_normal[1]*val_normal[1]/3.0; + su2double thetaz = theta + val_normal[2]*val_normal[2]/3.0; + + su2double etax = val_normal[1]*val_normal[2]/3.0; + su2double etay = val_normal[0]*val_normal[2]/3.0; + su2double etaz = val_normal[0]*val_normal[1]/3.0; + + su2double pix = val_Mean_PrimVar[1]*thetax + val_Mean_PrimVar[2]*etaz + val_Mean_PrimVar[3]*etay; + su2double piy = val_Mean_PrimVar[1]*etaz + val_Mean_PrimVar[2]*thetay + val_Mean_PrimVar[3]*etax; + su2double piz = val_Mean_PrimVar[1]*etay + val_Mean_PrimVar[2]*etax + val_Mean_PrimVar[3]*thetaz; + + val_Proj_Jac_Tensor_i[0][0] = 0.0; + val_Proj_Jac_Tensor_i[0][1] = 0.0; + val_Proj_Jac_Tensor_i[0][2] = 0.0; + val_Proj_Jac_Tensor_i[0][3] = 0.0; + val_Proj_Jac_Tensor_i[0][4] = 0.0; + val_Proj_Jac_Tensor_i[1][0] = factor1*pix; + val_Proj_Jac_Tensor_i[1][1] = -factor1*thetax; + val_Proj_Jac_Tensor_i[1][2] = -factor1*etaz; + val_Proj_Jac_Tensor_i[1][3] = -factor1*etay; + val_Proj_Jac_Tensor_i[1][4] = 0.0; + val_Proj_Jac_Tensor_i[2][0] = factor1*piy; + val_Proj_Jac_Tensor_i[2][1] = -factor1*etaz; + val_Proj_Jac_Tensor_i[2][2] = -factor1*thetay; + val_Proj_Jac_Tensor_i[2][3] = -factor1*etax; + val_Proj_Jac_Tensor_i[2][4] = 0.0; + val_Proj_Jac_Tensor_i[3][0] = factor1*piz; + val_Proj_Jac_Tensor_i[3][1] = -factor1*etay; + val_Proj_Jac_Tensor_i[3][2] = -factor1*etax; + val_Proj_Jac_Tensor_i[3][3] = -factor1*thetaz; + val_Proj_Jac_Tensor_i[3][4] = 0.0; + val_Proj_Jac_Tensor_i[4][0] = val_Proj_Jac_Tensor_i[1][0]*val_Mean_PrimVar[1]+val_Proj_Jac_Tensor_i[2][0]*val_Mean_PrimVar[2]+val_Proj_Jac_Tensor_i[3][0]*val_Mean_PrimVar[3]; + val_Proj_Jac_Tensor_i[4][0] += -factor2*theta*dTdu0; + val_Proj_Jac_Tensor_i[4][1] = val_Proj_Jac_Tensor_i[1][1]*val_Mean_PrimVar[1]+val_Proj_Jac_Tensor_i[2][1]*val_Mean_PrimVar[2]+val_Proj_Jac_Tensor_i[3][1]*val_Mean_PrimVar[3]; + val_Proj_Jac_Tensor_i[4][1] += -factor2*theta*dTdu1; + val_Proj_Jac_Tensor_i[4][2] = val_Proj_Jac_Tensor_i[1][2]*val_Mean_PrimVar[1]+val_Proj_Jac_Tensor_i[2][2]*val_Mean_PrimVar[2]+val_Proj_Jac_Tensor_i[3][2]*val_Mean_PrimVar[3]; + val_Proj_Jac_Tensor_i[4][2] += -factor2*theta*dTdu2; + val_Proj_Jac_Tensor_i[4][3] = val_Proj_Jac_Tensor_i[1][3]*val_Mean_PrimVar[1]+val_Proj_Jac_Tensor_i[2][3]*val_Mean_PrimVar[2]+val_Proj_Jac_Tensor_i[3][3]*val_Mean_PrimVar[3]; + val_Proj_Jac_Tensor_i[4][3] += -factor2*theta*dTdu3; + val_Proj_Jac_Tensor_i[4][4] = -factor2*theta*dTdu4; + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + val_Proj_Jac_Tensor_j[iVar][jVar] = -val_Proj_Jac_Tensor_i[iVar][jVar]; + + su2double factor = 0.5/rho; + val_Proj_Jac_Tensor_i[4][0] -= factor*proj_viscousflux_vel; + val_Proj_Jac_Tensor_j[4][0] -= factor*proj_viscousflux_vel; + val_Proj_Jac_Tensor_i[4][1] += factor*val_Proj_Visc_Flux[1]; + val_Proj_Jac_Tensor_j[4][1] += factor*val_Proj_Visc_Flux[1]; + val_Proj_Jac_Tensor_i[4][2] += factor*val_Proj_Visc_Flux[2]; + val_Proj_Jac_Tensor_j[4][2] += factor*val_Proj_Visc_Flux[2]; + val_Proj_Jac_Tensor_i[4][3] += factor*val_Proj_Visc_Flux[3]; + val_Proj_Jac_Tensor_j[4][3] += factor*val_Proj_Visc_Flux[3]; + + + + + } + + + + } + + + + + +//void CNumerics::GetViscousProjJacs(su2double *val_Mean_PrimVar, +// su2double **val_gradprimvar, +// su2double *val_Mean_SecVar, +// su2double val_laminar_viscosity, +// su2double val_eddy_viscosity, +// su2double val_thermal_conductivity, +// su2double val_heat_capacity_cp, +// su2double val_dist_ij, +// su2double *val_normal, su2double val_dS, +// su2double *val_Proj_Visc_Flux, +// su2double **val_Proj_Jac_Tensor_i, +// su2double **val_Proj_Jac_Tensor_j) { +// +// /* Viscous flux Jacobians for arbitrary equations of state */ +// +// // order of primitives: T, vx, vy, vz, P, rho, h, c, MuLam, MuEddy, kt, Cp +// // order of secondary: dPdrho_e, dPde_rho, dTdrho_e, dTde_rho, dmudrho_T, dmudT_rho, dktdrho_T, dktdT_rho +// +// unsigned short iDim, iVar, jVar; +// su2double **val_Proj_Jac_Tensor_i_P, **val_Proj_Jac_Tensor_j_P; +// su2double **val_Jac_PC; +// +// su2double sqvel = 0.0; +// for (iDim = 0; iDim < nDim; iDim++) { +// sqvel += val_Mean_PrimVar[iDim+1]*val_Mean_PrimVar[iDim+1]; +// } +// +// su2double vx = val_Mean_PrimVar[1]; +// su2double vy = val_Mean_PrimVar[2]; +// su2double vz = val_Mean_PrimVar[3]; +// su2double rho = val_Mean_PrimVar[nDim+2]; +// su2double P = val_Mean_PrimVar[nDim+1]; +// su2double dmudrho_T = val_Mean_SecVar[4]; +// su2double dmudT_rho = val_Mean_SecVar[5]; +// su2double dktdrho_T = val_Mean_SecVar[6]; +// su2double dktdT_rho = val_Mean_SecVar[7]; +// +// su2double total_viscosity = val_laminar_viscosity + val_eddy_viscosity; +// su2double total_conductivity = val_thermal_conductivity + val_heat_capacity_cp*val_eddy_viscosity/Prandtl_Turb; +// +// val_Proj_Jac_Tensor_i_P = new su2double* [nVar]; +// val_Proj_Jac_Tensor_j_P = new su2double* [nVar]; +// val_Jac_PC = new su2double* [nVar]; +// +// for (unsigned short iVar = 0; iVar < nVar; iVar++) { +// val_Proj_Jac_Tensor_i_P[iVar] = new su2double [nVar]; +// val_Proj_Jac_Tensor_j_P[iVar] = new su2double [nVar]; +// val_Jac_PC[iVar] = new su2double [nVar]; +// } +// +// for (unsigned short iVar = 0; iVar < nVar; iVar++) { +// for (unsigned short jVar = 0; jVar < nVar; jVar++) { +// val_Proj_Jac_Tensor_i[iVar][jVar] = 0.0; +// val_Proj_Jac_Tensor_j[iVar][jVar] = 0.0; +// val_Proj_Jac_Tensor_i_P[iVar][jVar] = 0.0; +// val_Proj_Jac_Tensor_j_P[iVar][jVar] = 0.0; +// val_Jac_PC[iVar][jVar] = 0.0; +// } +// } +// +// if (nDim == 2) { +// +// /* 2D Jacobian: (Fv1, Fv2, Fv3, Fv4) --> (T, vx, vy, rho) */ +// +// su2double factor1 = 4.0/3.0*pow(val_normal[0],2) + pow(val_normal[1],2); +// su2double factor2 = 1.0/3.0*val_normal[0]*val_normal[1]; +// su2double factor3 = 4.0/3.0*pow(val_normal[1],2) + pow(val_normal[0],2); +// +// val_Proj_Jac_Tensor_i_P[0][0] = 0.0; +// val_Proj_Jac_Tensor_i_P[0][1] = 0.0; +// val_Proj_Jac_Tensor_i_P[0][2] = 0.0; +// val_Proj_Jac_Tensor_i_P[0][3] = 0.0; +// +// val_Proj_Jac_Tensor_i_P[1][0] = 0.5*dmudT_rho*val_Proj_Visc_Flux[1]/total_viscosity; +// val_Proj_Jac_Tensor_i_P[1][1] = -total_viscosity/val_dist_ij*factor1; +// val_Proj_Jac_Tensor_i_P[1][2] = -total_viscosity/val_dist_ij*factor2; +// val_Proj_Jac_Tensor_i_P[1][3] = 0.5*dmudrho_T*val_Proj_Visc_Flux[1]/total_viscosity; +// +// val_Proj_Jac_Tensor_i_P[2][0] = 0.5*dmudT_rho*val_Proj_Visc_Flux[2]/total_viscosity; +// val_Proj_Jac_Tensor_i_P[2][1] = -total_viscosity/val_dist_ij*factor2; +// val_Proj_Jac_Tensor_i_P[2][2] = -total_viscosity/val_dist_ij*factor3; +// val_Proj_Jac_Tensor_i_P[2][3] = 0.5*dmudrho_T*val_Proj_Visc_Flux[2]/total_viscosity; +// +// val_Proj_Jac_Tensor_i_P[3][0] = vx*val_Proj_Jac_Tensor_i_P[1][0] + vy*val_Proj_Jac_Tensor_i_P[2][0]; +// val_Proj_Jac_Tensor_i_P[3][1] = vx*val_Proj_Jac_Tensor_i_P[1][1] + vy*val_Proj_Jac_Tensor_i_P[2][1]; +// val_Proj_Jac_Tensor_i_P[3][2] = vx*val_Proj_Jac_Tensor_i_P[1][2] + vy*val_Proj_Jac_Tensor_i_P[2][2]; +// val_Proj_Jac_Tensor_i_P[3][3] = vx*val_Proj_Jac_Tensor_i_P[1][3] + vy*val_Proj_Jac_Tensor_i_P[2][3]; +// +// su2double etax = pow(val_normal[0],2)/val_dist_ij; +// su2double etay = pow(val_normal[1],2)/val_dist_ij; +// val_Proj_Jac_Tensor_i_P[3][0] += -total_conductivity*etax + 0.5*val_normal[0]*dktdT_rho*val_gradprimvar[0][0] - total_conductivity*etay + 0.5*val_normal[1]*dktdT_rho*val_gradprimvar[0][1]; +// val_Proj_Jac_Tensor_i_P[3][1] += 1.0/2.0*val_Proj_Visc_Flux[1]; +// val_Proj_Jac_Tensor_i_P[3][2] += 1.0/2.0*val_Proj_Visc_Flux[2]; +// val_Proj_Jac_Tensor_i_P[3][3] += 0.5*val_normal[0]*dktdrho_T*val_gradprimvar[0][0] +0.5*val_normal[1]*dktdrho_T*val_gradprimvar[0][1]; +// +// for (iVar = 0; iVar < nVar; iVar++) { +// for (jVar = 0; jVar < nVar; jVar++) { +// val_Proj_Jac_Tensor_i_P[iVar][jVar] *= val_dS; +// val_Proj_Jac_Tensor_j_P[iVar][jVar] = -val_Proj_Jac_Tensor_i_P[iVar][jVar]; /*Jacobian j*/ +// } +// } +// +// /* 2D Jacobian: (T, vx, vy, rho) --> (u1, u2, u3, u4) */ +// GetPrimitive2Conservative (val_Mean_PrimVar, val_Mean_SecVar, val_Jac_PC); +// +// /* 2D Jacobian: (Fv1, Fv2, Fv3, Fv4) --> (u1, u2, u3, u4) */ +// for (iVar = 0; iVar < nVar; iVar++) { +// for (jVar = 0; jVar < nVar; jVar++) { +// for (unsigned short kVar = 0; kVar < nVar; kVar++) { +// val_Proj_Jac_Tensor_i[iVar][jVar] += val_Proj_Jac_Tensor_i_P[iVar][kVar]*val_Jac_PC[kVar][jVar]; +// val_Proj_Jac_Tensor_j[iVar][jVar] += val_Proj_Jac_Tensor_j_P[iVar][kVar]*val_Jac_PC[kVar][jVar]; +// } +// } +// } +// +//// for (iVar = 0; iVar < nVar; iVar++) { +//// for (jVar = 0; jVar < nVar; jVar++) { +//// cout << val_Proj_Jac_Tensor_i[iVar][jVar] << " " << val_Proj_Jac_Tensor_j[iVar][jVar] << endl; +//// } +//// } +//// getchar(); +// +// } +// else { +// +// /* 3D Jacobian: (Fv1, Fv2, Fv3, Fv4, Fv5) --> (T, vx, vy, vz, rho) */ +// +//// su2double factor1 = 4.0/3.0*pow(val_normal[0],2) + pow(val_normal[1],2) + pow(val_normal[2],2); +//// su2double factor2 = 1.0/3.0*val_normal[0]*val_normal[1]; +//// su2double factor3 = 1.0/3.0*val_normal[0]*val_normal[2]; +//// su2double factor4 = pow(val_normal[0],2) + 4.0/3.0*pow(val_normal[1],2) + pow(val_normal[2],2); +//// su2double factor5 = 1.0/3.0*val_normal[1]*val_normal[2]; +//// su2double factor6 = pow(val_normal[0],2) + pow(val_normal[1],2) + 4.0/3.0*pow(val_normal[2],2); +// +// su2double thetax = 4.0/3.0*pow(val_normal[0],2) + pow(val_normal[1],2) + pow(val_normal[2],2); +// su2double thetay = pow(val_normal[0],2) + 4.0/3.0*pow(val_normal[1],2) + pow(val_normal[2],2); +// su2double thetaz = pow(val_normal[0],2) + pow(val_normal[1],2) + 4.0/3.0*pow(val_normal[2],2); +// su2double pix = 1.0/3.0*val_normal[0]*val_normal[1]; +// su2double piy = 1.0/3.0*val_normal[0]*val_normal[2]; +// su2double piz = 1.0/3.0*val_normal[1]*val_normal[2]; +// +// val_Proj_Jac_Tensor_i_P[0][0] = 0.0; +// val_Proj_Jac_Tensor_i_P[0][1] = 0.0; +// val_Proj_Jac_Tensor_i_P[0][2] = 0.0; +// val_Proj_Jac_Tensor_i_P[0][3] = 0.0; +// val_Proj_Jac_Tensor_i_P[0][4] = 0.0; +// +// val_Proj_Jac_Tensor_i_P[1][0] = 0.5*dmudT_rho*val_Proj_Visc_Flux[1]/total_viscosity; +// val_Proj_Jac_Tensor_i_P[1][1] = -total_viscosity/val_dist_ij*thetax; +// val_Proj_Jac_Tensor_i_P[1][2] = -total_viscosity/val_dist_ij*pix; +// val_Proj_Jac_Tensor_i_P[1][3] = -total_viscosity/val_dist_ij*piy; +// val_Proj_Jac_Tensor_i_P[1][4] = 0.5*dmudrho_T*val_Proj_Visc_Flux[1]/total_viscosity; +// +// val_Proj_Jac_Tensor_i_P[2][0] = 0.5*dmudT_rho*val_Proj_Visc_Flux[2]/total_viscosity; +// val_Proj_Jac_Tensor_i_P[2][1] = -total_viscosity/val_dist_ij*pix; +// val_Proj_Jac_Tensor_i_P[2][2] = -total_viscosity/val_dist_ij*thetay; +// val_Proj_Jac_Tensor_i_P[2][3] = -total_viscosity/val_dist_ij*piz; +// val_Proj_Jac_Tensor_i_P[2][4] = 0.5*dmudrho_T*val_Proj_Visc_Flux[2]/total_viscosity; +// +// val_Proj_Jac_Tensor_i_P[3][0] = 0.5*dmudT_rho*val_Proj_Visc_Flux[3]/total_viscosity; +// val_Proj_Jac_Tensor_i_P[3][1] = -total_viscosity/val_dist_ij*piy; +// val_Proj_Jac_Tensor_i_P[3][2] = -total_viscosity/val_dist_ij*piz; +// val_Proj_Jac_Tensor_i_P[3][3] = -total_viscosity/val_dist_ij*thetaz; +// val_Proj_Jac_Tensor_i_P[3][4] = 0.5*dmudrho_T*val_Proj_Visc_Flux[3]/total_viscosity; +// +// val_Proj_Jac_Tensor_i_P[4][0] = vx*val_Proj_Jac_Tensor_i_P[1][0] + vy*val_Proj_Jac_Tensor_i_P[2][0] + vz*val_Proj_Jac_Tensor_i_P[3][0]; +// val_Proj_Jac_Tensor_i_P[4][1] = vx*val_Proj_Jac_Tensor_i_P[1][1] + vy*val_Proj_Jac_Tensor_i_P[2][1] + vz*val_Proj_Jac_Tensor_i_P[3][1]; +// val_Proj_Jac_Tensor_i_P[4][2] = vx*val_Proj_Jac_Tensor_i_P[1][2] + vy*val_Proj_Jac_Tensor_i_P[2][2] + vz*val_Proj_Jac_Tensor_i_P[3][2]; +// val_Proj_Jac_Tensor_i_P[4][3] = vx*val_Proj_Jac_Tensor_i_P[1][3] + vy*val_Proj_Jac_Tensor_i_P[2][3] + vz*val_Proj_Jac_Tensor_i_P[3][3]; +// val_Proj_Jac_Tensor_i_P[4][4] = vx*val_Proj_Jac_Tensor_i_P[1][4] + vy*val_Proj_Jac_Tensor_i_P[2][4] + vz*val_Proj_Jac_Tensor_i_P[3][4]; +// +// su2double etax = pow(val_normal[0],2)/val_dist_ij; +// su2double etay = pow(val_normal[1],2)/val_dist_ij; +// su2double etaz = pow(val_normal[2],2)/val_dist_ij; +// val_Proj_Jac_Tensor_i_P[4][0] += -total_conductivity*etax - total_conductivity*etay - total_conductivity*etaz; +// val_Proj_Jac_Tensor_i_P[4][1] += 1.0/2.0*val_Proj_Visc_Flux[1]; +// val_Proj_Jac_Tensor_i_P[4][2] += 1.0/2.0*val_Proj_Visc_Flux[2]; +// val_Proj_Jac_Tensor_i_P[4][3] += 1.0/2.0*val_Proj_Visc_Flux[3]; +// +// val_Proj_Jac_Tensor_i_P[4][0] += 0.5*val_normal[0]*dktdT_rho*val_gradprimvar[0][0] + 0.5*val_normal[1]*dktdT_rho*val_gradprimvar[0][1] + 0.5*val_normal[2]*dktdT_rho*val_gradprimvar[0][2]; +// val_Proj_Jac_Tensor_i_P[4][4] += 0.5*val_normal[0]*dktdrho_T*val_gradprimvar[0][0] + 0.5*val_normal[1]*dktdrho_T*val_gradprimvar[0][1] + 0.5*val_normal[2]*dktdrho_T*val_gradprimvar[0][2]; +// +// for (iVar = 0; iVar < nVar; iVar++) { +// for (jVar = 0; jVar < nVar; jVar++) { +// val_Proj_Jac_Tensor_i_P[iVar][jVar] *= val_dS; +// val_Proj_Jac_Tensor_j_P[iVar][jVar] = -val_Proj_Jac_Tensor_i_P[iVar][jVar]; /*Jacobian j*/ +// } +// } +// +// /* 3D Jacobian: (T, vx, vy, vz, rho) --> (u1, u2, u3, u4, u5) */ +// GetPrimitive2Conservative (val_Mean_PrimVar, val_Mean_SecVar, val_Jac_PC); +// +// /* 3D Jacobian: (Fv1, Fv2, Fv3, Fv4, Fv5) --> (u1, u2, u3, u4, u5) */ +// for (iVar = 0; iVar < nVar; iVar++) { +// for (jVar = 0; jVar < nVar; jVar++) { +// for (unsigned short kVar = 0; kVar < nVar; kVar++) { +// val_Proj_Jac_Tensor_i[iVar][jVar] += val_Proj_Jac_Tensor_i_P[iVar][kVar]*val_Jac_PC[kVar][jVar]; +// val_Proj_Jac_Tensor_j[iVar][jVar] += val_Proj_Jac_Tensor_j_P[iVar][kVar]*val_Jac_PC[kVar][jVar]; +// } +// } +// } +// +//// for (iVar = 0; iVar < nVar; iVar++) { +//// for (jVar = 0; jVar < nVar; jVar++) { +//// cout << val_Proj_Jac_Tensor_i[iVar][jVar] << " " << val_Proj_Jac_Tensor_j[iVar][jVar] << endl; +//// } +//// } +//// getchar(); +// +// } +// +// /*--- Deallocate ---*/ +// for (unsigned short iVar = 0; iVar < nVar; iVar++) { +// delete [] val_Proj_Jac_Tensor_i_P[iVar]; +// delete [] val_Proj_Jac_Tensor_j_P[iVar]; +// delete [] val_Jac_PC[iVar]; +// } +// delete [] val_Proj_Jac_Tensor_i_P; +// delete [] val_Proj_Jac_Tensor_j_P; +// delete [] val_Jac_PC; +// +//} + +void CNumerics::GetPrimitive2Conservative (su2double *val_Mean_PrimVar, su2double *val_Mean_SecVar, su2double **val_Jac_PC) { + + unsigned short iVar, jVar, iDim; + + // order of primitives: T, vx, vy, vz, P, rho, h, c, MuLam, MuEddy, kt, Cp + // order of secondary: dPdrho_e, dPde_rho, dTdrho_e, dTde_rho, dmudrho_T, dmudT_rho, dktdrho_T, dktdT_rho + + su2double vx = val_Mean_PrimVar[1]; + su2double vy = val_Mean_PrimVar[2]; + su2double vz = val_Mean_PrimVar[3]; + su2double rho = val_Mean_PrimVar[nDim+2]; + su2double P = val_Mean_PrimVar[nDim+1]; + su2double e = val_Mean_PrimVar[nDim+3] - P/rho; + su2double dTdrho_e = val_Mean_SecVar[2]; + su2double dTde_rho = val_Mean_SecVar[3]; + + su2double sqvel = 0.0; + + for (iDim = 0; iDim < nDim; iDim++) { + sqvel += val_Mean_PrimVar[iDim+1]*val_Mean_PrimVar[iDim+1]; + } + + /*--- Initialize the Jacobian matrix ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + for (jVar = 0; jVar < nVar; jVar++) { + val_Jac_PC[iVar][jVar] = 0.0; + } + } + + /*--- Primitives to conservatives Jacobian matrix : (T, vx, vy, vz, rho) --> (u1, u2, u3, u4, u5) ---*/ + if (nDim == 2) { + + val_Jac_PC[0][0] = dTdrho_e - e/rho*dTde_rho + 0.5*dTde_rho*sqvel/rho; + val_Jac_PC[0][1] = -1/rho*dTde_rho*vx; + val_Jac_PC[0][2] = -1/rho*dTde_rho*vy; + val_Jac_PC[0][3] = 1/rho*dTde_rho; + + val_Jac_PC[1][0] = -vx/rho; + val_Jac_PC[1][1] = 1/rho; + val_Jac_PC[1][2] = 0.0; + val_Jac_PC[1][3] = 0.0; + + val_Jac_PC[2][0] = -vy/rho; + val_Jac_PC[2][1] = 0.0; + val_Jac_PC[2][2] = 1/rho; + val_Jac_PC[2][3] = 0.0; + + val_Jac_PC[3][0] = 1.0; + val_Jac_PC[3][1] = 0.0; + val_Jac_PC[3][2] = 0.0; + val_Jac_PC[3][3] = 0.0; + + } + else { + + val_Jac_PC[0][0] = dTdrho_e - e/rho*dTde_rho + 0.5*dTde_rho*sqvel/rho; + val_Jac_PC[0][1] = -1/rho*dTde_rho*vx; + val_Jac_PC[0][2] = -1/rho*dTde_rho*vy; + val_Jac_PC[0][3] = -1/rho*dTde_rho*vz; + val_Jac_PC[0][4] = 1/rho*dTde_rho; + + val_Jac_PC[1][0] = -vx/rho; + val_Jac_PC[1][1] = 1/rho; + val_Jac_PC[1][2] = 0.0; + val_Jac_PC[1][3] = 0.0; + val_Jac_PC[1][4] = 0.0; + + val_Jac_PC[2][0] = -vy/rho; + val_Jac_PC[2][1] = 0.0; + val_Jac_PC[2][2] = 1/rho; + val_Jac_PC[2][3] = 0.0; + val_Jac_PC[2][4] = 0.0; + + val_Jac_PC[3][0] = -vz/rho; + val_Jac_PC[3][1] = 0.0; + val_Jac_PC[3][2] = 0.0; + val_Jac_PC[3][3] = 1/rho; + val_Jac_PC[3][4] = 0.0; + + val_Jac_PC[4][0] = 1.0; + val_Jac_PC[4][1] = 0.0; + val_Jac_PC[4][2] = 0.0; + val_Jac_PC[4][3] = 0.0; + val_Jac_PC[4][4] = 0.0; + + } +} + +void CNumerics::GetViscousArtCompProjJacs(su2double val_laminar_viscosity, + su2double val_eddy_viscosity, su2double val_dist_ij, su2double *val_normal, su2double val_dS, + su2double **val_Proj_Jac_Tensor_i, su2double **val_Proj_Jac_Tensor_j) { + unsigned short iDim, iVar, jVar; + + su2double theta = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + theta += val_normal[iDim]*val_normal[iDim]; + + su2double total_viscosity = val_laminar_viscosity + val_eddy_viscosity; + su2double factor = total_viscosity/(val_dist_ij)*val_dS; + + if (nDim == 3) { + su2double thetax = theta + val_normal[0]*val_normal[0]/3.0; + su2double thetay = theta + val_normal[1]*val_normal[1]/3.0; + su2double thetaz = theta + val_normal[2]*val_normal[2]/3.0; + + su2double etax = val_normal[1]*val_normal[2]/3.0; + su2double etay = val_normal[0]*val_normal[2]/3.0; + su2double etaz = val_normal[0]*val_normal[1]/3.0; + + val_Proj_Jac_Tensor_i[0][0] = 0.0; + val_Proj_Jac_Tensor_i[0][1] = 0.0; + val_Proj_Jac_Tensor_i[0][2] = 0.0; + val_Proj_Jac_Tensor_i[0][3] = 0.0; + val_Proj_Jac_Tensor_i[1][0] = 0.0; + val_Proj_Jac_Tensor_i[1][1] = -factor*thetax; + val_Proj_Jac_Tensor_i[1][2] = -factor*etaz; + val_Proj_Jac_Tensor_i[1][3] = -factor*etay; + val_Proj_Jac_Tensor_i[2][0] = 0.0; + val_Proj_Jac_Tensor_i[2][1] = -factor*etaz; + val_Proj_Jac_Tensor_i[2][2] = -factor*thetay; + val_Proj_Jac_Tensor_i[2][3] = -factor*etax; + val_Proj_Jac_Tensor_i[3][0] = 0.0; + val_Proj_Jac_Tensor_i[3][1] = -factor*etay; + val_Proj_Jac_Tensor_i[3][2] = -factor*etax; + val_Proj_Jac_Tensor_i[3][3] = -factor*thetaz; + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + val_Proj_Jac_Tensor_j[iVar][jVar] = -val_Proj_Jac_Tensor_i[iVar][jVar]; + + } + + if (nDim == 2) { + su2double thetax = theta + val_normal[0]*val_normal[0]/3.0; + su2double thetay = theta + val_normal[1]*val_normal[1]/3.0; + su2double etaz = val_normal[0]*val_normal[1]/3.0; + + val_Proj_Jac_Tensor_i[0][0] = 0.0; + val_Proj_Jac_Tensor_i[0][1] = 0.0; + val_Proj_Jac_Tensor_i[0][2] = 0.0; + val_Proj_Jac_Tensor_i[1][0] = 0.0; + val_Proj_Jac_Tensor_i[1][1] = -factor*thetax; + val_Proj_Jac_Tensor_i[1][2] = -factor*etaz; + val_Proj_Jac_Tensor_i[2][0] = 0.0; + val_Proj_Jac_Tensor_i[2][1] = -factor*etaz; + val_Proj_Jac_Tensor_i[2][2] = -factor*thetay; + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + val_Proj_Jac_Tensor_j[iVar][jVar] = -val_Proj_Jac_Tensor_i[iVar][jVar]; + } + +} + +void CNumerics::CreateBasis(su2double *val_Normal) { + unsigned short iDim; + su2double modm, modl; + + /*--- Define l as a vector in the plane normal to the supplied vector ---*/ + l[0] = 0.0; + l[1] = -val_Normal[2]; + l[2] = val_Normal[1]; + + /*--- Check for the zero vector and re-assign if needed ---*/ + if (l[0] == 0.0 && l[1] == 0.0 && l[2] == 0.0) { + l[0] = -val_Normal[2]; + l[1] = 0.0; + l[2] = val_Normal[0]; + } + + /*--- Take vector product of n * l to make m ---*/ + m[0] = val_Normal[1]*l[2] - val_Normal[2]*l[1]; + m[1] = val_Normal[2]*l[0] - val_Normal[0]*l[2]; + m[2] = val_Normal[0]*l[1] - val_Normal[1]*l[0]; + + /*--- Normalize ---*/ + modm =0 ; modl = 0; + for (iDim =0 ; iDim < nDim; iDim++) { + modm += m[iDim]*m[iDim]; + modl += l[iDim]*l[iDim]; + } + modm = sqrt(modm); + modl = sqrt(modl); + for (iDim =0 ; iDim < nDim; iDim++) { + l[iDim] = l[iDim]/modl; + m[iDim] = m[iDim]/modm; + } +} + +CSourceNothing::CSourceNothing(unsigned short val_nDim, unsigned short val_nVar, CConfig *config) : CNumerics(val_nDim, val_nVar, config) { } + +CSourceNothing::~CSourceNothing(void) { } diff --git a/SU2_CFD/src/output_cgns.cpp b/SU2_CFD/src/output_cgns.cpp index 8a2b2f48e7a..21097e0c41d 100644 --- a/SU2_CFD/src/output_cgns.cpp +++ b/SU2_CFD/src/output_cgns.cpp @@ -1,513 +1,513 @@ -/*! - * \file output_cgns.cpp - * \brief Main subroutines for output solver information - * \author T. Economon, M. Colonno - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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_structure.hpp" - -void COutput::SetCGNS_Coordinates(CConfig *config, CGeometry *geometry, unsigned short iZone) { - -#ifdef HAVE_CGNS - - /*--- local CGNS variables ---*/ - int cgns_file, cgns_coord, element_dims, physical_dims, cgns_err; - unsigned long iExtIter = config->GetExtIter(); - string base_file, buffer, elements_name; - stringstream name, results_file; - bool unsteady = config->GetUnsteady_Simulation(); - cgsize_t isize[3][1]; - - /*--- Create CGNS base file name ---*/ - base_file = config->GetFlow_FileName(); - - /*--- Add CGNS extension. ---*/ - base_file = base_file.append(".cgns"); - - /*--- Create CGNS results file name ---*/ - if (unsteady) { - - buffer = config->GetFlow_FileName(); - - results_file.str(string()); results_file << buffer; - if (((int)iExtIter >= 0) && ((int)iExtIter < 10)) results_file << "_0000" << iExtIter; - if (((int)iExtIter >= 10) && ((int)iExtIter < 100)) results_file << "_000" << iExtIter; - if (((int)iExtIter >= 100) && ((int)iExtIter < 1000)) results_file << "_00" << iExtIter; - if (((int)iExtIter >= 1000) && ((int)iExtIter < 10000)) results_file << "_0" << iExtIter; - if ((int)iExtIter >= 10000) results_file << iExtIter; - results_file << ".cgns"; - } - - /*--- Write base file if not already done ---*/ - if (!wrote_base_file) { - - /*--- Write base file ---*/ - cgns_err = cg_open((char *)base_file.c_str(), CG_MODE_MODIFY, &cgns_file); - if (cgns_err) cg_error_print(); - - element_dims = geometry->GetnDim(); // Currently (release 2.0) only all-2D or all-3D zones permitted - physical_dims = element_dims; - - isize[0][0] = (cgsize_t)nGlobal_Poin; // vertex size - isize[1][0] = (cgsize_t)nGlobal_Elem; // cell size - isize[2][0] = 0; // boundary vertex size (zero if elements not sorted) - - cgns_err = cg_goto(cgns_file, cgns_base,"Zone_t", cgns_zone,"end"); - if (cgns_err) cg_error_print(); -// -// cgns_err = cg_goto(cgns_file, cgns_base, cgns_zone,"end"); -// if (cgns_err) cg_error_print(); - - /*--- write CGNS node coordinates ---*/ - cgns_err = cg_coord_write(cgns_file, cgns_base, cgns_zone, RealDouble,"x", Coords[0], &cgns_coord); - if (cgns_err) cg_error_print(); - cgns_err = cg_coord_write(cgns_file, cgns_base, cgns_zone, RealDouble,"y", Coords[1], &cgns_coord); - if (cgns_err) cg_error_print(); - if (geometry->GetnDim() == 3) { - cgns_err = cg_coord_write(cgns_file, cgns_base, cgns_zone, RealDouble,"z", Coords[2], &cgns_coord); - if (cgns_err) cg_error_print(); - } - - cgns_err = cg_close(cgns_file); - if (cgns_err) cg_error_print(); - - wrote_base_file = true; - - } - - /*--- Set up results file for this time step if necessary ---*/ - if (unsteady) { - - cgns_err = cg_open((char *)results_file.str().c_str(), CG_MODE_WRITE, &cgns_file); - - element_dims = geometry->GetnDim(); // Currently (release 4.0.1 "Cardinal") only all-2D or all-3D zones permitted - physical_dims = element_dims; - - /*--- write CGNS base data (one base assumed as of version 4.0.1 "Cardinal") ---*/ - cgns_err = cg_base_write(cgns_file,"SU2 Base", element_dims, physical_dims, &cgns_base_results); - if (cgns_err) cg_error_print(); - - isize[0][0] = (cgsize_t)geometry->GetGlobal_nPointDomain(); // vertex size - isize[1][0] = (cgsize_t)nGlobal_Elem; // cell size - isize[2][0] = 0; // boundary vertex size (zero if elements not sorted) - - /*--- write CGNS zone data ---*/ - cgns_err = cg_zone_write(cgns_file, cgns_base_results,"SU2 Zone", isize[0],Unstructured, &cgns_zone_results); - if (cgns_err) cg_error_print(); - - cgns_err = cg_goto(cgns_file, cgns_base_results,"Zone_t", cgns_zone_results,"end"); - if (cgns_err) cg_error_print(); - - /*--- Write CGNS node coordinates, if appliciable ---*/ - if (config->GetGrid_Movement()) { - - /*--- write CGNS node coordinates ---*/ - cgns_err = cg_coord_write(cgns_file, cgns_base_results, cgns_zone_results, RealDouble,"x", Coords[0], &cgns_coord); - if (cgns_err) cg_error_print(); - cgns_err = cg_coord_write(cgns_file, cgns_base_results, cgns_zone_results, RealDouble,"y", Coords[1], &cgns_coord); - if (cgns_err) cg_error_print(); - if (geometry->GetnDim() == 3) { - cgns_err = cg_coord_write(cgns_file, cgns_base_results, cgns_zone_results, RealDouble,"z", Coords[2], &cgns_coord); - if (cgns_err) cg_error_print(); - } - } - else { - /*--- Write a CGNS link for the node coordinates ---*/ - cgns_err = cg_link_write("GridCoordinates",(char *)base_file.c_str(),"/SU2 Base/SU2 Zone/GridCoordinates"); - if (cgns_err) cg_error_print(); - } - - /*--- Write a CGNS link for each element type connectivity ---*/ - if (nGlobal_Tria > 0) cgns_err = cg_link_write("Triangle Elements",(char *)base_file.c_str(),"/SU2 Base/SU2 Zone/Triangle Elements"); - if (nGlobal_Quad > 0) cgns_err = cg_link_write("Quadrilateral Elements",(char *)base_file.c_str(),"/SU2 Base/SU2 Zone/Quadrilateral Elements"); - if (nGlobal_Tetr > 0) cgns_err = cg_link_write("Tetrahedral Elements",(char *)base_file.c_str(),"/SU2 Base/SU2 Zone/Tetrahedral Elements"); - if (nGlobal_Hexa > 0) cgns_err = cg_link_write("Hexahedral Elements",(char *)base_file.c_str(),"/SU2 Base/SU2 Zone/Hexahedral Elements"); - if (nGlobal_Pyra > 0) cgns_err = cg_link_write("Pyramid Elements",(char *)base_file.c_str(),"/SU2 Base/SU2 Zone/Pyramid Elements"); - if (nGlobal_Pris > 0) cgns_err = cg_link_write("Prism Elements",(char *)base_file.c_str(),"/SU2 Base/SU2 Zone/Prism Elements"); - if (nGlobal_Line > 0) cgns_err = cg_link_write("Line Elements",(char *)base_file.c_str(),"/SU2 Base/SU2 Zone/Line Elements"); - if (cgns_err) cg_error_print(); - - - /*--- Close CGNS file ---*/ - cgns_err = cg_close(cgns_file); - if (cgns_err) cg_error_print(); - - } - - - -#else // Not built with CGNS support - - cout << "CGNS file requested but SU2 was built without CGNS support. No file written" << "\n"; - -#endif - -} - -void COutput::SetCGNS_Connectivity(CConfig *config, CGeometry *geometry, unsigned short iZone) { - -#ifdef HAVE_CGNS - - /*--- local CGNS variables ---*/ - int cgns_file, element_dims, physical_dims, cgns_err; - int cgns_section; - unsigned long iExtIter = config->GetExtIter(); - string base_file, buffer, elements_name; - stringstream name, results_file; - bool unsteady = config->GetUnsteady_Simulation(); - cgsize_t isize[3][1], elem_start, elem_end; - - /*--- Create CGNS base file name ---*/ - base_file = config->GetFlow_FileName(); - - /*--- Add CGNS extension. ---*/ - base_file = base_file.append(".cgns"); - - /*--- Create CGNS results file name ---*/ - if (unsteady) { - - buffer = config->GetFlow_FileName(); - - results_file.str(string()); results_file << buffer; - if (((int)iExtIter >= 0) && ((int)iExtIter < 10)) results_file << "_0000" << iExtIter; - if (((int)iExtIter >= 10) && ((int)iExtIter < 100)) results_file << "_000" << iExtIter; - if (((int)iExtIter >= 100) && ((int)iExtIter < 1000)) results_file << "_00" << iExtIter; - if (((int)iExtIter >= 1000) && ((int)iExtIter < 10000)) results_file << "_0" << iExtIter; - if ((int)iExtIter >= 10000) results_file << iExtIter; - results_file << ".cgns"; - } - - /*--- Write base file if not already done ---*/ - if (!wrote_base_file) { - - /*--- Write base file ---*/ - cgns_err = cg_open((char *)base_file.c_str(), CG_MODE_WRITE, &cgns_file); - if (cgns_err) cg_error_print(); - - element_dims = geometry->GetnDim(); // Currently (release 2.0) only all-2D or all-3D zones permitted - physical_dims = element_dims; - - /*--- write CGNS base data (one base assumed as of version 4.0.1 "Cardinal") ---*/ - cgns_err = cg_base_write(cgns_file,"SU2 Base", element_dims, physical_dims, &cgns_base); - if (cgns_err) cg_error_print(); - - /*--- write CGNS descriptor data ---*/ - cgns_err = cg_goto(cgns_file, cgns_base,"end"); - if (cgns_err) cg_error_print(); - - cgns_err = cg_equationset_write(physical_dims); - if (cgns_err) cg_error_print(); - - /*--- Write governing equations to CGNS file ---*/ - cgns_err = cg_goto(cgns_file, cgns_base,"FlowEquationSet_t",1,"end"); - if (cgns_err) cg_error_print(); - switch (config->GetKind_Solver()) { - case EULER: - cgns_err = cg_governing_write(Euler); break; - case NAVIER_STOKES: - cgns_err = cg_governing_write(NSLaminar); break; - case RANS: - cgns_err = cg_governing_write(NSTurbulent); break; - default: - break; // cgns_err = cg_governing_write(CG_UserDefined); - } - if (cgns_err) cg_error_print(); - - if (unsteady) cgns_err = cg_simulation_type_write(cgns_file, cgns_base, TimeAccurate); - else cgns_err = cg_simulation_type_write(cgns_file, cgns_base, NonTimeAccurate); - if (cgns_err) cg_error_print(); - - cgns_err = cg_descriptor_write("Solver Information","SU2 version 4.0.1 \"Cardinal\""); - if (cgns_err) cg_error_print(); - - isize[0][0] = (cgsize_t)geometry->GetGlobal_nPointDomain(); //; // vertex size - isize[1][0] = (cgsize_t)nGlobal_Elem; // cell size - isize[2][0] = 0; // boundary vertex size (zero if elements not sorted) - - /*--- write CGNS zone data ---*/ - cgns_err = cg_zone_write(cgns_file, cgns_base,"SU2 Zone", isize[0],Unstructured, &cgns_zone); - if (cgns_err) cg_error_print(); - - cgns_err = cg_goto(cgns_file, cgns_base,"Zone_t", cgns_zone,"end"); - if (cgns_err) cg_error_print(); - - /*--- Reference Note: CGNS element type list: - NODE, BAR_2, BAR_3, TRI_3, TRI_6, QUAD_4, QUAD_8, QUAD_9, TETRA_4, TETRA_10, PYRA_5, - PYRA_14, PENTA_6, PENTA_15, PENTA_18, HEXA_8, HEXA_20, HEXA_27, MIXED, PYRA_13, NGON_n, NFACE_n ---*/ - - /*--- Write a CGNS section for each element type ---*/ - // ier = cg_section_write(int fn, int B, int Z, char *ElementSectionName, ElementType_t type, - // cgsize_t start, cgsize_t end, int nbndry, cgsize_t *Elements, int *S); - - if (nGlobal_Tria > 0) { - elem_start = 1; elem_end = (int)nGlobal_Tria; - cgns_err = cg_section_write(cgns_file, cgns_base, cgns_zone, - "Triangle Elements", TRI_3, elem_start, elem_end, - 0,(cgsize_t *)Conn_Tria, &cgns_section); - } - if (nGlobal_Quad > 0) { - elem_start = 1; elem_end = (int)nGlobal_Quad; - cgns_err = cg_section_write(cgns_file, cgns_base, cgns_zone,"Quadrilateral Elements", QUAD_4, - elem_start, elem_end,0,(cgsize_t *)Conn_Quad, &cgns_section); - } - if (nGlobal_Tetr > 0) { - elem_start = 1; elem_end = (int)nGlobal_Tetr; - cgns_err = cg_section_write(cgns_file, cgns_base, cgns_zone,"Tetrahedral Elements", TETRA_4, - elem_start, elem_end,0,(cgsize_t *)Conn_Tetr, &cgns_section); - } - if (nGlobal_Hexa > 0) { - elem_start = 1; elem_end = (int)nGlobal_Hexa; - cgns_err = cg_section_write(cgns_file, cgns_base, cgns_zone,"Hexahedral Elements", HEXA_8, - elem_start, elem_end,0,(cgsize_t *)Conn_Hexa, &cgns_section); - } - if (nGlobal_Pyra > 0) { - elem_start = 1; elem_end = (int)nGlobal_Pyra; - cgns_err = cg_section_write(cgns_file, cgns_base, cgns_zone,"Pyramid Elements", PYRA_5, - elem_start, elem_end,0,(cgsize_t *)Conn_Pyra, &cgns_section); - } - if (nGlobal_Pris > 0) { - elem_start = 1; elem_end = (int)nGlobal_Pris; - cgns_err = cg_section_write(cgns_file, cgns_base, cgns_zone,"Prism Elements", PENTA_6, - elem_start, elem_end,0,(cgsize_t *)Conn_Pris, &cgns_section); - } - if (nGlobal_Line > 0) { - elem_start = 1; elem_end = (int)nGlobal_Line; - cgns_err = cg_section_write(cgns_file, cgns_base, cgns_zone,"Line Elements", BAR_2, - elem_start, elem_end,0,(cgsize_t *)Conn_Line, &cgns_section); - } - if (cgns_err) cg_error_print(); - - - cgns_err = cg_close(cgns_file); - if (cgns_err) cg_error_print(); - - } - -#else // Not built with CGNS support - - cout << "CGNS file requested but SU2 was built without CGNS support. No file written" << "\n"; - -#endif - -} - -void COutput::SetCGNS_Solution(CConfig *config, CGeometry *geometry, unsigned short iZone) { - -#ifdef HAVE_CGNS - - /*--- local CGNS variables ---*/ - int cgns_file, cgns_flow, cgns_field, cgns_err; -// int element_dims; - unsigned long jVar, iVar, iExtIter = config->GetExtIter(); - string base_file, buffer, elements_name; - stringstream name, results_file; - bool unsteady = config->GetUnsteady_Simulation(); - - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - - /*--- Create CGNS base file name ---*/ - base_file = config->GetFlow_FileName(); - - /*--- Add CGNS extension. ---*/ - base_file = base_file.append(".cgns"); - - /*--- Create CGNS results file name ---*/ - if (unsteady) { - - buffer = config->GetFlow_FileName(); - - results_file.str(string()); results_file << buffer; - if (((int)iExtIter >= 0) && ((int)iExtIter < 10)) results_file << "_0000" << iExtIter; - if (((int)iExtIter >= 10) && ((int)iExtIter < 100)) results_file << "_000" << iExtIter; - if (((int)iExtIter >= 100) && ((int)iExtIter < 1000)) results_file << "_00" << iExtIter; - if (((int)iExtIter >= 1000) && ((int)iExtIter < 10000)) results_file << "_0" << iExtIter; - if ((int)iExtIter >= 10000) results_file << iExtIter; - results_file << ".cgns"; - } - - if (!unsteady) { - - /*--- Write base file ---*/ - cgns_err = cg_open((char *)base_file.c_str(), CG_MODE_MODIFY, &cgns_file); - if (cgns_err) cg_error_print(); - -// element_dims = geometry->GetnDim(); // Currently (release 2.0) only all-2D or all-3D zones permitted - - /*--- write CGNS descriptor data ---*/ - cgns_err = cg_goto(cgns_file, cgns_base,"end"); - if (cgns_err) cg_error_print(); - - /*--- Create a CGNS solution node ---*/ - cgns_err = cg_sol_write(cgns_file, cgns_base, cgns_zone,"Solution", Vertex, &cgns_flow); - if (cgns_err) cg_error_print(); - - cgns_err = cg_goto(cgns_file, cgns_base,"Zone_t", cgns_zone,"FlowSolution_t", cgns_flow,"end"); - if (cgns_err) cg_error_print(); - - cgns_err = cg_gridlocation_write(Vertex); - if (cgns_err) cg_error_print(); - } - - - //wrote_CGNS_base = true; - else { - - /*--- Set up results file for this time step if necessary ---*/ - - cgns_err = cg_open((char *)results_file.str().c_str(), CG_MODE_MODIFY, &cgns_file); - -// element_dims = geometry->GetnDim(); // Currently (release 2.0) only all-2D or all-3D zones permitted -// -// /*--- write CGNS base data (one base assumed as of version 4.0.1 "Cardinal") ---*/ -// cgns_err = cg_base_write(cgns_file,"SU2 Base", element_dims, physical_dims, &cgns_base); -// if (cgns_err) cg_error_print(); - -// /*--- write CGNS zone data ---*/ -// cgns_err = cg_zone_write(cgns_file, cgns_base,"SU2 Zone", isize[0],Unstructured, &cgns_zone); -// if (cgns_err) cg_error_print(); - - cgns_err = cg_goto(cgns_file, cgns_base_results,"Zone_t", cgns_zone_results,"end"); - if (cgns_err) cg_error_print(); - - /*--- Write a CGNS solution node for this time step ---*/ - cgns_err = cg_sol_write(cgns_file, cgns_base_results, cgns_zone_results,"Solution", Vertex, &cgns_flow); - if (cgns_err) cg_error_print(); - - cgns_err = cg_goto(cgns_file, cgns_base_results,"Zone_t", cgns_zone_results,"FlowSolution_t", cgns_flow,"end"); - if (cgns_err) cg_error_print(); - - cgns_err = cg_gridlocation_write(Vertex); - if (cgns_err) cg_error_print(); - - cgns_base = cgns_base_results; - cgns_zone = cgns_zone_results; - } -// else { -// -// /*--- Open CGNS file for soltuion writing ---*/ -// cgns_err = cg_open((char *)base_file.c_str(), CG_MODE_MODIFY, &cgns_file); -// cgns_base = 1; cgns_zone = 1; cgns_flow = 1; // fix for multiple zones -// -// } - - /* Reference Note on solution variables: - index 0 --> (nVar_Consv-1) = Conservative Variables - nVar_Consv --> (2*nVar_Consv-1) = Conservative Variable Residuals - (2*nVar_Consv-1)+ = Additional p, M, T, laminar, eddy depending on solver used */ - - /*--- Write conservative variables to CGNS file ---*/ - for (iVar = 0; iVar < nVar_Consv; iVar++) { - name.str(string()); name << "Conservative Variable " << iVar+1; - cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,(char *)name.str().c_str(), Data[iVar], &cgns_field); - if (cgns_err) cg_error_print(); - } - - /*--- Write primitive variable residuals to CGNS file ---*/ - if (config->GetWrt_Limiters()) { - for (jVar = 0; jVar < nVar_Consv; jVar++) { - name.str(string()); name << "Primitive Limiter " << jVar+1; - cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,(char *)name.str().c_str(), Data[iVar], &cgns_field); iVar++; - if (cgns_err) cg_error_print(); - } - } - - /*--- Write conservative variable residuals to CGNS file ---*/ - if (config->GetWrt_Residuals()) { - for (jVar = 0; jVar < nVar_Consv; jVar++) { - name.str(string()); name << "Conservative Residual " << jVar+1; - cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,(char *)name.str().c_str(), Data[iVar], &cgns_field); iVar++; - if (cgns_err) cg_error_print(); - } - } - - /*--- Write grid velocities to CGNS file, if applicable ---*/ - if (config->GetGrid_Movement()) { - cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Grid Velocity X", Data[iVar], &cgns_field); iVar++; - if (cgns_err) cg_error_print(); - cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Grid Velocity Y", Data[iVar], &cgns_field); iVar++; - if (cgns_err) cg_error_print(); - if (geometry->GetnDim() == 3) { - cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Grid Velocity Z", Data[iVar], &cgns_field); iVar++; - if (cgns_err) cg_error_print(); - } - } - - if (compressible) { - switch (config->GetKind_Solver()) { - - /*--- Write pressure and Mach data to CGNS file ---*/ - case EULER: - cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Pressure", Data[iVar], &cgns_field); iVar++; - if (cgns_err) cg_error_print(); - cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Mach", Data[iVar], &cgns_field); iVar++; - if (cgns_err) cg_error_print(); - break; - - /*--- Write temperature and laminar viscosity to CGNS file, if applicable ---*/ - case NAVIER_STOKES: - cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Pressure", Data[iVar], &cgns_field); iVar++; - if (cgns_err) cg_error_print(); - cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Mach", Data[iVar], &cgns_field); iVar++; - if (cgns_err) cg_error_print(); - cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Temperature", Data[iVar], &cgns_field); iVar++; - if (cgns_err) cg_error_print(); - cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Viscosity", Data[iVar], &cgns_field); iVar++; - if (cgns_err) cg_error_print(); - break; - - /*--- Write eddy viscosity to CGNS file, if applicable ---*/ - case RANS: - cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Pressure", Data[iVar], &cgns_field); iVar++; - if (cgns_err) cg_error_print(); - cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Mach", Data[iVar], &cgns_field); iVar++; - if (cgns_err) cg_error_print(); - cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Temperature", Data[iVar], &cgns_field); iVar++; - if (cgns_err) cg_error_print(); - cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Viscosity", Data[iVar], &cgns_field); iVar++; - if (cgns_err) cg_error_print(); - cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Eddy Viscosity", Data[iVar], &cgns_field); iVar++; - if (cgns_err) cg_error_print(); - break; - - default: - cout << "Error: Unrecognized equation type \n"; - exit(EXIT_FAILURE); break; - } - } - - /*--- Close CGNS file ---*/ - cgns_err = cg_close(cgns_file); - if (cgns_err) cg_error_print(); - -#else // Not built with CGNS support - - cout << "CGNS file requested but SU2 was built without CGNS support. No file written" << "\n"; - -#endif - -} +/*! + * \file output_cgns.cpp + * \brief Main subroutines for output solver information + * \author T. Economon, M. Colonno + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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_structure.hpp" + +void COutput::SetCGNS_Coordinates(CConfig *config, CGeometry *geometry, unsigned short iZone) { + +#ifdef HAVE_CGNS + + /*--- local CGNS variables ---*/ + int cgns_file, cgns_coord, element_dims, physical_dims, cgns_err; + unsigned long iExtIter = config->GetExtIter(); + string base_file, buffer, elements_name; + stringstream name, results_file; + bool unsteady = config->GetUnsteady_Simulation(); + cgsize_t isize[3][1]; + + /*--- Create CGNS base file name ---*/ + base_file = config->GetFlow_FileName(); + + /*--- Add CGNS extension. ---*/ + base_file = base_file.append(".cgns"); + + /*--- Create CGNS results file name ---*/ + if (unsteady) { + + buffer = config->GetFlow_FileName(); + + results_file.str(string()); results_file << buffer; + if (((int)iExtIter >= 0) && ((int)iExtIter < 10)) results_file << "_0000" << iExtIter; + if (((int)iExtIter >= 10) && ((int)iExtIter < 100)) results_file << "_000" << iExtIter; + if (((int)iExtIter >= 100) && ((int)iExtIter < 1000)) results_file << "_00" << iExtIter; + if (((int)iExtIter >= 1000) && ((int)iExtIter < 10000)) results_file << "_0" << iExtIter; + if ((int)iExtIter >= 10000) results_file << iExtIter; + results_file << ".cgns"; + } + + /*--- Write base file if not already done ---*/ + if (!wrote_base_file) { + + /*--- Write base file ---*/ + cgns_err = cg_open((char *)base_file.c_str(), CG_MODE_MODIFY, &cgns_file); + if (cgns_err) cg_error_print(); + + element_dims = geometry->GetnDim(); // Currently (release 2.0) only all-2D or all-3D zones permitted + physical_dims = element_dims; + + isize[0][0] = (cgsize_t)nGlobal_Poin; // vertex size + isize[1][0] = (cgsize_t)nGlobal_Elem; // cell size + isize[2][0] = 0; // boundary vertex size (zero if elements not sorted) + + cgns_err = cg_goto(cgns_file, cgns_base,"Zone_t", cgns_zone,"end"); + if (cgns_err) cg_error_print(); +// +// cgns_err = cg_goto(cgns_file, cgns_base, cgns_zone,"end"); +// if (cgns_err) cg_error_print(); + + /*--- write CGNS node coordinates ---*/ + cgns_err = cg_coord_write(cgns_file, cgns_base, cgns_zone, RealDouble,"x", Coords[0], &cgns_coord); + if (cgns_err) cg_error_print(); + cgns_err = cg_coord_write(cgns_file, cgns_base, cgns_zone, RealDouble,"y", Coords[1], &cgns_coord); + if (cgns_err) cg_error_print(); + if (geometry->GetnDim() == 3) { + cgns_err = cg_coord_write(cgns_file, cgns_base, cgns_zone, RealDouble,"z", Coords[2], &cgns_coord); + if (cgns_err) cg_error_print(); + } + + cgns_err = cg_close(cgns_file); + if (cgns_err) cg_error_print(); + + wrote_base_file = true; + + } + + /*--- Set up results file for this time step if necessary ---*/ + if (unsteady) { + + cgns_err = cg_open((char *)results_file.str().c_str(), CG_MODE_WRITE, &cgns_file); + + element_dims = geometry->GetnDim(); // Currently (release 4.0.1 "Cardinal") only all-2D or all-3D zones permitted + physical_dims = element_dims; + + /*--- write CGNS base data (one base assumed as of version 4.0.1 "Cardinal") ---*/ + cgns_err = cg_base_write(cgns_file,"SU2 Base", element_dims, physical_dims, &cgns_base_results); + if (cgns_err) cg_error_print(); + + isize[0][0] = (cgsize_t)geometry->GetGlobal_nPointDomain(); // vertex size + isize[1][0] = (cgsize_t)nGlobal_Elem; // cell size + isize[2][0] = 0; // boundary vertex size (zero if elements not sorted) + + /*--- write CGNS zone data ---*/ + cgns_err = cg_zone_write(cgns_file, cgns_base_results,"SU2 Zone", isize[0],Unstructured, &cgns_zone_results); + if (cgns_err) cg_error_print(); + + cgns_err = cg_goto(cgns_file, cgns_base_results,"Zone_t", cgns_zone_results,"end"); + if (cgns_err) cg_error_print(); + + /*--- Write CGNS node coordinates, if appliciable ---*/ + if (config->GetGrid_Movement()) { + + /*--- write CGNS node coordinates ---*/ + cgns_err = cg_coord_write(cgns_file, cgns_base_results, cgns_zone_results, RealDouble,"x", Coords[0], &cgns_coord); + if (cgns_err) cg_error_print(); + cgns_err = cg_coord_write(cgns_file, cgns_base_results, cgns_zone_results, RealDouble,"y", Coords[1], &cgns_coord); + if (cgns_err) cg_error_print(); + if (geometry->GetnDim() == 3) { + cgns_err = cg_coord_write(cgns_file, cgns_base_results, cgns_zone_results, RealDouble,"z", Coords[2], &cgns_coord); + if (cgns_err) cg_error_print(); + } + } + else { + /*--- Write a CGNS link for the node coordinates ---*/ + cgns_err = cg_link_write("GridCoordinates",(char *)base_file.c_str(),"/SU2 Base/SU2 Zone/GridCoordinates"); + if (cgns_err) cg_error_print(); + } + + /*--- Write a CGNS link for each element type connectivity ---*/ + if (nGlobal_Tria > 0) cgns_err = cg_link_write("Triangle Elements",(char *)base_file.c_str(),"/SU2 Base/SU2 Zone/Triangle Elements"); + if (nGlobal_Quad > 0) cgns_err = cg_link_write("Quadrilateral Elements",(char *)base_file.c_str(),"/SU2 Base/SU2 Zone/Quadrilateral Elements"); + if (nGlobal_Tetr > 0) cgns_err = cg_link_write("Tetrahedral Elements",(char *)base_file.c_str(),"/SU2 Base/SU2 Zone/Tetrahedral Elements"); + if (nGlobal_Hexa > 0) cgns_err = cg_link_write("Hexahedral Elements",(char *)base_file.c_str(),"/SU2 Base/SU2 Zone/Hexahedral Elements"); + if (nGlobal_Pyra > 0) cgns_err = cg_link_write("Pyramid Elements",(char *)base_file.c_str(),"/SU2 Base/SU2 Zone/Pyramid Elements"); + if (nGlobal_Pris > 0) cgns_err = cg_link_write("Prism Elements",(char *)base_file.c_str(),"/SU2 Base/SU2 Zone/Prism Elements"); + if (nGlobal_Line > 0) cgns_err = cg_link_write("Line Elements",(char *)base_file.c_str(),"/SU2 Base/SU2 Zone/Line Elements"); + if (cgns_err) cg_error_print(); + + + /*--- Close CGNS file ---*/ + cgns_err = cg_close(cgns_file); + if (cgns_err) cg_error_print(); + + } + + + +#else // Not built with CGNS support + + cout << "CGNS file requested but SU2 was built without CGNS support. No file written" << "\n"; + +#endif + +} + +void COutput::SetCGNS_Connectivity(CConfig *config, CGeometry *geometry, unsigned short iZone) { + +#ifdef HAVE_CGNS + + /*--- local CGNS variables ---*/ + int cgns_file, element_dims, physical_dims, cgns_err; + int cgns_section; + unsigned long iExtIter = config->GetExtIter(); + string base_file, buffer, elements_name; + stringstream name, results_file; + bool unsteady = config->GetUnsteady_Simulation(); + cgsize_t isize[3][1], elem_start, elem_end; + + /*--- Create CGNS base file name ---*/ + base_file = config->GetFlow_FileName(); + + /*--- Add CGNS extension. ---*/ + base_file = base_file.append(".cgns"); + + /*--- Create CGNS results file name ---*/ + if (unsteady) { + + buffer = config->GetFlow_FileName(); + + results_file.str(string()); results_file << buffer; + if (((int)iExtIter >= 0) && ((int)iExtIter < 10)) results_file << "_0000" << iExtIter; + if (((int)iExtIter >= 10) && ((int)iExtIter < 100)) results_file << "_000" << iExtIter; + if (((int)iExtIter >= 100) && ((int)iExtIter < 1000)) results_file << "_00" << iExtIter; + if (((int)iExtIter >= 1000) && ((int)iExtIter < 10000)) results_file << "_0" << iExtIter; + if ((int)iExtIter >= 10000) results_file << iExtIter; + results_file << ".cgns"; + } + + /*--- Write base file if not already done ---*/ + if (!wrote_base_file) { + + /*--- Write base file ---*/ + cgns_err = cg_open((char *)base_file.c_str(), CG_MODE_WRITE, &cgns_file); + if (cgns_err) cg_error_print(); + + element_dims = geometry->GetnDim(); // Currently (release 2.0) only all-2D or all-3D zones permitted + physical_dims = element_dims; + + /*--- write CGNS base data (one base assumed as of version 4.0.1 "Cardinal") ---*/ + cgns_err = cg_base_write(cgns_file,"SU2 Base", element_dims, physical_dims, &cgns_base); + if (cgns_err) cg_error_print(); + + /*--- write CGNS descriptor data ---*/ + cgns_err = cg_goto(cgns_file, cgns_base,"end"); + if (cgns_err) cg_error_print(); + + cgns_err = cg_equationset_write(physical_dims); + if (cgns_err) cg_error_print(); + + /*--- Write governing equations to CGNS file ---*/ + cgns_err = cg_goto(cgns_file, cgns_base,"FlowEquationSet_t",1,"end"); + if (cgns_err) cg_error_print(); + switch (config->GetKind_Solver()) { + case EULER: + cgns_err = cg_governing_write(Euler); break; + case NAVIER_STOKES: + cgns_err = cg_governing_write(NSLaminar); break; + case RANS: + cgns_err = cg_governing_write(NSTurbulent); break; + default: + break; // cgns_err = cg_governing_write(CG_UserDefined); + } + if (cgns_err) cg_error_print(); + + if (unsteady) cgns_err = cg_simulation_type_write(cgns_file, cgns_base, TimeAccurate); + else cgns_err = cg_simulation_type_write(cgns_file, cgns_base, NonTimeAccurate); + if (cgns_err) cg_error_print(); + + cgns_err = cg_descriptor_write("Solver Information","SU2 version 4.0.1 \"Cardinal\""); + if (cgns_err) cg_error_print(); + + isize[0][0] = (cgsize_t)geometry->GetGlobal_nPointDomain(); //; // vertex size + isize[1][0] = (cgsize_t)nGlobal_Elem; // cell size + isize[2][0] = 0; // boundary vertex size (zero if elements not sorted) + + /*--- write CGNS zone data ---*/ + cgns_err = cg_zone_write(cgns_file, cgns_base,"SU2 Zone", isize[0],Unstructured, &cgns_zone); + if (cgns_err) cg_error_print(); + + cgns_err = cg_goto(cgns_file, cgns_base,"Zone_t", cgns_zone,"end"); + if (cgns_err) cg_error_print(); + + /*--- Reference Note: CGNS element type list: + NODE, BAR_2, BAR_3, TRI_3, TRI_6, QUAD_4, QUAD_8, QUAD_9, TETRA_4, TETRA_10, PYRA_5, + PYRA_14, PENTA_6, PENTA_15, PENTA_18, HEXA_8, HEXA_20, HEXA_27, MIXED, PYRA_13, NGON_n, NFACE_n ---*/ + + /*--- Write a CGNS section for each element type ---*/ + // ier = cg_section_write(int fn, int B, int Z, char *ElementSectionName, ElementType_t type, + // cgsize_t start, cgsize_t end, int nbndry, cgsize_t *Elements, int *S); + + if (nGlobal_Tria > 0) { + elem_start = 1; elem_end = (int)nGlobal_Tria; + cgns_err = cg_section_write(cgns_file, cgns_base, cgns_zone, + "Triangle Elements", TRI_3, elem_start, elem_end, + 0,(cgsize_t *)Conn_Tria, &cgns_section); + } + if (nGlobal_Quad > 0) { + elem_start = 1; elem_end = (int)nGlobal_Quad; + cgns_err = cg_section_write(cgns_file, cgns_base, cgns_zone,"Quadrilateral Elements", QUAD_4, + elem_start, elem_end,0,(cgsize_t *)Conn_Quad, &cgns_section); + } + if (nGlobal_Tetr > 0) { + elem_start = 1; elem_end = (int)nGlobal_Tetr; + cgns_err = cg_section_write(cgns_file, cgns_base, cgns_zone,"Tetrahedral Elements", TETRA_4, + elem_start, elem_end,0,(cgsize_t *)Conn_Tetr, &cgns_section); + } + if (nGlobal_Hexa > 0) { + elem_start = 1; elem_end = (int)nGlobal_Hexa; + cgns_err = cg_section_write(cgns_file, cgns_base, cgns_zone,"Hexahedral Elements", HEXA_8, + elem_start, elem_end,0,(cgsize_t *)Conn_Hexa, &cgns_section); + } + if (nGlobal_Pyra > 0) { + elem_start = 1; elem_end = (int)nGlobal_Pyra; + cgns_err = cg_section_write(cgns_file, cgns_base, cgns_zone,"Pyramid Elements", PYRA_5, + elem_start, elem_end,0,(cgsize_t *)Conn_Pyra, &cgns_section); + } + if (nGlobal_Pris > 0) { + elem_start = 1; elem_end = (int)nGlobal_Pris; + cgns_err = cg_section_write(cgns_file, cgns_base, cgns_zone,"Prism Elements", PENTA_6, + elem_start, elem_end,0,(cgsize_t *)Conn_Pris, &cgns_section); + } + if (nGlobal_Line > 0) { + elem_start = 1; elem_end = (int)nGlobal_Line; + cgns_err = cg_section_write(cgns_file, cgns_base, cgns_zone,"Line Elements", BAR_2, + elem_start, elem_end,0,(cgsize_t *)Conn_Line, &cgns_section); + } + if (cgns_err) cg_error_print(); + + + cgns_err = cg_close(cgns_file); + if (cgns_err) cg_error_print(); + + } + +#else // Not built with CGNS support + + cout << "CGNS file requested but SU2 was built without CGNS support. No file written" << "\n"; + +#endif + +} + +void COutput::SetCGNS_Solution(CConfig *config, CGeometry *geometry, unsigned short iZone) { + +#ifdef HAVE_CGNS + + /*--- local CGNS variables ---*/ + int cgns_file, cgns_flow, cgns_field, cgns_err; +// int element_dims; + unsigned long jVar, iVar, iExtIter = config->GetExtIter(); + string base_file, buffer, elements_name; + stringstream name, results_file; + bool unsteady = config->GetUnsteady_Simulation(); + + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + + /*--- Create CGNS base file name ---*/ + base_file = config->GetFlow_FileName(); + + /*--- Add CGNS extension. ---*/ + base_file = base_file.append(".cgns"); + + /*--- Create CGNS results file name ---*/ + if (unsteady) { + + buffer = config->GetFlow_FileName(); + + results_file.str(string()); results_file << buffer; + if (((int)iExtIter >= 0) && ((int)iExtIter < 10)) results_file << "_0000" << iExtIter; + if (((int)iExtIter >= 10) && ((int)iExtIter < 100)) results_file << "_000" << iExtIter; + if (((int)iExtIter >= 100) && ((int)iExtIter < 1000)) results_file << "_00" << iExtIter; + if (((int)iExtIter >= 1000) && ((int)iExtIter < 10000)) results_file << "_0" << iExtIter; + if ((int)iExtIter >= 10000) results_file << iExtIter; + results_file << ".cgns"; + } + + if (!unsteady) { + + /*--- Write base file ---*/ + cgns_err = cg_open((char *)base_file.c_str(), CG_MODE_MODIFY, &cgns_file); + if (cgns_err) cg_error_print(); + +// element_dims = geometry->GetnDim(); // Currently (release 2.0) only all-2D or all-3D zones permitted + + /*--- write CGNS descriptor data ---*/ + cgns_err = cg_goto(cgns_file, cgns_base,"end"); + if (cgns_err) cg_error_print(); + + /*--- Create a CGNS solution node ---*/ + cgns_err = cg_sol_write(cgns_file, cgns_base, cgns_zone,"Solution", Vertex, &cgns_flow); + if (cgns_err) cg_error_print(); + + cgns_err = cg_goto(cgns_file, cgns_base,"Zone_t", cgns_zone,"FlowSolution_t", cgns_flow,"end"); + if (cgns_err) cg_error_print(); + + cgns_err = cg_gridlocation_write(Vertex); + if (cgns_err) cg_error_print(); + } + + + //wrote_CGNS_base = true; + else { + + /*--- Set up results file for this time step if necessary ---*/ + + cgns_err = cg_open((char *)results_file.str().c_str(), CG_MODE_MODIFY, &cgns_file); + +// element_dims = geometry->GetnDim(); // Currently (release 2.0) only all-2D or all-3D zones permitted +// +// /*--- write CGNS base data (one base assumed as of version 4.0.1 "Cardinal") ---*/ +// cgns_err = cg_base_write(cgns_file,"SU2 Base", element_dims, physical_dims, &cgns_base); +// if (cgns_err) cg_error_print(); + +// /*--- write CGNS zone data ---*/ +// cgns_err = cg_zone_write(cgns_file, cgns_base,"SU2 Zone", isize[0],Unstructured, &cgns_zone); +// if (cgns_err) cg_error_print(); + + cgns_err = cg_goto(cgns_file, cgns_base_results,"Zone_t", cgns_zone_results,"end"); + if (cgns_err) cg_error_print(); + + /*--- Write a CGNS solution node for this time step ---*/ + cgns_err = cg_sol_write(cgns_file, cgns_base_results, cgns_zone_results,"Solution", Vertex, &cgns_flow); + if (cgns_err) cg_error_print(); + + cgns_err = cg_goto(cgns_file, cgns_base_results,"Zone_t", cgns_zone_results,"FlowSolution_t", cgns_flow,"end"); + if (cgns_err) cg_error_print(); + + cgns_err = cg_gridlocation_write(Vertex); + if (cgns_err) cg_error_print(); + + cgns_base = cgns_base_results; + cgns_zone = cgns_zone_results; + } +// else { +// +// /*--- Open CGNS file for soltuion writing ---*/ +// cgns_err = cg_open((char *)base_file.c_str(), CG_MODE_MODIFY, &cgns_file); +// cgns_base = 1; cgns_zone = 1; cgns_flow = 1; // fix for multiple zones +// +// } + + /* Reference Note on solution variables: + index 0 --> (nVar_Consv-1) = Conservative Variables + nVar_Consv --> (2*nVar_Consv-1) = Conservative Variable Residuals + (2*nVar_Consv-1)+ = Additional p, M, T, laminar, eddy depending on solver used */ + + /*--- Write conservative variables to CGNS file ---*/ + for (iVar = 0; iVar < nVar_Consv; iVar++) { + name.str(string()); name << "Conservative Variable " << iVar+1; + cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,(char *)name.str().c_str(), Data[iVar], &cgns_field); + if (cgns_err) cg_error_print(); + } + + /*--- Write primitive variable residuals to CGNS file ---*/ + if (config->GetWrt_Limiters()) { + for (jVar = 0; jVar < nVar_Consv; jVar++) { + name.str(string()); name << "Primitive Limiter " << jVar+1; + cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,(char *)name.str().c_str(), Data[iVar], &cgns_field); iVar++; + if (cgns_err) cg_error_print(); + } + } + + /*--- Write conservative variable residuals to CGNS file ---*/ + if (config->GetWrt_Residuals()) { + for (jVar = 0; jVar < nVar_Consv; jVar++) { + name.str(string()); name << "Conservative Residual " << jVar+1; + cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,(char *)name.str().c_str(), Data[iVar], &cgns_field); iVar++; + if (cgns_err) cg_error_print(); + } + } + + /*--- Write grid velocities to CGNS file, if applicable ---*/ + if (config->GetGrid_Movement()) { + cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Grid Velocity X", Data[iVar], &cgns_field); iVar++; + if (cgns_err) cg_error_print(); + cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Grid Velocity Y", Data[iVar], &cgns_field); iVar++; + if (cgns_err) cg_error_print(); + if (geometry->GetnDim() == 3) { + cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Grid Velocity Z", Data[iVar], &cgns_field); iVar++; + if (cgns_err) cg_error_print(); + } + } + + if (compressible) { + switch (config->GetKind_Solver()) { + + /*--- Write pressure and Mach data to CGNS file ---*/ + case EULER: + cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Pressure", Data[iVar], &cgns_field); iVar++; + if (cgns_err) cg_error_print(); + cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Mach", Data[iVar], &cgns_field); iVar++; + if (cgns_err) cg_error_print(); + break; + + /*--- Write temperature and laminar viscosity to CGNS file, if applicable ---*/ + case NAVIER_STOKES: + cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Pressure", Data[iVar], &cgns_field); iVar++; + if (cgns_err) cg_error_print(); + cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Mach", Data[iVar], &cgns_field); iVar++; + if (cgns_err) cg_error_print(); + cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Temperature", Data[iVar], &cgns_field); iVar++; + if (cgns_err) cg_error_print(); + cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Viscosity", Data[iVar], &cgns_field); iVar++; + if (cgns_err) cg_error_print(); + break; + + /*--- Write eddy viscosity to CGNS file, if applicable ---*/ + case RANS: + cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Pressure", Data[iVar], &cgns_field); iVar++; + if (cgns_err) cg_error_print(); + cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Mach", Data[iVar], &cgns_field); iVar++; + if (cgns_err) cg_error_print(); + cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Temperature", Data[iVar], &cgns_field); iVar++; + if (cgns_err) cg_error_print(); + cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Viscosity", Data[iVar], &cgns_field); iVar++; + if (cgns_err) cg_error_print(); + cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Eddy Viscosity", Data[iVar], &cgns_field); iVar++; + if (cgns_err) cg_error_print(); + break; + + default: + cout << "Error: Unrecognized equation type \n"; + exit(EXIT_FAILURE); break; + } + } + + /*--- Close CGNS file ---*/ + cgns_err = cg_close(cgns_file); + if (cgns_err) cg_error_print(); + +#else // Not built with CGNS support + + cout << "CGNS file requested but SU2 was built without CGNS support. No file written" << "\n"; + +#endif + +} diff --git a/SU2_CFD/src/output_fieldview.cpp b/SU2_CFD/src/output_fieldview.cpp index 904f5d3262d..826c3cf137f 100644 --- a/SU2_CFD/src/output_fieldview.cpp +++ b/SU2_CFD/src/output_fieldview.cpp @@ -1,786 +1,786 @@ -/*! - * \file output_fieldview.cpp - * \brief Main subroutines for output solver information. - * \author F. Palacios, T. Economon, M. Colonno - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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_structure.hpp" - -void COutput::SetFieldViewASCII(CConfig *config, CGeometry *geometry, unsigned short val_iZone, unsigned short val_nZone) { - - unsigned short iDim, iVar, nDim = geometry->GetnDim(), ngrids = 1, nbvars, nvars; - unsigned short Kind_Solver = config->GetKind_Solver(); - - unsigned long iPoint, iElem, iNode, nbfaces; - - unsigned long iExtIter = config->GetExtIter(); - bool adjoint = config->GetAdjoint(); - bool disc_adjoint = config->GetDiscrete_Adjoint(); - - bool grid_movement = config->GetGrid_Movement(); - - char cstr[200], buffer[50]; - string filename, FieldName; - - /*--- Write file name with extension ---*/ - - if (adjoint || disc_adjoint) filename = config->GetAdj_FileName(); - else filename = config->GetFlow_FileName(); - - if (Kind_Solver == LINEAR_ELASTICITY) - filename = config->GetStructure_FileName().c_str(); - - if (Kind_Solver == WAVE_EQUATION) - filename = config->GetWave_FileName().c_str(); - - if (Kind_Solver == HEAT_EQUATION) - filename = config->GetHeat_FileName().c_str(); - - if (Kind_Solver == POISSON_EQUATION) - filename = config->GetStructure_FileName().c_str(); - - strcpy (cstr, filename.c_str()); - - /*--- Special cases where a number needs to be appended to the file name. ---*/ - - if ((Kind_Solver == EULER || Kind_Solver == NAVIER_STOKES || Kind_Solver == RANS || - Kind_Solver == ADJ_EULER || Kind_Solver == ADJ_NAVIER_STOKES || Kind_Solver == ADJ_RANS) && - (val_nZone > 1) && (config->GetUnsteady_Simulation() != TIME_SPECTRAL)) { - SPRINTF (buffer, "_%d", SU2_TYPE::Int(val_iZone)); - strcat(cstr, buffer); - } - - if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { - - if (config->GetKind_SU2() == SU2_SOL) { val_iZone = iExtIter; } - - if (SU2_TYPE::Int(val_iZone) < 10) SPRINTF (buffer, "_0000%d.uns", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 10) && (SU2_TYPE::Int(val_iZone) < 100)) SPRINTF (buffer, "_000%d.uns", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 100) && (SU2_TYPE::Int(val_iZone) < 1000)) SPRINTF (buffer, "_00%d.uns", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 1000) && (SU2_TYPE::Int(val_iZone) < 10000)) SPRINTF (buffer, "_0%d.uns", SU2_TYPE::Int(val_iZone)); - if (SU2_TYPE::Int(val_iZone) >= 10000) SPRINTF (buffer, "_%d.uns", SU2_TYPE::Int(val_iZone)); - - } - else if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { - if (SU2_TYPE::Int(iExtIter) < 10) SPRINTF (buffer, "_0000%d.uns", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.uns", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.uns", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.uns", SU2_TYPE::Int(iExtIter)); - if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.uns", SU2_TYPE::Int(iExtIter)); - } - else { SPRINTF (buffer, ".uns"); } - - strcat(cstr, buffer); - - /*--- Open FieldView ASCII file and write the header ---*/ - - ofstream FieldView_File; - FieldView_File.open(cstr, ios::out); - FieldView_File.precision(6); - - FieldView_File << "FIELDVIEW 3 0" << endl; - - /*--- Output constants for time, fsmach, alpha and re. ---*/ - - FieldView_File << "Constants" << endl; - FieldView_File << config->GetExtIter() <<"\t"<< config->GetMach() <<"\t"<< config->GetAoA() <<"\t"<< config->GetReynolds() << endl; - - /*--- Output the number of grids. ---*/ - - FieldView_File << "Grids\t" << ngrids << endl; - - /*--- Output the table of boundary types, starting with the number of types. - Note that this differs from the binary/unformatted specification. - Each boundary type name is preceded by 3 integer flags. - The first flag indicates whether this boundary type is a wall. - A flag value of 1 indicates a wall, and a value of 0 indicates - a non-wall. Walls are significant for streamline calculation. - The second flag indicates whether the boundary type has surface - results. A value of 1 means surface results will be present for - this boundary type (if any boundary variables are specified in the - Boundary Variable Names section below). A value of 0 means no surface - results will be present. - The third flag indicates whether boundary faces of this type have - consistent "clockness" for the purpose of calculating a surface - normal. A value of 1 means that all faces of this type are - written following a "right hand rule" for clockness. In other - words, if the vertices are written on counter-clockwise: - 4 --- 3 - | | - 1 --- 2 - then the normal to the face is pointing towards you (not away - from you). A value of 0 means that the faces do not have any - consistent clockness. The "clockness" of surface normals is - only used for calculating certain special surface integrals - that involve surface normals. If the surface normals flag - is 0, these special integrals will not be available. ---*/ - - FieldView_File << "Boundary Table\t1" << endl; - FieldView_File << "1\t0\t1\tMARKER_PLOTTING" << endl; - - /*--- Output the table of variable names, starting with the number of - variables. The number of variables can be zero. - Note that vector variables are specified by a ';' and vector name - following the first scalar name of 3 scalar components of the - vector. If writing 2-D results, the third component must still - be provided here, and its values must be written in the variables - section below (typically padded with zeros.) ---*/ - - if (config->GetKind_SU2() == SU2_SOL) { - - /*--- If SU2_SOL called this routine, we already have a set of output - variables with the appropriate string tags stored in the config class. ---*/ - - nvars = nVar_Total-nDim; - - FieldView_File << "Variable Names\t" << nvars << endl; - - for (unsigned short iField = 1+nDim; iField < config->fields.size(); iField++) { - - /*--- Remove all su2double-quote characters ---*/ - - FieldName = config->fields[iField]; - - FieldName.erase( - remove(FieldName.begin(), FieldName.end(), '\"' ), - FieldName.end() - ); - - FieldView_File << FieldName << endl; - } - - /*--- SU2 does not generate boundary variables ---*/ - - nbvars = 0; - FieldView_File << "Boundary Variable Names\t" << nbvars << endl; - - } - - else { - - nvars = nVar_Total; - - FieldView_File << "Variable Names\t" << nvars << endl; - - for (iVar = 0; iVar < nVar_Consv; iVar++) { - FieldView_File << "Conservative_" << iVar+1 << endl; - } - - /*--- Add names for any extra variables (this will need to be adjusted). ---*/ - - if (config->GetWrt_Limiters()) { - for (iVar = 0; iVar < nVar_Consv; iVar++) { - FieldView_File << "Limiter_" << iVar+1 << endl; - } - } - - if (config->GetWrt_Residuals()) { - for (iVar = 0; iVar < nVar_Consv; iVar++) { - FieldView_File << "Residual_" << iVar+1 << endl; - } - } - - if (grid_movement) { - if (nDim == 2) FieldView_File << "Grid_Velx\nGrid_Vely" << endl; - else FieldView_File << "Grid_Velx\nGrid_Vely\nGrid_Velz" << endl; - } - - if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - FieldView_File << "Pressure\nTemperature\nPressure_Coefficient\nMach" << endl; - } - - if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - FieldView_File << "Laminar_Viscosity\nSkin_Friction_Coefficient\nHeat_Flux\nY_Plus" << endl; - } - - if (Kind_Solver == RANS) { - FieldView_File << "Eddy_Viscosity" << endl; - } - - if (config->GetWrt_SharpEdges()) { - if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - FieldView_File << "Sharp_Edge_Dist" << endl; - } - } - - if (( Kind_Solver == ADJ_EULER ) || - ( Kind_Solver == ADJ_NAVIER_STOKES ) || - ( Kind_Solver == ADJ_RANS ) ) { - FieldView_File << "Surface_Sensitivity\nSolution_Sensor" << endl; - } - - if (( Kind_Solver == DISC_ADJ_EULER ) || - ( Kind_Solver == DISC_ADJ_NAVIER_STOKES ) || - ( Kind_Solver == DISC_ADJ_RANS ) ) { - if (nDim == 2) FieldView_File << "Surface_Sensitivity\nSensitivity_x\nSensitivity_y" << endl; - else FieldView_File << "Surface_Sensitivity\nSensitivity_x\nSensitivity_y\nSensitivity_z" << endl; - } - - /*--- SU2 does not generate boundary variables ---*/ - - nbvars = 0; - FieldView_File << "Boundary Variable Names\t" << nbvars << endl; - - } - - /*--- Output the node definition section for this grid - Output the X, Y, Z coordinates of successive nodes. - Note that this differs from the binary/unformatted specification. ---*/ - - if (nDim == 3) { - - FieldView_File << "Nodes\t" << nGlobal_Poin << endl; - - for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { - if (config->GetKind_SU2() != SU2_SOL) { - for (iDim = 0; iDim < nDim; iDim++) - FieldView_File << scientific << Coords[iDim][iPoint] << "\t"; - } - else { - for (iDim = 0; iDim < nDim; iDim++) - FieldView_File << scientific << Data[iDim][iPoint] << "\t"; - } - FieldView_File << endl; - } - - } - - else { - - FieldView_File << "Nodes\t" << nGlobal_Poin*2 << endl; - - for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { - if (config->GetKind_SU2() != SU2_SOL) { - for (iDim = 0; iDim < nDim; iDim++) - FieldView_File << scientific << Coords[iDim][iPoint] << "\t"; - } - else { - for (iDim = 0; iDim < nDim; iDim++) - FieldView_File << scientific << Data[iDim][iPoint] << "\t"; - } - FieldView_File << scientific << "0.0" << endl; - } - for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { - if (config->GetKind_SU2() != SU2_SOL) { - for (iDim = 0; iDim < nDim; iDim++) - FieldView_File << scientific << Coords[iDim][iPoint] << "\t"; - } - else { - for (iDim = 0; iDim < nDim; iDim++) - FieldView_File << scientific << Data[iDim][iPoint] << "\t"; - } - FieldView_File << scientific << "-1E-10" << endl; - } - - } - - /*--- Output the boundary face definitions. - Note that this differs from the binary/unformatted specification. - Each face is preceded by an index into the boundary table at the - top of the file and the number of face vertices, 3 or 4. - All faces here have 4 vertices. If the face is triangular, - the last vertex should be zero. - TIP: FIELDVIEW assumes that boundary faces are not in random - order. It assumes that faces of the same type tend to occur - in groups. If your boundary faces are in random order, you - may want to output them one boundary type at a time. This - will give you better performance (less memory, greater speed) - in FIELDVIEW. ---*/ - - - if (nDim ==2) { - - nbfaces = nGlobal_Tria + nGlobal_Quad; - - FieldView_File << "Boundary Faces\t" << nbfaces << endl; - - for (iElem = 0; iElem < nGlobal_Tria; iElem++) { - iNode = iElem*N_POINTS_TRIANGLE; - FieldView_File <<"1\t3\t"<< Conn_Tria[iNode+0] << "\t"; - FieldView_File << Conn_Tria[iNode+1] << "\t"; - FieldView_File << Conn_Tria[iNode+2] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Quad; iElem++) { - iNode = iElem*N_POINTS_QUADRILATERAL; - FieldView_File <<"1\t4\t"<< Conn_Quad[iNode+0] << "\t"; - FieldView_File << Conn_Quad[iNode+1] << "\t"; - FieldView_File << Conn_Quad[iNode+2] << "\t"; - FieldView_File << Conn_Quad[iNode+3] << "\n"; - } - - } - - if (nDim ==3) { - - nbfaces = nGlobal_BoundTria + nGlobal_BoundQuad; - - FieldView_File << "Boundary Faces\t" << nbfaces << endl; - - for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { - iNode = iElem*N_POINTS_TRIANGLE; - FieldView_File << "1\t3\t" << Conn_BoundTria[iNode+0] << "\t"; - FieldView_File << Conn_BoundTria[iNode+1] << "\t"; - FieldView_File << Conn_BoundTria[iNode+2] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { - iNode = iElem*N_POINTS_QUADRILATERAL; - FieldView_File << "1\t4\t" << Conn_BoundQuad[iNode+0] << "\t"; - FieldView_File << Conn_BoundQuad[iNode+1] << "\t"; - FieldView_File << Conn_BoundQuad[iNode+2] << "\t"; - FieldView_File << Conn_BoundQuad[iNode+3] << "\n"; - } - - } - - - /*--- Output the elements section for this grid. - Note that this differs from the binary/unformatted specification. - It contains the headers and node definitions of all elements. - In this example, each element starts with 2 for type 'hex', - with a subtype of 1 (the only subtype currently supported). - This is followed by the node indices for the element. ---*/ - - - FieldView_File << "Elements" << endl; - - for (iElem = 0; iElem < nGlobal_Tria; iElem++) { - iNode = iElem*N_POINTS_TRIANGLE; - FieldView_File <<"3\t1\t"<< Conn_Tria[iNode+0] << "\t"; - FieldView_File << Conn_Tria[iNode+1] << "\t"; - FieldView_File << Conn_Tria[iNode+2] << "\t"; - FieldView_File << nGlobal_Poin+Conn_Tria[iNode+0] << "\t"; - FieldView_File << nGlobal_Poin+Conn_Tria[iNode+1] << "\t"; - FieldView_File << nGlobal_Poin+Conn_Tria[iNode+2] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Quad; iElem++) { - iNode = iElem*N_POINTS_QUADRILATERAL; - FieldView_File <<"2\t1\t"<< Conn_Quad[iNode+0] << "\t"; - FieldView_File << Conn_Quad[iNode+1] << "\t"; - FieldView_File << Conn_Quad[iNode+2] << "\t"; - FieldView_File << Conn_Quad[iNode+3] << "\t"; - FieldView_File << nGlobal_Poin+Conn_Quad[iNode+0] << "\t"; - FieldView_File << nGlobal_Poin+Conn_Quad[iNode+1] << "\t"; - FieldView_File << nGlobal_Poin+Conn_Quad[iNode+2] << "\t"; - FieldView_File << nGlobal_Poin+Conn_Quad[iNode+3] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Tetr; iElem++) { - iNode = iElem*N_POINTS_TETRAHEDRON; - FieldView_File <<"1\t1\t"<< Conn_Tetr[iNode+0] << "\t" << Conn_Tetr[iNode+1] << "\t"; - FieldView_File << Conn_Tetr[iNode+2] << "\t" << Conn_Tetr[iNode+3] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Hexa; iElem++) { - iNode = iElem*N_POINTS_HEXAHEDRON; - FieldView_File <<"2\t1\t"<< Conn_Hexa[iNode+0] << "\t" << Conn_Hexa[iNode+1] << "\t"; - FieldView_File << Conn_Hexa[iNode+2] << "\t" << Conn_Hexa[iNode+3] << "\t"; - FieldView_File << Conn_Hexa[iNode+4] << "\t" << Conn_Hexa[iNode+5] << "\t"; - FieldView_File << Conn_Hexa[iNode+6] << "\t" << Conn_Hexa[iNode+7] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Pris; iElem++) { - iNode = iElem*N_POINTS_PRISM; - FieldView_File <<"3\t1\t"<< Conn_Pris[iNode+0] << "\t" << Conn_Pris[iNode+1] << "\t"; - FieldView_File << Conn_Pris[iNode+2] << "\t" << Conn_Pris[iNode+3] << "\t"; - FieldView_File << Conn_Pris[iNode+4] << "\t" << Conn_Pris[iNode+5] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Pyra; iElem++) { - iNode = iElem*N_POINTS_PYRAMID; - FieldView_File <<"4\t1\t"<< Conn_Pyra[iNode+0] << "\t" << Conn_Pyra[iNode+1] << "\t"; - FieldView_File << Conn_Pyra[iNode+2] << "\t" << Conn_Pyra[iNode+3] << "\t"; - FieldView_File << Conn_Pyra[iNode+4] << "\n"; - } - - /*--- Output the variables data for this grid. - Note that all of the data for the first variable is output - before any of the data for the second variable. - You should skip this section if the number of variables is zero. - The variables must be in the same order as the "Variable Names" - section. ---*/ - - FieldView_File << "Variables" << endl; - - /*--- Loop over the vars/residuals and write the values to file ---*/ - - if (config->GetKind_SU2() != SU2_SOL) { - for (iVar = 0; iVar < nvars; iVar++) { - for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { - FieldView_File << scientific << Data[iVar][iPoint] << endl; - } - if (nDim == 2) { - for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { - FieldView_File << scientific << Data[iVar][iPoint] << endl; - } - } - } - } - else { - for (iVar = 0; iVar < nvars; iVar++) { - for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { - FieldView_File << scientific << Data[iVar+nDim][iPoint] << endl; - } - if (nDim == 2) { - for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { - FieldView_File << scientific << Data[iVar+nDim][iPoint] << endl; - } - } - } - } - - /*--- Output the boundary variables data for this grid. - Note that all of the data for the first variable is output - before any of the data for the second variable. - Remember that the Boundary Table above has a "surface results - flag" indicating which boundary types have surface results. - The data should be written in the same order as the faces in - the Boundary Faces section, skipping over faces whose boundary - type has a surface results flag of zero (false). - For each variable, you should write one number per boundary face. - You should skip this section if the number of boundary - variables is zero. ---*/ - - FieldView_File << "Boundary Variables" << endl; - - - FieldView_File.close(); - -} - -void COutput::SetFieldViewASCII_Mesh(CConfig *config, CGeometry *geometry) { } - -void COutput::SetFieldViewBinary(CConfig *config, CGeometry *geometry, unsigned short val_iZone, unsigned short val_nZone) { - - unsigned short iDim, iVar, nDim = geometry->GetnDim(), ngrids = 1, nbvars, nvars; - unsigned short Kind_Solver = config->GetKind_Solver(); - - unsigned long iPoint, iElem, iNode, nbfaces; - unsigned long iExtIter = config->GetExtIter(); - bool adjoint = config->GetAdjoint(); - bool disc_adjoint = config->GetDiscrete_Adjoint(); - - char cstr[200], buffer[50]; - string filename; - - /*--- Write file name with extension ---*/ - - if (adjoint || disc_adjoint) filename = config->GetAdj_FileName(); - else filename = config->GetFlow_FileName(); - - if (Kind_Solver == LINEAR_ELASTICITY) - filename = config->GetStructure_FileName().c_str(); - - if (Kind_Solver == WAVE_EQUATION) - filename = config->GetWave_FileName().c_str(); - - if (Kind_Solver == HEAT_EQUATION) - filename = config->GetHeat_FileName().c_str(); - - if (Kind_Solver == POISSON_EQUATION) - filename = config->GetStructure_FileName().c_str(); - - strcpy (cstr, filename.c_str()); - - /*--- Special cases where a number needs to be appended to the file name. ---*/ - - if ((Kind_Solver == EULER || Kind_Solver == NAVIER_STOKES || Kind_Solver == RANS || - Kind_Solver == ADJ_EULER || Kind_Solver == ADJ_NAVIER_STOKES || Kind_Solver == ADJ_RANS) && - (val_nZone > 1) && (config->GetUnsteady_Simulation() != TIME_SPECTRAL)) { - SPRINTF (buffer, "_%d", SU2_TYPE::Int(val_iZone)); - strcat(cstr, buffer); - } - - if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { - - if (config->GetKind_SU2() == SU2_SOL) { val_iZone = iExtIter; } - - if (SU2_TYPE::Int(val_iZone) < 10) SPRINTF (buffer, "_0000%d.uns", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 10) && (SU2_TYPE::Int(val_iZone) < 100)) SPRINTF (buffer, "_000%d.uns", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 100) && (SU2_TYPE::Int(val_iZone) < 1000)) SPRINTF (buffer, "_00%d.uns", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 1000) && (SU2_TYPE::Int(val_iZone) < 10000)) SPRINTF (buffer, "_0%d.uns", SU2_TYPE::Int(val_iZone)); - if (SU2_TYPE::Int(val_iZone) >= 10000) SPRINTF (buffer, "_%d.uns", SU2_TYPE::Int(val_iZone)); - - } - else if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { - if (SU2_TYPE::Int(iExtIter) < 10) SPRINTF (buffer, "_0000%d.uns", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.uns", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.uns", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.uns", SU2_TYPE::Int(iExtIter)); - if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.uns", SU2_TYPE::Int(iExtIter)); - } - else { SPRINTF (buffer, ".uns"); } - - strcat(cstr, buffer); - - /*--- Open FieldView ASCII file and write the header ---*/ - - ofstream FieldView_File; - FieldView_File.open(cstr, ios::out); - FieldView_File.precision(6); - - FieldView_File << "FIELDVIEW 3 0" << endl; - - /*--- Output constants for time, fsmach, alpha and re. ---*/ - - FieldView_File << "Constants" << endl; - FieldView_File << config->GetExtIter() <<"\t"<< config->GetMach() <<"\t"<< config->GetAoA() <<"\t"<< config->GetReynolds() << endl; - - /*--- Output the number of grids. ---*/ - - FieldView_File << "Grids\t" << ngrids << endl; - - /*--- Output the table of boundary types, starting with the number of types. - Note that this differs from the binary/unformatted specification. - Each boundary type name is preceded by 3 integer flags. - The first flag indicates whether this boundary type is a wall. - A flag value of 1 indicates a wall, and a value of 0 indicates - a non-wall. Walls are significant for streamline calculation. - The second flag indicates whether the boundary type has surface - results. A value of 1 means surface results will be present for - this boundary type (if any boundary variables are specified in the - Boundary Variable Names section below). A value of 0 means no surface - results will be present. - The third flag indicates whether boundary faces of this type have - consistent "clockness" for the purpose of calculating a surface - normal. A value of 1 means that all faces of this type are - written following a "right hand rule" for clockness. In other - words, if the vertices are written on counter-clockwise: - 4 --- 3 - | | - 1 --- 2 - then the normal to the face is pointing towards you (not away - from you). A value of 0 means that the faces do not have any - consistent clockness. The "clockness" of surface normals is - only used for calculating certain special surface integrals - that involve surface normals. If the surface normals flag - is 0, these special integrals will not be available. ---*/ - - FieldView_File << "Boundary Table\t1" << endl; - FieldView_File << "1\t0\t1\tMARKER_PLOTTING" << endl; - - /*--- Output the table of variable names, starting with the number of - variables. The number of variables can be zero. - Note that vector variables are specified by a ';' and vector name - following the first scalar name of 3 scalar components of the - vector. If writing 2-D results, the third component must still - be provided here, and its values must be written in the variables - section below (typically padded with zeros.) ---*/ - - if (config->GetKind_SU2() == SU2_SOL) { - - /*--- If SU2_SOL called this routine, we already have a set of output - variables with the appropriate string tags stored in the config class. ---*/ - - nvars = config->fields.size() - 1 - nDim; - - FieldView_File << "Variable Names\t" << nvars << endl; - - for (unsigned short iField = 1+nDim; iField < config->fields.size(); iField++) { - FieldView_File << config->fields[iField] << endl; - } - - /*--- SU2 does not generate boundary variables ---*/ - - nbvars = 0; - FieldView_File << "Boundary Variable Names\t" << nbvars << endl; - - } - - else { - - nvars = nVar_Consv + nDim; - - FieldView_File << "Variable Names\t" << nvars-nDim << endl; - - for (iVar = 0; iVar < nVar_Consv; iVar++) { - FieldView_File << "Conservative_" << iVar+1 << endl; - } - - /*--- SU2 does not generate boundary variables ---*/ - - nbvars = 0; - FieldView_File << "Boundary Variable Names\t" << nbvars << endl; - - } - - /*--- Output the node definition section for this grid ---*/ - - FieldView_File << "Nodes\t" << nGlobal_Poin << endl; - - /*--- Output the X, Y, Z coordinates of successive nodes. - Note that this differs from the binary/unformatted specification. ---*/ - - for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { - - if (config->GetKind_SU2() != SU2_SOL) { - for (iDim = 0; iDim < nDim; iDim++) - FieldView_File << scientific << Coords[iDim][iPoint] << "\t"; - } - else { - for (iVar = 0; iVar < nVar_Total; iVar++) - FieldView_File << scientific << Data[iVar][iPoint] << "\t"; - } - FieldView_File << endl; - - } - - /*--- Output the boundary face definitions. - Note that this differs from the binary/unformatted specification. - Each face is preceded by an index into the boundary table at the - top of the file and the number of face vertices, 3 or 4. - All faces here have 4 vertices. If the face is triangular, - the last vertex should be zero. - TIP: FIELDVIEW assumes that boundary faces are not in random - order. It assumes that faces of the same type tend to occur - in groups. If your boundary faces are in random order, you - may want to output them one boundary type at a time. This - will give you better performance (less memory, greater speed) - in FIELDVIEW. ---*/ - - nbfaces = nGlobal_Line + nGlobal_BoundTria + nGlobal_BoundQuad; - - FieldView_File << "Boundary Faces\t" << nbfaces << endl; - - for (iElem = 0; iElem < nGlobal_Line; iElem++) { - iNode = iElem*N_POINTS_LINE; - FieldView_File << "1\t2\t" << Conn_Line[iNode+0] << "\t"; - FieldView_File << "1\t2\t" << Conn_Line[iNode+1] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { - iNode = iElem*N_POINTS_TRIANGLE; - FieldView_File << "1\t3\t" << Conn_BoundTria[iNode+0] << "\t"; - FieldView_File << Conn_BoundTria[iNode+1] << "\t"; - FieldView_File << Conn_BoundTria[iNode+2] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { - iNode = iElem*N_POINTS_QUADRILATERAL; - FieldView_File << "1\t4\t" << Conn_BoundQuad[iNode+0] << "\t"; - FieldView_File << Conn_BoundQuad[iNode+1] << "\t"; - FieldView_File << Conn_BoundQuad[iNode+2] << "\t"; - FieldView_File << Conn_BoundQuad[iNode+3] << "\n"; - } - - /*--- Output the elements section for this grid. - Note that this differs from the binary/unformatted specification. - It contains the headers and node definitions of all elements. - In this example, each element starts with 2 for type 'hex', - with a subtype of 1 (the only subtype currently supported). - This is followed by the node indices for the element. ---*/ - - - FieldView_File << "Elements" << endl; - - for (iElem = 0; iElem < nGlobal_Tria; iElem++) { - iNode = iElem*N_POINTS_TRIANGLE; - FieldView_File <<"2\t1\t"<< Conn_Tria[iNode+0] << "\t"; - FieldView_File << Conn_Tria[iNode+1] << "\t"; - FieldView_File << Conn_Tria[iNode+2] << "\t"; - FieldView_File << Conn_Tria[iNode+2] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Quad; iElem++) { - iNode = iElem*N_POINTS_QUADRILATERAL; - FieldView_File <<"2\t1\t"<< Conn_Quad[iNode+0] << "\t"; - FieldView_File << Conn_Quad[iNode+1] << "\t"; - FieldView_File << Conn_Quad[iNode+2] << "\t"; - FieldView_File << Conn_Quad[iNode+3] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Tetr; iElem++) { - iNode = iElem*N_POINTS_TETRAHEDRON; - FieldView_File <<"1\t1\t"<< Conn_Tetr[iNode+0] << "\t" << Conn_Tetr[iNode+1] << "\t"; - FieldView_File << Conn_Tetr[iNode+2] << "\t" << Conn_Tetr[iNode+2] << "\t"; - FieldView_File << Conn_Tetr[iNode+3] << "\t" << Conn_Tetr[iNode+3] << "\t"; - FieldView_File << Conn_Tetr[iNode+3] << "\t" << Conn_Tetr[iNode+3] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Hexa; iElem++) { - iNode = iElem*N_POINTS_HEXAHEDRON; - FieldView_File <<"2\t1\t"<< Conn_Hexa[iNode+0] << "\t" << Conn_Hexa[iNode+1] << "\t"; - FieldView_File << Conn_Hexa[iNode+2] << "\t" << Conn_Hexa[iNode+3] << "\t"; - FieldView_File << Conn_Hexa[iNode+4] << "\t" << Conn_Hexa[iNode+5] << "\t"; - FieldView_File << Conn_Hexa[iNode+6] << "\t" << Conn_Hexa[iNode+7] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Pris; iElem++) { - iNode = iElem*N_POINTS_PRISM; - FieldView_File <<"3\t1\t"<< Conn_Pris[iNode+0] << "\t" << Conn_Pris[iNode+1] << "\t"; - FieldView_File << Conn_Pris[iNode+1] << "\t" << Conn_Pris[iNode+2] << "\t"; - FieldView_File << Conn_Pris[iNode+3] << "\t" << Conn_Pris[iNode+4] << "\t"; - FieldView_File << Conn_Pris[iNode+4] << "\t" << Conn_Pris[iNode+5] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Pyra; iElem++) { - iNode = iElem*N_POINTS_PYRAMID; - FieldView_File <<"4\t1\t"<< Conn_Pyra[iNode+0] << "\t" << Conn_Pyra[iNode+1] << "\t"; - FieldView_File << Conn_Pyra[iNode+2] << "\t" << Conn_Pyra[iNode+3] << "\t"; - FieldView_File << Conn_Pyra[iNode+4] << "\t" << Conn_Pyra[iNode+4] << "\t"; - FieldView_File << Conn_Pyra[iNode+4] << "\t" << Conn_Pyra[iNode+4] << "\n"; - } - - /*--- Output the variables data for this grid. - Note that all of the data for the first variable is output - before any of the data for the second variable. - You should skip this section if the number of variables is zero. - The variables must be in the same order as the "Variable Names" - section. ---*/ - - FieldView_File << "Variables" << endl; - - /*--- Loop over the vars/residuals and write the values to file ---*/ - for (iVar = nDim; iVar < nVar_Total; iVar++) { - for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { - FieldView_File << scientific << Data[iVar][iPoint] << endl; - } - } - - /*--- Output the boundary variables data for this grid. - Note that all of the data for the first variable is output - before any of the data for the second variable. - Remember that the Boundary Table above has a "surface results - flag" indicating which boundary types have surface results. - The data should be written in the same order as the faces in - the Boundary Faces section, skipping over faces whose boundary - type has a surface results flag of zero (false). - For each variable, you should write one number per boundary face. - You should skip this section if the number of boundary - variables is zero. ---*/ - - FieldView_File << "Boundary Variables" << endl; - - - FieldView_File.close(); - -} - -void COutput::SetFieldViewBinary_Mesh(CConfig *config, CGeometry *geometry) { } +/*! + * \file output_fieldview.cpp + * \brief Main subroutines for output solver information. + * \author F. Palacios, T. Economon, M. Colonno + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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_structure.hpp" + +void COutput::SetFieldViewASCII(CConfig *config, CGeometry *geometry, unsigned short val_iZone, unsigned short val_nZone) { + + unsigned short iDim, iVar, nDim = geometry->GetnDim(), ngrids = 1, nbvars, nvars; + unsigned short Kind_Solver = config->GetKind_Solver(); + + unsigned long iPoint, iElem, iNode, nbfaces; + + unsigned long iExtIter = config->GetExtIter(); + bool adjoint = config->GetAdjoint(); + bool disc_adjoint = config->GetDiscrete_Adjoint(); + + bool grid_movement = config->GetGrid_Movement(); + + char cstr[200], buffer[50]; + string filename, FieldName; + + /*--- Write file name with extension ---*/ + + if (adjoint || disc_adjoint) filename = config->GetAdj_FileName(); + else filename = config->GetFlow_FileName(); + + if (Kind_Solver == LINEAR_ELASTICITY) + filename = config->GetStructure_FileName().c_str(); + + if (Kind_Solver == WAVE_EQUATION) + filename = config->GetWave_FileName().c_str(); + + if (Kind_Solver == HEAT_EQUATION) + filename = config->GetHeat_FileName().c_str(); + + if (Kind_Solver == POISSON_EQUATION) + filename = config->GetStructure_FileName().c_str(); + + strcpy (cstr, filename.c_str()); + + /*--- Special cases where a number needs to be appended to the file name. ---*/ + + if ((Kind_Solver == EULER || Kind_Solver == NAVIER_STOKES || Kind_Solver == RANS || + Kind_Solver == ADJ_EULER || Kind_Solver == ADJ_NAVIER_STOKES || Kind_Solver == ADJ_RANS) && + (val_nZone > 1) && (config->GetUnsteady_Simulation() != TIME_SPECTRAL)) { + SPRINTF (buffer, "_%d", SU2_TYPE::Int(val_iZone)); + strcat(cstr, buffer); + } + + if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { + + if (config->GetKind_SU2() == SU2_SOL) { val_iZone = iExtIter; } + + if (SU2_TYPE::Int(val_iZone) < 10) SPRINTF (buffer, "_0000%d.uns", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 10) && (SU2_TYPE::Int(val_iZone) < 100)) SPRINTF (buffer, "_000%d.uns", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 100) && (SU2_TYPE::Int(val_iZone) < 1000)) SPRINTF (buffer, "_00%d.uns", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 1000) && (SU2_TYPE::Int(val_iZone) < 10000)) SPRINTF (buffer, "_0%d.uns", SU2_TYPE::Int(val_iZone)); + if (SU2_TYPE::Int(val_iZone) >= 10000) SPRINTF (buffer, "_%d.uns", SU2_TYPE::Int(val_iZone)); + + } + else if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { + if (SU2_TYPE::Int(iExtIter) < 10) SPRINTF (buffer, "_0000%d.uns", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.uns", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.uns", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.uns", SU2_TYPE::Int(iExtIter)); + if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.uns", SU2_TYPE::Int(iExtIter)); + } + else { SPRINTF (buffer, ".uns"); } + + strcat(cstr, buffer); + + /*--- Open FieldView ASCII file and write the header ---*/ + + ofstream FieldView_File; + FieldView_File.open(cstr, ios::out); + FieldView_File.precision(6); + + FieldView_File << "FIELDVIEW 3 0" << endl; + + /*--- Output constants for time, fsmach, alpha and re. ---*/ + + FieldView_File << "Constants" << endl; + FieldView_File << config->GetExtIter() <<"\t"<< config->GetMach() <<"\t"<< config->GetAoA() <<"\t"<< config->GetReynolds() << endl; + + /*--- Output the number of grids. ---*/ + + FieldView_File << "Grids\t" << ngrids << endl; + + /*--- Output the table of boundary types, starting with the number of types. + Note that this differs from the binary/unformatted specification. + Each boundary type name is preceded by 3 integer flags. + The first flag indicates whether this boundary type is a wall. + A flag value of 1 indicates a wall, and a value of 0 indicates + a non-wall. Walls are significant for streamline calculation. + The second flag indicates whether the boundary type has surface + results. A value of 1 means surface results will be present for + this boundary type (if any boundary variables are specified in the + Boundary Variable Names section below). A value of 0 means no surface + results will be present. + The third flag indicates whether boundary faces of this type have + consistent "clockness" for the purpose of calculating a surface + normal. A value of 1 means that all faces of this type are + written following a "right hand rule" for clockness. In other + words, if the vertices are written on counter-clockwise: + 4 --- 3 + | | + 1 --- 2 + then the normal to the face is pointing towards you (not away + from you). A value of 0 means that the faces do not have any + consistent clockness. The "clockness" of surface normals is + only used for calculating certain special surface integrals + that involve surface normals. If the surface normals flag + is 0, these special integrals will not be available. ---*/ + + FieldView_File << "Boundary Table\t1" << endl; + FieldView_File << "1\t0\t1\tMARKER_PLOTTING" << endl; + + /*--- Output the table of variable names, starting with the number of + variables. The number of variables can be zero. + Note that vector variables are specified by a ';' and vector name + following the first scalar name of 3 scalar components of the + vector. If writing 2-D results, the third component must still + be provided here, and its values must be written in the variables + section below (typically padded with zeros.) ---*/ + + if (config->GetKind_SU2() == SU2_SOL) { + + /*--- If SU2_SOL called this routine, we already have a set of output + variables with the appropriate string tags stored in the config class. ---*/ + + nvars = nVar_Total-nDim; + + FieldView_File << "Variable Names\t" << nvars << endl; + + for (unsigned short iField = 1+nDim; iField < config->fields.size(); iField++) { + + /*--- Remove all su2double-quote characters ---*/ + + FieldName = config->fields[iField]; + + FieldName.erase( + remove(FieldName.begin(), FieldName.end(), '\"' ), + FieldName.end() + ); + + FieldView_File << FieldName << endl; + } + + /*--- SU2 does not generate boundary variables ---*/ + + nbvars = 0; + FieldView_File << "Boundary Variable Names\t" << nbvars << endl; + + } + + else { + + nvars = nVar_Total; + + FieldView_File << "Variable Names\t" << nvars << endl; + + for (iVar = 0; iVar < nVar_Consv; iVar++) { + FieldView_File << "Conservative_" << iVar+1 << endl; + } + + /*--- Add names for any extra variables (this will need to be adjusted). ---*/ + + if (config->GetWrt_Limiters()) { + for (iVar = 0; iVar < nVar_Consv; iVar++) { + FieldView_File << "Limiter_" << iVar+1 << endl; + } + } + + if (config->GetWrt_Residuals()) { + for (iVar = 0; iVar < nVar_Consv; iVar++) { + FieldView_File << "Residual_" << iVar+1 << endl; + } + } + + if (grid_movement) { + if (nDim == 2) FieldView_File << "Grid_Velx\nGrid_Vely" << endl; + else FieldView_File << "Grid_Velx\nGrid_Vely\nGrid_Velz" << endl; + } + + if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + FieldView_File << "Pressure\nTemperature\nPressure_Coefficient\nMach" << endl; + } + + if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + FieldView_File << "Laminar_Viscosity\nSkin_Friction_Coefficient\nHeat_Flux\nY_Plus" << endl; + } + + if (Kind_Solver == RANS) { + FieldView_File << "Eddy_Viscosity" << endl; + } + + if (config->GetWrt_SharpEdges()) { + if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + FieldView_File << "Sharp_Edge_Dist" << endl; + } + } + + if (( Kind_Solver == ADJ_EULER ) || + ( Kind_Solver == ADJ_NAVIER_STOKES ) || + ( Kind_Solver == ADJ_RANS ) ) { + FieldView_File << "Surface_Sensitivity\nSolution_Sensor" << endl; + } + + if (( Kind_Solver == DISC_ADJ_EULER ) || + ( Kind_Solver == DISC_ADJ_NAVIER_STOKES ) || + ( Kind_Solver == DISC_ADJ_RANS ) ) { + if (nDim == 2) FieldView_File << "Surface_Sensitivity\nSensitivity_x\nSensitivity_y" << endl; + else FieldView_File << "Surface_Sensitivity\nSensitivity_x\nSensitivity_y\nSensitivity_z" << endl; + } + + /*--- SU2 does not generate boundary variables ---*/ + + nbvars = 0; + FieldView_File << "Boundary Variable Names\t" << nbvars << endl; + + } + + /*--- Output the node definition section for this grid + Output the X, Y, Z coordinates of successive nodes. + Note that this differs from the binary/unformatted specification. ---*/ + + if (nDim == 3) { + + FieldView_File << "Nodes\t" << nGlobal_Poin << endl; + + for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { + if (config->GetKind_SU2() != SU2_SOL) { + for (iDim = 0; iDim < nDim; iDim++) + FieldView_File << scientific << Coords[iDim][iPoint] << "\t"; + } + else { + for (iDim = 0; iDim < nDim; iDim++) + FieldView_File << scientific << Data[iDim][iPoint] << "\t"; + } + FieldView_File << endl; + } + + } + + else { + + FieldView_File << "Nodes\t" << nGlobal_Poin*2 << endl; + + for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { + if (config->GetKind_SU2() != SU2_SOL) { + for (iDim = 0; iDim < nDim; iDim++) + FieldView_File << scientific << Coords[iDim][iPoint] << "\t"; + } + else { + for (iDim = 0; iDim < nDim; iDim++) + FieldView_File << scientific << Data[iDim][iPoint] << "\t"; + } + FieldView_File << scientific << "0.0" << endl; + } + for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { + if (config->GetKind_SU2() != SU2_SOL) { + for (iDim = 0; iDim < nDim; iDim++) + FieldView_File << scientific << Coords[iDim][iPoint] << "\t"; + } + else { + for (iDim = 0; iDim < nDim; iDim++) + FieldView_File << scientific << Data[iDim][iPoint] << "\t"; + } + FieldView_File << scientific << "-1E-10" << endl; + } + + } + + /*--- Output the boundary face definitions. + Note that this differs from the binary/unformatted specification. + Each face is preceded by an index into the boundary table at the + top of the file and the number of face vertices, 3 or 4. + All faces here have 4 vertices. If the face is triangular, + the last vertex should be zero. + TIP: FIELDVIEW assumes that boundary faces are not in random + order. It assumes that faces of the same type tend to occur + in groups. If your boundary faces are in random order, you + may want to output them one boundary type at a time. This + will give you better performance (less memory, greater speed) + in FIELDVIEW. ---*/ + + + if (nDim ==2) { + + nbfaces = nGlobal_Tria + nGlobal_Quad; + + FieldView_File << "Boundary Faces\t" << nbfaces << endl; + + for (iElem = 0; iElem < nGlobal_Tria; iElem++) { + iNode = iElem*N_POINTS_TRIANGLE; + FieldView_File <<"1\t3\t"<< Conn_Tria[iNode+0] << "\t"; + FieldView_File << Conn_Tria[iNode+1] << "\t"; + FieldView_File << Conn_Tria[iNode+2] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Quad; iElem++) { + iNode = iElem*N_POINTS_QUADRILATERAL; + FieldView_File <<"1\t4\t"<< Conn_Quad[iNode+0] << "\t"; + FieldView_File << Conn_Quad[iNode+1] << "\t"; + FieldView_File << Conn_Quad[iNode+2] << "\t"; + FieldView_File << Conn_Quad[iNode+3] << "\n"; + } + + } + + if (nDim ==3) { + + nbfaces = nGlobal_BoundTria + nGlobal_BoundQuad; + + FieldView_File << "Boundary Faces\t" << nbfaces << endl; + + for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { + iNode = iElem*N_POINTS_TRIANGLE; + FieldView_File << "1\t3\t" << Conn_BoundTria[iNode+0] << "\t"; + FieldView_File << Conn_BoundTria[iNode+1] << "\t"; + FieldView_File << Conn_BoundTria[iNode+2] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { + iNode = iElem*N_POINTS_QUADRILATERAL; + FieldView_File << "1\t4\t" << Conn_BoundQuad[iNode+0] << "\t"; + FieldView_File << Conn_BoundQuad[iNode+1] << "\t"; + FieldView_File << Conn_BoundQuad[iNode+2] << "\t"; + FieldView_File << Conn_BoundQuad[iNode+3] << "\n"; + } + + } + + + /*--- Output the elements section for this grid. + Note that this differs from the binary/unformatted specification. + It contains the headers and node definitions of all elements. + In this example, each element starts with 2 for type 'hex', + with a subtype of 1 (the only subtype currently supported). + This is followed by the node indices for the element. ---*/ + + + FieldView_File << "Elements" << endl; + + for (iElem = 0; iElem < nGlobal_Tria; iElem++) { + iNode = iElem*N_POINTS_TRIANGLE; + FieldView_File <<"3\t1\t"<< Conn_Tria[iNode+0] << "\t"; + FieldView_File << Conn_Tria[iNode+1] << "\t"; + FieldView_File << Conn_Tria[iNode+2] << "\t"; + FieldView_File << nGlobal_Poin+Conn_Tria[iNode+0] << "\t"; + FieldView_File << nGlobal_Poin+Conn_Tria[iNode+1] << "\t"; + FieldView_File << nGlobal_Poin+Conn_Tria[iNode+2] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Quad; iElem++) { + iNode = iElem*N_POINTS_QUADRILATERAL; + FieldView_File <<"2\t1\t"<< Conn_Quad[iNode+0] << "\t"; + FieldView_File << Conn_Quad[iNode+1] << "\t"; + FieldView_File << Conn_Quad[iNode+2] << "\t"; + FieldView_File << Conn_Quad[iNode+3] << "\t"; + FieldView_File << nGlobal_Poin+Conn_Quad[iNode+0] << "\t"; + FieldView_File << nGlobal_Poin+Conn_Quad[iNode+1] << "\t"; + FieldView_File << nGlobal_Poin+Conn_Quad[iNode+2] << "\t"; + FieldView_File << nGlobal_Poin+Conn_Quad[iNode+3] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Tetr; iElem++) { + iNode = iElem*N_POINTS_TETRAHEDRON; + FieldView_File <<"1\t1\t"<< Conn_Tetr[iNode+0] << "\t" << Conn_Tetr[iNode+1] << "\t"; + FieldView_File << Conn_Tetr[iNode+2] << "\t" << Conn_Tetr[iNode+3] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Hexa; iElem++) { + iNode = iElem*N_POINTS_HEXAHEDRON; + FieldView_File <<"2\t1\t"<< Conn_Hexa[iNode+0] << "\t" << Conn_Hexa[iNode+1] << "\t"; + FieldView_File << Conn_Hexa[iNode+2] << "\t" << Conn_Hexa[iNode+3] << "\t"; + FieldView_File << Conn_Hexa[iNode+4] << "\t" << Conn_Hexa[iNode+5] << "\t"; + FieldView_File << Conn_Hexa[iNode+6] << "\t" << Conn_Hexa[iNode+7] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Pris; iElem++) { + iNode = iElem*N_POINTS_PRISM; + FieldView_File <<"3\t1\t"<< Conn_Pris[iNode+0] << "\t" << Conn_Pris[iNode+1] << "\t"; + FieldView_File << Conn_Pris[iNode+2] << "\t" << Conn_Pris[iNode+3] << "\t"; + FieldView_File << Conn_Pris[iNode+4] << "\t" << Conn_Pris[iNode+5] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Pyra; iElem++) { + iNode = iElem*N_POINTS_PYRAMID; + FieldView_File <<"4\t1\t"<< Conn_Pyra[iNode+0] << "\t" << Conn_Pyra[iNode+1] << "\t"; + FieldView_File << Conn_Pyra[iNode+2] << "\t" << Conn_Pyra[iNode+3] << "\t"; + FieldView_File << Conn_Pyra[iNode+4] << "\n"; + } + + /*--- Output the variables data for this grid. + Note that all of the data for the first variable is output + before any of the data for the second variable. + You should skip this section if the number of variables is zero. + The variables must be in the same order as the "Variable Names" + section. ---*/ + + FieldView_File << "Variables" << endl; + + /*--- Loop over the vars/residuals and write the values to file ---*/ + + if (config->GetKind_SU2() != SU2_SOL) { + for (iVar = 0; iVar < nvars; iVar++) { + for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { + FieldView_File << scientific << Data[iVar][iPoint] << endl; + } + if (nDim == 2) { + for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { + FieldView_File << scientific << Data[iVar][iPoint] << endl; + } + } + } + } + else { + for (iVar = 0; iVar < nvars; iVar++) { + for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { + FieldView_File << scientific << Data[iVar+nDim][iPoint] << endl; + } + if (nDim == 2) { + for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { + FieldView_File << scientific << Data[iVar+nDim][iPoint] << endl; + } + } + } + } + + /*--- Output the boundary variables data for this grid. + Note that all of the data for the first variable is output + before any of the data for the second variable. + Remember that the Boundary Table above has a "surface results + flag" indicating which boundary types have surface results. + The data should be written in the same order as the faces in + the Boundary Faces section, skipping over faces whose boundary + type has a surface results flag of zero (false). + For each variable, you should write one number per boundary face. + You should skip this section if the number of boundary + variables is zero. ---*/ + + FieldView_File << "Boundary Variables" << endl; + + + FieldView_File.close(); + +} + +void COutput::SetFieldViewASCII_Mesh(CConfig *config, CGeometry *geometry) { } + +void COutput::SetFieldViewBinary(CConfig *config, CGeometry *geometry, unsigned short val_iZone, unsigned short val_nZone) { + + unsigned short iDim, iVar, nDim = geometry->GetnDim(), ngrids = 1, nbvars, nvars; + unsigned short Kind_Solver = config->GetKind_Solver(); + + unsigned long iPoint, iElem, iNode, nbfaces; + unsigned long iExtIter = config->GetExtIter(); + bool adjoint = config->GetAdjoint(); + bool disc_adjoint = config->GetDiscrete_Adjoint(); + + char cstr[200], buffer[50]; + string filename; + + /*--- Write file name with extension ---*/ + + if (adjoint || disc_adjoint) filename = config->GetAdj_FileName(); + else filename = config->GetFlow_FileName(); + + if (Kind_Solver == LINEAR_ELASTICITY) + filename = config->GetStructure_FileName().c_str(); + + if (Kind_Solver == WAVE_EQUATION) + filename = config->GetWave_FileName().c_str(); + + if (Kind_Solver == HEAT_EQUATION) + filename = config->GetHeat_FileName().c_str(); + + if (Kind_Solver == POISSON_EQUATION) + filename = config->GetStructure_FileName().c_str(); + + strcpy (cstr, filename.c_str()); + + /*--- Special cases where a number needs to be appended to the file name. ---*/ + + if ((Kind_Solver == EULER || Kind_Solver == NAVIER_STOKES || Kind_Solver == RANS || + Kind_Solver == ADJ_EULER || Kind_Solver == ADJ_NAVIER_STOKES || Kind_Solver == ADJ_RANS) && + (val_nZone > 1) && (config->GetUnsteady_Simulation() != TIME_SPECTRAL)) { + SPRINTF (buffer, "_%d", SU2_TYPE::Int(val_iZone)); + strcat(cstr, buffer); + } + + if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { + + if (config->GetKind_SU2() == SU2_SOL) { val_iZone = iExtIter; } + + if (SU2_TYPE::Int(val_iZone) < 10) SPRINTF (buffer, "_0000%d.uns", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 10) && (SU2_TYPE::Int(val_iZone) < 100)) SPRINTF (buffer, "_000%d.uns", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 100) && (SU2_TYPE::Int(val_iZone) < 1000)) SPRINTF (buffer, "_00%d.uns", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 1000) && (SU2_TYPE::Int(val_iZone) < 10000)) SPRINTF (buffer, "_0%d.uns", SU2_TYPE::Int(val_iZone)); + if (SU2_TYPE::Int(val_iZone) >= 10000) SPRINTF (buffer, "_%d.uns", SU2_TYPE::Int(val_iZone)); + + } + else if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { + if (SU2_TYPE::Int(iExtIter) < 10) SPRINTF (buffer, "_0000%d.uns", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.uns", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.uns", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.uns", SU2_TYPE::Int(iExtIter)); + if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.uns", SU2_TYPE::Int(iExtIter)); + } + else { SPRINTF (buffer, ".uns"); } + + strcat(cstr, buffer); + + /*--- Open FieldView ASCII file and write the header ---*/ + + ofstream FieldView_File; + FieldView_File.open(cstr, ios::out); + FieldView_File.precision(6); + + FieldView_File << "FIELDVIEW 3 0" << endl; + + /*--- Output constants for time, fsmach, alpha and re. ---*/ + + FieldView_File << "Constants" << endl; + FieldView_File << config->GetExtIter() <<"\t"<< config->GetMach() <<"\t"<< config->GetAoA() <<"\t"<< config->GetReynolds() << endl; + + /*--- Output the number of grids. ---*/ + + FieldView_File << "Grids\t" << ngrids << endl; + + /*--- Output the table of boundary types, starting with the number of types. + Note that this differs from the binary/unformatted specification. + Each boundary type name is preceded by 3 integer flags. + The first flag indicates whether this boundary type is a wall. + A flag value of 1 indicates a wall, and a value of 0 indicates + a non-wall. Walls are significant for streamline calculation. + The second flag indicates whether the boundary type has surface + results. A value of 1 means surface results will be present for + this boundary type (if any boundary variables are specified in the + Boundary Variable Names section below). A value of 0 means no surface + results will be present. + The third flag indicates whether boundary faces of this type have + consistent "clockness" for the purpose of calculating a surface + normal. A value of 1 means that all faces of this type are + written following a "right hand rule" for clockness. In other + words, if the vertices are written on counter-clockwise: + 4 --- 3 + | | + 1 --- 2 + then the normal to the face is pointing towards you (not away + from you). A value of 0 means that the faces do not have any + consistent clockness. The "clockness" of surface normals is + only used for calculating certain special surface integrals + that involve surface normals. If the surface normals flag + is 0, these special integrals will not be available. ---*/ + + FieldView_File << "Boundary Table\t1" << endl; + FieldView_File << "1\t0\t1\tMARKER_PLOTTING" << endl; + + /*--- Output the table of variable names, starting with the number of + variables. The number of variables can be zero. + Note that vector variables are specified by a ';' and vector name + following the first scalar name of 3 scalar components of the + vector. If writing 2-D results, the third component must still + be provided here, and its values must be written in the variables + section below (typically padded with zeros.) ---*/ + + if (config->GetKind_SU2() == SU2_SOL) { + + /*--- If SU2_SOL called this routine, we already have a set of output + variables with the appropriate string tags stored in the config class. ---*/ + + nvars = config->fields.size() - 1 - nDim; + + FieldView_File << "Variable Names\t" << nvars << endl; + + for (unsigned short iField = 1+nDim; iField < config->fields.size(); iField++) { + FieldView_File << config->fields[iField] << endl; + } + + /*--- SU2 does not generate boundary variables ---*/ + + nbvars = 0; + FieldView_File << "Boundary Variable Names\t" << nbvars << endl; + + } + + else { + + nvars = nVar_Consv + nDim; + + FieldView_File << "Variable Names\t" << nvars-nDim << endl; + + for (iVar = 0; iVar < nVar_Consv; iVar++) { + FieldView_File << "Conservative_" << iVar+1 << endl; + } + + /*--- SU2 does not generate boundary variables ---*/ + + nbvars = 0; + FieldView_File << "Boundary Variable Names\t" << nbvars << endl; + + } + + /*--- Output the node definition section for this grid ---*/ + + FieldView_File << "Nodes\t" << nGlobal_Poin << endl; + + /*--- Output the X, Y, Z coordinates of successive nodes. + Note that this differs from the binary/unformatted specification. ---*/ + + for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { + + if (config->GetKind_SU2() != SU2_SOL) { + for (iDim = 0; iDim < nDim; iDim++) + FieldView_File << scientific << Coords[iDim][iPoint] << "\t"; + } + else { + for (iVar = 0; iVar < nVar_Total; iVar++) + FieldView_File << scientific << Data[iVar][iPoint] << "\t"; + } + FieldView_File << endl; + + } + + /*--- Output the boundary face definitions. + Note that this differs from the binary/unformatted specification. + Each face is preceded by an index into the boundary table at the + top of the file and the number of face vertices, 3 or 4. + All faces here have 4 vertices. If the face is triangular, + the last vertex should be zero. + TIP: FIELDVIEW assumes that boundary faces are not in random + order. It assumes that faces of the same type tend to occur + in groups. If your boundary faces are in random order, you + may want to output them one boundary type at a time. This + will give you better performance (less memory, greater speed) + in FIELDVIEW. ---*/ + + nbfaces = nGlobal_Line + nGlobal_BoundTria + nGlobal_BoundQuad; + + FieldView_File << "Boundary Faces\t" << nbfaces << endl; + + for (iElem = 0; iElem < nGlobal_Line; iElem++) { + iNode = iElem*N_POINTS_LINE; + FieldView_File << "1\t2\t" << Conn_Line[iNode+0] << "\t"; + FieldView_File << "1\t2\t" << Conn_Line[iNode+1] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { + iNode = iElem*N_POINTS_TRIANGLE; + FieldView_File << "1\t3\t" << Conn_BoundTria[iNode+0] << "\t"; + FieldView_File << Conn_BoundTria[iNode+1] << "\t"; + FieldView_File << Conn_BoundTria[iNode+2] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { + iNode = iElem*N_POINTS_QUADRILATERAL; + FieldView_File << "1\t4\t" << Conn_BoundQuad[iNode+0] << "\t"; + FieldView_File << Conn_BoundQuad[iNode+1] << "\t"; + FieldView_File << Conn_BoundQuad[iNode+2] << "\t"; + FieldView_File << Conn_BoundQuad[iNode+3] << "\n"; + } + + /*--- Output the elements section for this grid. + Note that this differs from the binary/unformatted specification. + It contains the headers and node definitions of all elements. + In this example, each element starts with 2 for type 'hex', + with a subtype of 1 (the only subtype currently supported). + This is followed by the node indices for the element. ---*/ + + + FieldView_File << "Elements" << endl; + + for (iElem = 0; iElem < nGlobal_Tria; iElem++) { + iNode = iElem*N_POINTS_TRIANGLE; + FieldView_File <<"2\t1\t"<< Conn_Tria[iNode+0] << "\t"; + FieldView_File << Conn_Tria[iNode+1] << "\t"; + FieldView_File << Conn_Tria[iNode+2] << "\t"; + FieldView_File << Conn_Tria[iNode+2] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Quad; iElem++) { + iNode = iElem*N_POINTS_QUADRILATERAL; + FieldView_File <<"2\t1\t"<< Conn_Quad[iNode+0] << "\t"; + FieldView_File << Conn_Quad[iNode+1] << "\t"; + FieldView_File << Conn_Quad[iNode+2] << "\t"; + FieldView_File << Conn_Quad[iNode+3] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Tetr; iElem++) { + iNode = iElem*N_POINTS_TETRAHEDRON; + FieldView_File <<"1\t1\t"<< Conn_Tetr[iNode+0] << "\t" << Conn_Tetr[iNode+1] << "\t"; + FieldView_File << Conn_Tetr[iNode+2] << "\t" << Conn_Tetr[iNode+2] << "\t"; + FieldView_File << Conn_Tetr[iNode+3] << "\t" << Conn_Tetr[iNode+3] << "\t"; + FieldView_File << Conn_Tetr[iNode+3] << "\t" << Conn_Tetr[iNode+3] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Hexa; iElem++) { + iNode = iElem*N_POINTS_HEXAHEDRON; + FieldView_File <<"2\t1\t"<< Conn_Hexa[iNode+0] << "\t" << Conn_Hexa[iNode+1] << "\t"; + FieldView_File << Conn_Hexa[iNode+2] << "\t" << Conn_Hexa[iNode+3] << "\t"; + FieldView_File << Conn_Hexa[iNode+4] << "\t" << Conn_Hexa[iNode+5] << "\t"; + FieldView_File << Conn_Hexa[iNode+6] << "\t" << Conn_Hexa[iNode+7] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Pris; iElem++) { + iNode = iElem*N_POINTS_PRISM; + FieldView_File <<"3\t1\t"<< Conn_Pris[iNode+0] << "\t" << Conn_Pris[iNode+1] << "\t"; + FieldView_File << Conn_Pris[iNode+1] << "\t" << Conn_Pris[iNode+2] << "\t"; + FieldView_File << Conn_Pris[iNode+3] << "\t" << Conn_Pris[iNode+4] << "\t"; + FieldView_File << Conn_Pris[iNode+4] << "\t" << Conn_Pris[iNode+5] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Pyra; iElem++) { + iNode = iElem*N_POINTS_PYRAMID; + FieldView_File <<"4\t1\t"<< Conn_Pyra[iNode+0] << "\t" << Conn_Pyra[iNode+1] << "\t"; + FieldView_File << Conn_Pyra[iNode+2] << "\t" << Conn_Pyra[iNode+3] << "\t"; + FieldView_File << Conn_Pyra[iNode+4] << "\t" << Conn_Pyra[iNode+4] << "\t"; + FieldView_File << Conn_Pyra[iNode+4] << "\t" << Conn_Pyra[iNode+4] << "\n"; + } + + /*--- Output the variables data for this grid. + Note that all of the data for the first variable is output + before any of the data for the second variable. + You should skip this section if the number of variables is zero. + The variables must be in the same order as the "Variable Names" + section. ---*/ + + FieldView_File << "Variables" << endl; + + /*--- Loop over the vars/residuals and write the values to file ---*/ + for (iVar = nDim; iVar < nVar_Total; iVar++) { + for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { + FieldView_File << scientific << Data[iVar][iPoint] << endl; + } + } + + /*--- Output the boundary variables data for this grid. + Note that all of the data for the first variable is output + before any of the data for the second variable. + Remember that the Boundary Table above has a "surface results + flag" indicating which boundary types have surface results. + The data should be written in the same order as the faces in + the Boundary Faces section, skipping over faces whose boundary + type has a surface results flag of zero (false). + For each variable, you should write one number per boundary face. + You should skip this section if the number of boundary + variables is zero. ---*/ + + FieldView_File << "Boundary Variables" << endl; + + + FieldView_File.close(); + +} + +void COutput::SetFieldViewBinary_Mesh(CConfig *config, CGeometry *geometry) { } diff --git a/SU2_CFD/src/output_structure.cpp b/SU2_CFD/src/output_structure.cpp index 4baaee5a8bc..26b3ae580dd 100644 --- a/SU2_CFD/src/output_structure.cpp +++ b/SU2_CFD/src/output_structure.cpp @@ -1,7849 +1,7849 @@ -/*! - * \file output_structure.cpp - * \brief Main subroutines for output solver information - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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_structure.hpp" - -COutput::COutput(void) { - - /*--- Initialize point and connectivity counters to zero. ---*/ - - nGlobal_Poin = 0; - nSurf_Poin = 0; - nGlobal_Elem = 0; - nSurf_Elem = 0; - nGlobal_Tria = 0; - nGlobal_Quad = 0; - nGlobal_Tetr = 0; - nGlobal_Hexa = 0; - nGlobal_Pris = 0; - nGlobal_Pyra = 0; - nGlobal_Line = 0; - nGlobal_BoundTria = 0; - nGlobal_BoundQuad = 0; - - /*--- Initialize CGNS write flag ---*/ - - wrote_base_file = false; - - /*--- Initialize CGNS write flag ---*/ - - wrote_CGNS_base = false; - - /*--- Initialize Tecplot surface flag ---*/ - - wrote_surf_file = false; - - /*--- Initialize Paraview write flag ---*/ - - wrote_Paraview_base = false; - - /*--- Initialize residual ---*/ - - RhoRes_New = EPS; - RhoRes_Old = EPS; - -} - -COutput::~COutput(void) { } - -void COutput::SetSurfaceCSV_Flow(CConfig *config, CGeometry *geometry, - CSolver *FlowSolver, unsigned long iExtIter, - unsigned short val_iZone) { - - unsigned short iMarker; - unsigned long iPoint, iVertex, Global_Index; - su2double PressCoeff = 0.0, SkinFrictionCoeff; - su2double xCoord = 0.0, yCoord = 0.0, zCoord = 0.0, Mach, Pressure; - char cstr[200]; - - unsigned short solver = config->GetKind_Solver(); - unsigned short nDim = geometry->GetnDim(); - -#ifndef HAVE_MPI - - su2double HeatFlux; - char buffer [50]; - ofstream SurfFlow_file; - - /*--- Write file name with extension if unsteady ---*/ - strcpy (cstr, config->GetSurfFlowCoeff_FileName().c_str()); - - if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { - if (SU2_TYPE::Int(val_iZone) < 10) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 10) && (SU2_TYPE::Int(val_iZone) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 100) && (SU2_TYPE::Int(val_iZone) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 1000) && (SU2_TYPE::Int(val_iZone) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(val_iZone)); - if (SU2_TYPE::Int(val_iZone) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(val_iZone)); - - } else if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { - if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(iExtIter)); - if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(iExtIter)); - } - else - SPRINTF (buffer, ".csv"); - - strcat (cstr, buffer); - SurfFlow_file.precision(15); - SurfFlow_file.open(cstr, ios::out); - - SurfFlow_file << "\"Global_Index\", \"x_coord\", \"y_coord\", "; - if (nDim == 3) SurfFlow_file << "\"z_coord\", "; - SurfFlow_file << "\"Pressure\", \"Pressure_Coefficient\", "; - - switch (solver) { - case EULER : SurfFlow_file << "\"Mach_Number\"" << endl; break; - case NAVIER_STOKES: case RANS: SurfFlow_file << "\"Skin_Friction_Coefficient\", \"Heat_Flux\"" << endl; break; - } - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_Plotting(iMarker) == YES) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Global_Index = geometry->node[iPoint]->GetGlobalIndex(); - xCoord = geometry->node[iPoint]->GetCoord(0); - yCoord = geometry->node[iPoint]->GetCoord(1); - if (nDim == 3) zCoord = geometry->node[iPoint]->GetCoord(2); - - /*--- The output should be in inches ---*/ - - if (config->GetSystemMeasurements() == US) { - xCoord *= 12.0; yCoord *= 12.0; - if (nDim == 3) zCoord *= 12.0; - } - - Pressure = FlowSolver->node[iPoint]->GetPressure(); - PressCoeff = FlowSolver->GetCPressure(iMarker, iVertex); - SurfFlow_file << scientific << Global_Index << ", " << xCoord << ", " << yCoord << ", "; - if (nDim == 3) SurfFlow_file << scientific << zCoord << ", "; - SurfFlow_file << scientific << Pressure << ", " << PressCoeff << ", "; - switch (solver) { - case EULER : - Mach = sqrt(FlowSolver->node[iPoint]->GetVelocity2()) / FlowSolver->node[iPoint]->GetSoundSpeed(); - SurfFlow_file << scientific << Mach << endl; - break; - case NAVIER_STOKES: case RANS: - SkinFrictionCoeff = FlowSolver->GetCSkinFriction(iMarker, iVertex); - HeatFlux = FlowSolver->GetHeatFlux(iMarker, iVertex); - SurfFlow_file << scientific << SkinFrictionCoeff << ", " << HeatFlux << endl; - break; - } - } - } - } - - SurfFlow_file.close(); - -#else - - int rank, iProcessor, nProcessor; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); - - unsigned long Buffer_Send_nVertex[1], *Buffer_Recv_nVertex = NULL; - unsigned long nVertex_Surface = 0, nLocalVertex_Surface = 0; - unsigned long MaxLocalVertex_Surface = 0; - - /*--- Find the max number of surface vertices among all - partitions and set up buffers. The master node will handle the - writing of the CSV file after gathering all of the data. ---*/ - - nLocalVertex_Surface = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_Plotting(iMarker) == YES) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if (geometry->node[iPoint]->GetDomain()) nLocalVertex_Surface++; - } - - /*--- Communicate the number of local vertices on each partition - to the master node ---*/ - - Buffer_Send_nVertex[0] = nLocalVertex_Surface; - if (rank == MASTER_NODE) Buffer_Recv_nVertex = new unsigned long [nProcessor]; - - SU2_MPI::Allreduce(&nLocalVertex_Surface, &MaxLocalVertex_Surface, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Gather(&Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Recv_nVertex, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); - - /*--- Send and Recv buffers ---*/ - - su2double *Buffer_Send_Coord_x = new su2double [MaxLocalVertex_Surface]; - su2double *Buffer_Recv_Coord_x = NULL; - - su2double *Buffer_Send_Coord_y = new su2double [MaxLocalVertex_Surface]; - su2double *Buffer_Recv_Coord_y = NULL; - - su2double *Buffer_Send_Coord_z = new su2double [MaxLocalVertex_Surface]; - su2double *Buffer_Recv_Coord_z = NULL; - - su2double *Buffer_Send_Press = new su2double [MaxLocalVertex_Surface]; - su2double *Buffer_Recv_Press = NULL; - - su2double *Buffer_Send_CPress = new su2double [MaxLocalVertex_Surface]; - su2double *Buffer_Recv_CPress = NULL; - - su2double *Buffer_Send_Mach = new su2double [MaxLocalVertex_Surface]; - su2double *Buffer_Recv_Mach = NULL; - - su2double *Buffer_Send_SkinFriction = new su2double [MaxLocalVertex_Surface]; - su2double *Buffer_Recv_SkinFriction = NULL; - - su2double *Buffer_Send_HeatTransfer = new su2double [MaxLocalVertex_Surface]; - su2double *Buffer_Recv_HeatTransfer = NULL; - - unsigned long *Buffer_Send_GlobalIndex = new unsigned long [MaxLocalVertex_Surface]; - unsigned long *Buffer_Recv_GlobalIndex = NULL; - - /*--- Prepare the receive buffers on the master node only. ---*/ - - if (rank == MASTER_NODE) { - Buffer_Recv_Coord_x = new su2double [nProcessor*MaxLocalVertex_Surface]; - Buffer_Recv_Coord_y = new su2double [nProcessor*MaxLocalVertex_Surface]; - if (nDim == 3) Buffer_Recv_Coord_z = new su2double [nProcessor*MaxLocalVertex_Surface]; - Buffer_Recv_Press = new su2double [nProcessor*MaxLocalVertex_Surface]; - Buffer_Recv_CPress = new su2double [nProcessor*MaxLocalVertex_Surface]; - Buffer_Recv_Mach = new su2double [nProcessor*MaxLocalVertex_Surface]; - Buffer_Recv_SkinFriction = new su2double [nProcessor*MaxLocalVertex_Surface]; - Buffer_Recv_HeatTransfer = new su2double [nProcessor*MaxLocalVertex_Surface]; - Buffer_Recv_GlobalIndex = new unsigned long [nProcessor*MaxLocalVertex_Surface]; - } - - /*--- Loop over all vertices in this partition and load the - data of the specified type into the buffer to be sent to - the master node. ---*/ - - nVertex_Surface = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_Plotting(iMarker) == YES) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if (geometry->node[iPoint]->GetDomain()) { - Buffer_Send_Press[nVertex_Surface] = FlowSolver->node[iPoint]->GetPressure(); - Buffer_Send_CPress[nVertex_Surface] = FlowSolver->GetCPressure(iMarker, iVertex); - Buffer_Send_Coord_x[nVertex_Surface] = geometry->node[iPoint]->GetCoord(0); - Buffer_Send_Coord_y[nVertex_Surface] = geometry->node[iPoint]->GetCoord(1); - if (nDim == 3) { Buffer_Send_Coord_z[nVertex_Surface] = geometry->node[iPoint]->GetCoord(2); } - - /*--- If US system, the output should be in inches ---*/ - - if (config->GetSystemMeasurements() == US) { - Buffer_Send_Coord_x[nVertex_Surface] *= 12.0; - Buffer_Send_Coord_y[nVertex_Surface] *= 12.0; - if (nDim == 3) Buffer_Send_Coord_z[nVertex_Surface] *= 12.0; - } - - Buffer_Send_GlobalIndex[nVertex_Surface] = geometry->node[iPoint]->GetGlobalIndex(); - - if (solver == EULER) - Buffer_Send_Mach[nVertex_Surface] = sqrt(FlowSolver->node[iPoint]->GetVelocity2()) / FlowSolver->node[iPoint]->GetSoundSpeed(); - if ((solver == NAVIER_STOKES) || (solver == RANS)) - Buffer_Send_SkinFriction[nVertex_Surface] = FlowSolver->GetCSkinFriction(iMarker, iVertex); - nVertex_Surface++; - } - } - - /*--- Send the information to the master node ---*/ - - SU2_MPI::Gather(Buffer_Send_Coord_x, MaxLocalVertex_Surface, MPI_DOUBLE, Buffer_Recv_Coord_x, MaxLocalVertex_Surface, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Coord_y, MaxLocalVertex_Surface, MPI_DOUBLE, Buffer_Recv_Coord_y, MaxLocalVertex_Surface, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - if (nDim == 3) SU2_MPI::Gather(Buffer_Send_Coord_z, MaxLocalVertex_Surface, MPI_DOUBLE, Buffer_Recv_Coord_z, MaxLocalVertex_Surface, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Press, MaxLocalVertex_Surface, MPI_DOUBLE, Buffer_Recv_Press, MaxLocalVertex_Surface, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_CPress, MaxLocalVertex_Surface, MPI_DOUBLE, Buffer_Recv_CPress, MaxLocalVertex_Surface, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - if (solver == EULER) SU2_MPI::Gather(Buffer_Send_Mach, MaxLocalVertex_Surface, MPI_DOUBLE, Buffer_Recv_Mach, MaxLocalVertex_Surface, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - if ((solver == NAVIER_STOKES) || (solver == RANS)) SU2_MPI::Gather(Buffer_Send_SkinFriction, MaxLocalVertex_Surface, MPI_DOUBLE, Buffer_Recv_SkinFriction, MaxLocalVertex_Surface, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_GlobalIndex, MaxLocalVertex_Surface, MPI_UNSIGNED_LONG, Buffer_Recv_GlobalIndex, MaxLocalVertex_Surface, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); - - /*--- The master node unpacks the data and writes the surface CSV file ---*/ - - if (rank == MASTER_NODE) { - - /*--- Write file name with extension if unsteady ---*/ - char buffer[50]; - string filename = config->GetSurfFlowCoeff_FileName(); - ofstream SurfFlow_file; - - /*--- Write file name with extension if unsteady ---*/ - strcpy (cstr, filename.c_str()); - if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { - if (SU2_TYPE::Int(val_iZone) < 10) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 10) && (SU2_TYPE::Int(val_iZone) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 100) && (SU2_TYPE::Int(val_iZone) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 1000) && (SU2_TYPE::Int(val_iZone) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(val_iZone)); - if (SU2_TYPE::Int(val_iZone) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(val_iZone)); - - } else if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { - if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(iExtIter)); - if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(iExtIter)); - } - else - SPRINTF (buffer, ".csv"); - - strcat (cstr, buffer); - SurfFlow_file.precision(15); - SurfFlow_file.open(cstr, ios::out); - - SurfFlow_file << "\"Global_Index\", \"x_coord\", \"y_coord\", "; - if (nDim == 3) SurfFlow_file << "\"z_coord\", "; - SurfFlow_file << "\"Pressure\", \"Pressure_Coefficient\", "; - - switch (solver) { - case EULER : SurfFlow_file << "\"Mach_Number\"" << endl; break; - case NAVIER_STOKES: case RANS: SurfFlow_file << "\"Skin_Friction_Coefficient\"" << endl; break; - } - - /*--- Loop through all of the collected data and write each node's values ---*/ - - unsigned long Total_Index; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (iVertex = 0; iVertex < Buffer_Recv_nVertex[iProcessor]; iVertex++) { - - /*--- Current index position and global index ---*/ - Total_Index = iProcessor*MaxLocalVertex_Surface+iVertex; - Global_Index = Buffer_Recv_GlobalIndex[Total_Index]; - - /*--- Retrieve the merged data for this node ---*/ - xCoord = Buffer_Recv_Coord_x[Total_Index]; - yCoord = Buffer_Recv_Coord_y[Total_Index]; - if (nDim == 3) zCoord = Buffer_Recv_Coord_z[Total_Index]; - Pressure = Buffer_Recv_Press[Total_Index]; - PressCoeff = Buffer_Recv_CPress[Total_Index]; - - /*--- Write the first part of the data ---*/ - SurfFlow_file << scientific << Global_Index << ", " << xCoord << ", " << yCoord << ", "; - if (nDim == 3) SurfFlow_file << scientific << zCoord << ", "; - SurfFlow_file << scientific << Pressure << ", " << PressCoeff << ", "; - - /*--- Write the solver-dependent part of the data ---*/ - switch (solver) { - case EULER : - Mach = Buffer_Recv_Mach[Total_Index]; - SurfFlow_file << scientific << Mach << endl; - break; - case NAVIER_STOKES: case RANS: - SkinFrictionCoeff = Buffer_Recv_SkinFriction[Total_Index]; - SurfFlow_file << scientific << SkinFrictionCoeff << endl; - break; - } - } - } - - /*--- Close the CSV file ---*/ - SurfFlow_file.close(); - - /*--- Release the recv buffers on the master node ---*/ - - delete [] Buffer_Recv_Coord_x; - delete [] Buffer_Recv_Coord_y; - if (nDim == 3) delete [] Buffer_Recv_Coord_z; - delete [] Buffer_Recv_Press; - delete [] Buffer_Recv_CPress; - delete [] Buffer_Recv_Mach; - delete [] Buffer_Recv_SkinFriction; - delete [] Buffer_Recv_HeatTransfer; - delete [] Buffer_Recv_GlobalIndex; - - delete [] Buffer_Recv_nVertex; - - } - - /*--- Release the memory for the remaining buffers and exit ---*/ - - delete [] Buffer_Send_Coord_x; - delete [] Buffer_Send_Coord_y; - delete [] Buffer_Send_Coord_z; - delete [] Buffer_Send_Press; - delete [] Buffer_Send_CPress; - delete [] Buffer_Send_Mach; - delete [] Buffer_Send_SkinFriction; - delete [] Buffer_Send_HeatTransfer; - delete [] Buffer_Send_GlobalIndex; - -#endif - -} - -void COutput::SetSurfaceCSV_Adjoint(CConfig *config, CGeometry *geometry, CSolver *AdjSolver, CSolver *FlowSolution, unsigned long iExtIter, unsigned short val_iZone) { - -#ifndef HAVE_MPI - - unsigned long iPoint, iVertex, Global_Index; - su2double *Solution, xCoord, yCoord, zCoord; - unsigned short iMarker; - char cstr[200], buffer[50]; - ofstream SurfAdj_file; - - /*--- Write file name with extension if unsteady ---*/ - strcpy (cstr, config->GetSurfAdjCoeff_FileName().c_str()); - - if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { - if (SU2_TYPE::Int(val_iZone) < 10) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 10) && (SU2_TYPE::Int(val_iZone) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 100) && (SU2_TYPE::Int(val_iZone) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 1000) && (SU2_TYPE::Int(val_iZone) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(val_iZone)); - if (SU2_TYPE::Int(val_iZone) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(val_iZone)); - - } else if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { - if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(iExtIter)); - if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(iExtIter)); - } - else - SPRINTF (buffer, ".csv"); - - strcat(cstr, buffer); - SurfAdj_file.precision(15); - SurfAdj_file.open(cstr, ios::out); - - if (geometry->GetnDim() == 2) { - SurfAdj_file << "\"Point\",\"Sensitivity\",\"PsiRho\",\"Phi_x\",\"Phi_y\",\"PsiE\",\"x_coord\",\"y_coord\""; - if (config->GetDiscrete_Adjoint()){ - SurfAdj_file << ",\"x_Sens\",\"y_Sens\""; - } - SurfAdj_file << endl; - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_Plotting(iMarker) == YES) - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Global_Index = geometry->node[iPoint]->GetGlobalIndex(); - Solution = AdjSolver->node[iPoint]->GetSolution(); - xCoord = geometry->node[iPoint]->GetCoord(0); - yCoord = geometry->node[iPoint]->GetCoord(1); - - /*--- If US system, the output should be in inches ---*/ - - if (config->GetSystemMeasurements() == US) { - xCoord *= 12.0; - yCoord *= 12.0; - } - - SurfAdj_file << scientific << Global_Index << ", " << AdjSolver->GetCSensitivity(iMarker, iVertex) << ", " << Solution[0] << ", " - << Solution[1] << ", " << Solution[2] << ", " << Solution[3] <<", " << xCoord <<", "<< yCoord; - if (config->GetDiscrete_Adjoint()){ - SurfAdj_file << ", " << AdjSolver->node[iPoint]->GetSensitivity(0) << ", " << AdjSolver->node[iPoint]->GetSensitivity(1); - } - SurfAdj_file << endl; - } - } - } - - if (geometry->GetnDim() == 3) { - SurfAdj_file << "\"Point\",\"Sensitivity\",\"PsiRho\",\"Phi_x\",\"Phi_y\",\"Phi_z\",\"PsiE\",\"x_coord\",\"y_coord\",\"z_coord\""; - if (config->GetDiscrete_Adjoint()){ - SurfAdj_file << ",\"x_Sens\",\"y_Sens\",\"z_Sens\""; - } - SurfAdj_file << endl; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_Plotting(iMarker) == YES) - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Global_Index = geometry->node[iPoint]->GetGlobalIndex(); - Solution = AdjSolver->node[iPoint]->GetSolution(); - - xCoord = geometry->node[iPoint]->GetCoord(0); - yCoord = geometry->node[iPoint]->GetCoord(1); - zCoord = geometry->node[iPoint]->GetCoord(2); - - /*--- If US system, the output should be in inches ---*/ - - if (config->GetSystemMeasurements() == US) { - xCoord *= 12.0; - yCoord *= 12.0; - zCoord *= 12.0; - } - - SurfAdj_file << scientific << Global_Index << ", " << AdjSolver->GetCSensitivity(iMarker, iVertex) << ", " << Solution[0] << ", " - << Solution[1] << ", " << Solution[2] << ", " << Solution[3] << ", " << Solution[4] << ", "<< xCoord <<", "<< yCoord <<", "<< zCoord; - if (config->GetDiscrete_Adjoint()){ - SurfAdj_file << ", " << AdjSolver->node[iPoint]->GetSensitivity(0) << ", " << AdjSolver->node[iPoint]->GetSensitivity(1) - << ", " << AdjSolver->node[iPoint]->GetSensitivity(2); - } - SurfAdj_file << endl; - } - } - } - - SurfAdj_file.close(); - -#else - int rank, iProcessor, nProcessor; - - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); - - unsigned short nDim = geometry->GetnDim(), iMarker; - su2double *Solution, *Coord; - unsigned long Buffer_Send_nVertex[1], iVertex, iPoint, nVertex_Surface = 0, nLocalVertex_Surface = 0, - MaxLocalVertex_Surface = 0, nBuffer_Scalar; - unsigned long *Buffer_Receive_nVertex = NULL; - ofstream SurfAdj_file; - - /*--- Write the surface .csv file ---*/ - nLocalVertex_Surface = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_Plotting(iMarker) == YES) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if (geometry->node[iPoint]->GetDomain()) nLocalVertex_Surface ++; - } - - if (rank == MASTER_NODE) - Buffer_Receive_nVertex = new unsigned long [nProcessor]; - - Buffer_Send_nVertex[0] = nLocalVertex_Surface; - - SU2_MPI::Allreduce(&nLocalVertex_Surface, &MaxLocalVertex_Surface, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Gather(&Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); - - su2double *Buffer_Send_Coord_x = new su2double[MaxLocalVertex_Surface]; - su2double *Buffer_Send_Coord_y= new su2double[MaxLocalVertex_Surface]; - su2double *Buffer_Send_Coord_z= new su2double[MaxLocalVertex_Surface]; - unsigned long *Buffer_Send_GlobalPoint= new unsigned long[MaxLocalVertex_Surface]; - su2double *Buffer_Send_Sensitivity= new su2double[MaxLocalVertex_Surface]; - su2double *Buffer_Send_PsiRho= new su2double[MaxLocalVertex_Surface]; - su2double *Buffer_Send_Phi_x= new su2double[MaxLocalVertex_Surface]; - su2double *Buffer_Send_Phi_y= new su2double[MaxLocalVertex_Surface]; - su2double *Buffer_Send_Phi_z= new su2double[MaxLocalVertex_Surface]; - su2double *Buffer_Send_PsiE= new su2double[MaxLocalVertex_Surface]; - - su2double *Buffer_Send_Sens_x = NULL, *Buffer_Send_Sens_y = NULL, *Buffer_Send_Sens_z = NULL; - - if (config->GetDiscrete_Adjoint()){ - Buffer_Send_Sens_x = new su2double[MaxLocalVertex_Surface]; - Buffer_Send_Sens_y = new su2double[MaxLocalVertex_Surface]; - if (nDim == 3){ - Buffer_Send_Sens_z = new su2double[MaxLocalVertex_Surface]; - } - } - - nVertex_Surface = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_Plotting(iMarker) == YES) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if (geometry->node[iPoint]->GetDomain()) { - Solution = AdjSolver->node[iPoint]->GetSolution(); - //Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - Coord = geometry->node[iPoint]->GetCoord(); - //d = AdjSolver->node[iPoint]->GetForceProj_Vector(); - Buffer_Send_GlobalPoint[nVertex_Surface] = geometry->node[iPoint]->GetGlobalIndex(); - Buffer_Send_Coord_x[nVertex_Surface] = Coord[0]; - Buffer_Send_Coord_y[nVertex_Surface] = Coord[1]; - Buffer_Send_Sensitivity[nVertex_Surface] = AdjSolver->GetCSensitivity(iMarker, iVertex); - Buffer_Send_PsiRho[nVertex_Surface] = Solution[0]; - Buffer_Send_Phi_x[nVertex_Surface] = Solution[1]; - Buffer_Send_Phi_y[nVertex_Surface] = Solution[2]; - if (nDim == 2) Buffer_Send_PsiE[nVertex_Surface] = Solution[3]; - if (nDim == 3) { - Buffer_Send_Coord_z[nVertex_Surface] = Coord[2]; - Buffer_Send_Phi_z[nVertex_Surface] = Solution[3]; - Buffer_Send_PsiE[nVertex_Surface] = Solution[4]; - } - if (config->GetDiscrete_Adjoint()){ - Buffer_Send_Sens_x[nVertex_Surface] = AdjSolver->node[iPoint]->GetSensitivity(0); - Buffer_Send_Sens_y[nVertex_Surface] = AdjSolver->node[iPoint]->GetSensitivity(1); - if (nDim == 3){ - Buffer_Send_Sens_z[nVertex_Surface] = AdjSolver->node[iPoint]->GetSensitivity(2); - } - } - - /*--- If US system, the output should be in inches ---*/ - - if (config->GetSystemMeasurements() == US) { - Buffer_Send_Coord_x[nVertex_Surface] *= 12.0; - Buffer_Send_Coord_y[nVertex_Surface] *= 12.0; - if (nDim == 3) Buffer_Send_Coord_z[nVertex_Surface] *= 12.0; - } - - nVertex_Surface++; - } - } - - su2double *Buffer_Receive_Coord_x = NULL, *Buffer_Receive_Coord_y = NULL, *Buffer_Receive_Coord_z = NULL, *Buffer_Receive_Sensitivity = NULL, - *Buffer_Receive_PsiRho = NULL, *Buffer_Receive_Phi_x = NULL, *Buffer_Receive_Phi_y = NULL, *Buffer_Receive_Phi_z = NULL, - *Buffer_Receive_PsiE = NULL, *Buffer_Receive_Sens_x = NULL, *Buffer_Receive_Sens_y = NULL, *Buffer_Receive_Sens_z = NULL; - unsigned long *Buffer_Receive_GlobalPoint = NULL; - - if (rank == MASTER_NODE) { - Buffer_Receive_Coord_x = new su2double [nProcessor*MaxLocalVertex_Surface]; - Buffer_Receive_Coord_y = new su2double [nProcessor*MaxLocalVertex_Surface]; - if (nDim == 3) Buffer_Receive_Coord_z = new su2double [nProcessor*MaxLocalVertex_Surface]; - Buffer_Receive_GlobalPoint = new unsigned long [nProcessor*MaxLocalVertex_Surface]; - Buffer_Receive_Sensitivity = new su2double [nProcessor*MaxLocalVertex_Surface]; - Buffer_Receive_PsiRho = new su2double [nProcessor*MaxLocalVertex_Surface]; - Buffer_Receive_Phi_x = new su2double [nProcessor*MaxLocalVertex_Surface]; - Buffer_Receive_Phi_y = new su2double [nProcessor*MaxLocalVertex_Surface]; - if (nDim == 3) Buffer_Receive_Phi_z = new su2double [nProcessor*MaxLocalVertex_Surface]; - Buffer_Receive_PsiE = new su2double [nProcessor*MaxLocalVertex_Surface]; - if (config->GetDiscrete_Adjoint()){ - Buffer_Receive_Sens_x = new su2double[nProcessor*MaxLocalVertex_Surface]; - Buffer_Receive_Sens_y = new su2double[nProcessor*MaxLocalVertex_Surface]; - if (nDim == 3){ - Buffer_Receive_Sens_z = new su2double[nProcessor*MaxLocalVertex_Surface]; - } - } - } - - nBuffer_Scalar = MaxLocalVertex_Surface; - - /*--- Send the information to the Master node ---*/ - SU2_MPI::Gather(Buffer_Send_Coord_x, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Coord_x, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Coord_y, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Coord_y, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - if (nDim == 3) SU2_MPI::Gather(Buffer_Send_Coord_z, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Coord_z, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_GlobalPoint, nBuffer_Scalar, MPI_UNSIGNED_LONG, Buffer_Receive_GlobalPoint, nBuffer_Scalar, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Sensitivity, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Sensitivity, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_PsiRho, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_PsiRho, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Phi_x, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Phi_x, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Phi_y, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Phi_y, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - if (nDim == 3) SU2_MPI::Gather(Buffer_Send_Phi_z, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Phi_z, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_PsiE, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_PsiE, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - if (config->GetDiscrete_Adjoint()){ - SU2_MPI::Gather(Buffer_Send_Sens_x, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Sens_x, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Sens_y, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Sens_y, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - if (nDim == 3){ - SU2_MPI::Gather(Buffer_Send_Sens_z, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Sens_z, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - } - } - - /*--- The master node is the one who writes the surface files ---*/ - if (rank == MASTER_NODE) { - unsigned long iVertex, GlobalPoint, position; - char cstr[200], buffer[50]; - ofstream SurfAdj_file; - string filename = config->GetSurfAdjCoeff_FileName(); - - /*--- Write file name with extension if unsteady ---*/ - strcpy (cstr, filename.c_str()); - - if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { - if (SU2_TYPE::Int(val_iZone) < 10) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 10) && (SU2_TYPE::Int(val_iZone) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 100) && (SU2_TYPE::Int(val_iZone) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 1000) && (SU2_TYPE::Int(val_iZone) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(val_iZone)); - if (SU2_TYPE::Int(val_iZone) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(val_iZone)); - - } else if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { - if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(iExtIter)); - if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(iExtIter)); - } - else - SPRINTF (buffer, ".csv"); - - strcat (cstr, buffer); - SurfAdj_file.open(cstr, ios::out); - SurfAdj_file.precision(15); - - /*--- Write the 2D surface flow coefficient file ---*/ - if (geometry->GetnDim() == 2) { - - SurfAdj_file << "\"Point\",\"Sensitivity\",\"PsiRho\",\"Phi_x\",\"Phi_y\",\"PsiE\",\"x_coord\",\"y_coord\""; - if (config->GetDiscrete_Adjoint()){ - SurfAdj_file << ",\" x_Sens\",\"y_Sens\""; - } - SurfAdj_file << endl; - - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) - for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { - - position = iProcessor*MaxLocalVertex_Surface+iVertex; - GlobalPoint = Buffer_Receive_GlobalPoint[position]; - - SurfAdj_file << scientific << GlobalPoint << - ", " << Buffer_Receive_Sensitivity[position] << ", " << Buffer_Receive_PsiRho[position] << - ", " << Buffer_Receive_Phi_x[position] << ", " << Buffer_Receive_Phi_y[position] << - ", " << Buffer_Receive_PsiE[position] << ", " << Buffer_Receive_Coord_x[position] << - ", "<< Buffer_Receive_Coord_y[position]; - if (config->GetDiscrete_Adjoint()){ - SurfAdj_file << ", " << Buffer_Receive_Sens_x[position] << ", " << Buffer_Receive_Sens_y[position]; - } - SurfAdj_file << endl; - } - } - - /*--- Write the 3D surface flow coefficient file ---*/ - if (geometry->GetnDim() == 3) { - - SurfAdj_file << "\"Point\",\"Sensitivity\",\"PsiRho\",\"Phi_x\",\"Phi_y\",\"Phi_z\",\"PsiE\",\"x_coord\",\"y_coord\",\"z_coord\"" << endl; - if (config->GetDiscrete_Adjoint()){ - SurfAdj_file << ",\"x_Sens\",\"y_Sens\",\"z_Sens\""; - } - SurfAdj_file << endl; - - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) - for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { - position = iProcessor*MaxLocalVertex_Surface+iVertex; - GlobalPoint = Buffer_Receive_GlobalPoint[position]; - - SurfAdj_file << scientific << GlobalPoint << - ", " << Buffer_Receive_Sensitivity[position] << ", " << Buffer_Receive_PsiRho[position] << - ", " << Buffer_Receive_Phi_x[position] << ", " << Buffer_Receive_Phi_y[position] << ", " << Buffer_Receive_Phi_z[position] << - ", " << Buffer_Receive_PsiE[position] <<", "<< Buffer_Receive_Coord_x[position] << - ", "<< Buffer_Receive_Coord_y[position] <<", "<< Buffer_Receive_Coord_z[position]; - if (config->GetDiscrete_Adjoint()){ - SurfAdj_file << ", " << Buffer_Receive_Sens_x[position] << ", " << Buffer_Receive_Sens_y[position] << ", " << Buffer_Receive_Sens_z[position]; - } - SurfAdj_file << endl; - } - } - - } - - if (rank == MASTER_NODE) { - delete [] Buffer_Receive_nVertex; - delete [] Buffer_Receive_Coord_x; - delete [] Buffer_Receive_Coord_y; - if (nDim == 3) delete [] Buffer_Receive_Coord_z; - delete [] Buffer_Receive_Sensitivity; - delete [] Buffer_Receive_PsiRho; - delete [] Buffer_Receive_Phi_x; - delete [] Buffer_Receive_Phi_y; - if (nDim == 3) delete [] Buffer_Receive_Phi_z; - delete [] Buffer_Receive_PsiE; - delete [] Buffer_Receive_GlobalPoint; - if (config->GetDiscrete_Adjoint()){ - delete [] Buffer_Receive_Sens_x; - delete [] Buffer_Receive_Sens_y; - if (nDim == 3){ - delete [] Buffer_Receive_Sens_z; - } - } - } - - delete [] Buffer_Send_Coord_x; - delete [] Buffer_Send_Coord_y; - delete [] Buffer_Send_Coord_z; - delete [] Buffer_Send_GlobalPoint; - delete [] Buffer_Send_Sensitivity; - delete [] Buffer_Send_PsiRho; - delete [] Buffer_Send_Phi_x; - delete [] Buffer_Send_Phi_y; - delete [] Buffer_Send_Phi_z; - delete [] Buffer_Send_PsiE; - if (Buffer_Send_Sens_x != NULL) delete [] Buffer_Send_Sens_x; - if (Buffer_Send_Sens_y != NULL) delete [] Buffer_Send_Sens_y; - if (Buffer_Send_Sens_z != NULL) delete [] Buffer_Send_Sens_z; - - SurfAdj_file.close(); - -#endif -} - -void COutput::MergeConnectivity(CConfig *config, CGeometry *geometry, unsigned short val_iZone) { - - int rank = MASTER_NODE; - int size = SINGLE_NODE; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); -#endif - - /*--- Flags identifying the types of files to be written. ---*/ - - bool Wrt_Vol = config->GetWrt_Vol_Sol(); - bool Wrt_Srf = config->GetWrt_Srf_Sol(); - - /*--- Merge connectivity for each type of element (excluding halos). Note - that we only need to merge the connectivity once, as it does not change - during computation. Check whether the base file has been written. ---*/ - - /*--- Merge volumetric grid. ---*/ - - if (Wrt_Vol) { - - if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_Tria != 0)) - cout <<"Merging volumetric triangle grid connectivity." << endl; - MergeVolumetricConnectivity(config, geometry, TRIANGLE ); - - if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_Quad != 0)) - cout <<"Merging volumetric quadrilateral grid connectivity." << endl; - MergeVolumetricConnectivity(config, geometry, QUADRILATERAL ); - - if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_Tetr != 0)) - cout <<"Merging volumetric tetrahedron grid connectivity." << endl; - MergeVolumetricConnectivity(config, geometry, TETRAHEDRON ); - - if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_Hexa != 0)) - cout <<"Merging volumetric hexahedron grid connectivity." << endl; - MergeVolumetricConnectivity(config, geometry, HEXAHEDRON ); - - if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_Pris != 0)) - cout <<"Merging volumetric prism grid connectivity." << endl; - MergeVolumetricConnectivity(config, geometry, PRISM ); - - if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_Pyra != 0)) - cout <<"Merging volumetric pyramid grid connectivity." << endl; - MergeVolumetricConnectivity(config, geometry, PYRAMID ); - - } - - /*--- Merge surface grid. ---*/ - - if (Wrt_Srf) { - - if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_Line != 0)) - cout <<"Merging surface line grid connectivity." << endl; - MergeSurfaceConnectivity(config, geometry, LINE); - - if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_BoundTria != 0)) - cout <<"Merging surface triangle grid connectivity." << endl; - MergeSurfaceConnectivity(config, geometry, TRIANGLE); - - if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_BoundQuad != 0)) - cout <<"Merging surface quadrilateral grid connectivity." << endl; - MergeSurfaceConnectivity(config, geometry, QUADRILATERAL); - - } - - /*--- Update total number of volume elements after merge. ---*/ - - nGlobal_Elem = nGlobal_Tria + nGlobal_Quad + nGlobal_Tetr + - nGlobal_Hexa + nGlobal_Pyra + nGlobal_Pris; - - /*--- Update total number of surface elements after merge. ---*/ - - nSurf_Elem = nGlobal_Line + nGlobal_BoundTria + nGlobal_BoundQuad; - -} - -void COutput::MergeCoordinates(CConfig *config, CGeometry *geometry) { - - /*--- Local variables needed on all processors ---*/ - - unsigned short iDim, nDim = geometry->GetnDim(); - unsigned long iPoint; - -#ifndef HAVE_MPI - - /*--- In serial, the single process has access to all geometry, so simply - load the coordinates into the data structure. ---*/ - - unsigned short iMarker; - unsigned long iVertex, nTotalPoints = 0; - int SendRecv; - - /*--- First, create a structure to locate any periodic halo nodes ---*/ - int *Local_Halo = new int[geometry->GetnPoint()]; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - Local_Halo[iPoint] = !geometry->node[iPoint]->GetDomain(); - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { - SendRecv = config->GetMarker_All_SendRecv(iMarker); - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && - (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 1) && - (SendRecv < 0)) { - Local_Halo[iPoint] = false; - } - } - - } - } - - /*--- Total number of points in the mesh (this might include periodic points). ---*/ - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - if (!Local_Halo[iPoint]) nTotalPoints++; - - nGlobal_Poin = nTotalPoints; - nGlobal_Doma = geometry->GetnPointDomain(); - - /*--- Allocate the coordinates data structure. ---*/ - - Coords = new su2double*[nDim]; - for (iDim = 0; iDim < nDim; iDim++) { - Coords[iDim] = new su2double[nGlobal_Poin]; - } - - /*--- Loop over the mesh to collect the coords of the local points ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check if the node belongs to the domain (i.e, not a halo node). - Sort by the global index, even in serial there is a renumbering (e.g. RCM). ---*/ - - if (!Local_Halo[iPoint]) { - - /*--- Retrieve the current coordinates at this node. ---*/ - - unsigned long iGlobal_Index = geometry->node[iPoint]->GetGlobalIndex(); - - for (iDim = 0; iDim < nDim; iDim++) { - Coords[iDim][iGlobal_Index] = geometry->node[iPoint]->GetCoord(iDim); - - /*--- If US system, the output should be in inches ---*/ - - if ((config->GetSystemMeasurements() == US) && (config->GetKind_SU2() != SU2_DEF)) { - Coords[iDim][iGlobal_Index] *= 12.0; - } - - } - - } - } - - - delete [] Local_Halo; - -#else - - /*--- MPI preprocessing ---*/ - int iProcessor, nProcessor, rank; - unsigned long jPoint; - - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); - - bool Wrt_Halo = config->GetWrt_Halo(), isPeriodic; - - /*--- Local variables needed for merging the geometry with MPI. ---*/ - - unsigned long iVertex, iMarker; - unsigned long Buffer_Send_nPoin[1], *Buffer_Recv_nPoin = NULL; - unsigned long nLocalPoint = 0, MaxLocalPoint = 0; - unsigned long iGlobal_Index = 0, nBuffer_Scalar = 0; - - if (rank == MASTER_NODE) Buffer_Recv_nPoin = new unsigned long[nProcessor]; - - int *Local_Halo = new int[geometry->GetnPoint()]; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - Local_Halo[iPoint] = !geometry->node[iPoint]->GetDomain(); - - /*--- Search all send/recv boundaries on this partition for any periodic - nodes that were part of the original domain. We want to recover these - for visualization purposes. ---*/ - - if (Wrt_Halo) { - nLocalPoint = geometry->GetnPoint(); - } else { - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { - - /*--- Checking for less than or equal to the rank, because there may - be some periodic halo nodes that send info to the same rank. ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - isPeriodic = ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && - (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 1)); - if (isPeriodic) Local_Halo[iPoint] = false; - } - } - } - - /*--- Sum total number of nodes that belong to the domain ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - if (Local_Halo[iPoint] == false) - nLocalPoint++; - } - Buffer_Send_nPoin[0] = nLocalPoint; - - /*--- Communicate the total number of nodes on this domain. ---*/ - - SU2_MPI::Gather(&Buffer_Send_nPoin, 1, MPI_UNSIGNED_LONG, - Buffer_Recv_nPoin, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalPoint, &MaxLocalPoint, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - - if (rank == MASTER_NODE) { - nGlobal_Doma = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - nGlobal_Doma += Buffer_Recv_nPoin[iProcessor]; - } - } - nBuffer_Scalar = MaxLocalPoint; - - /*--- Send and Recv buffers. ---*/ - - su2double *Buffer_Send_X = new su2double[MaxLocalPoint]; - su2double *Buffer_Recv_X = NULL; - - su2double *Buffer_Send_Y = new su2double[MaxLocalPoint]; - su2double *Buffer_Recv_Y = NULL; - - su2double *Buffer_Send_Z = NULL, *Buffer_Recv_Z = NULL; - if (nDim == 3) Buffer_Send_Z = new su2double[MaxLocalPoint]; - - unsigned long *Buffer_Send_GlobalIndex = new unsigned long[MaxLocalPoint]; - unsigned long *Buffer_Recv_GlobalIndex = NULL; - - /*--- Prepare the receive buffers in the master node only. ---*/ - - if (rank == MASTER_NODE) { - - Buffer_Recv_X = new su2double[nProcessor*MaxLocalPoint]; - Buffer_Recv_Y = new su2double[nProcessor*MaxLocalPoint]; - if (nDim == 3) Buffer_Recv_Z = new su2double[nProcessor*MaxLocalPoint]; - Buffer_Recv_GlobalIndex = new unsigned long[nProcessor*MaxLocalPoint]; - - /*--- Sum total number of nodes to be written and allocate arrays ---*/ - nGlobal_Poin = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - nGlobal_Poin += Buffer_Recv_nPoin[iProcessor]; - } - Coords = new su2double*[nDim]; - for (iDim = 0; iDim < nDim; iDim++) { - Coords[iDim] = new su2double[nGlobal_Poin]; - } - } - - /*--- Main communication routine. Loop over each coordinate and perform - the MPI comm. Temporary 1-D buffers are used to send the coordinates at - all nodes on each partition to the master node. These are then unpacked - by the master and sorted by global index in one large n-dim. array. ---*/ - - /*--- Loop over this partition to collect the coords of the local points. ---*/ - su2double *Coords_Local; jPoint = 0; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos and write only if requested ---*/ - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Retrieve local coordinates at this node. ---*/ - Coords_Local = geometry->node[iPoint]->GetCoord(); - - /*--- Load local coords into the temporary send buffer. ---*/ - Buffer_Send_X[jPoint] = Coords_Local[0]; - Buffer_Send_Y[jPoint] = Coords_Local[1]; - if (nDim == 3) Buffer_Send_Z[jPoint] = Coords_Local[2]; - - /*--- If US system, the output should be in inches ---*/ - - if ((config->GetSystemMeasurements() == US) && (config->GetKind_SU2() != SU2_DEF)) { - Buffer_Send_X[jPoint] *= 12.0; - Buffer_Send_Y[jPoint] *= 12.0; - if (nDim == 3) Buffer_Send_Z[jPoint] *= 12.0; - } - - /*--- Store the global index for this local node. ---*/ - Buffer_Send_GlobalIndex[jPoint] = geometry->node[iPoint]->GetGlobalIndex(); - - /*--- Increment jPoint as the counter. We need this because iPoint - may include halo nodes that we skip over during this loop. ---*/ - jPoint++; - } - } - - /*--- Gather the coordinate data on the master node using MPI. ---*/ - - SU2_MPI::Gather(Buffer_Send_X, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_X, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Y, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Y, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - if (nDim == 3) { - SU2_MPI::Gather(Buffer_Send_Z, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Z, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - } - SU2_MPI::Gather(Buffer_Send_GlobalIndex, nBuffer_Scalar, MPI_UNSIGNED_LONG, Buffer_Recv_GlobalIndex, nBuffer_Scalar, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - jPoint = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoin[iProcessor]; iPoint++) { - /*--- Get global index, then loop over each variable and store ---*/ - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - Coords[0][iGlobal_Index] = Buffer_Recv_X[jPoint]; - Coords[1][iGlobal_Index] = Buffer_Recv_Y[jPoint]; - if (nDim == 3) Coords[2][iGlobal_Index] = Buffer_Recv_Z[jPoint]; - jPoint++; - } - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - - /*--- Immediately release the temporary data buffers. ---*/ - - delete [] Local_Halo; - delete [] Buffer_Send_X; - delete [] Buffer_Send_Y; - if (Buffer_Send_Z != NULL) delete [] Buffer_Send_Z; - delete [] Buffer_Send_GlobalIndex; - if (rank == MASTER_NODE) { - delete [] Buffer_Recv_X; - delete [] Buffer_Recv_Y; - if (Buffer_Recv_Z != NULL) delete [] Buffer_Recv_Z; - delete [] Buffer_Recv_GlobalIndex; - delete [] Buffer_Recv_nPoin; - } - -#endif - -} - -void COutput::MergeVolumetricConnectivity(CConfig *config, CGeometry *geometry, unsigned short Elem_Type) { - - int iProcessor; - unsigned short NODES_PER_ELEMENT; - unsigned long iPoint, iNode, jNode; - unsigned long iElem = 0; - unsigned long nLocalElem = 0, nElem_Total = 0; - - unsigned long iVertex, iMarker; - unsigned long jElem; - int SendRecv, RecvFrom; - - unsigned long Buffer_Send_nElem[1], *Buffer_Recv_nElem = NULL; - unsigned long nBuffer_Scalar = 0; - unsigned long kNode = 0, kElem = 0; - unsigned long MaxLocalElem = 0, iGlobal_Index, jPoint, kPoint; - - bool Wrt_Halo = config->GetWrt_Halo(); - bool *Write_Elem = NULL, notPeriodic, notHalo, addedPeriodic; - - int *Conn_Elem = NULL; - - int rank = MASTER_NODE; - int size = SINGLE_NODE; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); -#endif - - - /*--- Store the local number of this element type and the number of nodes - per this element type. In serial, this will be the total number of this - element type in the entire mesh. In parallel, it is the number on only - the current partition. ---*/ - - switch (Elem_Type) { - case TRIANGLE: - nLocalElem = geometry->GetnElemTria(); - NODES_PER_ELEMENT = N_POINTS_TRIANGLE; - break; - case QUADRILATERAL: - nLocalElem = geometry->GetnElemQuad(); - NODES_PER_ELEMENT = N_POINTS_QUADRILATERAL; - break; - case TETRAHEDRON: - nLocalElem = geometry->GetnElemTetr(); - NODES_PER_ELEMENT = N_POINTS_TETRAHEDRON; - break; - case HEXAHEDRON: - nLocalElem = geometry->GetnElemHexa(); - NODES_PER_ELEMENT = N_POINTS_HEXAHEDRON; - break; - case PRISM: - nLocalElem = geometry->GetnElemPris(); - NODES_PER_ELEMENT = N_POINTS_PRISM; - break; - case PYRAMID: - nLocalElem = geometry->GetnElemPyra(); - NODES_PER_ELEMENT = N_POINTS_PYRAMID; - break; - default: - cout << "Error: Unrecognized element type \n"; - exit(EXIT_FAILURE); break; - } - - /*--- Find the max number of this element type among all - partitions and set up buffers. ---*/ - - Buffer_Send_nElem[0] = nLocalElem; - if (rank == MASTER_NODE) Buffer_Recv_nElem = new unsigned long[size]; - -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&nLocalElem, &MaxLocalElem, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Gather(&Buffer_Send_nElem, 1, MPI_UNSIGNED_LONG, Buffer_Recv_nElem, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); -#else - MaxLocalElem = nLocalElem; - Buffer_Recv_nElem[0] = Buffer_Send_nElem[0]; -#endif - - nBuffer_Scalar = MaxLocalElem*NODES_PER_ELEMENT; - - /*--- Send and Recv buffers ---*/ - - unsigned long *Buffer_Send_Elem = new unsigned long[nBuffer_Scalar]; - unsigned long *Buffer_Recv_Elem = NULL; - - unsigned short *Buffer_Send_Halo = new unsigned short[MaxLocalElem]; - unsigned short *Buffer_Recv_Halo = NULL; - - /*--- Prepare the receive buffers on the master node only. ---*/ - - if (rank == MASTER_NODE) { - Buffer_Recv_Elem = new unsigned long[size*nBuffer_Scalar]; - Buffer_Recv_Halo = new unsigned short[size*MaxLocalElem]; - Conn_Elem = new int[size*MaxLocalElem*NODES_PER_ELEMENT]; - } - - /*--- Force the removal of all added periodic elements (use global index). - First, we isolate and create a list of all added periodic points, excluding - those that we part of the original domain (we want these to be in the - output files). ---*/ - - vector Added_Periodic; - Added_Periodic.clear(); - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { - SendRecv = config->GetMarker_All_SendRecv(iMarker); - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && - (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 0) && - (SendRecv < 0)) { - Added_Periodic.push_back(geometry->node[iPoint]->GetGlobalIndex()); - } - } - } - } - - /*--- Now we communicate this information to all processors, so that they - can force the removal of these particular nodes by flagging them as halo - points. In general, this should be a small percentage of the total mesh, - so the communication/storage costs here shouldn't be prohibitive. ---*/ - - /*--- First communicate the number of points that each rank has found ---*/ - unsigned long nAddedPeriodic = 0, maxAddedPeriodic = 0; - unsigned long Buffer_Send_nAddedPeriodic[1], *Buffer_Recv_nAddedPeriodic = NULL; - Buffer_Recv_nAddedPeriodic = new unsigned long[size]; - - nAddedPeriodic = Added_Periodic.size(); - Buffer_Send_nAddedPeriodic[0] = nAddedPeriodic; - -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&nAddedPeriodic, &maxAddedPeriodic, 1, MPI_UNSIGNED_LONG, - MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(&Buffer_Send_nAddedPeriodic, 1, MPI_UNSIGNED_LONG, - Buffer_Recv_nAddedPeriodic, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#else - maxAddedPeriodic = nAddedPeriodic; - Buffer_Recv_nAddedPeriodic[0] = Buffer_Send_nAddedPeriodic[0]; -#endif - - /*--- Communicate the global index values of all added periodic nodes. ---*/ - unsigned long *Buffer_Send_AddedPeriodic = new unsigned long[maxAddedPeriodic]; - unsigned long *Buffer_Recv_AddedPeriodic = new unsigned long[size*maxAddedPeriodic]; - - for (iPoint = 0; iPoint < Added_Periodic.size(); iPoint++) { - Buffer_Send_AddedPeriodic[iPoint] = Added_Periodic[iPoint]; - } - - /*--- Gather the element connectivity information. All processors will now - have a copy of the global index values for all added periodic points. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Allgather(Buffer_Send_AddedPeriodic, maxAddedPeriodic, MPI_UNSIGNED_LONG, - Buffer_Recv_AddedPeriodic, maxAddedPeriodic, MPI_UNSIGNED_LONG, - MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < maxAddedPeriodic; iPoint++) Buffer_Recv_AddedPeriodic[iPoint] = Buffer_Send_AddedPeriodic[iPoint]; -#endif - - /*--- Search all send/recv boundaries on this partition for halo cells. In - particular, consider only the recv conditions (these are the true halo - nodes). Check the ranks of the processors that are communicating and - choose to keep only the halo cells from the higher rank processor. Here, - we are also choosing to keep periodic nodes that were part of the original - domain. We will check the communicated list of added periodic points. ---*/ - - int *Local_Halo = new int[geometry->GetnPoint()]; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - Local_Halo[iPoint] = !geometry->node[iPoint]->GetDomain(); - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { - SendRecv = config->GetMarker_All_SendRecv(iMarker); - RecvFrom = abs(SendRecv)-1; - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - iGlobal_Index = geometry->node[iPoint]->GetGlobalIndex(); - - /*--- We need to keep one copy of overlapping halo cells. ---*/ - notHalo = ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() == 0) && - (SendRecv < 0) && (rank > RecvFrom)); - - /*--- We want to keep the periodic nodes that were part of the original domain ---*/ - notPeriodic = ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && - (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 1) && - (SendRecv < 0)); - - /*--- Lastly, check that this isn't an added periodic point that - we will forcibly remove. Use the communicated list of these points. ---*/ - addedPeriodic = false; kPoint = 0; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (jPoint = 0; jPoint < Buffer_Recv_nAddedPeriodic[iProcessor]; jPoint++) { - if (iGlobal_Index == Buffer_Recv_AddedPeriodic[kPoint+jPoint]) - addedPeriodic = true; - } - /*--- Adjust jNode to index of next proc's data in the buffers. ---*/ - kPoint = (iProcessor+1)*maxAddedPeriodic; - } - - /*--- If we found either of these types of nodes, flag them to be kept. ---*/ - if ((notHalo || notPeriodic) && !addedPeriodic) { - Local_Halo[iPoint] = false; - } - } - } - } - - /*--- Loop over all elements in this partition and load the - elements of the current type into the buffer to be sent to - the master node. ---*/ - - jNode = 0; jElem = 0; - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - if (geometry->elem[iElem]->GetVTK_Type() == Elem_Type) { - - /*--- Loop over all nodes in this element and load the - connectivity into the send buffer. ---*/ - - Buffer_Send_Halo[jElem] = false; - for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) { - - /*--- Store the global index values directly. ---*/ - - iPoint = geometry->elem[iElem]->GetNode(iNode); - Buffer_Send_Elem[jNode] = geometry->node[iPoint]->GetGlobalIndex(); - - /*--- Check if this is a halo node. If so, flag this element - as a halo cell. We will use this later to sort and remove - any duplicates from the connectivity list. ---*/ - - if (Local_Halo[iPoint]) { - Buffer_Send_Halo[jElem] = true; - } - - /*--- Increment jNode as the counter. We need this because iElem - may include other elements that we skip over during this loop. ---*/ - - jNode++; - } - jElem++; - } - } - - /*--- Gather the element connectivity information. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Elem, nBuffer_Scalar, MPI_UNSIGNED_LONG, Buffer_Recv_Elem, nBuffer_Scalar, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Halo, MaxLocalElem, MPI_UNSIGNED_SHORT, Buffer_Recv_Halo, MaxLocalElem, MPI_UNSIGNED_SHORT, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Elem[iPoint] = Buffer_Send_Elem[iPoint]; - for (iPoint = 0; iPoint < MaxLocalElem; iPoint++) Buffer_Recv_Halo[iPoint] = Buffer_Send_Halo[iPoint]; -#endif - - /*--- The master node unpacks and sorts the connectivity. ---*/ - - if (rank == MASTER_NODE) { - - /*--- We need to remove any duplicate elements (halo cells) that - exist on multiple partitions. Start by initializing all elements - to the "write" state by using a boolean array. ---*/ - - Write_Elem = new bool[size*MaxLocalElem]; - for (iElem = 0; iElem < size*MaxLocalElem; iElem++) { - Write_Elem[iElem] = true; - } - - /*--- Remove the rind layer from the solution only if requested ---*/ - - if (!Wrt_Halo) { - - /*--- Loop for flagging duplicate elements so that they are not - included in the final connectivity list. ---*/ - - kElem = 0; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iElem = 0; iElem < Buffer_Recv_nElem[iProcessor]; iElem++) { - - /*--- Check if this element was marked as a halo. ---*/ - if (Buffer_Recv_Halo[kElem+iElem]) - Write_Elem[kElem+iElem] = false; - - } - kElem = (iProcessor+1)*MaxLocalElem; - } - } - - /*--- Store the unique connectivity list for this element type. ---*/ - - jNode = 0; kNode = 0; jElem = 0; nElem_Total = 0; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iElem = 0; iElem < Buffer_Recv_nElem[iProcessor]; iElem++) { - - /*--- Only write the elements that were flagged for it. ---*/ - if (Write_Elem[jElem+iElem]) { - - /*--- Increment total count for this element type ---*/ - nElem_Total++; - - /*--- Get global index, then loop over each variable and store. - Note that we are adding one to the index value because CGNS/Tecplot - use 1-based indexing.---*/ - - for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) { - Conn_Elem[kNode] = (int)Buffer_Recv_Elem[jNode+iElem*NODES_PER_ELEMENT+iNode] + 1; - kNode++; - } - } - } - /*--- Adjust jNode to index of next proc's data in the buffers. ---*/ - jElem = (iProcessor+1)*MaxLocalElem; - jNode = (iProcessor+1)*nBuffer_Scalar; - } - } - - /*--- Immediately release the temporary buffers. ---*/ - delete [] Buffer_Send_Elem; - delete [] Buffer_Send_Halo; - delete [] Buffer_Recv_nAddedPeriodic; - delete [] Buffer_Send_AddedPeriodic; - delete [] Buffer_Recv_AddedPeriodic; - delete [] Local_Halo; - if (rank == MASTER_NODE) { - delete [] Buffer_Recv_nElem; - delete [] Buffer_Recv_Elem; - delete [] Buffer_Recv_Halo; - delete [] Write_Elem; - } - - /*--- Store the particular global element count in the class data, - and set the class data pointer to the connectivity array. ---*/ - - if (rank == MASTER_NODE) { - switch (Elem_Type) { - case TRIANGLE: - nGlobal_Tria = nElem_Total; - if (nGlobal_Tria > 0) Conn_Tria = Conn_Elem; - break; - case QUADRILATERAL: - nGlobal_Quad = nElem_Total; - if (nGlobal_Quad > 0) Conn_Quad = Conn_Elem; - break; - case TETRAHEDRON: - nGlobal_Tetr = nElem_Total; - if (nGlobal_Tetr > 0) Conn_Tetr = Conn_Elem; - break; - case HEXAHEDRON: - nGlobal_Hexa = nElem_Total; - if (nGlobal_Hexa > 0) Conn_Hexa = Conn_Elem; - break; - case PRISM: - nGlobal_Pris = nElem_Total; - if (nGlobal_Pris > 0) Conn_Pris = Conn_Elem; - break; - case PYRAMID: - nGlobal_Pyra = nElem_Total; - if (nGlobal_Pyra > 0) Conn_Pyra = Conn_Elem; - break; - default: - cout << "Error: Unrecognized element type \n"; - exit(EXIT_FAILURE); break; - } - } - -} - -void COutput::MergeSurfaceConnectivity(CConfig *config, CGeometry *geometry, unsigned short Elem_Type) { - - unsigned short NODES_PER_ELEMENT; - - unsigned short iMarker; - unsigned long iPoint, iNode, jNode; - unsigned long iElem = 0; - unsigned long nLocalElem = 0, nElem_Total = 0; - - int iProcessor; - unsigned long jElem; - - unsigned long iVertex; - - int SendRecv, RecvFrom; - - unsigned long Buffer_Send_nElem[1], *Buffer_Recv_nElem = NULL; - unsigned long nBuffer_Scalar = 0; - unsigned long kNode = 0, kElem = 0; - unsigned long MaxLocalElem = 0, iGlobal_Index, jPoint, kPoint; - - bool Wrt_Halo = config->GetWrt_Halo(); - bool *Write_Elem = NULL, notPeriodic, notHalo, addedPeriodic; - - - int *Conn_Elem = NULL; - - int rank = MASTER_NODE; - int size = SINGLE_NODE; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); -#endif - - /*--- Store the local number of this element type and the number of nodes - per this element type. In serial, this will be the total number of this - element type in the entire mesh. In parallel, it is the number on only - the current partition. ---*/ - - nLocalElem = 0; - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_Plotting(iMarker) == YES) { - for (iElem = 0; iElem < geometry->GetnElem_Bound(iMarker); iElem++) { - if (geometry->bound[iMarker][iElem]->GetVTK_Type() == Elem_Type) { - nLocalElem++; - } - } - } - } - - switch (Elem_Type) { - case LINE: - NODES_PER_ELEMENT = N_POINTS_LINE; - break; - case TRIANGLE: - NODES_PER_ELEMENT = N_POINTS_TRIANGLE; - break; - case QUADRILATERAL: - NODES_PER_ELEMENT = N_POINTS_QUADRILATERAL; - break; - default: - cout << "Error: Unrecognized element type \n"; - exit(EXIT_FAILURE); break; - } - - /*--- Find the max number of this element type among all - partitions and set up buffers. ---*/ - - Buffer_Send_nElem[0] = nLocalElem; - if (rank == MASTER_NODE) Buffer_Recv_nElem = new unsigned long[size]; - -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&nLocalElem, &MaxLocalElem, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Gather(&Buffer_Send_nElem, 1, MPI_UNSIGNED_LONG, Buffer_Recv_nElem, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); -#else - MaxLocalElem = nLocalElem; - Buffer_Recv_nElem[0] = Buffer_Send_nElem[0]; -#endif - - nBuffer_Scalar = MaxLocalElem*NODES_PER_ELEMENT; - - /*--- Send and Recv buffers ---*/ - - unsigned long *Buffer_Send_Elem = new unsigned long[nBuffer_Scalar]; - unsigned long *Buffer_Recv_Elem = NULL; - - unsigned short *Buffer_Send_Halo = new unsigned short[MaxLocalElem]; - unsigned short *Buffer_Recv_Halo = NULL; - - /*--- Prepare the receive buffers on the master node only. ---*/ - - if (rank == MASTER_NODE) { - Buffer_Recv_Elem = new unsigned long[size*nBuffer_Scalar]; - Buffer_Recv_Halo = new unsigned short[size*MaxLocalElem]; - Conn_Elem = new int[size*MaxLocalElem*NODES_PER_ELEMENT]; - } - - /*--- Force the removal of all added periodic elements (use global index). - First, we isolate and create a list of all added periodic points, excluding - those that we part of the original domain (we want these to be in the - output files). ---*/ - - vector Added_Periodic; - Added_Periodic.clear(); - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { - SendRecv = config->GetMarker_All_SendRecv(iMarker); - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && - (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 0) && - (SendRecv < 0)) { - Added_Periodic.push_back(geometry->node[iPoint]->GetGlobalIndex()); - } - } - } - } - - /*--- Now we communicate this information to all processors, so that they - can force the removal of these particular nodes by flagging them as halo - points. In general, this should be a small percentage of the total mesh, - so the communication/storage costs here shouldn't be prohibitive. ---*/ - - /*--- First communicate the number of points that each rank has found ---*/ - unsigned long nAddedPeriodic = 0, maxAddedPeriodic = 0; - unsigned long Buffer_Send_nAddedPeriodic[1], *Buffer_Recv_nAddedPeriodic = NULL; - Buffer_Recv_nAddedPeriodic = new unsigned long[size]; - - nAddedPeriodic = Added_Periodic.size(); - Buffer_Send_nAddedPeriodic[0] = nAddedPeriodic; - -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&nAddedPeriodic, &maxAddedPeriodic, 1, MPI_UNSIGNED_LONG, - MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(&Buffer_Send_nAddedPeriodic, 1, MPI_UNSIGNED_LONG, - Buffer_Recv_nAddedPeriodic, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#else - maxAddedPeriodic = nAddedPeriodic; - Buffer_Recv_nAddedPeriodic[0] = Buffer_Send_nAddedPeriodic[0]; -#endif - - /*--- Communicate the global index values of all added periodic nodes. ---*/ - unsigned long *Buffer_Send_AddedPeriodic = new unsigned long[maxAddedPeriodic]; - unsigned long *Buffer_Recv_AddedPeriodic = new unsigned long[size*maxAddedPeriodic]; - - for (iPoint = 0; iPoint < Added_Periodic.size(); iPoint++) { - Buffer_Send_AddedPeriodic[iPoint] = Added_Periodic[iPoint]; - } - - /*--- Gather the element connectivity information. All processors will now - have a copy of the global index values for all added periodic points. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Allgather(Buffer_Send_AddedPeriodic, maxAddedPeriodic, MPI_UNSIGNED_LONG, - Buffer_Recv_AddedPeriodic, maxAddedPeriodic, MPI_UNSIGNED_LONG, - MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < maxAddedPeriodic; iPoint++) Buffer_Recv_AddedPeriodic[iPoint] = Buffer_Send_AddedPeriodic[iPoint]; -#endif - - /*--- Search all send/recv boundaries on this partition for halo cells. In - particular, consider only the recv conditions (these are the true halo - nodes). Check the ranks of the processors that are communicating and - choose to keep only the halo cells from the higher rank processor. Here, - we are also choosing to keep periodic nodes that were part of the original - domain. We will check the communicated list of added periodic points. ---*/ - - int *Local_Halo = new int[geometry->GetnPoint()]; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - Local_Halo[iPoint] = !geometry->node[iPoint]->GetDomain(); - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { - SendRecv = config->GetMarker_All_SendRecv(iMarker); - RecvFrom = abs(SendRecv)-1; - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - iGlobal_Index = geometry->node[iPoint]->GetGlobalIndex(); - - /*--- We need to keep one copy of overlapping halo cells. ---*/ - notHalo = ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() == 0) && - (SendRecv < 0) && (rank > RecvFrom)); - - /*--- We want to keep the periodic nodes that were part of the original domain ---*/ - notPeriodic = ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && - (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 1) && - (SendRecv < 0)); - - /*--- Lastly, check that this isn't an added periodic point that - we will forcibly remove. Use the communicated list of these points. ---*/ - addedPeriodic = false; kPoint = 0; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (jPoint = 0; jPoint < Buffer_Recv_nAddedPeriodic[iProcessor]; jPoint++) { - if (iGlobal_Index == Buffer_Recv_AddedPeriodic[kPoint+jPoint]) - addedPeriodic = true; - } - /*--- Adjust jNode to index of next proc's data in the buffers. ---*/ - kPoint = (iProcessor+1)*maxAddedPeriodic; - } - - /*--- If we found either of these types of nodes, flag them to be kept. ---*/ - if ((notHalo || notPeriodic) && !addedPeriodic) { - Local_Halo[iPoint] = false; - } - } - } - } - - /*--- Loop over all elements in this partition and load the - elements of the current type into the buffer to be sent to - the master node. ---*/ - jNode = 0; jElem = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_Plotting(iMarker) == YES) - for (iElem = 0; iElem < geometry->GetnElem_Bound(iMarker); iElem++) { - - if (geometry->bound[iMarker][iElem]->GetVTK_Type() == Elem_Type) { - - /*--- Loop over all nodes in this element and load the - connectivity into the send buffer. ---*/ - - Buffer_Send_Halo[jElem] = false; - for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) { - - /*--- Store the global index values directly. ---*/ - - iPoint = geometry->bound[iMarker][iElem]->GetNode(iNode); - Buffer_Send_Elem[jNode] = geometry->node[iPoint]->GetGlobalIndex(); - - /*--- Check if this is a halo node. If so, flag this element - as a halo cell. We will use this later to sort and remove - any duplicates from the connectivity list. ---*/ - - if (Local_Halo[iPoint]) - Buffer_Send_Halo[jElem] = true; - - /*--- Increment jNode as the counter. We need this because iElem - may include other elements that we skip over during this loop. ---*/ - - jNode++; - } - jElem++; - } - } - - /*--- Gather the element connectivity information. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Elem, nBuffer_Scalar, MPI_UNSIGNED_LONG, Buffer_Recv_Elem, nBuffer_Scalar, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Halo, MaxLocalElem, MPI_UNSIGNED_SHORT, Buffer_Recv_Halo, MaxLocalElem, MPI_UNSIGNED_SHORT, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Elem[iPoint] = Buffer_Send_Elem[iPoint]; - for (iPoint = 0; iPoint < MaxLocalElem; iPoint++) Buffer_Recv_Halo[iPoint] = Buffer_Send_Halo[iPoint]; -#endif - - /*--- The master node unpacks and sorts the connectivity. ---*/ - - if (rank == MASTER_NODE) { - - /*--- We need to remove any duplicate elements (halo cells) that - exist on multiple partitions. Start by initializing all elements - to the "write" state by using a boolean array. ---*/ - - Write_Elem = new bool[size*MaxLocalElem]; - for (iElem = 0; iElem < size*MaxLocalElem; iElem++) { - Write_Elem[iElem] = true; - } - - /*--- Remove the rind layer from the solution only if requested ---*/ - - if (!Wrt_Halo) { - - /*--- Loop for flagging duplicate elements so that they are not - included in the final connectivity list. ---*/ - - kElem = 0; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iElem = 0; iElem < Buffer_Recv_nElem[iProcessor]; iElem++) { - - /*--- Check if this element was marked as a halo. ---*/ - if (Buffer_Recv_Halo[kElem+iElem]) - Write_Elem[kElem+iElem] = false; - - } - kElem = (iProcessor+1)*MaxLocalElem; - } - } - - /*--- Store the unique connectivity list for this element type. ---*/ - - jNode = 0; kNode = 0; jElem = 0; nElem_Total = 0; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iElem = 0; iElem < Buffer_Recv_nElem[iProcessor]; iElem++) { - - /*--- Only write the elements that were flagged for it. ---*/ - if (Write_Elem[jElem+iElem]) { - - /*--- Increment total count for this element type ---*/ - nElem_Total++; - - /*--- Get global index, then loop over each variable and store. - Note that we are adding one to the index value because CGNS/Tecplot - use 1-based indexing.---*/ - - for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) { - Conn_Elem[kNode] = (int)Buffer_Recv_Elem[jNode+iElem*NODES_PER_ELEMENT+iNode] + 1; - kNode++; - } - } - } - /*--- Adjust jNode to index of next proc's data in the buffers. ---*/ - jElem = (iProcessor+1)*MaxLocalElem; - jNode = (iProcessor+1)*nBuffer_Scalar; - } - } - - /*--- Immediately release the temporary buffers. ---*/ - delete [] Buffer_Send_Elem; - delete [] Buffer_Send_Halo; - delete [] Buffer_Recv_nAddedPeriodic; - delete [] Buffer_Send_AddedPeriodic; - delete [] Buffer_Recv_AddedPeriodic; - delete [] Local_Halo; - if (rank == MASTER_NODE) { - delete [] Buffer_Recv_nElem; - delete [] Buffer_Recv_Elem; - delete [] Buffer_Recv_Halo; - delete [] Write_Elem; - } - - /*--- Store the particular global element count in the class data, - and set the class data pointer to the connectivity array. ---*/ - - if (rank == MASTER_NODE) { - switch (Elem_Type) { - case LINE: - nGlobal_Line = nElem_Total; - if (nGlobal_Line > 0) Conn_Line = Conn_Elem; - break; - case TRIANGLE: - nGlobal_BoundTria = nElem_Total; - if (nGlobal_BoundTria > 0) Conn_BoundTria = Conn_Elem; - break; - case QUADRILATERAL: - nGlobal_BoundQuad = nElem_Total; - if (nGlobal_BoundQuad > 0) Conn_BoundQuad = Conn_Elem; - break; - default: - cout << "Error: Unrecognized element type \n"; - exit(EXIT_FAILURE); break; - } - } - -} - -void COutput::MergeSolution(CConfig *config, CGeometry *geometry, CSolver **solver, unsigned short val_iZone) { - - unsigned short Kind_Solver = config->GetKind_Solver(); - unsigned short iVar = 0, jVar = 0, FirstIndex = NONE, SecondIndex = NONE, ThirdIndex = NONE; - unsigned short nVar_First = 0, nVar_Second = 0, nVar_Third = 0; - unsigned short iVar_GridVel = 0, iVar_PressCp = 0, iVar_Density = 0, iVar_Lam = 0, iVar_MachMean = 0, - iVar_ViscCoeffs = 0, iVar_Sens = 0, iVar_Extra = 0, iVar_Eddy = 0, iVar_Sharp = 0, - iVar_FEA_Stress = 0, iVar_FEA_Stress_3D = 0, iVar_FEA_Extra = 0, iVar_SensDim = 0; - - unsigned long iPoint = 0, jPoint = 0, iVertex = 0, iMarker = 0; - su2double Gas_Constant, Mach2Vel, Mach_Motion, RefDensity, RefPressure = 0.0, factor = 0.0; - - su2double *Aux_Frict = NULL, *Aux_Heat = NULL, *Aux_yPlus = NULL, *Aux_Sens = NULL; - - unsigned short CurrentIndex; - int *Local_Halo; - unsigned long Buffer_Send_nPoint[1], *Buffer_Recv_nPoint = NULL; - unsigned long nLocalPoint = 0, MaxLocalPoint = 0; - unsigned long iGlobal_Index = 0, nBuffer_Scalar = 0; - bool Wrt_Halo = config->GetWrt_Halo(), isPeriodic; - - int iProcessor; - int rank = MASTER_NODE; - int size = SINGLE_NODE; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); -#endif - - bool grid_movement = (config->GetGrid_Movement()); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool transition = (config->GetKind_Trans_Model() == LM); - bool flow = (( config->GetKind_Solver() == EULER ) || - ( config->GetKind_Solver() == NAVIER_STOKES ) || - ( config->GetKind_Solver() == RANS ) || - ( config->GetKind_Solver() == ADJ_EULER ) || - ( config->GetKind_Solver() == ADJ_NAVIER_STOKES ) || - ( config->GetKind_Solver() == ADJ_RANS ) ); - - unsigned short iDim; - unsigned short nDim = geometry->GetnDim(); - su2double RefAreaCoeff = config->GetRefAreaCoeff(); - su2double Gamma = config->GetGamma(); - su2double RefVel2, *Normal, Area; - - /*--- Set the non-dimensionalization ---*/ - if (flow) { - if (grid_movement) { - Gas_Constant = config->GetGas_ConstantND(); - Mach2Vel = sqrt(Gamma*Gas_Constant*config->GetTemperature_FreeStreamND()); - Mach_Motion = config->GetMach_Motion(); - RefVel2 = (Mach_Motion*Mach2Vel)*(Mach_Motion*Mach2Vel); - } - else { - RefVel2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - RefVel2 += solver[FLOW_SOL]->GetVelocity_Inf(iDim)*solver[FLOW_SOL]->GetVelocity_Inf(iDim); - } - RefDensity = solver[FLOW_SOL]->GetDensity_Inf(); - RefPressure = solver[FLOW_SOL]->GetPressure_Inf(); - factor = 1.0 / (0.5*RefDensity*RefAreaCoeff*RefVel2); - } - - /*--- Prepare send buffers for the conservative variables. Need to - find the total number of conservative variables and also the - index for their particular solution container. ---*/ - - switch (Kind_Solver) { - case EULER : case NAVIER_STOKES: FirstIndex = FLOW_SOL; SecondIndex = NONE; ThirdIndex = NONE; break; - case RANS : FirstIndex = FLOW_SOL; SecondIndex = TURB_SOL; if (transition) ThirdIndex=TRANS_SOL; else ThirdIndex = NONE; break; - case POISSON_EQUATION: FirstIndex = POISSON_SOL; SecondIndex = NONE; ThirdIndex = NONE; break; - case WAVE_EQUATION: FirstIndex = WAVE_SOL; SecondIndex = NONE; ThirdIndex = NONE; break; - case HEAT_EQUATION: FirstIndex = HEAT_SOL; SecondIndex = NONE; ThirdIndex = NONE; break; - case LINEAR_ELASTICITY: FirstIndex = FEA_SOL; SecondIndex = NONE; ThirdIndex = NONE; break; - case ADJ_EULER : case ADJ_NAVIER_STOKES : FirstIndex = ADJFLOW_SOL; SecondIndex = NONE; ThirdIndex = NONE; break; - case ADJ_RANS : FirstIndex = ADJFLOW_SOL; if (config->GetFrozen_Visc()) SecondIndex = NONE; else SecondIndex = ADJTURB_SOL; ThirdIndex = NONE; break; - case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: FirstIndex = ADJFLOW_SOL; SecondIndex = NONE; ThirdIndex = NONE; break; - case DISC_ADJ_RANS: FirstIndex = ADJFLOW_SOL; SecondIndex = ADJTURB_SOL; ThirdIndex = NONE; break; - default: SecondIndex = NONE; ThirdIndex = NONE; break; - } - - nVar_First = solver[FirstIndex]->GetnVar(); - if (SecondIndex != NONE) nVar_Second = solver[SecondIndex]->GetnVar(); - if (ThirdIndex != NONE) nVar_Third = solver[ThirdIndex]->GetnVar(); - nVar_Consv = nVar_First + nVar_Second + nVar_Third; - nVar_Total = nVar_Consv; - - if (!config->GetLow_MemoryOutput()) { - - /*--- Add the limiters ---*/ - - if (config->GetWrt_Limiters()) nVar_Total += nVar_Consv; - - /*--- Add the residuals ---*/ - - if (config->GetWrt_Residuals()) nVar_Total += nVar_Consv; - - /*--- Add the grid velocity to the restart file for the unsteady adjoint ---*/ - - if (grid_movement) { - iVar_GridVel = nVar_Total; - if (geometry->GetnDim() == 2) nVar_Total += 2; - else if (geometry->GetnDim() == 3) nVar_Total += 3; - } - - /*--- Add density to the restart file ---*/ - - if ((config->GetKind_Regime() == FREESURFACE)) { - iVar_Density = nVar_Total; nVar_Total += 1; - } - - /*--- Add Pressure, Temperature, Cp, Mach to the restart file ---*/ - - if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - iVar_PressCp = nVar_Total; nVar_Total += 3; - iVar_MachMean = nVar_Total; nVar_Total += 1; - } - - /*--- Add Laminar Viscosity, Skin Friction, Heat Flux, & yPlus to the restart file ---*/ - - if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - iVar_Lam = nVar_Total; nVar_Total += 1; - iVar_ViscCoeffs = nVar_Total; nVar_Total += 3; - } - - /*--- Add Eddy Viscosity to the restart file ---*/ - - if (Kind_Solver == RANS) { - iVar_Eddy = nVar_Total; nVar_Total += 1; - } - - /*--- Add Sharp edges to the restart file ---*/ - - if (config->GetWrt_SharpEdges()) { - if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - iVar_Sharp = nVar_Total; nVar_Total += 1; - } - } - - //if (Kind_Solver == POISSON_EQUATION) { - // iVar_EF = nVar_Total; nVar_Total += geometry->GetnDim(); - //} - - if (( Kind_Solver == ADJ_EULER ) || ( Kind_Solver == ADJ_NAVIER_STOKES ) || - ( Kind_Solver == ADJ_RANS )) { - iVar_Sens = nVar_Total; nVar_Total += 2; - } - - if (Kind_Solver == LINEAR_ELASTICITY) { - iVar_FEA_Stress = nVar_Total; nVar_Total += 3; - if (geometry->GetnDim() == 3) {iVar_FEA_Stress_3D = nVar_Total; nVar_Total += 3;} - iVar_FEA_Extra = nVar_Total; nVar_Total += 2; - } - - if ((Kind_Solver == DISC_ADJ_EULER) || - (Kind_Solver == DISC_ADJ_NAVIER_STOKES) || - (Kind_Solver == DISC_ADJ_RANS)){ - iVar_Sens = nVar_Total; nVar_Total += 1; - iVar_SensDim = nVar_Total; nVar_Total += nDim; - } - - if (config->GetExtraOutput()) { - if (Kind_Solver == RANS) { - iVar_Extra = nVar_Total; nVar_Extra = solver[TURB_SOL]->GetnOutputVariables(); nVar_Total += nVar_Extra; - } - } - - } - - Local_Halo = new int[geometry->GetnPoint()]; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - Local_Halo[iPoint] = !geometry->node[iPoint]->GetDomain(); - - /*--- Search all send/recv boundaries on this partition for any periodic - nodes that were part of the original domain. We want to recover these - for visualization purposes. ---*/ - - if (Wrt_Halo) { - nLocalPoint = geometry->GetnPoint(); - } else { - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { - - /*--- Checking for less than or equal to the rank, because there may - be some periodic halo nodes that send info to the same rank. ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - isPeriodic = ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && - (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 1)); - if (isPeriodic) Local_Halo[iPoint] = false; - } - } - } - - /*--- Sum total number of nodes that belong to the domain ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - if (Local_Halo[iPoint] == false) - nLocalPoint++; - - } - Buffer_Send_nPoint[0] = nLocalPoint; - - /*--- Each processor sends its local number of nodes to the master. ---*/ - - if (rank == MASTER_NODE) Buffer_Recv_nPoint = new unsigned long[size]; - -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&nLocalPoint, &MaxLocalPoint, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Gather(&Buffer_Send_nPoint, 1, MPI_UNSIGNED_LONG, Buffer_Recv_nPoint, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); -#else - MaxLocalPoint = nLocalPoint; - Buffer_Recv_nPoint[0] = Buffer_Send_nPoint[0]; -#endif - - nBuffer_Scalar = MaxLocalPoint; - - /*--- Send and Recv buffers. ---*/ - - su2double *Buffer_Send_Var = new su2double[MaxLocalPoint]; - su2double *Buffer_Recv_Var = NULL; - - su2double *Buffer_Send_Res = new su2double[MaxLocalPoint]; - su2double *Buffer_Recv_Res = NULL; - - su2double *Buffer_Send_Vol = new su2double[MaxLocalPoint]; - su2double *Buffer_Recv_Vol = NULL; - - unsigned long *Buffer_Send_GlobalIndex = new unsigned long[MaxLocalPoint]; - unsigned long *Buffer_Recv_GlobalIndex = NULL; - - /*--- Auxiliary vectors for surface coefficients ---*/ - - if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - Aux_Frict = new su2double[geometry->GetnPoint()]; - Aux_Heat = new su2double[geometry->GetnPoint()]; - Aux_yPlus = new su2double[geometry->GetnPoint()]; - } - - if ((Kind_Solver == ADJ_EULER) || - (Kind_Solver == ADJ_NAVIER_STOKES) || - (Kind_Solver == ADJ_RANS) || - (Kind_Solver == DISC_ADJ_EULER) || - (Kind_Solver == DISC_ADJ_NAVIER_STOKES) || - (Kind_Solver == DISC_ADJ_RANS)) { - Aux_Sens = new su2double[geometry->GetnPoint()]; - } - - /*--- Prepare the receive buffers in the master node only. ---*/ - - if (rank == MASTER_NODE) { - - Buffer_Recv_Var = new su2double[size*MaxLocalPoint]; - Buffer_Recv_Res = new su2double[size*MaxLocalPoint]; - Buffer_Recv_Vol = new su2double[size*MaxLocalPoint]; - Buffer_Recv_GlobalIndex = new unsigned long[size*MaxLocalPoint]; - - /*--- Sum total number of nodes to be written and allocate arrays ---*/ - nGlobal_Poin = 0; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - nGlobal_Poin += Buffer_Recv_nPoint[iProcessor]; - } - Data = new su2double*[nVar_Total]; - for (iVar = 0; iVar < nVar_Total; iVar++) { - Data[iVar] = new su2double[nGlobal_Poin]; - } - } - - /*--- Main communication routine. Loop over each variable that has - been requested by the user and perform the MPI comm. Temporary - 1-D buffers are used to send the solution for each variable at all - nodes on each partition to the master node. These are then unpacked - by the master and sorted by global index in one large n-dim. array. ---*/ - - for (iVar = 0; iVar < nVar_Consv; iVar++) { - - /*--- Logic for which solution class to draw from. ---*/ - - jVar = iVar; - CurrentIndex = FirstIndex; - if ((SecondIndex != NONE) && (iVar > nVar_First-1)) { - jVar = iVar - nVar_First; - CurrentIndex = SecondIndex; - } - if ((SecondIndex != NONE) && (ThirdIndex != NONE) && (iVar > (nVar_First + nVar_Second-1))) { - jVar = iVar - nVar_First - nVar_Second; - CurrentIndex = ThirdIndex; - } - - /*--- Loop over this partition to collect the current variable ---*/ - - jPoint = 0; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos & write only if requested ---*/ - - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Get this variable into the temporary send buffer. ---*/ - - Buffer_Send_Var[jPoint] = solver[CurrentIndex]->node[iPoint]->GetSolution(jVar); - - if (!config->GetLow_MemoryOutput()) { - - if (config->GetWrt_Limiters()) { - Buffer_Send_Vol[jPoint] = solver[CurrentIndex]->node[iPoint]->GetLimiter_Primitive(jVar); - } - - if (config->GetWrt_Residuals()) { - Buffer_Send_Res[jPoint] = solver[CurrentIndex]->LinSysRes.GetBlock(iPoint, jVar); - } - - } - - /*--- Only send/recv the volumes & global indices during the first loop ---*/ - - if (iVar == 0) { - Buffer_Send_GlobalIndex[jPoint] = geometry->node[iPoint]->GetGlobalIndex(); - } - - jPoint++; - - } - } - - /*--- Gather the data on the master node. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; -#endif - if (!config->GetLow_MemoryOutput()) { - - if (config->GetWrt_Limiters()) { -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Vol, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Vol, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Vol[iPoint] = Buffer_Send_Vol[iPoint]; -#endif - } - - if (config->GetWrt_Residuals()) { -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; -#endif - } - - } - - if (iVar == 0) { -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_GlobalIndex, nBuffer_Scalar, MPI_UNSIGNED_LONG, Buffer_Recv_GlobalIndex, nBuffer_Scalar, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_GlobalIndex[iPoint] = Buffer_Send_GlobalIndex[iPoint]; -#endif - } - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - jPoint = 0; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - - Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; - - if (!config->GetLow_MemoryOutput()) { - - if (config->GetWrt_Limiters()) { - Data[iVar+nVar_Consv][iGlobal_Index] = Buffer_Recv_Vol[jPoint]; - } - - if (config->GetWrt_Residuals()) { - unsigned short ExtraIndex; - ExtraIndex = nVar_Consv; - if (config->GetWrt_Limiters()) ExtraIndex = 2*nVar_Consv; - Data[iVar+ExtraIndex][iGlobal_Index] = Buffer_Recv_Res[jPoint]; - } - - } - - jPoint++; - } - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - - } - - if (!config->GetLow_MemoryOutput()) { - - /*--- Additional communication routine for the grid velocity. Note that - we are reusing the same temporary buffers from above for efficiency. - Also, in the future more routines like this could be used to write - an arbitrary number of additional variables to the file. ---*/ - - if (grid_movement) { - - /*--- Loop over this partition to collect the current variable ---*/ - - jPoint = 0; su2double *Grid_Vel; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos & write only if requested ---*/ - - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Load buffers with the three grid velocity components. ---*/ - - Grid_Vel = geometry->node[iPoint]->GetGridVel(); - Buffer_Send_Var[jPoint] = Grid_Vel[0]; - Buffer_Send_Res[jPoint] = Grid_Vel[1]; - if (geometry->GetnDim() == 3) Buffer_Send_Vol[jPoint] = Grid_Vel[2]; - jPoint++; - } - } - - /*--- Gather the data on the master node. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - if (geometry->GetnDim() == 3) { - SU2_MPI::Gather(Buffer_Send_Vol, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Vol, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - } -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; - if (geometry->GetnDim() == 3) { - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Vol[iPoint] = Buffer_Send_Vol[iPoint]; - } -#endif - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - jPoint = 0; iVar = iVar_GridVel; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; - Data[iVar+1][iGlobal_Index] = Buffer_Recv_Res[jPoint]; - if (geometry->GetnDim() == 3) - Data[iVar+2][iGlobal_Index] = Buffer_Recv_Vol[jPoint]; - jPoint++; - } - - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - } - - /*--- Communicate the Density in Free-surface problems ---*/ - - if (config->GetKind_Regime() == FREESURFACE) { - - /*--- Loop over this partition to collect the current variable ---*/ - - jPoint = 0; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos & write only if requested ---*/ - - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Load buffers with the pressure and mach variables. ---*/ - Buffer_Send_Var[jPoint] = solver[FLOW_SOL]->node[iPoint]->GetDensityInc(); - jPoint++; - } - } - - /*--- Gather the data on the master node. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; -#endif - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - jPoint = 0; iVar = iVar_Density; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; - jPoint++; - } - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - - } - - /*--- Communicate Pressure, Cp, and Mach ---*/ - - if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - - /*--- First, loop through the mesh in order to find and store the - value of the coefficient of pressure at any surface nodes. They - will be placed in an auxiliary vector and then communicated like - all other volumetric variables. ---*/ - - /*--- Loop over this partition to collect the current variable ---*/ - - jPoint = 0; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos & write only if requested ---*/ - - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Load buffers with the pressure, Cp, and mach variables. ---*/ - - if (compressible) { - Buffer_Send_Var[jPoint] = solver[FLOW_SOL]->node[iPoint]->GetPressure(); - Buffer_Send_Res[jPoint] = solver[FLOW_SOL]->node[iPoint]->GetTemperature(); - Buffer_Send_Vol[jPoint] = (solver[FLOW_SOL]->node[iPoint]->GetPressure() - RefPressure)*factor*RefAreaCoeff; - } - if (incompressible || freesurface) { - Buffer_Send_Var[jPoint] = solver[FLOW_SOL]->node[iPoint]->GetPressureInc(); - Buffer_Send_Res[jPoint] = 0.0; - Buffer_Send_Vol[jPoint] = (solver[FLOW_SOL]->node[iPoint]->GetPressureInc() - RefPressure)*factor*RefAreaCoeff; - } - jPoint++; - } - } - - /*--- Gather the data on the master node. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Vol, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Vol, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Vol[iPoint] = Buffer_Send_Vol[iPoint]; -#endif - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - jPoint = 0; iVar = iVar_PressCp; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; - Data[iVar+1][iGlobal_Index] = Buffer_Recv_Res[jPoint]; - Data[iVar+2][iGlobal_Index] = Buffer_Recv_Vol[jPoint]; - jPoint++; - } - - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - } - - /*--- Communicate Mach---*/ - - if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - - /*--- Loop over this partition to collect the current variable ---*/ - - jPoint = 0; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos & write only if requested ---*/ - - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Load buffers with the temperature and laminar viscosity variables. ---*/ - - if (compressible) { - Buffer_Send_Var[jPoint] = sqrt(solver[FLOW_SOL]->node[iPoint]->GetVelocity2())/ - solver[FLOW_SOL]->node[iPoint]->GetSoundSpeed(); - } - if (incompressible || freesurface) { - Buffer_Send_Var[jPoint] = sqrt(solver[FLOW_SOL]->node[iPoint]->GetVelocity2())*config->GetVelocity_Ref()/ - sqrt(config->GetBulk_Modulus()/(solver[FLOW_SOL]->node[iPoint]->GetDensityInc()*config->GetDensity_Ref())); - } - jPoint++; - } - } - - /*--- Gather the data on the master node. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; -#endif - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - jPoint = 0; iVar = iVar_MachMean; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; - jPoint++; - } - - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - } - - /*--- Laminar Viscosity ---*/ - - if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - - /*--- Loop over this partition to collect the current variable ---*/ - - jPoint = 0; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos & write only if requested ---*/ - - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Load buffers with the temperature and laminar viscosity variables. ---*/ - - if (compressible) { - Buffer_Send_Res[jPoint] = solver[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); - } - if (incompressible || freesurface) { - Buffer_Send_Res[jPoint] = solver[FLOW_SOL]->node[iPoint]->GetLaminarViscosityInc(); - } - jPoint++; - } - } - - /*--- Gather the data on the master node. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; -#endif - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - jPoint = 0; iVar = iVar_Lam; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - Data[iVar][iGlobal_Index] = Buffer_Recv_Res[jPoint]; - jPoint++; - } - - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - - /*--- Communicate skin friction, heat transfer, y+ ---*/ - - /*--- First, loop through the mesh in order to find and store the - value of the viscous coefficients at any surface nodes. They - will be placed in an auxiliary vector and then communicated like - all other volumetric variables. ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - Aux_Frict[iPoint] = 0.0; - Aux_Heat[iPoint] = 0.0; - Aux_yPlus[iPoint] = 0.0; - } - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_Plotting(iMarker) == YES) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Aux_Frict[iPoint] = solver[FLOW_SOL]->GetCSkinFriction(iMarker, iVertex); - Aux_Heat[iPoint] = solver[FLOW_SOL]->GetHeatFlux(iMarker, iVertex); - Aux_yPlus[iPoint] = solver[FLOW_SOL]->GetYPlus(iMarker, iVertex); - } - } - - /*--- Loop over this partition to collect the current variable ---*/ - - jPoint = 0; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos & write only if requested ---*/ - - - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Load buffers with the skin friction, heat transfer, y+ variables. ---*/ - - if (compressible) { - Buffer_Send_Var[jPoint] = Aux_Frict[iPoint]; - Buffer_Send_Res[jPoint] = Aux_Heat[iPoint]; - Buffer_Send_Vol[jPoint] = Aux_yPlus[iPoint]; - } - if (incompressible || freesurface) { - Buffer_Send_Var[jPoint] = Aux_Frict[iPoint]; - Buffer_Send_Res[jPoint] = Aux_Heat[iPoint]; - Buffer_Send_Vol[jPoint] = Aux_yPlus[iPoint]; - } - jPoint++; - } - } - - /*--- Gather the data on the master node. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Vol, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Vol, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Vol[iPoint] = Buffer_Send_Vol[iPoint]; -#endif - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - jPoint = 0; iVar = iVar_ViscCoeffs; - - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - Data[iVar+0][iGlobal_Index] = Buffer_Recv_Var[jPoint]; - Data[iVar+1][iGlobal_Index] = Buffer_Recv_Res[jPoint]; - Data[iVar+2][iGlobal_Index] = Buffer_Recv_Vol[jPoint]; - jPoint++; - } - - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - } - - /*--- Communicate the Eddy Viscosity ---*/ - - if (Kind_Solver == RANS) { - - /*--- Loop over this partition to collect the current variable ---*/ - - jPoint = 0; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos & write only if requested ---*/ - - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Load buffers with the pressure and mach variables. ---*/ - - if (compressible) { - Buffer_Send_Var[jPoint] = solver[FLOW_SOL]->node[iPoint]->GetEddyViscosity(); - } - if (incompressible || freesurface) { - Buffer_Send_Var[jPoint] = solver[FLOW_SOL]->node[iPoint]->GetEddyViscosityInc(); - } - jPoint++; - } - } - - /*--- Gather the data on the master node. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; -#endif - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - jPoint = 0; iVar = iVar_Eddy; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; - jPoint++; - } - - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - - } - - /*--- Communicate the Sharp Edges ---*/ - - if (config->GetWrt_SharpEdges()) { - - if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - - /*--- Loop over this partition to collect the current variable ---*/ - jPoint = 0; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos & write only if requested ---*/ - - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Load buffers with the pressure and mach variables. ---*/ - - Buffer_Send_Var[jPoint] = geometry->node[iPoint]->GetSharpEdge_Distance(); - jPoint++; - } - } - - /*--- Gather the data on the master node. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; -#endif - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - jPoint = 0; iVar = iVar_Sharp; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; - jPoint++; - } - - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - } - } - - /*--- Communicate the surface sensitivity ---*/ - - if ((Kind_Solver == ADJ_EULER) || - (Kind_Solver == ADJ_NAVIER_STOKES) || - (Kind_Solver == ADJ_RANS) || - (Kind_Solver == DISC_ADJ_EULER) || - (Kind_Solver == DISC_ADJ_NAVIER_STOKES) || - (Kind_Solver == DISC_ADJ_RANS)) { - - /*--- First, loop through the mesh in order to find and store the - value of the surface sensitivity at any surface nodes. They - will be placed in an auxiliary vector and then communicated like - all other volumetric variables. ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) Aux_Sens[iPoint] = 0.0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_Plotting(iMarker) == YES) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; - Area = sqrt (Area); - Aux_Sens[iPoint] = solver[ADJFLOW_SOL]->GetCSensitivity(iMarker, iVertex)/Area; - } - } - - /*--- Loop over this partition to collect the current variable ---*/ - - jPoint = 0; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos & write only if requested ---*/ - - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Load buffers with the skin friction, heat transfer, y+ variables. ---*/ - - Buffer_Send_Var[jPoint] = Aux_Sens[iPoint]; - if ((config->GetKind_ConvNumScheme() == SPACE_CENTERED) && (!config->GetDiscrete_Adjoint())) - Buffer_Send_Res[jPoint] = solver[ADJFLOW_SOL]->node[iPoint]->GetSensor(iPoint); - if ((config->GetKind_ConvNumScheme() == SPACE_UPWIND) && (!config->GetDiscrete_Adjoint())) - Buffer_Send_Res[jPoint] = solver[ADJFLOW_SOL]->node[iPoint]->GetLimiter(0); - - jPoint++; - } - } - - /*--- Gather the data on the master node. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - if (!config->GetDiscrete_Adjoint()) - SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; - if (!config->GetDiscrete_Adjoint()) - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; -#endif - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - jPoint = 0; iVar = iVar_Sens; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - Data[iVar+0][iGlobal_Index] = Buffer_Recv_Var[jPoint]; - if (!config->GetDiscrete_Adjoint()) - Data[iVar+1][iGlobal_Index] = Buffer_Recv_Res[jPoint]; - jPoint++; - } - - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - } - - if ((Kind_Solver == DISC_ADJ_EULER) || - (Kind_Solver == DISC_ADJ_NAVIER_STOKES) || - (Kind_Solver == DISC_ADJ_RANS)) { - /*--- Loop over this partition to collect the current variable ---*/ - - jPoint = 0; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos & write only if requested ---*/ - - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Load buffers with the skin friction, heat transfer, y+ variables. ---*/ - - Buffer_Send_Var[jPoint] = solver[ADJFLOW_SOL]->node[iPoint]->GetSensitivity(0); - Buffer_Send_Res[jPoint] = solver[ADJFLOW_SOL]->node[iPoint]->GetSensitivity(1); - if (nDim == 3) - Buffer_Send_Vol[jPoint] = solver[ADJFLOW_SOL]->node[iPoint]->GetSensitivity(2); - jPoint++; - } - } - - /*--- Gather the data on the master node. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - if (nDim == 3) - SU2_MPI::Gather(Buffer_Send_Vol, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Vol, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; - if (nDim == 3) - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Vol[iPoint] = Buffer_Send_Vol[iPoint]; -#endif - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - jPoint = 0; iVar = iVar_SensDim; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - Data[iVar+0][iGlobal_Index] = Buffer_Recv_Var[jPoint]; - Data[iVar+1][iGlobal_Index] = Buffer_Recv_Res[jPoint]; - if (nDim == 3) - Data[iVar+2][iGlobal_Index] = Buffer_Recv_Vol[jPoint]; - jPoint++; - } - - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - } - - /*--- Communicate the Linear elasticity stresses (2D) ---*/ - - if (Kind_Solver == LINEAR_ELASTICITY) { - - /*--- Loop over this partition to collect the current variable ---*/ - - jPoint = 0; su2double **Stress; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos & write only if requested ---*/ - - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Load buffers with the three grid velocity components. ---*/ - - Stress = solver[FEA_SOL]->node[iPoint]->GetStress(); - /*--- Sigma xx ---*/ - Buffer_Send_Var[jPoint] = Stress[0][0]; - /*--- Sigma yy ---*/ - Buffer_Send_Res[jPoint] = Stress[1][1]; - /*--- Sigma xy ---*/ - Buffer_Send_Vol[jPoint] = Stress[0][1]; - jPoint++; - } - } - - /*--- Gather the data on the master node. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Vol, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Vol, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Vol[iPoint] = Buffer_Send_Vol[iPoint]; -#endif - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - jPoint = 0; iVar = iVar_FEA_Stress; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; - Data[iVar+1][iGlobal_Index] = Buffer_Recv_Res[jPoint]; - Data[iVar+2][iGlobal_Index] = Buffer_Recv_Vol[jPoint]; - jPoint++; - } - - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - } - - /*--- Communicate the Linear elasticity stresses (3D) ---*/ - - if ((Kind_Solver == LINEAR_ELASTICITY) && (geometry->GetnDim() == 3)) { - - /*--- Loop over this partition to collect the current variable ---*/ - - jPoint = 0; su2double **Stress; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos & write only if requested ---*/ - - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Load buffers with the three grid velocity components. ---*/ - - Stress = solver[FEA_SOL]->node[iPoint]->GetStress(); - /*--- Sigma zz ---*/ - Buffer_Send_Var[jPoint] = Stress[2][2]; - /*--- Sigma xz ---*/ - Buffer_Send_Res[jPoint] = Stress[0][2]; - /*--- Sigma yz ---*/ - Buffer_Send_Vol[jPoint] = Stress[1][2]; - jPoint++; - } - } - - /*--- Gather the data on the master node. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Vol, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Vol, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Vol[iPoint] = Buffer_Send_Vol[iPoint]; - -#endif - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - jPoint = 0; iVar = iVar_FEA_Stress_3D; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; - Data[iVar+1][iGlobal_Index] = Buffer_Recv_Res[jPoint]; - Data[iVar+2][iGlobal_Index] = Buffer_Recv_Vol[jPoint]; - jPoint++; - } - - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - } - - - /*--- Communicate the Linear elasticity ---*/ - - if ( Kind_Solver == LINEAR_ELASTICITY ) { - - /*--- Loop over this partition to collect the current variable ---*/ - jPoint = 0; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos & write only if requested ---*/ - - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Load buffers with the temperature and laminar viscosity variables. ---*/ - - Buffer_Send_Var[jPoint] = solver[FEA_SOL]->node[iPoint]->GetVonMises_Stress(); - Buffer_Send_Res[jPoint] = solver[FEA_SOL]->node[iPoint]->GetFlow_Pressure(); - jPoint++; - } - } - - /*--- Gather the data on the master node. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; -#endif - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - jPoint = 0; iVar = iVar_FEA_Extra; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; - Data[iVar+1][iGlobal_Index] = Buffer_Recv_Res[jPoint]; - jPoint++; - } - - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - } - - if (config->GetExtraOutput()) { - - for (jVar = 0; jVar < nVar_Extra; jVar++) { - - /*--- Loop over this partition to collect the current variable ---*/ - - jPoint = 0; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos & write only if requested ---*/ - - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Get this variable into the temporary send buffer. ---*/ - - if (Kind_Solver == RANS) { - Buffer_Send_Var[jPoint] = solver[TURB_SOL]->OutputVariables[iPoint*nVar_Extra+jVar]; - } - jPoint++; - - } - } - - /*--- Gather the data on the master node. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; -#endif - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - jPoint = 0; iVar = iVar_Extra; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - Data[iVar+jVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; - jPoint++; - } - - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - } - } - - } - - /*--- Immediately release the temporary buffers. ---*/ - - delete [] Buffer_Send_Var; - delete [] Buffer_Send_Res; - delete [] Buffer_Send_Vol; - delete [] Buffer_Send_GlobalIndex; - if (rank == MASTER_NODE) { - delete [] Buffer_Recv_Var; - delete [] Buffer_Recv_Res; - delete [] Buffer_Recv_Vol; - delete [] Buffer_Recv_GlobalIndex; - } - - /*--- Release memory needed for surface coefficients ---*/ - - delete [] Local_Halo; - - if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - delete [] Aux_Frict; delete [] Aux_Heat; delete [] Aux_yPlus; - } - if (( Kind_Solver == ADJ_EULER ) || - ( Kind_Solver == ADJ_NAVIER_STOKES ) || - ( Kind_Solver == ADJ_RANS ) || - ( Kind_Solver == DISC_ADJ_EULER ) || - ( Kind_Solver == DISC_ADJ_NAVIER_STOKES ) || - ( Kind_Solver == DISC_ADJ_RANS )) { - delete [] Aux_Sens; - } - -} - -void COutput::MergeBaselineSolution(CConfig *config, CGeometry *geometry, CSolver *solver, unsigned short val_iZone) { - - /*--- Local variables needed on all processors ---*/ - unsigned short iVar; - unsigned long iPoint = 0, jPoint = 0; - - nVar_Total = config->fields.size() - 1; - - /*--- Merge the solution either in serial or parallel. ---*/ - -#ifndef HAVE_MPI - - /*--- In serial, the single process has access to all solution data, - so it is simple to retrieve and store inside Solution_Data. ---*/ - - unsigned short iMarker; - unsigned long iVertex, nTotalPoints = 0; - int SendRecv; - - /*--- First, create a structure to locate any periodic halo nodes ---*/ - int *Local_Halo = new int[geometry->GetnPoint()]; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - Local_Halo[iPoint] = !geometry->node[iPoint]->GetDomain(); - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { - SendRecv = config->GetMarker_All_SendRecv(iMarker); - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && - (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 1) && - (SendRecv < 0)) { - Local_Halo[iPoint] = false; - } - } - - } - } - - /*--- Total number of points in the mesh (this might include periodic points). ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - if (!Local_Halo[iPoint]) nTotalPoints++; - - nGlobal_Poin = nTotalPoints; - Data = new su2double*[nVar_Total]; - for (iVar = 0; iVar < nVar_Total; iVar++) { - Data[iVar] = new su2double[nGlobal_Poin]; - } - - /*--- Loop over all points in the mesh, but only write data - for nodes in the domain (ignore periodic halo nodes). ---*/ - - jPoint = 0; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - if (!Local_Halo[iPoint]) { - - /*--- Solution (first, and second system of equations) ---*/ - - unsigned short jVar = 0; - for (iVar = 0; iVar < nVar_Total; iVar++) { - Data[jVar][jPoint] = solver->node[iPoint]->GetSolution(iVar); - jVar++; - } - } - - /*--- Increment jPoint as the counter. We need this because iPoint - may include halo nodes that we skip over during this loop. ---*/ - - jPoint++; - - } - -#else - - /*--- MPI preprocessing ---*/ - - int rank, nProcessor, iProcessor; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); - - /*--- Local variables needed for merging with MPI ---*/ - - unsigned long iVertex, iMarker; - unsigned long Buffer_Send_nPoint[1], *Buffer_Recv_nPoint = NULL; - unsigned long nLocalPoint = 0, MaxLocalPoint = 0; - unsigned long iGlobal_Index = 0, nBuffer_Scalar = 0; - - int *Local_Halo = new int[geometry->GetnPoint()]; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - Local_Halo[iPoint] = !geometry->node[iPoint]->GetDomain(); - - bool Wrt_Halo = config->GetWrt_Halo(), isPeriodic; - - /*--- Search all send/recv boundaries on this partition for any periodic - nodes that were part of the original domain. We want to recover these - for visualization purposes. ---*/ - - if (Wrt_Halo) { - nLocalPoint = geometry->GetnPoint(); - } else { - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { - - /*--- Checking for less than or equal to the rank, because there may - be some periodic halo nodes that send info to the same rank. ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - isPeriodic = ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && - (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 1)); - if (isPeriodic) Local_Halo[iPoint] = false; - } - } - } - - /*--- Sum total number of nodes that belong to the domain ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - if (Local_Halo[iPoint] == false) - nLocalPoint++; - - } - Buffer_Send_nPoint[0] = nLocalPoint; - - if (rank == MASTER_NODE) Buffer_Recv_nPoint = new unsigned long[nProcessor]; - - SU2_MPI::Allreduce(&nLocalPoint, &MaxLocalPoint, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Gather(&Buffer_Send_nPoint, 1, MPI_UNSIGNED_LONG, Buffer_Recv_nPoint, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); - - nBuffer_Scalar = MaxLocalPoint; - - /*--- Send and Recv buffers. ---*/ - - su2double *Buffer_Send_Var = new su2double[MaxLocalPoint]; - su2double *Buffer_Recv_Var = NULL; - - unsigned long *Buffer_Send_GlobalIndex = new unsigned long[MaxLocalPoint]; - unsigned long *Buffer_Recv_GlobalIndex = NULL; - - /*--- Prepare the receive buffers in the master node only. ---*/ - if (rank == MASTER_NODE) { - - Buffer_Recv_Var = new su2double[nProcessor*MaxLocalPoint]; - Buffer_Recv_GlobalIndex = new unsigned long[nProcessor*MaxLocalPoint]; - - /*--- Sum total number of nodes to be written and allocate arrays ---*/ - nGlobal_Poin = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - nGlobal_Poin += Buffer_Recv_nPoint[iProcessor]; - } - Data = new su2double*[nVar_Total]; - for (iVar = 0; iVar < nVar_Total; iVar++) { - Data[iVar] = new su2double[nGlobal_Poin]; - } - - } - - /*--- Main communication routine. Loop over each variable that has - been requested by the user and perform the MPI comm. Temporary - 1-D buffers are used to send the solution for each variable at all - nodes on each partition to the master node. These are then unpacked - by the master and sorted by global index in one large n-dim. array. ---*/ - - for (iVar = 0; iVar < nVar_Total; iVar++) { - - /*--- Loop over this partition to collect the current variable ---*/ - jPoint = 0; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos and write only if requested ---*/ - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Get this variable into the temporary send buffer. ---*/ - Buffer_Send_Var[jPoint] = solver->node[iPoint]->GetSolution(iVar); - - /*--- Only send/recv the volumes & global indices during the first loop ---*/ - if (iVar == 0) { - Buffer_Send_GlobalIndex[jPoint] = geometry->node[iPoint]->GetGlobalIndex(); - } - jPoint++; - } - } - - /*--- Gather the data on the master node. ---*/ - - SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - if (iVar == 0) { - SU2_MPI::Gather(Buffer_Send_GlobalIndex, nBuffer_Scalar, MPI_UNSIGNED_LONG, Buffer_Recv_GlobalIndex, nBuffer_Scalar, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); - } - - /*--- The master node unpacks and sorts this variable by global index ---*/ - if (rank == MASTER_NODE) { - jPoint = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; - jPoint++; - } - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - } - - /*--- Immediately release the temporary buffers. ---*/ - - delete [] Buffer_Send_Var; - delete [] Buffer_Send_GlobalIndex; - if (rank == MASTER_NODE) { - delete [] Buffer_Recv_Var; - delete [] Buffer_Recv_GlobalIndex; - } - -#endif - - delete [] Local_Halo; - -} - -void COutput::SetRestart(CConfig *config, CGeometry *geometry, CSolver **solver, unsigned short val_iZone) { - - /*--- Local variables ---*/ - - unsigned short Kind_Solver = config->GetKind_Solver(); - unsigned short iVar, iDim, nDim = geometry->GetnDim(); - unsigned long iPoint, iExtIter = config->GetExtIter(); - bool grid_movement = config->GetGrid_Movement(); - ofstream restart_file; - string filename; - - /*--- Retrieve filename from config ---*/ - - if ((config->GetAdjoint()) || (config->GetDiscrete_Adjoint())) { - filename = config->GetRestart_AdjFileName(); - filename = config->GetObjFunc_Extension(filename); - } else { - filename = config->GetRestart_FlowFileName(); - filename = config->GetRestart_FlowFileName(filename, val_iZone); - } - - /*--- Unsteady problems require an iteration number to be appended. ---*/ - - if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { - filename = config->GetUnsteady_FileName(filename, SU2_TYPE::Int(val_iZone)); - } else if (config->GetWrt_Unsteady()) { - filename = config->GetUnsteady_FileName(filename, SU2_TYPE::Int(iExtIter)); - } - - /*--- Open the restart file and write the solution. ---*/ - - restart_file.open(filename.c_str(), ios::out); - restart_file.precision(15); - - /*--- Write the header line based on the particular solver ----*/ - - restart_file << "\"PointID\""; - - /*--- Mesh coordinates are always written to the restart first ---*/ - - if (nDim == 2) { - restart_file << "\t\"x\"\t\"y\""; - } else { - restart_file << "\t\"x\"\t\"y\"\t\"z\""; - } - - for (iVar = 0; iVar < nVar_Consv; iVar++) { - if ( Kind_Solver == LINEAR_ELASTICITY ) - restart_file << "\t\"Displacement_" << iVar+1<<"\""; - else - restart_file << "\t\"Conservative_" << iVar+1<<"\""; - } - - if (!config->GetLow_MemoryOutput()) { - - if (config->GetWrt_Limiters()) { - for (iVar = 0; iVar < nVar_Consv; iVar++) { - restart_file << "\t\"Limiter_" << iVar+1<<"\""; - } - } - if (config->GetWrt_Residuals()) { - for (iVar = 0; iVar < nVar_Consv; iVar++) { - restart_file << "\t\"Residual_" << iVar+1<<"\""; - } - } - - /*--- Mesh velocities for dynamic mesh cases ---*/ - - if (grid_movement) { - if (nDim == 2) { - restart_file << "\t\"Grid_Velx\"\t\"Grid_Vely\""; - } else { - restart_file << "\t\"Grid_Velx\"\t\"Grid_Vely\"\t\"Grid_Velz\""; - } - } - - /*--- Solver specific output variables ---*/ - - if (config->GetKind_Regime() == FREESURFACE) { - restart_file << "\t\"Density\""; - } - - if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - restart_file << "\t\"Pressure\"\t\"Temperature\"\t\"Pressure_Coefficient\"\t\"Mach\""; - } - - if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - restart_file << "\t\"Laminar_Viscosity\"\t\"Skin_Friction_Coefficient\"\t\"Heat_Flux\"\t\"Y_Plus\""; - } - - if (Kind_Solver == RANS) { - restart_file << "\t\"Eddy_Viscosity\""; - } - - if (config->GetWrt_SharpEdges()) { - if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - restart_file << "\t\"Sharp_Edge_Dist\""; - } - } - - if (Kind_Solver == POISSON_EQUATION) { - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) - restart_file << "\t\"poissonField_" << iDim+1 << "\""; - } - - if ((Kind_Solver == ADJ_EULER ) || - (Kind_Solver == ADJ_NAVIER_STOKES ) || - (Kind_Solver == ADJ_RANS ) ) { - restart_file << "\t\"Surface_Sensitivity\"\t\"Solution_Sensor\""; - } - if (( Kind_Solver == DISC_ADJ_EULER ) || - ( Kind_Solver == DISC_ADJ_NAVIER_STOKES ) || - ( Kind_Solver == DISC_ADJ_RANS )) { - restart_file << "\t\"Surface_Sensitivity\"\t\"Sensitivity_x\"\t\"Sensitivity_y\""; - if (geometry->GetnDim() == 3){ - restart_file << "\t\"Sensitivity_z\""; - } - } - - if ((Kind_Solver == LINEAR_ELASTICITY) && (geometry->GetnDim() == 2)) { - restart_file << "\t\"Sxx\"\t\"Syy\"\t\"Sxy\"\t\"Von_Mises_Stress\"\t\"Flow_Pressure\""; - } - - if ((Kind_Solver == LINEAR_ELASTICITY) && (geometry->GetnDim() == 3)) { - restart_file << "\t\"Sxx\"\t\"Syy\"\t\"Sxy\"\t\"Szz\"\t\"Sxz\"\t\"Syz\"\t\"Von_Mises_Stress\"\t\"Flow_Pressure\""; - } - - if (config->GetExtraOutput()) { - string *headings = NULL; - //if (Kind_Solver == RANS) { - headings = solver[TURB_SOL]->OutputHeadingNames; - //} - - for (iVar = 0; iVar < nVar_Extra; iVar++) { - if (headings == NULL) { - restart_file << "\t\"ExtraOutput_" << iVar+1<<"\""; - } else{ - restart_file << "\t\""<< headings[iVar] <<"\""; - } - } - } - } - - restart_file << endl; - - /*--- Write the restart file ---*/ - - for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) { - - /*--- Index of the point ---*/ - restart_file << iPoint << "\t"; - - /*--- Write the grid coordinates first ---*/ - for (iDim = 0; iDim < nDim; iDim++) { - restart_file << scientific << Coords[iDim][iPoint] << "\t"; - } - - /*--- Loop over the variables and write the values to file ---*/ - for (iVar = 0; iVar < nVar_Total; iVar++) { - restart_file << scientific << Data[iVar][iPoint] << "\t"; - } - restart_file << endl; - } - - restart_file.close(); - -} - -void COutput::DeallocateCoordinates(CConfig *config, CGeometry *geometry) { - - unsigned short iDim, nDim = geometry->GetnDim(); - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- The master node alone owns all data found in this routine. ---*/ - - if (rank == MASTER_NODE) { - - /*--- Deallocate memory for coordinate data ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - delete [] Coords[iDim]; - } - delete [] Coords; - - } -} - -void COutput::DeallocateConnectivity(CConfig *config, CGeometry *geometry, bool surf_sol) { - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- The master node alone owns all data found in this routine. ---*/ - if (rank == MASTER_NODE) { - - /*--- Deallocate memory for connectivity data ---*/ - if (surf_sol) { - if (nGlobal_Line > 0) delete [] Conn_Line; - if (nGlobal_BoundTria > 0) delete [] Conn_BoundTria; - if (nGlobal_BoundQuad > 0) delete [] Conn_BoundQuad; - } - else { - if (nGlobal_Tria > 0) delete [] Conn_Tria; - if (nGlobal_Quad > 0) delete [] Conn_Quad; - if (nGlobal_Tetr > 0) delete [] Conn_Tetr; - if (nGlobal_Hexa > 0) delete [] Conn_Hexa; - if (nGlobal_Pris > 0) delete [] Conn_Pris; - if (nGlobal_Pyra > 0) delete [] Conn_Pyra; - } - - } -} - -void COutput::DeallocateSolution(CConfig *config, CGeometry *geometry) { - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- The master node alone owns all data found in this routine. ---*/ - if (rank == MASTER_NODE) { - - /*--- Deallocate memory for solution data ---*/ - for (unsigned short iVar = 0; iVar < nVar_Total; iVar++) { - delete [] Data[iVar]; - } - delete [] Data; - - } -} - -void COutput::SetConvHistory_Header(ofstream *ConvHist_file, CConfig *config) { - char cstr[200], buffer[50], turb_resid[1000]; - unsigned short iMarker, iMarker_Monitoring; - string Monitoring_Tag, monitoring_coeff, aeroelastic_coeff; - - bool rotating_frame = config->GetRotating_Frame(); - bool aeroelastic = config->GetAeroelastic_Simulation(); - bool equiv_area = config->GetEquivArea(); - bool turbulent = ((config->GetKind_Solver() == RANS) || (config->GetKind_Solver() == ADJ_RANS) || - (config->GetKind_Solver() == DISC_ADJ_RANS)); - bool frozen_turb = config->GetFrozen_Visc(); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool inv_design = (config->GetInvDesign_Cp() || config->GetInvDesign_HeatFlux()); - bool output_1d = config->GetWrt_1D_Output(); - bool output_per_surface = false; - bool output_massflow = (config->GetKind_ObjFunc() == MASS_FLOW_RATE); - if (config->GetnMarker_Monitoring() > 1) output_per_surface = true; - - unsigned short direct_diff = config->GetDirectDiff(); - - bool isothermal = false; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if ((config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL )) - isothermal = true; - - /*--- Write file name with extension ---*/ - - string filename = config->GetConv_FileName(); - strcpy (cstr, filename.data()); - - if (config->GetWrt_Unsteady() && config->GetRestart()) { - long iExtIter = config->GetUnst_RestartIter(); - if (SU2_TYPE::Int(iExtIter) < 10) SPRINTF (buffer, "_0000%d", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d", SU2_TYPE::Int(iExtIter)); - if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d", SU2_TYPE::Int(iExtIter)); - strcat(cstr, buffer); - } - - if ((config->GetOutput_FileFormat() == TECPLOT) || - (config->GetOutput_FileFormat() == FIELDVIEW)) SPRINTF (buffer, ".dat"); - else if ((config->GetOutput_FileFormat() == TECPLOT_BINARY) || - (config->GetOutput_FileFormat() == FIELDVIEW_BINARY)) SPRINTF (buffer, ".plt"); - else if (config->GetOutput_FileFormat() == PARAVIEW) SPRINTF (buffer, ".csv"); - strcat(cstr, buffer); - - ConvHist_file->open(cstr, ios::out); - ConvHist_file->precision(15); - - /*--- Begin of the header ---*/ - - char begin[]= "\"Iteration\""; - - /*--- Header for the coefficients ---*/ - - char flow_coeff[]= ",\"CLift\",\"CDrag\",\"CSideForce\",\"CMx\",\"CMy\",\"CMz\",\"CFx\",\"CFy\",\"CFz\",\"CL/CD\""; - char heat_coeff[]= ",\"HeatFlux_Total\",\"HeatFlux_Maximum\""; - char equivalent_area_coeff[]= ",\"CEquivArea\",\"CNearFieldOF\""; - char rotating_frame_coeff[]= ",\"CMerit\",\"CT\",\"CQ\""; - char free_surface_coeff[]= ",\"CFreeSurface\""; - char wave_coeff[]= ",\"CWave\""; - char fea_coeff[]= ",\"CFEA\""; - char adj_coeff[]= ",\"Sens_Geo\",\"Sens_Mach\",\"Sens_AoA\",\"Sens_Press\",\"Sens_Temp\",\"Sens_AoS\",\"Sens_BPress\""; - char oneD_outputs[]= ",\"Avg_TotalPress\",\"Avg_Mach\",\"Avg_Temperature\",\"MassFlowRate\",\"FluxAvg_Pressure\",\"FluxAvg_Density\",\"FluxAvg_Velocity\",\"FluxAvg_Enthalpy\""; - char Cp_inverse_design[]= ",\"Cp_Diff\""; - char Heat_inverse_design[]= ",\"HeatFlux_Diff\""; - char mass_flow_rate[] = ",\"MassFlowRate\""; - char d_flow_coeff[] = ",\"D(CLift)\",\"D(CDrag)\",\"D(CSideForce)\",\"D(CMx)\",\"D(CMy)\",\"D(CMz)\",\"D(CFx)\",\"D(CFy)\",\"D(CFz)\",\"D(CL/CD)\""; - - /* Find the markers being monitored and create a header for them */ - for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { - Monitoring_Tag = config->GetMarker_Monitoring(iMarker_Monitoring); - monitoring_coeff += ",\"CLift_" + Monitoring_Tag + "\""; - monitoring_coeff += ",\"CDrag_" + Monitoring_Tag + "\""; - monitoring_coeff += ",\"CSideForce_" + Monitoring_Tag + "\""; - monitoring_coeff += ",\"CL/CD_" + Monitoring_Tag + "\""; - monitoring_coeff += ",\"CFx_" + Monitoring_Tag + "\""; - monitoring_coeff += ",\"CFy_" + Monitoring_Tag + "\""; - monitoring_coeff += ",\"CFz_" + Monitoring_Tag + "\""; - monitoring_coeff += ",\"CMx_" + Monitoring_Tag + "\""; - monitoring_coeff += ",\"CMy_" + Monitoring_Tag + "\""; - monitoring_coeff += ",\"CMz_" + Monitoring_Tag + "\""; - aeroelastic_coeff += ",\"plunge_" + Monitoring_Tag + "\""; - aeroelastic_coeff += ",\"pitch_" + Monitoring_Tag + "\""; - } - - /*--- Header for the residuals ---*/ - - char flow_resid[]= ",\"Res_Flow[0]\",\"Res_Flow[1]\",\"Res_Flow[2]\",\"Res_Flow[3]\",\"Res_Flow[4]\""; - char adj_flow_resid[]= ",\"Res_AdjFlow[0]\",\"Res_AdjFlow[1]\",\"Res_AdjFlow[2]\",\"Res_AdjFlow[3]\",\"Res_AdjFlow[4]\""; - switch (config->GetKind_Turb_Model()) { - case SA: SPRINTF (turb_resid, ",\"Res_Turb[0]\""); break; - case SA_NEG: SPRINTF (turb_resid, ",\"Res_Turb[0]\""); break; - case SST: SPRINTF (turb_resid, ",\"Res_Turb[0]\",\"Res_Turb[1]\""); break; - } - char adj_turb_resid[]= ",\"Res_AdjTurb[0]\""; - char levelset_resid[]= ",\"Res_LevelSet\""; - char adj_levelset_resid[]= ",\"Res_AdjLevelSet\""; - char wave_resid[]= ",\"Res_Wave[0]\",\"Res_Wave[1]\""; - char fea_resid[]= ",\"Res_FEA\""; - char heat_resid[]= ",\"Res_Heat\""; - - /*--- End of the header ---*/ - - char end[]= ",\"Linear_Solver_Iterations\",\"CFL_Number\",\"Time(min)\"\n"; - - if ((config->GetOutput_FileFormat() == TECPLOT) || - (config->GetOutput_FileFormat() == TECPLOT_BINARY) || - (config->GetOutput_FileFormat() == FIELDVIEW) || - (config->GetOutput_FileFormat() == FIELDVIEW_BINARY)) { - ConvHist_file[0] << "TITLE = \"SU2 Simulation\"" << endl; - ConvHist_file[0] << "VARIABLES = "; - } - - /*--- Write the header, case depending ---*/ - switch (config->GetKind_Solver()) { - - case EULER : case NAVIER_STOKES: case RANS : - ConvHist_file[0] << begin << flow_coeff; - if (isothermal) ConvHist_file[0] << heat_coeff; - if (equiv_area) ConvHist_file[0] << equivalent_area_coeff; - if (inv_design) { - ConvHist_file[0] << Cp_inverse_design; - if (isothermal) ConvHist_file[0] << Heat_inverse_design; - } - if (rotating_frame) ConvHist_file[0] << rotating_frame_coeff; - ConvHist_file[0] << flow_resid; - if (turbulent) ConvHist_file[0] << turb_resid; - if (aeroelastic) ConvHist_file[0] << aeroelastic_coeff; - if (output_per_surface) ConvHist_file[0] << monitoring_coeff; - if (output_1d) ConvHist_file[0] << oneD_outputs; - if (output_massflow and !output_1d) ConvHist_file[0]<< mass_flow_rate; - if (direct_diff != NO_DERIVATIVE) ConvHist_file[0] << d_flow_coeff; - ConvHist_file[0] << end; - if (freesurface) { - ConvHist_file[0] << begin << flow_coeff << free_surface_coeff; - ConvHist_file[0] << flow_resid << levelset_resid << end; - } - - break; - - case ADJ_EULER : case ADJ_NAVIER_STOKES : case ADJ_RANS: - case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: - ConvHist_file[0] << begin << adj_coeff << adj_flow_resid; - if ((turbulent) && (!frozen_turb)) ConvHist_file[0] << adj_turb_resid; - ConvHist_file[0] << end; - if (freesurface) { - ConvHist_file[0] << begin << adj_coeff << adj_flow_resid << adj_levelset_resid << end; - } - break; - - case WAVE_EQUATION: - ConvHist_file[0] << begin << wave_coeff; - ConvHist_file[0] << wave_resid << end; - break; - - case HEAT_EQUATION: - ConvHist_file[0] << begin << heat_coeff; - ConvHist_file[0] << heat_resid << end; - break; - - case LINEAR_ELASTICITY: - ConvHist_file[0] << begin << fea_coeff; - ConvHist_file[0] << fea_resid << end; - break; - - } - - if (config->GetOutput_FileFormat() == TECPLOT || - config->GetOutput_FileFormat() == TECPLOT_BINARY || - config->GetOutput_FileFormat() == FIELDVIEW || - config->GetOutput_FileFormat() == FIELDVIEW_BINARY) { - ConvHist_file[0] << "ZONE T= \"Convergence history\"" << endl; - } - -} - - -void COutput::SetConvHistory_Body(ofstream *ConvHist_file, - CGeometry ***geometry, - CSolver ****solver_container, - CConfig **config, - CIntegration ***integration, - bool DualTime_Iteration, - su2double timeused, - unsigned short val_iZone) { - - bool output_1d = config[val_iZone]->GetWrt_1D_Output(); - bool output_massflow = (config[val_iZone]->GetKind_ObjFunc() == MASS_FLOW_RATE); - unsigned short FinestMesh = config[val_iZone]->GetFinestMesh(); - - int rank; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#else - rank = MASTER_NODE; -#endif - - /*--- If 1-D outputs requested, calculated them. Requires info from all nodes, - Get area-averaged and flux-averaged values at the specified surface ---*/ - - if (output_1d) { - switch (config[val_iZone]->GetKind_Solver()) { - case EULER: case NAVIER_STOKES: case RANS: - case ADJ_EULER: case ADJ_NAVIER_STOKES: case ADJ_RANS: - OneDimensionalOutput(solver_container[val_iZone][FinestMesh][FLOW_SOL], geometry[val_iZone][FinestMesh], config[val_iZone]); - break; - } - } - if (output_massflow and !output_1d) { - switch (config[val_iZone]->GetKind_Solver()) { - case EULER: case NAVIER_STOKES: case RANS: - case ADJ_EULER: case ADJ_NAVIER_STOKES: case ADJ_RANS: - SetMassFlowRate(solver_container[val_iZone][FinestMesh][FLOW_SOL], geometry[val_iZone][FinestMesh], config[val_iZone]); - break; - } - } - - /*--- Output using only the master node ---*/ - if (rank == MASTER_NODE) { - - unsigned long iIntIter = config[val_iZone]->GetIntIter(); - unsigned long iExtIter = config[val_iZone]->GetExtIter(); - - /*--- WARNING: These buffers have hard-coded lengths. Note that you - may have to adjust them to be larger if adding more entries. ---*/ - char begin[1000], direct_coeff[1000], surface_coeff[1000], aeroelastic_coeff[1000], monitoring_coeff[10000], - adjoint_coeff[1000], flow_resid[1000], adj_flow_resid[1000], turb_resid[1000], trans_resid[1000], - adj_turb_resid[1000], levelset_resid[1000], adj_levelset_resid[1000], wave_coeff[1000], - heat_coeff[1000], fea_coeff[1000], wave_resid[1000], heat_resid[1000], fea_resid[1000], end[1000], - oneD_outputs[1000], massflow_outputs[1000], d_direct_coeff[1000]; - - su2double dummy = 0.0, *Coord; - unsigned short iVar, iMarker, iMarker_Monitoring; - - unsigned long LinSolvIter = 0, iPointMaxResid; - su2double timeiter = timeused/su2double(iExtIter+1); - - unsigned short nDim = geometry[val_iZone][FinestMesh]->GetnDim(); - - bool compressible = (config[val_iZone]->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config[val_iZone]->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config[val_iZone]->GetKind_Regime() == FREESURFACE); - - bool rotating_frame = config[val_iZone]->GetRotating_Frame(); - bool aeroelastic = config[val_iZone]->GetAeroelastic_Simulation(); - bool equiv_area = config[val_iZone]->GetEquivArea(); - bool inv_design = (config[val_iZone]->GetInvDesign_Cp() || config[val_iZone]->GetInvDesign_HeatFlux()); - bool transition = (config[val_iZone]->GetKind_Trans_Model() == LM); - bool isothermal = false; - for (iMarker = 0; iMarker < config[val_iZone]->GetnMarker_All(); iMarker++) - if ((config[val_iZone]->GetMarker_All_KindBC(iMarker) == ISOTHERMAL)) - isothermal = true; - bool turbulent = ((config[val_iZone]->GetKind_Solver() == RANS) || (config[val_iZone]->GetKind_Solver() == ADJ_RANS) || - (config[val_iZone]->GetKind_Solver() == DISC_ADJ_RANS)); - bool adjoint = config[val_iZone]->GetAdjoint() || config[val_iZone]->GetDiscrete_Adjoint(); - bool disc_adj = config[val_iZone]->GetDiscrete_Adjoint(); - bool wave = (config[val_iZone]->GetKind_Solver() == WAVE_EQUATION); - bool heat = (config[val_iZone]->GetKind_Solver() == HEAT_EQUATION); - bool fea = (config[val_iZone]->GetKind_Solver() == LINEAR_ELASTICITY); - bool flow = (config[val_iZone]->GetKind_Solver() == EULER) || (config[val_iZone]->GetKind_Solver() == NAVIER_STOKES) || - (config[val_iZone]->GetKind_Solver() == RANS) || (config[val_iZone]->GetKind_Solver() == ADJ_EULER) || - (config[val_iZone]->GetKind_Solver() == ADJ_NAVIER_STOKES) || (config[val_iZone]->GetKind_Solver() == ADJ_RANS); - - bool turbo = config[val_iZone]->GetBoolTurboPerf(); - string inMarker_Tag, outMarker_Tag; - - bool output_per_surface = false; - if (config[val_iZone]->GetnMarker_Monitoring() > 1) output_per_surface = true; - - unsigned short direct_diff = config[val_iZone]->GetDirectDiff(); - - - /*--- Initialize variables to store information from all domains (direct solution) ---*/ - su2double Total_CLift = 0.0, Total_CDrag = 0.0, Total_CSideForce = 0.0, Total_CMx = 0.0, Total_CMy = 0.0, Total_CMz = 0.0, Total_CEff = 0.0, - Total_CEquivArea = 0.0, Total_CNearFieldOF = 0.0, Total_CFx = 0.0, Total_CFy = 0.0, Total_CFz = 0.0, Total_CMerit = 0.0, - Total_CT = 0.0, Total_CQ = 0.0, Total_CFreeSurface = 0.0, Total_CWave = 0.0, Total_CHeat = 0.0, Total_CpDiff = 0.0, Total_HeatFluxDiff = 0.0, - Total_CFEA = 0.0, Total_Heat = 0.0, Total_MaxHeat = 0.0, Total_Mdot = 0.0; - su2double OneD_AvgStagPress = 0.0, OneD_AvgMach = 0.0, OneD_AvgTemp = 0.0, OneD_MassFlowRate = 0.0, - OneD_FluxAvgPress = 0.0, OneD_FluxAvgDensity = 0.0, OneD_FluxAvgVelocity = 0.0, OneD_FluxAvgEntalpy = 0.0; - - /*--- Initialize variables to store information from all zone for turboperformance (direct solution) ---*/ - su2double *TotalStaticEfficiency = NULL, - *TotalTotalEfficiency = NULL, - *KineticEnergyLoss = NULL, - *TotalPressureLoss = NULL, - *MassFlowIn = NULL, - *MassFlowOut = NULL, - *FlowAngleIn = NULL, - *FlowAngleOut = NULL, - *EulerianWork = NULL, - *TotalEnthalpyIn = NULL, - *PressureRatio = NULL, - *PressureOut = NULL, - *EnthalpyOut = NULL, - *MachIn = NULL, - *MachOut = NULL, - *NormalMachIn = NULL, - *NormalMachOut = NULL, - *VelocityOutIs = NULL; - - - - /*--- Initialize variables to store information from all domains (adjoint solution) ---*/ - su2double Total_Sens_Geo = 0.0, Total_Sens_Mach = 0.0, Total_Sens_AoA = 0.0; - su2double Total_Sens_Press = 0.0, Total_Sens_Temp = 0.0, Total_Sens_BPress=0.0; - - /*--- Initialize variables to store information from all domains (direct differentiation) ---*/ - su2double D_Total_CLift = 0.0, D_Total_CDrag = 0.0, D_Total_CSideForce = 0.0, D_Total_CMx = 0.0, D_Total_CMy = 0.0, D_Total_CMz = 0.0, D_Total_CEff = 0.0, D_Total_CFx = 0.0, D_Total_CFy = 0.0, D_Total_CFz = 0.0; - - /*--- Residual arrays ---*/ - su2double *residual_flow = NULL, - *residual_turbulent = NULL, - *residual_transition = NULL, - *residual_levelset = NULL; - su2double *residual_adjflow = NULL, - *residual_adjturbulent = NULL, - *residual_adjlevelset = NULL; - su2double *residual_wave = NULL; - su2double *residual_fea = NULL; - su2double *residual_heat = NULL; - - /*--- Coefficients Monitored arrays ---*/ - su2double *aeroelastic_plunge = NULL, - *aeroelastic_pitch = NULL, - *Surface_CLift = NULL, - *Surface_CDrag = NULL, - *Surface_CSideForce = NULL, - *Surface_CEff = NULL, - *Surface_CFx = NULL, - *Surface_CFy = NULL, - *Surface_CFz = NULL, - *Surface_CMx = NULL, - *Surface_CMy = NULL, - *Surface_CMz = NULL; - - /*--- Initialize number of variables ---*/ - unsigned short nVar_Flow = 0, nVar_LevelSet = 0, nVar_Turb = 0, - nVar_Trans = 0, nVar_Wave = 0, nVar_Heat = 0, nVar_FEA = 0, - nVar_AdjFlow = 0, nVar_AdjLevelSet = 0, nVar_AdjTurb = 0; - - /*--- Direct problem variables ---*/ - if (compressible) nVar_Flow = nDim+2; else nVar_Flow = nDim+1; - if (turbulent) { - switch (config[val_iZone]->GetKind_Turb_Model()) { - case SA: nVar_Turb = 1; break; - case SA_NEG: nVar_Turb = 1; break; - case SST: nVar_Turb = 2; break; - } - } - if (transition) nVar_Trans = 2; - if (wave) nVar_Wave = 2; - if (fea) nVar_FEA = nDim; - if (heat) nVar_Heat = 1; - if (freesurface) nVar_LevelSet = 1; - - /*--- Adjoint problem variables ---*/ - if (compressible) nVar_AdjFlow = nDim+2; else nVar_AdjFlow = nDim+1; - if (turbulent) { - switch (config[val_iZone]->GetKind_Turb_Model()) { - case SA: nVar_AdjTurb = 1; break; - case SA_NEG: nVar_AdjTurb = 1; break; - case SST: nVar_AdjTurb = 2; break; - } - } - if (freesurface) nVar_AdjLevelSet = 1; - - /*--- Allocate memory for the residual ---*/ - residual_flow = new su2double[nVar_Flow]; - residual_turbulent = new su2double[nVar_Turb]; - residual_transition = new su2double[nVar_Trans]; - residual_levelset = new su2double[nVar_LevelSet]; - residual_wave = new su2double[nVar_Wave]; - residual_fea = new su2double[nVar_FEA]; - residual_heat = new su2double[nVar_Heat]; - - residual_adjflow = new su2double[nVar_AdjFlow]; - residual_adjturbulent = new su2double[nVar_AdjTurb]; - residual_adjlevelset = new su2double[nVar_AdjLevelSet]; - - /*--- Allocate memory for the coefficients being monitored ---*/ - aeroelastic_plunge = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - aeroelastic_pitch = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CLift = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CDrag = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CSideForce = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CEff = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CFx = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CFy = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CFz = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CMx = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CMy = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CMz = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - - /*--- Allocate memory for the turboperformace ---*/ - TotalStaticEfficiency = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - TotalTotalEfficiency = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - KineticEnergyLoss = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - TotalPressureLoss = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - MassFlowIn = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - MassFlowOut = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - FlowAngleIn = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - FlowAngleOut = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - EulerianWork = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - TotalEnthalpyIn = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - PressureRatio = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - PressureOut = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - EnthalpyOut = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - MachIn = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - MachOut = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - NormalMachIn = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - NormalMachOut = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - VelocityOutIs = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; - - - - - - /*--- Write information from nodes ---*/ - switch (config[val_iZone]->GetKind_Solver()) { - - case EULER: case NAVIER_STOKES: case RANS: - case ADJ_EULER: case ADJ_NAVIER_STOKES: case ADJ_RANS: - case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: - - /*--- Flow solution coefficients ---*/ - Total_CLift = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CLift(); - Total_CDrag = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CDrag(); - Total_CSideForce = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CSideForce(); - Total_CEff = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CEff(); - Total_CMx = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CMx(); - Total_CMy = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CMy(); - Total_CMz = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CMz(); - Total_CFx = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CFx(); - Total_CFy = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CFy(); - Total_CFz = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CFz(); - - if (direct_diff != NO_DERIVATIVE){ - D_Total_CLift = SU2_TYPE::GetDerivative(Total_CLift); - D_Total_CDrag = SU2_TYPE::GetDerivative(Total_CDrag); - D_Total_CSideForce = SU2_TYPE::GetDerivative(Total_CSideForce); - D_Total_CEff = SU2_TYPE::GetDerivative(Total_CEff); - D_Total_CMx = SU2_TYPE::GetDerivative(Total_CMx); - D_Total_CMy = SU2_TYPE::GetDerivative(Total_CMy); - D_Total_CMz = SU2_TYPE::GetDerivative(Total_CMz); - D_Total_CFx = SU2_TYPE::GetDerivative(Total_CFx); - D_Total_CFy = SU2_TYPE::GetDerivative(Total_CFy); - D_Total_CFz = SU2_TYPE::GetDerivative(Total_CFz); - } - - if (freesurface) { - Total_CFreeSurface = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CFreeSurface(); - } - - if (isothermal) { - Total_Heat = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_HeatFlux(); - Total_MaxHeat = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_MaxHeatFlux(); - } - - if (equiv_area) { - Total_CEquivArea = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CEquivArea(); - Total_CNearFieldOF = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CNearFieldOF(); - - /*--- Note that there is a redefinition of the nearfield based functionals ---*/ - Total_CEquivArea = config[val_iZone]->GetWeightCd()*Total_CDrag + (1.0-config[val_iZone]->GetWeightCd())*Total_CEquivArea; - Total_CNearFieldOF = config[val_iZone]->GetWeightCd()*Total_CDrag + (1.0-config[val_iZone]->GetWeightCd())*Total_CNearFieldOF; - } - - if (inv_design) { - Total_CpDiff = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CpDiff(); - if (isothermal) { - Total_HeatFluxDiff = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_HeatFluxDiff(); - } - } - - if (rotating_frame) { - Total_CT = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CT(); - Total_CQ = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CQ(); - Total_CMerit = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CMerit(); - } - - if (aeroelastic) { - /*--- Look over the markers being monitored and get the desired values ---*/ - for (iMarker_Monitoring = 0; iMarker_Monitoring < config[ZONE_0]->GetnMarker_Monitoring(); iMarker_Monitoring++) { - aeroelastic_plunge[iMarker_Monitoring] = config[val_iZone]->GetAeroelastic_plunge(iMarker_Monitoring); - aeroelastic_pitch[iMarker_Monitoring] = config[val_iZone]->GetAeroelastic_pitch(iMarker_Monitoring); - } - } - - if (output_per_surface) { - /*--- Look over the markers being monitored and get the desired values ---*/ - for (iMarker_Monitoring = 0; iMarker_Monitoring < config[ZONE_0]->GetnMarker_Monitoring(); iMarker_Monitoring++) { - Surface_CLift[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CLift(iMarker_Monitoring); - Surface_CDrag[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CDrag(iMarker_Monitoring); - Surface_CSideForce[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CSideForce(iMarker_Monitoring); - Surface_CEff[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CEff(iMarker_Monitoring); - Surface_CFx[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFx(iMarker_Monitoring); - Surface_CFy[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFy(iMarker_Monitoring); - Surface_CFz[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFz(iMarker_Monitoring); - Surface_CMx[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMx(iMarker_Monitoring); - Surface_CMy[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMy(iMarker_Monitoring); - Surface_CMz[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMz(iMarker_Monitoring); - } - } - - if (turbo) { - /*--- Loop over the nMarker of turboperformance and get the desired values ---*/ - for (iMarker_Monitoring = 0; iMarker_Monitoring < config[ZONE_0]->Get_nMarkerTurboPerf(); iMarker_Monitoring++) { - TotalStaticEfficiency[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotalStaticEfficiency(iMarker_Monitoring); - TotalTotalEfficiency[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotalTotalEfficiency(iMarker_Monitoring); - KineticEnergyLoss[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetKineticEnergyLoss(iMarker_Monitoring); - TotalPressureLoss[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotalPressureLoss(iMarker_Monitoring); - MassFlowIn[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetMassFlowIn(iMarker_Monitoring); - MassFlowOut[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetMassFlowOut(iMarker_Monitoring); - FlowAngleIn[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetFlowAngleIn(iMarker_Monitoring); - FlowAngleOut[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetFlowAngleOut(iMarker_Monitoring); - EulerianWork[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetEulerianWork(iMarker_Monitoring); - TotalEnthalpyIn[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotalEnthalpyIn(iMarker_Monitoring); - PressureRatio[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetPressureRatio(iMarker_Monitoring); - PressureOut[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetPressureOut(iMarker_Monitoring); - EnthalpyOut[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetEnthalpyOut(iMarker_Monitoring); - MachIn[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetMachIn(iMarker_Monitoring); - MachOut[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetMachOut(iMarker_Monitoring); - NormalMachIn[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetNormalMachIn(iMarker_Monitoring); - NormalMachOut[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetNormalMachOut(iMarker_Monitoring); - VelocityOutIs[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetVelocityOutIs(iMarker_Monitoring); - } - } - - -// if (fluid_structure) { -// Total_CFEA = solver_container[ZONE_0][FinestMesh][FEA_SOL]->GetTotal_CFEA(); -// } - - if (output_1d) { - - /*--- Get area-averaged and flux-averaged values at the specified surface ---*/ - - OneD_AvgStagPress = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_TotalPress(); - OneD_AvgMach = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_Mach(); - OneD_AvgTemp = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_Temp(); - OneD_MassFlowRate = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_MassFlowRate(); - - OneD_FluxAvgPress = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_FluxAvgPress(); - OneD_FluxAvgDensity = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_FluxAvgDensity(); - OneD_FluxAvgVelocity = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_FluxAvgVelocity(); - OneD_FluxAvgEntalpy = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_FluxAvgEntalpy(); - - } - /*--- Get Mass Flow at the Monitored Markers ---*/ - - - if (output_massflow) { - Total_Mdot = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_MassFlowRate(); - } - - /*--- Flow Residuals ---*/ - - for (iVar = 0; iVar < nVar_Flow; iVar++) - residual_flow[iVar] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetRes_RMS(iVar); - - /*--- Turbulent residual ---*/ - - if (turbulent) { - for (iVar = 0; iVar < nVar_Turb; iVar++) - residual_turbulent[iVar] = solver_container[val_iZone][FinestMesh][TURB_SOL]->GetRes_RMS(iVar); - } - - /*--- Transition residual ---*/ - - if (transition) { - for (iVar = 0; iVar < nVar_Trans; iVar++) - residual_transition[iVar] = solver_container[val_iZone][FinestMesh][TRANS_SOL]->GetRes_RMS(iVar); - } - - /*--- Free Surface residual ---*/ - - if (freesurface) { - for (iVar = 0; iVar < nVar_LevelSet; iVar++) - residual_levelset[iVar] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetRes_RMS(nDim+1); - } - - /*--- FEA residual ---*/ -// if (fluid_structure) { -// for (iVar = 0; iVar < nVar_FEA; iVar++) -// residual_fea[iVar] = solver_container[ZONE_0][FinestMesh][FEA_SOL]->GetRes_RMS(iVar); -// } - - /*--- Iterations of the linear solver ---*/ - - LinSolvIter = (unsigned long) solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetIterLinSolver(); - - /*--- Adjoint solver ---*/ - - if (adjoint) { - - /*--- Adjoint solution coefficients ---*/ - - Total_Sens_Geo = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetTotal_Sens_Geo(); - Total_Sens_Mach = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetTotal_Sens_Mach(); - Total_Sens_AoA = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetTotal_Sens_AoA(); - Total_Sens_Press = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetTotal_Sens_Press(); - Total_Sens_Temp = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetTotal_Sens_Temp(); - Total_Sens_BPress = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetTotal_Sens_BPress(); - - /*--- Adjoint flow residuals ---*/ - - for (iVar = 0; iVar < nVar_AdjFlow; iVar++) { - residual_adjflow[iVar] = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetRes_RMS(iVar); - } - - /*--- Adjoint turbulent residuals ---*/ - - if (turbulent) { - if (!config[val_iZone]->GetFrozen_Visc()) { - for (iVar = 0; iVar < nVar_AdjTurb; iVar++) - residual_adjturbulent[iVar] = solver_container[val_iZone][FinestMesh][ADJTURB_SOL]->GetRes_RMS(iVar); - } - } - - /*--- Adjoint level set residuals ---*/ - - if (freesurface) { - for (iVar = 0; iVar < nVar_AdjLevelSet; iVar++) - residual_adjlevelset[iVar] = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetRes_RMS(nDim+1); - } - - } - - break; - - case WAVE_EQUATION: - - /*--- Wave coefficients ---*/ - - Total_CWave = solver_container[val_iZone][FinestMesh][WAVE_SOL]->GetTotal_CWave(); - - /*--- Wave Residuals ---*/ - - for (iVar = 0; iVar < nVar_Wave; iVar++) { - residual_wave[iVar] = solver_container[val_iZone][FinestMesh][WAVE_SOL]->GetRes_RMS(iVar); - } - - break; - - case HEAT_EQUATION: - - /*--- Heat coefficients ---*/ - - Total_CHeat = solver_container[val_iZone][FinestMesh][HEAT_SOL]->GetTotal_CHeat(); - - /*--- Wave Residuals ---*/ - - for (iVar = 0; iVar < nVar_Heat; iVar++) { - residual_heat[iVar] = solver_container[val_iZone][FinestMesh][HEAT_SOL]->GetRes_RMS(iVar); - } - - break; - - case LINEAR_ELASTICITY: - - /*--- FEA coefficients ---*/ - - Total_CFEA = solver_container[val_iZone][FinestMesh][FEA_SOL]->GetTotal_CFEA(); - - /*--- Plasma Residuals ---*/ - - for (iVar = 0; iVar < nVar_FEA; iVar++) { - residual_fea[iVar] = solver_container[val_iZone][FinestMesh][FEA_SOL]->GetRes_RMS(iVar); - } - - break; - - } - - /*--- Header frequency ---*/ - - bool Unsteady = ((config[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - bool In_NoDualTime = (!DualTime_Iteration && (iExtIter % config[val_iZone]->GetWrt_Con_Freq() == 0)); - bool In_DualTime_0 = (DualTime_Iteration && (iIntIter % config[val_iZone]->GetWrt_Con_Freq_DualTime() == 0)); - bool In_DualTime_1 = (!DualTime_Iteration && Unsteady); - bool In_DualTime_2 = (Unsteady && DualTime_Iteration && (iExtIter % config[val_iZone]->GetWrt_Con_Freq() == 0)); - bool In_DualTime_3 = (Unsteady && !DualTime_Iteration && (iExtIter % config[val_iZone]->GetWrt_Con_Freq() == 0)); - - bool write_heads; - if (Unsteady) write_heads = (iIntIter == 0); - else write_heads = (((iExtIter % (config[val_iZone]->GetWrt_Con_Freq()*40)) == 0)); - bool write_turbo = (((iExtIter % (config[val_iZone]->GetWrt_Con_Freq()*200)) == 0)); - if ((In_NoDualTime || In_DualTime_0 || In_DualTime_1) && (In_NoDualTime || In_DualTime_2 || In_DualTime_3)) { - - /*--- Prepare the history file output, note that the dual - time output don't write to the history file ---*/ - if (!DualTime_Iteration) { - - /*--- Write the begining of the history file ---*/ - SPRINTF (begin, "%12d", SU2_TYPE::Int(iExtIter)); - - /*--- Write the end of the history file ---*/ - SPRINTF (end, ", %12.10f, %12.10f, %12.10f\n", su2double(LinSolvIter), config[val_iZone]->GetCFL(MESH_0), timeused/60.0); - - /*--- Write the solution and residual of the history file ---*/ - switch (config[val_iZone]->GetKind_Solver()) { - - case EULER : case NAVIER_STOKES: case RANS: - case ADJ_EULER: case ADJ_NAVIER_STOKES: case ADJ_RANS: case DISC_ADJ_EULER: - case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: - - /*--- Direct coefficients ---*/ - SPRINTF (direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", - Total_CLift, Total_CDrag, Total_CSideForce, Total_CMx, Total_CMy, Total_CMz, Total_CFx, Total_CFy, - Total_CFz, Total_CEff); - if (direct_diff != NO_DERIVATIVE){ - SPRINTF (d_direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", - D_Total_CLift, D_Total_CDrag, D_Total_CSideForce, D_Total_CMx, D_Total_CMy, D_Total_CMz, D_Total_CFx, D_Total_CFy, - D_Total_CFz, D_Total_CEff); - } - if (isothermal) - SPRINTF (direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", Total_CLift, Total_CDrag, Total_CSideForce, Total_CMx, Total_CMy, - Total_CMz, Total_CFx, Total_CFy, Total_CFz, Total_CEff, Total_Heat, Total_MaxHeat); - if (equiv_area) - SPRINTF (direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", Total_CLift, Total_CDrag, Total_CSideForce, Total_CMx, Total_CMy, Total_CMz, Total_CFx, Total_CFy, Total_CFz, Total_CEff, Total_CEquivArea, Total_CNearFieldOF); - if (inv_design) { - SPRINTF (direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", Total_CLift, Total_CDrag, Total_CSideForce, Total_CMx, Total_CMy, Total_CMz, Total_CFx, Total_CFy, Total_CFz, Total_CEff, Total_CpDiff); - Total_CpDiff = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CpDiff(); - if (isothermal) { - SPRINTF (direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", Total_CLift, Total_CDrag, Total_CSideForce, Total_CMx, Total_CMy, Total_CMz, Total_CFx, Total_CFy, Total_CFz, Total_CEff, Total_Heat, Total_MaxHeat, Total_CpDiff, Total_HeatFluxDiff); - } - } - if (rotating_frame) - SPRINTF (direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", Total_CLift, Total_CDrag, Total_CSideForce, Total_CMx, - Total_CMy, Total_CMz, Total_CFx, Total_CFy, Total_CFz, Total_CEff, Total_CMerit, Total_CT, Total_CQ); - - if (freesurface) { - SPRINTF (direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", Total_CLift, Total_CDrag, Total_CSideForce, Total_CMx, Total_CMy, Total_CMz, Total_CFx, Total_CFy, - Total_CFz, Total_CEff, Total_CFreeSurface); - } -// if (fluid_structure) -// SPRINTF (direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", Total_CLift, Total_CDrag, Total_CSideForce, Total_CMx, Total_CMy, Total_CMz, -// Total_CFx, Total_CFy, Total_CFz, Total_CEff, Total_CFEA); - - if (aeroelastic) { - for (iMarker_Monitoring = 0; iMarker_Monitoring < config[ZONE_0]->GetnMarker_Monitoring(); iMarker_Monitoring++) { - //Append one by one the surface coeff to aeroelastic coeff. (Think better way do this, maybe use string) - if (iMarker_Monitoring == 0) { - SPRINTF(aeroelastic_coeff, ", %12.10f", aeroelastic_plunge[iMarker_Monitoring]); - } - else { - SPRINTF(surface_coeff, ", %12.10f", aeroelastic_plunge[iMarker_Monitoring]); - strcat(aeroelastic_coeff, surface_coeff); - } - SPRINTF(surface_coeff, ", %12.10f", aeroelastic_pitch[iMarker_Monitoring]); - strcat(aeroelastic_coeff, surface_coeff); - } - } - - if (output_per_surface) { - for (iMarker_Monitoring = 0; iMarker_Monitoring < config[ZONE_0]->GetnMarker_Monitoring(); iMarker_Monitoring++) { - //Append one by one the surface coeff to monitoring coeff. (Think better way do this, maybe use string) - if (iMarker_Monitoring == 0) { - SPRINTF(monitoring_coeff, ", %12.10f", Surface_CLift[iMarker_Monitoring]); - } - else { - SPRINTF(surface_coeff, ", %12.10f", Surface_CLift[iMarker_Monitoring]); - strcat(monitoring_coeff, surface_coeff); - } - SPRINTF(surface_coeff, ", %12.10f", Surface_CDrag[iMarker_Monitoring]); - strcat(monitoring_coeff, surface_coeff); - SPRINTF(surface_coeff, ", %12.10f", Surface_CSideForce[iMarker_Monitoring]); - strcat(monitoring_coeff, surface_coeff); - SPRINTF(surface_coeff, ", %12.10f", Surface_CEff[iMarker_Monitoring]); - strcat(monitoring_coeff, surface_coeff); - SPRINTF(surface_coeff, ", %12.10f", Surface_CFx[iMarker_Monitoring]); - strcat(monitoring_coeff, surface_coeff); - SPRINTF(surface_coeff, ", %12.10f", Surface_CFy[iMarker_Monitoring]); - strcat(monitoring_coeff, surface_coeff); - SPRINTF(surface_coeff, ", %12.10f", Surface_CFz[iMarker_Monitoring]); - strcat(monitoring_coeff, surface_coeff); - SPRINTF(surface_coeff, ", %12.10f", Surface_CMx[iMarker_Monitoring]); - strcat(monitoring_coeff, surface_coeff); - SPRINTF(surface_coeff, ", %12.10f", Surface_CMy[iMarker_Monitoring]); - strcat(monitoring_coeff, surface_coeff); - SPRINTF(surface_coeff, ", %12.10f", Surface_CMz[iMarker_Monitoring]); - strcat(monitoring_coeff, surface_coeff); - } - } - - - /*--- Flow residual ---*/ - if (nDim == 2) { - if (compressible) SPRINTF (flow_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", log10 (residual_flow[0]), log10 (residual_flow[1]), log10 (residual_flow[2]), log10 (residual_flow[3]), dummy); - if (incompressible || freesurface) SPRINTF (flow_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", log10 (residual_flow[0]), log10 (residual_flow[1]), log10 (residual_flow[2]), dummy, dummy); - } - else { - if (compressible) SPRINTF (flow_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", log10 (residual_flow[0]), log10 (residual_flow[1]), log10 (residual_flow[2]), log10 (residual_flow[3]), log10 (residual_flow[4]) ); - if (incompressible || freesurface) SPRINTF (flow_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", log10 (residual_flow[0]), log10 (residual_flow[1]), log10 (residual_flow[2]), log10 (residual_flow[3]), dummy); - } - - /*--- Turbulent residual ---*/ - if (turbulent) { - switch(nVar_Turb) { - case 1: SPRINTF (turb_resid, ", %12.10f", log10 (residual_turbulent[0])); break; - case 2: SPRINTF (turb_resid, ", %12.10f, %12.10f", log10(residual_turbulent[0]), log10(residual_turbulent[1])); break; - } - } - /*---- Averaged stagnation pressure at an exit ----*/ - if (output_1d) { - SPRINTF( oneD_outputs, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", OneD_AvgStagPress, OneD_AvgMach, OneD_AvgTemp, OneD_MassFlowRate, OneD_FluxAvgPress, OneD_FluxAvgDensity, OneD_FluxAvgVelocity, OneD_FluxAvgEntalpy); - } - if (output_massflow && !output_1d) { - SPRINTF(massflow_outputs,", %12.10f", Total_Mdot); - } - - - /*--- Transition residual ---*/ - if (transition) { - SPRINTF (trans_resid, ", %12.10f, %12.10f", log10(residual_transition[0]), log10(residual_transition[1])); - } - - /*--- Free surface residual ---*/ - if (freesurface) { - SPRINTF (levelset_resid, ", %12.10f", log10 (residual_levelset[0])); - } - - /*--- Fluid structure residual ---*/ -// if (fluid_structure) { -// if (nDim == 2) SPRINTF (levelset_resid, ", %12.10f, %12.10f, 0.0", log10 (residual_fea[0]), log10 (residual_fea[1])); -// else SPRINTF (levelset_resid, ", %12.10f, %12.10f, %12.10f", log10 (residual_fea[0]), log10 (residual_fea[1]), log10 (residual_fea[2])); -// } - - if (adjoint) { - - /*--- Adjoint coefficients ---*/ - SPRINTF (adjoint_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, 0.0, %12.10f", Total_Sens_Geo, Total_Sens_Mach, Total_Sens_AoA, Total_Sens_Press, Total_Sens_Temp, Total_Sens_BPress); - - /*--- Adjoint flow residuals ---*/ - if (nDim == 2) { - if (compressible) SPRINTF (adj_flow_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, 0.0", log10 (residual_adjflow[0]), log10 (residual_adjflow[1]), log10 (residual_adjflow[2]), log10 (residual_adjflow[3]) ); - if (incompressible || freesurface) SPRINTF (adj_flow_resid, ", %12.10f, %12.10f, %12.10f, 0.0, 0.0", log10 (residual_adjflow[0]), log10 (residual_adjflow[1]), log10 (residual_adjflow[2]) ); - } - else { - if (compressible) SPRINTF (adj_flow_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", log10 (residual_adjflow[0]), log10 (residual_adjflow[1]), log10 (residual_adjflow[2]), log10 (residual_adjflow[3]), log10 (residual_adjflow[4]) ); - if (incompressible || freesurface) SPRINTF (adj_flow_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, 0.0", log10 (residual_adjflow[0]), log10 (residual_adjflow[1]), log10 (residual_adjflow[2]), log10 (residual_adjflow[3]) ); - } - - /*--- Adjoint turbulent residuals ---*/ - if (turbulent) - if (!config[val_iZone]->GetFrozen_Visc()) - SPRINTF (adj_turb_resid, ", %12.10f", log10 (residual_adjturbulent[0])); - - /*--- Adjoint free surface residuals ---*/ - if (freesurface) SPRINTF (adj_levelset_resid, ", %12.10f", log10 (residual_adjlevelset[0])); - } - - break; - - case WAVE_EQUATION: - - SPRINTF (direct_coeff, ", %12.10f", Total_CWave); - SPRINTF (wave_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", log10 (residual_wave[0]), log10 (residual_wave[1]), dummy, dummy, dummy ); - - break; - - case HEAT_EQUATION: - - SPRINTF (direct_coeff, ", %12.10f", Total_CHeat); - SPRINTF (heat_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", log10 (residual_heat[0]), dummy, dummy, dummy, dummy ); - - break; - - case LINEAR_ELASTICITY: - - SPRINTF (direct_coeff, ", %12.10f", Total_CFEA); - SPRINTF (fea_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", log10 (residual_fea[0]), dummy, dummy, dummy, dummy ); - - break; - - } - } - - /*--- Write the screen header---*/ - if ((write_heads) && !(!DualTime_Iteration && Unsteady)) { - - if (!Unsteady) { - switch (config[val_iZone]->GetKind_Solver()) { - case EULER : case NAVIER_STOKES: case RANS: - case ADJ_EULER : case ADJ_NAVIER_STOKES: case ADJ_RANS: - - cout << endl << "---------------------- Local Time Stepping Summary ----------------------" << endl; - - for (unsigned short iMesh = FinestMesh; iMesh <= config[val_iZone]->GetnMGLevels(); iMesh++) - cout << "MG level: "<< iMesh << " -> Min. DT: " << solver_container[val_iZone][iMesh][FLOW_SOL]->GetMin_Delta_Time()<< - ". Max. DT: " << solver_container[val_iZone][iMesh][FLOW_SOL]->GetMax_Delta_Time() << - ". CFL: " << config[val_iZone]->GetCFL(iMesh) << "." << endl; - - cout << "-------------------------------------------------------------------------" << endl; - - if (direct_diff != NO_DERIVATIVE){ - cout << endl << "---------------------- Direct Differentiation Summary -------------------" << endl; - cout << "Coefficients are differentiated with respect to "; - switch (direct_diff) { - case D_MACH: - cout << "Mach number." << endl; - break; - case D_AOA: - cout << "AoA." << endl; - break; - case D_SIDESLIP: - cout << "AoS." << endl; - break; - case D_REYNOLDS: - cout << "Reynolds number." << endl; - break; - case D_TURB2LAM: - cout << "Turb/Lam ratio." << endl; - break; - case D_PRESSURE: - cout << "Freestream Pressure." << endl; - break; - case D_TEMPERATURE: - cout << "Freestream Temperature." << endl; - break; - case D_DENSITY: - cout << "Freestream Density." << endl; - break; - case D_VISCOSITY: - cout << "Freestream Viscosity." << endl; - break; - case D_DESIGN: - cout << "Design Variables." << endl; - break; - default: - break; - } - - cout << " D_CLift(Total)" << " D_CDrag(Total)" << " D_CMz(Total)" <<" D_CEff(Total)" << endl; - cout.width(18); cout << D_Total_CLift; - cout.width(18); cout << D_Total_CDrag; - cout.width(18); cout << D_Total_CMz; - cout.width(18); cout << D_Total_CEff; - cout << endl << "-------------------------------------------------------------------------" << endl; - cout << endl; - } - if (turbo && write_turbo){ - cout << endl << "---------------------- Turbo Performance Summary -------------------" << endl; - for (iMarker_Monitoring = 0; iMarker_Monitoring < config[ZONE_0]->Get_nMarkerTurboPerf(); iMarker_Monitoring++){ - inMarker_Tag = config[ZONE_0]->GetMarker_TurboPerf_BoundIn(iMarker_Monitoring); - outMarker_Tag = config[ZONE_0]->GetMarker_TurboPerf_BoundOut(iMarker_Monitoring); - switch (config[ZONE_0]->GetKind_TurboPerf(iMarker_Monitoring)) { - case BLADE: - cout << "Blade performance between boundaries " << inMarker_Tag << " and "<< outMarker_Tag << " : "<GetWrt_Sol_Freq() << " iterations): "; - cout.precision(4); - cout.setf(ios::scientific, ios::floatfield); - cout << Total_Sens_Geo; - cout << endl << "-------------------------------------------------------------------------" << endl; - break; - - } - } - else { - if (flow) { - cout << endl << "Min DT: " << solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetMin_Delta_Time()<< - ".Max DT: " << solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetMax_Delta_Time() << - ".Dual Time step: " << config[val_iZone]->GetDelta_UnstTimeND() << "."; - } - else { - cout << endl << "Dual Time step: " << config[val_iZone]->GetDelta_UnstTimeND() << "."; - } - } - - switch (config[val_iZone]->GetKind_Solver()) { - case EULER : case NAVIER_STOKES: - - /*--- Visualize the maximum residual ---*/ - iPointMaxResid = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetPoint_Max(0); - Coord = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetPoint_Max_Coord(0); - - cout << endl << "----------------------- Residual Evolution Summary ----------------------" << endl; - - cout << "log10[Maximum residual]: " << log10(solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetRes_Max(0)) << "." << endl; - - if (config[val_iZone]->GetSystemMeasurements() == SI) { - cout <<"Maximum residual point " << iPointMaxResid << ", located at (" << Coord[0] << ", " << Coord[1]; - if (nDim == 3) cout << ", " << Coord[2]; - cout << ")." << endl; - } - else { - cout <<"Maximum residual point " << iPointMaxResid << ", located at (" << Coord[0]*12.0 << ", " << Coord[1]*12.0; - if (nDim == 3) cout << ", " << Coord[2]*12.0; - cout << ")." << endl; - } - - /*--- Print out the number of non-physical points and reconstructions ---*/ - - if (config[val_iZone]->GetNonphysical_Points() > 0) - cout << "There are " << config[val_iZone]->GetNonphysical_Points() << " non-physical points in the solution." << endl; - if (config[val_iZone]->GetNonphysical_Reconstr() > 0) - cout << "There are " << config[val_iZone]->GetNonphysical_Reconstr() << " non-physical states in the upwind reconstruction." << endl; - - cout << "-------------------------------------------------------------------------" << endl; - - if (!Unsteady) cout << endl << " Iter" << " Time(s)"; - else cout << endl << " IntIter" << " ExtIter"; - -// if (!fluid_structure) { - if (incompressible) cout << " Res[Press]" << " Res[Velx]" << " CLift(Total)" << " CDrag(Total)" << endl; - else if (freesurface) cout << " Res[Press]" << " Res[Dist]" << " CLift(Total)" << " CLevelSet" << endl; - else if (rotating_frame && nDim == 3) cout << " Res[Rho]" << " Res[RhoE]" << " CThrust(Total)" << " CTorque(Total)" << endl; - else if (aeroelastic) cout << " Res[Rho]" << " Res[RhoE]" << " CLift(Total)" << " CDrag(Total)" << " plunge" << " pitch" << endl; - else if (equiv_area) cout << " Res[Rho]" << " CLift(Total)" << " CDrag(Total)" << " CPress(N-F)" << endl; - else if (turbo) - switch (config[ZONE_0]->GetKind_TurboPerf(0)) { - case BLADE: - cout << " Res[Rho]" << " Res[RhoE]" << " KineticLoss(%)" << " D_MassFlow(%)" << endl; - break; - case STAGE: case TURBINE: - cout << " Res[Rho]" << " Res[RhoE]" << " TSEfficiency(%)" << " Outlet Pressure" << endl; - break; - default: - break; - } - else cout << " Res[Rho]" << " Res[RhoE]" << " CLift(Total)" << " CDrag(Total)" << endl; -// } -// else if (fluid_structure) cout << " Res[Rho]" << " Res[Displx]" << " CLift(Total)" << " CDrag(Total)" << endl; - - break; - - case RANS : - - /*--- Visualize the maximum residual ---*/ - iPointMaxResid = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetPoint_Max(0); - Coord = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetPoint_Max_Coord(0); - - cout << endl << "----------------------- Residual Evolution Summary ----------------------" << endl; - - cout << "log10[Maximum residual]: " << log10(solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetRes_Max(0)) << "." << endl; - if (config[val_iZone]->GetSystemMeasurements() == SI) { - cout <<"Maximum residual point " << iPointMaxResid << ", located at (" << Coord[0] << ", " << Coord[1]; - if (nDim == 3) cout << ", " << Coord[2]; - cout << ")." << endl; - } - else { - cout <<"Maximum residual point " << iPointMaxResid << ", located at (" << Coord[0]*12.0 << ", " << Coord[1]*12.0; - if (nDim == 3) cout << ", " << Coord[2]*12.0; - cout << ")." << endl; - } - cout <<"Maximum Omega " << solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOmega_Max() << ", maximum Strain Rate " << solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetStrainMag_Max() << "." << endl; - - /*--- Print out the number of non-physical points and reconstructions ---*/ - if (config[val_iZone]->GetNonphysical_Points() > 0) - cout << "There are " << config[val_iZone]->GetNonphysical_Points() << " non-physical points in the solution." << endl; - if (config[val_iZone]->GetNonphysical_Reconstr() > 0) - cout << "There are " << config[val_iZone]->GetNonphysical_Reconstr() << " non-physical states in the upwind reconstruction." << endl; - - cout << "-------------------------------------------------------------------------" << endl; - - if (!Unsteady) cout << endl << " Iter" << " Time(s)"; - else cout << endl << " IntIter" << " ExtIter"; - if (incompressible || freesurface) cout << " Res[Press]"; - else cout << " Res[Rho]";//, cout << " Res[RhoE]"; - - switch (config[val_iZone]->GetKind_Turb_Model()) { - case SA: cout << " Res[nu]"; break; - case SA_NEG: cout << " Res[nu]"; break; - case SST: cout << " Res[kine]" << " Res[omega]"; break; - } - - if (transition) { cout << " Res[Int]" << " Res[Re]"; } - else if (rotating_frame && nDim == 3 ) cout << " CThrust(Total)" << " CTorque(Total)" << endl; - else if (aeroelastic) cout << " CLift(Total)" << " CDrag(Total)" << " plunge" << " pitch" << endl; - else if (equiv_area) cout << " CLift(Total)" << " CDrag(Total)" << " CPress(N-F)" << endl; - else if (turbo) - switch (config[ZONE_0]->GetKind_TurboPerf(0)) { - case BLADE: - cout << " KineticLoss(%)" << " D_MassFlow(%)" << endl; - break; - case STAGE: case TURBINE: - cout << " TSEfficiency(%)" << " Outlet Pressure" << endl; - break; - default: - break; - } - - else cout << " CLift(Total)" << " CDrag(Total)" << endl; - - break; - - case WAVE_EQUATION : - if (!Unsteady) cout << endl << " Iter" << " Time(s)"; - else cout << endl << " IntIter" << " ExtIter"; - - cout << " Res[Wave]" << " CWave(Total)"<< endl; - break; - - case HEAT_EQUATION : - if (!Unsteady) cout << endl << " Iter" << " Time(s)"; - else cout << endl << " IntIter" << " ExtIter"; - - cout << " Res[Heat]" << " CHeat(Total)"<< endl; - break; - - case LINEAR_ELASTICITY : - if (!Unsteady) cout << endl << " Iter" << " Time(s)"; - else cout << endl << " IntIter" << " ExtIter"; - - if (nDim == 2) cout << " Res[Displx]" << " Res[Disply]" << " CFEA(Total)"<< endl; - if (nDim == 3) cout << " Res[Displx]" << " Res[Disply]" << " Res[Displz]" << " CFEA(Total)"<< endl; - break; - - case ADJ_EULER : case ADJ_NAVIER_STOKES : - case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: - - /*--- Visualize the maximum residual ---*/ - iPointMaxResid = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetPoint_Max(0); - Coord = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetPoint_Max_Coord(0); - cout << endl << "log10[Maximum residual]: " << log10(solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetRes_Max(0)) << "." << endl; - if (config[val_iZone]->GetSystemMeasurements() == SI) { - cout <<"Maximum residual point " << iPointMaxResid << ", located at (" << Coord[0] << ", " << Coord[1]; - if (nDim == 3) cout << ", " << Coord[2]; - cout << ")." << endl; - } - else { - cout <<"Maximum residual point " << iPointMaxResid << ", located at (" << Coord[0]*12.0 << ", " << Coord[1]*12.0; - if (nDim == 3) cout << ", " << Coord[2]*12.0; - cout << ")." << endl; - } - - /*--- Print out the number of non-physical points and reconstructions ---*/ - if (config[val_iZone]->GetNonphysical_Points() > 0) - cout << "There are " << config[val_iZone]->GetNonphysical_Points() << " non-physical points in the solution." << endl; - - if (!Unsteady) cout << endl << " Iter" << " Time(s)"; - else cout << endl << " IntIter" << " ExtIter"; - - if (incompressible || freesurface) cout << " Res[Psi_Press]" << " Res[Psi_Velx]"; - else cout << " Res[Psi_Rho]" << " Res[Psi_E]"; - if (disc_adj){ - cout << " Sens_Press" << " Sens_Mach" << endl; - } else { - if (output_1d) - cout << " Sens_Geo" << " Sens_BPress" << endl; - else - cout << " Sens_Geo" << " Sens_Mach" << endl; - } - if (freesurface) { - cout << " Res[Psi_Press]" << " Res[Psi_Dist]" << " Sens_Geo"; - if (output_1d) - cout << " Sens_BPress" << endl; - else - cout << " Sens_Mach" << endl; - } - break; - - case ADJ_RANS : case DISC_ADJ_RANS: - - /*--- Visualize the maximum residual ---*/ - iPointMaxResid = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetPoint_Max(0); - Coord = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetPoint_Max_Coord(0); - cout << endl << "log10[Maximum residual]: " << log10(solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetRes_Max(0)) << "." << endl; - if (config[val_iZone]->GetSystemMeasurements() == SI) { - cout <<"Maximum residual point " << iPointMaxResid << ", located at (" << Coord[0] << ", " << Coord[1]; - if (nDim == 3) cout << ", " << Coord[2]; - cout << ")." << endl; - } - else { - cout <<"Maximum residual point " << iPointMaxResid << ", located at (" << Coord[0]*12.0 << ", " << Coord[1]*12.0; - if (nDim == 3) cout << ", " << Coord[2]*12.0; - cout << ")." << endl; - } - - /*--- Print out the number of non-physical points and reconstructions ---*/ - if (config[val_iZone]->GetNonphysical_Points() > 0) - cout << "There are " << config[val_iZone]->GetNonphysical_Points() << " non-physical points in the solution." << endl; - - if (!Unsteady) cout << endl << " Iter" << " Time(s)"; - else cout << endl << " IntIter" << " ExtIter"; - - if (incompressible || freesurface) cout << " Res[Psi_Press]"; - else cout << " Res[Psi_Rho]"; - - if (!config[val_iZone]->GetFrozen_Visc()) { - cout << " Res[Psi_nu]"; - } - else { - if (incompressible || freesurface) cout << " Res[Psi_Velx]"; - else cout << " Res[Psi_E]"; - } - if (disc_adj){ - cout << " Sens_Press" << " Sens_Mach" << endl; - } else { - if (output_1d) - cout << " Sens_Geo" << " Sens_BPress" << endl; - else - cout << " Sens_Geo" << " Sens_Mach" << endl; - } - if (freesurface) { - cout << " Res[Psi_Press]" << " Res[Psi_Dist]" << " Sens_Geo"; - if (output_1d) - cout << " Sens_BPress" << endl; - else - cout << " Sens_Mach" << endl; - } - break; - - } - - } - - /*--- Write the solution on the screen and history file ---*/ - cout.precision(6); - cout.setf(ios::fixed, ios::floatfield); - - if (!Unsteady) { - cout.width(5); cout << iExtIter; - cout.width(11); cout << timeiter; - - } else { - cout.width(8); cout << iIntIter; - cout.width(8); cout << iExtIter; - } - - switch (config[val_iZone]->GetKind_Solver()) { - case EULER : case NAVIER_STOKES: - - if (!DualTime_Iteration) { - if (compressible) ConvHist_file[0] << begin << direct_coeff << flow_resid; - if (incompressible) ConvHist_file[0] << begin << direct_coeff << flow_resid; - if (freesurface) ConvHist_file[0] << begin << direct_coeff << flow_resid << levelset_resid << end; -// if (fluid_structure) ConvHist_file[0] << fea_resid; - if (aeroelastic) ConvHist_file[0] << aeroelastic_coeff; - if (output_per_surface) ConvHist_file[0] << monitoring_coeff; - if (output_1d) ConvHist_file[0] << oneD_outputs; - if (output_massflow and !output_1d) ConvHist_file[0] << massflow_outputs; - if (direct_diff != NO_DERIVATIVE) ConvHist_file[0] << d_direct_coeff; - ConvHist_file[0] << end; - ConvHist_file[0].flush(); - } - - cout.precision(6); - cout.setf(ios::fixed, ios::floatfield); - cout.width(13); cout << log10(residual_flow[0]); -// if (!fluid_structure && !equiv_area) { - if (!equiv_area) { - if (compressible) { - if (nDim == 2 ) { cout.width(14); cout << log10(residual_flow[3]); } - else { cout.width(14); cout << log10(residual_flow[4]); } - } - if (incompressible) { cout.width(14); cout << log10(residual_flow[1]); } - if (freesurface) { cout.width(14); cout << log10(residual_levelset[0]); } - } -// else if (fluid_structure) { cout.width(14); cout << log10(residual_fea[0]); } - - if (rotating_frame && nDim == 3 ) { - cout.setf(ios::scientific, ios::floatfield); - cout.width(15); cout << Total_CT; - cout.width(15); cout << Total_CQ; - cout.unsetf(ios_base::floatfield); - } - else if (equiv_area) { cout.width(15); cout << min(10000.0, max(-10000.0, Total_CLift)); cout.width(15); cout << min(10000.0, max(-10000.0, Total_CDrag)); cout.width(15); - cout.precision(4); - cout.setf(ios::scientific, ios::floatfield); - cout << Total_CNearFieldOF; } - else if (freesurface) { cout.width(15); cout << Total_CLift; cout.width(15); cout << Total_CFreeSurface; } - else if (turbo) { - cout.setf(ios::scientific, ios::floatfield); - switch (config[ZONE_0]->GetKind_TurboPerf(0)) { - case BLADE: - cout.width(15); cout << KineticEnergyLoss[0]*100.0; - cout.width(15); cout << abs((MassFlowIn[0] + MassFlowOut[0])/MassFlowIn[0])*100.0; - break; - case STAGE: case TURBINE: - cout.width(15); cout << TotalStaticEfficiency[0]*100.0; - cout.width(15); cout << PressureOut[0]; - break; - default: - break; - } - cout.unsetf(ios_base::floatfield); - } - else { cout.width(15); cout << min(10000.0, max(-10000.0, Total_CLift)); cout.width(15); cout << min(10000.0, max(-10000.0, Total_CDrag)); } - if (aeroelastic) { - cout.setf(ios::scientific, ios::floatfield); - cout.width(15); cout << aeroelastic_plunge[0]; //Only output the first marker being monitored to the console. - cout.width(15); cout << aeroelastic_pitch[0]; - cout.unsetf(ios_base::floatfield); - } - cout << endl; - - break; - - case RANS : - - if (!DualTime_Iteration) { - ConvHist_file[0] << begin << direct_coeff << flow_resid << turb_resid; - if (aeroelastic) ConvHist_file[0] << aeroelastic_coeff; - if (output_per_surface) ConvHist_file[0] << monitoring_coeff; - if (output_1d) ConvHist_file[0] << oneD_outputs; - if (output_massflow and !output_1d) ConvHist_file[0] << massflow_outputs; - if (direct_diff != NO_DERIVATIVE) ConvHist_file[0] << d_direct_coeff; - ConvHist_file[0] << end; - ConvHist_file[0].flush(); - } - - cout.precision(6); - cout.setf(ios::fixed, ios::floatfield); - - if (incompressible || freesurface) cout.width(13); - else cout.width(14); - cout << log10(residual_flow[0]); -// else cout.width(14), -// cout << log10(residual_flow[0]), -// cout.width(14); -// if ( nDim==2 ) cout << log10(residual_flow[3]); -// if ( nDim==3 ) cout << log10(residual_flow[4]); - - switch(nVar_Turb) { - case 1: cout.width(14); cout << log10(residual_turbulent[0]); break; - case 2: cout.width(14); cout << log10(residual_turbulent[0]); - cout.width(15); cout << log10(residual_turbulent[1]); break; - } - - if (transition) { cout.width(14); cout << log10(residual_transition[0]); cout.width(14); cout << log10(residual_transition[1]); } - - if (rotating_frame && nDim == 3 ) { - cout.setf(ios::scientific, ios::floatfield); - cout.width(15); cout << Total_CT; cout.width(15); - cout << Total_CQ; - cout.unsetf(ios_base::floatfield); - } - else if (equiv_area) { cout.width(15); cout << min(10000.0, max(-10000.0, Total_CLift)); cout.width(15); cout << min(10000.0, max(-10000.0, Total_CDrag)); cout.width(15); - cout.precision(4); - cout.setf(ios::scientific, ios::floatfield); - cout << Total_CNearFieldOF; } - else if (turbo) { - cout.setf(ios::scientific, ios::floatfield); - switch (config[ZONE_0]->GetKind_TurboPerf(0)) { - case BLADE: - cout.width(15); cout << KineticEnergyLoss[0]*100.0; - cout.width(15); cout << abs((MassFlowIn[0] + MassFlowOut[0])/MassFlowIn[0])*100.0; - break; - case STAGE: case TURBINE: - cout.width(15); cout << TotalStaticEfficiency[0]*100.0; - cout.width(15); cout << PressureOut[0]; - break; - default: - break; - } - cout.unsetf(ios_base::floatfield); - } - else { cout.width(15); cout << min(10000.0, max(-10000.0, Total_CLift)); cout.width(15); cout << min(10000.0, max(-10000.0, Total_CDrag)); } - - if (aeroelastic) { - cout.setf(ios::scientific, ios::floatfield); - cout.width(15); cout << aeroelastic_plunge[0]; //Only output the first marker being monitored to the console. - cout.width(15); cout << aeroelastic_pitch[0]; - cout.unsetf(ios_base::floatfield); - } - cout << endl; - - if (freesurface) { - if (!DualTime_Iteration) { - ConvHist_file[0] << begin << direct_coeff << flow_resid << levelset_resid << end; - ConvHist_file[0].flush(); - } - - cout.precision(6); - cout.setf(ios::fixed, ios::floatfield); - cout.width(13); cout << log10(residual_flow[0]); - cout.width(14); cout << log10(residual_levelset[0]); - cout.width(15); cout << Total_CLift; - cout.width(14); cout << Total_CFreeSurface; - - cout << endl; - } - - break; - - case WAVE_EQUATION: - - if (!DualTime_Iteration) { - ConvHist_file[0] << begin << wave_coeff << wave_resid << end; - ConvHist_file[0].flush(); - } - - cout.precision(6); - cout.setf(ios::fixed, ios::floatfield); - cout.width(14); cout << log10(residual_wave[0]); - cout.width(14); cout << Total_CWave; - cout << endl; - break; - - case HEAT_EQUATION: - - if (!DualTime_Iteration) { - ConvHist_file[0] << begin << heat_coeff << heat_resid << end; - ConvHist_file[0].flush(); - } - - cout.precision(6); - cout.setf(ios::fixed, ios::floatfield); - cout.width(14); cout << log10(residual_heat[0]); - cout.width(14); cout << Total_CHeat; - cout << endl; - break; - - case LINEAR_ELASTICITY: - - if (!DualTime_Iteration) { - ConvHist_file[0] << begin << fea_coeff << fea_resid << end; - ConvHist_file[0].flush(); - } - - cout.precision(6); - cout.setf(ios::fixed, ios::floatfield); - cout.width(15); cout << log10(residual_fea[0]); - cout.width(15); cout << log10(residual_fea[1]); - if (nDim == 3) { cout.width(15); cout << log10(residual_fea[2]); } - cout.precision(4); - cout.setf(ios::scientific, ios::floatfield); - cout.width(14); cout << Total_CFEA; - cout << endl; - break; - - case ADJ_EULER : case ADJ_NAVIER_STOKES : - case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: - - if (!DualTime_Iteration) { - ConvHist_file[0] << begin << adjoint_coeff << adj_flow_resid << end; - ConvHist_file[0].flush(); - } - - cout.precision(6); - cout.setf(ios::fixed, ios::floatfield); - if (compressible) { - cout.width(15); cout << log10(residual_adjflow[0]); - cout.width(15); cout << log10(residual_adjflow[nDim+1]); - } - if (incompressible || freesurface) { - cout.width(17); cout << log10(residual_adjflow[0]); - cout.width(16); cout << log10(residual_adjflow[1]); - } - - if (disc_adj){ - cout.precision(4); - cout.setf(ios::scientific, ios::floatfield); - cout.width(14); cout << Total_Sens_Press; - cout.width(14); cout << Total_Sens_Mach; - }else{ - cout.precision(4); - cout.setf(ios::scientific, ios::floatfield); - cout.width(14); cout << Total_Sens_Geo; - if (output_1d){ - cout.width(14); cout << Total_Sens_BPress; - } - else{ - cout.width(14); cout << Total_Sens_Mach; - } - } - cout << endl; - cout.unsetf(ios_base::floatfield); - - if (freesurface) { - if (!DualTime_Iteration) { - ConvHist_file[0] << begin << adjoint_coeff << adj_flow_resid << adj_levelset_resid << end; - ConvHist_file[0].flush(); - } - - cout.precision(6); - cout.setf(ios::fixed, ios::floatfield); - cout.width(17); cout << log10(residual_adjflow[0]); - cout.width(16); cout << log10(residual_adjlevelset[0]); - cout.precision(3); - cout.setf(ios::scientific, ios::floatfield); - cout.width(12); cout << Total_Sens_Geo; - if (output_1d){ - cout.width(12); cout << Total_Sens_BPress; - } - else{ - cout.width(12); cout << Total_Sens_Mach; - } - cout.unsetf(ios_base::floatfield); - cout << endl; - } - - break; - - case ADJ_RANS : case DISC_ADJ_RANS: - - if (!DualTime_Iteration) { - ConvHist_file[0] << begin << adjoint_coeff << adj_flow_resid; - if (!config[val_iZone]->GetFrozen_Visc()) - ConvHist_file[0] << adj_turb_resid; - ConvHist_file[0] << end; - ConvHist_file[0].flush(); - } - - cout.precision(6); - cout.setf(ios::fixed, ios::floatfield); - cout.width(17); cout << log10(residual_adjflow[0]); - if (!config[val_iZone]->GetFrozen_Visc()) { - cout.width(17); cout << log10(residual_adjturbulent[0]); - } - else { - if (compressible) { - if (geometry[val_iZone][FinestMesh]->GetnDim() == 2 ) { cout.width(15); cout << log10(residual_adjflow[3]); } - else { cout.width(15); cout << log10(residual_adjflow[4]); } - } - if (incompressible || freesurface) { - cout.width(15); cout << log10(residual_adjflow[1]); - } - } - if (disc_adj){ - cout.precision(4); - cout.setf(ios::scientific, ios::floatfield); - cout.width(14); cout << Total_Sens_Press; - cout.width(14); cout << Total_Sens_Mach; - }else{ - cout.precision(4); - cout.setf(ios::scientific, ios::floatfield); - cout.width(14); cout << Total_Sens_Geo; - if (output_1d){ - cout.width(14); cout << Total_Sens_BPress; - } - else{ - cout.width(14); cout << Total_Sens_Mach; - } - } - cout << endl; - cout.unsetf(ios_base::floatfield); - if (freesurface) { - if (!DualTime_Iteration) { - ConvHist_file[0] << begin << adjoint_coeff << adj_flow_resid << adj_levelset_resid; - ConvHist_file[0] << end; - ConvHist_file[0].flush(); - } - - cout.precision(6); - cout.setf(ios::fixed, ios::floatfield); - cout.width(17); cout << log10(residual_adjflow[0]); - cout.width(16); cout << log10(residual_adjlevelset[0]); - - cout.precision(4); - cout.setf(ios::scientific, ios::floatfield); - cout.width(12); cout << Total_Sens_Geo; - if (output_1d){ - cout.width(14); cout << Total_Sens_BPress; - } - else{ - cout.width(14); cout << Total_Sens_Mach; - } - cout << endl; - cout.unsetf(ios_base::floatfield); - } - - break; - - } - cout.unsetf(ios::fixed); - - delete [] residual_flow; - delete [] residual_turbulent; - delete [] residual_transition; - delete [] residual_levelset; - delete [] residual_wave; - delete [] residual_fea; - delete [] residual_heat; - - delete [] residual_adjflow; - delete [] residual_adjturbulent; - delete [] residual_adjlevelset; - - delete [] Surface_CLift; - delete [] Surface_CDrag; - delete [] Surface_CSideForce; - delete [] Surface_CEff; - delete [] Surface_CFx; - delete [] Surface_CFy; - delete [] Surface_CFz; - delete [] Surface_CMx; - delete [] Surface_CMy; - delete [] Surface_CMz; - delete [] aeroelastic_pitch; - delete [] aeroelastic_plunge; - - delete [] TotalStaticEfficiency; - delete [] TotalTotalEfficiency; - delete [] KineticEnergyLoss; - delete [] TotalPressureLoss; - delete [] MassFlowIn; - delete [] MassFlowOut; - delete [] FlowAngleIn; - delete [] FlowAngleOut; - delete [] EulerianWork; - delete [] TotalEnthalpyIn; - delete [] PressureRatio; - delete [] PressureOut; - delete [] EnthalpyOut; - delete [] MachIn; - delete [] MachOut; - delete [] NormalMachIn; - delete [] NormalMachOut; - delete [] VelocityOutIs; - } - } -} - -void COutput::SetCFL_Number(CSolver ****solver_container, CConfig **config, unsigned short val_iZone) { - - su2double CFLFactor = 1.0, power = 1.0, CFL = 0.0, CFLMin = 0.0, CFLMax = 0.0, Div = 1.0, Diff = 0.0, MGFactor[100]; - unsigned short iMesh; - - unsigned short FinestMesh = config[val_iZone]->GetFinestMesh(); - unsigned long ExtIter = config[val_iZone]->GetExtIter(); - - RhoRes_New = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetRes_RMS(0); - switch( config[val_iZone]->GetKind_Solver()){ - case ADJ_EULER : case ADJ_NAVIER_STOKES: case ADJ_RANS: - RhoRes_New = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetRes_RMS(0); - break; - } - - if (RhoRes_New < EPS) RhoRes_New = EPS; - if (RhoRes_Old < EPS) RhoRes_Old = RhoRes_New; - - Div = RhoRes_Old/RhoRes_New; - Diff = RhoRes_New-RhoRes_Old; - - /*--- Compute MG factor ---*/ - - for (iMesh = 0; iMesh <= config[val_iZone]->GetnMGLevels(); iMesh++) { - if (iMesh == MESH_0) MGFactor[iMesh] = 1.0; - else MGFactor[iMesh] = MGFactor[iMesh-1] * config[val_iZone]->GetCFL(iMesh)/config[val_iZone]->GetCFL(iMesh-1); - } - - if (Div < 1.0) power = config[val_iZone]->GetCFL_AdaptParam(0); - else power = config[val_iZone]->GetCFL_AdaptParam(1); - - /*--- Detect a stall in the residual ---*/ - - if ((fabs(Diff) <= RhoRes_New*1E-8) && (ExtIter != 0)) { Div = 0.1; power = config[val_iZone]->GetCFL_AdaptParam(1); } - - CFLMin = config[val_iZone]->GetCFL_AdaptParam(2); - CFLMax = config[val_iZone]->GetCFL_AdaptParam(3); - - CFLFactor = pow(Div, power); - - for (iMesh = 0; iMesh <= config[val_iZone]->GetnMGLevels(); iMesh++) { - CFL = config[val_iZone]->GetCFL(iMesh); - CFL *= CFLFactor; - - if ((iMesh == MESH_0) && (CFL <= CFLMin)) { - for (iMesh = 0; iMesh <= config[val_iZone]->GetnMGLevels(); iMesh++) { - config[val_iZone]->SetCFL(iMesh, 1.001*CFLMin*MGFactor[iMesh]); - } - break; - } - if ((iMesh == MESH_0) && (CFL >= CFLMax)) { - for (iMesh = 0; iMesh <= config[val_iZone]->GetnMGLevels(); iMesh++) - config[val_iZone]->SetCFL(iMesh, 0.999*CFLMax*MGFactor[iMesh]); - break; - } - - config[val_iZone]->SetCFL(iMesh, CFL); - - } - - RhoRes_Old = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetRes_RMS(0); - switch( config[val_iZone]->GetKind_Solver()){ - case ADJ_EULER : case ADJ_NAVIER_STOKES: case ADJ_RANS: - RhoRes_Old = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetRes_RMS(0); - break; - } - -} - - -void COutput::SetForces_Breakdown(CGeometry ***geometry, - CSolver ****solver_container, - CConfig **config, - CIntegration ***integration, - unsigned short val_iZone) { - - char cstr[200]; - unsigned short iMarker_Monitoring; - ofstream Breakdown_file; - - int rank = MASTER_NODE; - bool compressible = (config[val_iZone]->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config[val_iZone]->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config[val_iZone]->GetKind_Regime() == FREESURFACE); - bool unsteady = (config[val_iZone]->GetUnsteady_Simulation() != NO); - bool viscous = config[val_iZone]->GetViscous(); - bool grid_movement = config[val_iZone]->GetGrid_Movement(); - bool gravity = config[val_iZone]->GetGravityForce(); - bool turbulent = config[val_iZone]->GetKind_Solver() == RANS; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - unsigned short FinestMesh = config[val_iZone]->GetFinestMesh(); - unsigned short nDim = geometry[val_iZone][FinestMesh]->GetnDim(); - bool flow = ((config[val_iZone]->GetKind_Solver() == EULER) || (config[val_iZone]->GetKind_Solver() == NAVIER_STOKES) || - (config[val_iZone]->GetKind_Solver() == RANS)); - - /*--- Output the mean flow solution using only the master node ---*/ - - if ((rank == MASTER_NODE) && (flow)) { - - cout << "Writing the forces breakdown file." << endl; - - /*--- Initialize variables to store information from all domains (direct solution) ---*/ - - su2double Total_CLift = 0.0, Total_CDrag = 0.0, Total_CSideForce = 0.0, Total_CMx = 0.0, Total_CMy = 0.0, Total_CMz = 0.0, Total_CEff = 0.0, Total_CFx = 0.0, Total_CFy = 0.0, Total_CFz = 0.0, - Inv_CLift = 0.0, Inv_CDrag = 0.0, Inv_CSideForce = 0.0, Inv_CMx = 0.0, Inv_CMy = 0.0, Inv_CMz = 0.0, Inv_CEff = 0.0, Inv_CFx = 0.0, Inv_CFy = 0.0, Inv_CFz = 0.0, - *Surface_CLift = NULL, *Surface_CDrag = NULL, *Surface_CSideForce = NULL, *Surface_CEff = NULL, *Surface_CFx = NULL, *Surface_CFy = NULL, *Surface_CFz = NULL, *Surface_CMx = NULL, *Surface_CMy = NULL, *Surface_CMz = NULL, - *Surface_CLift_Inv = NULL, *Surface_CDrag_Inv = NULL, *Surface_CSideForce_Inv = NULL, *Surface_CEff_Inv = NULL, *Surface_CFx_Inv = NULL, *Surface_CFy_Inv = NULL, *Surface_CFz_Inv = NULL, *Surface_CMx_Inv = NULL, *Surface_CMy_Inv = NULL, *Surface_CMz_Inv = NULL; - time_t now = time(0); - string dt = ctime(&now); dt[24] = '.'; - - /*--- Allocate memory for the coefficients being monitored ---*/ - - Surface_CLift = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CDrag = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CSideForce = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CEff = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CFx = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CFy = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CFz = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CMx = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CMy = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CMz = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - - Surface_CLift_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CDrag_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CSideForce_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CEff_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CFx_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CFy_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CFz_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CMx_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CMy_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - Surface_CMz_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; - - /*--- Flow solution coefficients ---*/ - - Total_CLift = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CLift(); - Total_CDrag = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CDrag(); - Total_CSideForce = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CSideForce(); - Total_CEff = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CEff(); - Total_CMx = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CMx(); - Total_CMy = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CMy(); - Total_CMz = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CMz(); - Total_CFx = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CFx(); - Total_CFy = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CFy(); - Total_CFz = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CFz(); - - /*--- Flow inviscid solution coefficients ---*/ - - Inv_CLift = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CLift_Inv(); - Inv_CDrag = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CDrag_Inv(); - Inv_CSideForce = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CSideForce_Inv(); - Inv_CEff = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CEff_Inv(); - Inv_CMx = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CMx_Inv(); - Inv_CMy = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CMy_Inv(); - Inv_CMz = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CMz_Inv(); - Inv_CFx = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CFx_Inv(); - Inv_CFy = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CFy_Inv(); - Inv_CFz = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CFz_Inv(); - - /*--- Look over the markers being monitored and get the desired values ---*/ - - for (iMarker_Monitoring = 0; iMarker_Monitoring < config[ZONE_0]->GetnMarker_Monitoring(); iMarker_Monitoring++) { - Surface_CLift[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CLift(iMarker_Monitoring); - Surface_CDrag[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CDrag(iMarker_Monitoring); - Surface_CSideForce[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CSideForce(iMarker_Monitoring); - Surface_CEff[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CEff(iMarker_Monitoring); - Surface_CFx[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFx(iMarker_Monitoring); - Surface_CFy[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFy(iMarker_Monitoring); - Surface_CFz[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFz(iMarker_Monitoring); - Surface_CMx[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMx(iMarker_Monitoring); - Surface_CMy[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMy(iMarker_Monitoring); - Surface_CMz[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMz(iMarker_Monitoring); - - Surface_CLift_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CLift_Inv(iMarker_Monitoring); - Surface_CDrag_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CDrag_Inv(iMarker_Monitoring); - Surface_CSideForce_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CSideForce_Inv(iMarker_Monitoring); - Surface_CEff_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CEff_Inv(iMarker_Monitoring); - Surface_CFx_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFx_Inv(iMarker_Monitoring); - Surface_CFy_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFy_Inv(iMarker_Monitoring); - Surface_CFz_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFz_Inv(iMarker_Monitoring); - Surface_CMx_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMx_Inv(iMarker_Monitoring); - Surface_CMy_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMy_Inv(iMarker_Monitoring); - Surface_CMz_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMz_Inv(iMarker_Monitoring); - } - - /*--- Write file name with extension ---*/ - - string filename = config[val_iZone]->GetBreakdown_FileName(); - strcpy (cstr, filename.data()); - - Breakdown_file.open(cstr, ios::out); - - Breakdown_file << endl <<"-------------------------------------------------------------------------" << endl; - Breakdown_file <<"| ___ _ _ ___ |" << endl; - Breakdown_file <<"| / __| | | |_ ) Release 4.0.1 \"Cardinal\" |" << endl; - Breakdown_file <<"| \\__ \\ |_| |/ / |" << endl; - Breakdown_file <<"| |___/\\___//___| Suite (Computational Fluid Dynamics Code) |" << endl; - Breakdown_file << "| |" << endl; - Breakdown_file << "| Local date and time: " << dt << " |" << endl; - Breakdown_file <<"-------------------------------------------------------------------------" << endl; - Breakdown_file << "| SU2 Lead Dev.: Dr. Francisco Palacios, Francisco.D.Palacios@boeing.com|" << endl; - Breakdown_file << "| Dr. Thomas D. Economon, economon@stanford.edu |" << endl; - Breakdown_file <<"-------------------------------------------------------------------------" << endl; - Breakdown_file << "| SU2 Developers: |" << endl; - Breakdown_file << "| - Prof. Juan J. Alonso's group at Stanford University. |" << endl; - Breakdown_file << "| - Prof. Piero Colonna's group at Delft University of Technology. |" << endl; - Breakdown_file << "| - Prof. Nicolas R. Gauger's group at Kaiserslautern U. of Technology. |" << endl; - Breakdown_file << "| - Prof. Alberto Guardone's group at Polytechnic University of Milan. |" << endl; - Breakdown_file << "| - Prof. Rafael Palacios' group at Imperial College London. |" << endl; - Breakdown_file <<"-------------------------------------------------------------------------" << endl; - Breakdown_file << "| Copyright (C) 2012-2015 SU2, the open-source CFD code. |" << endl; - Breakdown_file << "| |" << endl; - Breakdown_file << "| SU2 is free software; you can redistribute it and/or |" << endl; - Breakdown_file << "| modify it under the terms of the GNU Lesser General Public |" << endl; - Breakdown_file << "| License as published by the Free Software Foundation; either |" << endl; - Breakdown_file << "| version 2.1 of the License, or (at your option) any later version. |" << endl; - Breakdown_file << "| |" << endl; - Breakdown_file << "| SU2 is distributed in the hope that it will be useful, |" << endl; - Breakdown_file << "| but WITHOUT ANY WARRANTY; without even the implied warranty of |" << endl; - Breakdown_file << "| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |" << endl; - Breakdown_file << "| Lesser General Public License for more details. |" << endl; - Breakdown_file << "| |" << endl; - Breakdown_file << "| You should have received a copy of the GNU Lesser General Public |" << endl; - Breakdown_file << "| License along with SU2. If not, see . |" << endl; - Breakdown_file <<"-------------------------------------------------------------------------" << endl; - - Breakdown_file.precision(6); - - Breakdown_file << endl << endl <<"Problem definition:" << endl << endl; - - if (compressible) { - if (viscous) { - Breakdown_file << "Viscous flow: Computing pressure using the ideal gas law" << endl; - Breakdown_file << "based on the free-stream temperature and a density computed" << endl; - Breakdown_file << "from the Reynolds number." << endl; - } else { - Breakdown_file << "Inviscid flow: Computing density based on free-stream" << endl; - Breakdown_file << "temperature and pressure using the ideal gas law." << endl; - } - } - - if (grid_movement) Breakdown_file << "Force coefficients computed using MACH_MOTION." << endl; - else Breakdown_file << "Force coefficients computed using free-stream values." << endl; - - if (incompressible || freesurface) { - Breakdown_file << "Viscous and Inviscid flow: rho_ref, and vel_ref" << endl; - Breakdown_file << "are based on the free-stream values, p_ref = rho_ref*vel_ref^2." << endl; - Breakdown_file << "The free-stream value of the pressure is 0." << endl; - Breakdown_file << "Mach number: "<< config[val_iZone]->GetMach() << ", computed using the Bulk modulus." << endl; - Breakdown_file << "Angle of attack (deg): "<< config[val_iZone]->GetAoA() << ", computed using the the free-stream velocity." << endl; - Breakdown_file << "Side slip angle (deg): "<< config[val_iZone]->GetAoS() << ", computed using the the free-stream velocity." << endl; - if (viscous) Breakdown_file << "Reynolds number: " << config[val_iZone]->GetReynolds() << ", computed using free-stream values."<< endl; - Breakdown_file << "Only dimensional computation, the grid should be dimensional." << endl; - } - - Breakdown_file <<"-- Input conditions:"<< endl; - - if (compressible) { - switch (config[val_iZone]->GetKind_FluidModel()) { - - case STANDARD_AIR: - Breakdown_file << "Fluid Model: STANDARD_AIR "<< endl; - Breakdown_file << "Specific gas constant: " << config[val_iZone]->GetGas_Constant(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " N.m/kg.K." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " lbf.ft/slug.R." << endl; - Breakdown_file << "Specific gas constant (non-dim): " << config[val_iZone]->GetGas_ConstantND()<< endl; - Breakdown_file << "Specific Heat Ratio: 1.4000 "<< endl; - break; - - case IDEAL_GAS: - Breakdown_file << "Fluid Model: IDEAL_GAS "<< endl; - Breakdown_file << "Specific gas constant: " << config[val_iZone]->GetGas_Constant() << " N.m/kg.K." << endl; - Breakdown_file << "Specific gas constant (non-dim): " << config[val_iZone]->GetGas_ConstantND()<< endl; - Breakdown_file << "Specific Heat Ratio: "<< config[val_iZone]->GetGamma() << endl; - break; - - case VW_GAS: - Breakdown_file << "Fluid Model: Van der Waals "<< endl; - Breakdown_file << "Specific gas constant: " << config[val_iZone]->GetGas_Constant() << " N.m/kg.K." << endl; - Breakdown_file << "Specific gas constant (non-dim): " << config[val_iZone]->GetGas_ConstantND()<< endl; - Breakdown_file << "Specific Heat Ratio: "<< config[val_iZone]->GetGamma() << endl; - Breakdown_file << "Critical Pressure: " << config[val_iZone]->GetPressure_Critical() << " Pa." << endl; - Breakdown_file << "Critical Temperature: " << config[val_iZone]->GetTemperature_Critical() << " K." << endl; - Breakdown_file << "Critical Pressure (non-dim): " << config[val_iZone]->GetPressure_Critical() /config[val_iZone]->GetPressure_Ref() << endl; - Breakdown_file << "Critical Temperature (non-dim) : " << config[val_iZone]->GetTemperature_Critical() /config[val_iZone]->GetTemperature_Ref() << endl; - break; - - case PR_GAS: - Breakdown_file << "Fluid Model: Peng-Robinson "<< endl; - Breakdown_file << "Specific gas constant: " << config[val_iZone]->GetGas_Constant() << " N.m/kg.K." << endl; - Breakdown_file << "Specific gas constant(non-dim): " << config[val_iZone]->GetGas_ConstantND()<< endl; - Breakdown_file << "Specific Heat Ratio: "<< config[val_iZone]->GetGamma() << endl; - Breakdown_file << "Critical Pressure: " << config[val_iZone]->GetPressure_Critical() << " Pa." << endl; - Breakdown_file << "Critical Temperature: " << config[val_iZone]->GetTemperature_Critical() << " K." << endl; - Breakdown_file << "Critical Pressure (non-dim): " << config[val_iZone]->GetPressure_Critical() /config[val_iZone]->GetPressure_Ref() << endl; - Breakdown_file << "Critical Temperature (non-dim) : " << config[val_iZone]->GetTemperature_Critical() /config[val_iZone]->GetTemperature_Ref() << endl; - break; - } - - if (viscous) { - - switch (config[val_iZone]->GetKind_ViscosityModel()) { - - case CONSTANT_VISCOSITY: - Breakdown_file << "Viscosity Model: CONSTANT_VISCOSITY "<< endl; - Breakdown_file << "Laminar Viscosity: " << config[val_iZone]->GetMu_ConstantND()*config[val_iZone]->GetViscosity_Ref(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " N.s/m^2." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " lbf.s/ft^2." << endl; - Breakdown_file << "Laminar Viscosity (non-dim): " << config[val_iZone]->GetMu_ConstantND()<< endl; - break; - - case SUTHERLAND: - Breakdown_file << "Viscosity Model: SUTHERLAND "<< endl; - Breakdown_file << "Ref. Laminar Viscosity: " << config[val_iZone]->GetMu_RefND()*config[val_iZone]->GetViscosity_Ref(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " N.s/m^2." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " lbf.s/ft^2." << endl; - Breakdown_file << "Ref. Temperature: " << config[val_iZone]->GetMu_Temperature_RefND()*config[val_iZone]->GetTemperature_Ref(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " K." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " R." << endl; - Breakdown_file << "Sutherland Constant: "<< config[val_iZone]->GetMu_SND()*config[val_iZone]->GetTemperature_Ref(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " K." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " R." << endl; - Breakdown_file << "Laminar Viscosity (non-dim): " << config[val_iZone]->GetMu_ConstantND()<< endl; - Breakdown_file << "Ref. Temperature (non-dim): " << config[val_iZone]->GetMu_Temperature_RefND()<< endl; - Breakdown_file << "Sutherland constant (non-dim): "<< config[val_iZone]->GetMu_SND()<< endl; - break; - - } - switch (config[val_iZone]->GetKind_ConductivityModel()) { - - case CONSTANT_PRANDTL: - Breakdown_file << "Conductivity Model: CONSTANT_PRANDTL "<< endl; - Breakdown_file << "Prandtl: " << config[val_iZone]->GetPrandtl_Lam()<< endl; - break; - - case CONSTANT_CONDUCTIVITY: - Breakdown_file << "Conductivity Model: CONSTANT_CONDUCTIVITY "<< endl; - Breakdown_file << "Molecular Conductivity: " << config[val_iZone]->GetKt_ConstantND()*config[val_iZone]->GetConductivity_Ref()<< " W/m^2.K." << endl; - Breakdown_file << "Molecular Conductivity (non-dim): " << config[val_iZone]->GetKt_ConstantND()<< endl; - break; - - } - } - } - - if (incompressible || freesurface) { - Breakdown_file << "Bulk modulus: " << config[val_iZone]->GetBulk_Modulus(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " Pa." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " psf." << endl; - Breakdown_file << "Artificial compressibility factor: " << config[val_iZone]->GetArtComp_Factor(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " Pa." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " psf." << endl; - } - - Breakdown_file << "Free-stream static pressure: " << config[val_iZone]->GetPressure_FreeStream(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " Pa." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " psf." << endl; - - Breakdown_file << "Free-stream total pressure: " << config[val_iZone]->GetPressure_FreeStream() * pow( 1.0+config[val_iZone]->GetMach()*config[val_iZone]->GetMach()*0.5*(config[val_iZone]->GetGamma()-1.0), config[val_iZone]->GetGamma()/(config[val_iZone]->GetGamma()-1.0) ); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " Pa." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " psf." << endl; - - if (compressible) { - Breakdown_file << "Free-stream temperature: " << config[val_iZone]->GetTemperature_FreeStream(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " K." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " R." << endl; - } - - Breakdown_file << "Free-stream density: " << config[val_iZone]->GetDensity_FreeStream(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " kg/m^3." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " slug/ft^3." << endl; - - if (nDim == 2) { - Breakdown_file << "Free-stream velocity: (" << config[val_iZone]->GetVelocity_FreeStream()[0] << ", "; - Breakdown_file << config[val_iZone]->GetVelocity_FreeStream()[1] << ")"; - } - if (nDim == 3) { - Breakdown_file << "Free-stream velocity: (" << config[val_iZone]->GetVelocity_FreeStream()[0] << ", "; - Breakdown_file << config[val_iZone]->GetVelocity_FreeStream()[1] << ", " << config[val_iZone]->GetVelocity_FreeStream()[2] << ")"; - } - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " m/s. "; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " ft/s. "; - - Breakdown_file << "Magnitude: " << config[val_iZone]->GetModVel_FreeStream(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " m/s." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " ft/s." << endl; - - if (compressible) { - Breakdown_file << "Free-stream total energy per unit mass: " << config[val_iZone]->GetEnergy_FreeStream(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " m^2/s^2." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " ft^2/s^2." << endl; - } - - if (viscous) { - Breakdown_file << "Free-stream viscosity: " << config[val_iZone]->GetViscosity_FreeStream(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " N.s/m^2." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " lbf.s/ft^2." << endl; - if (turbulent) { - Breakdown_file << "Free-stream turb. kinetic energy per unit mass: " << config[val_iZone]->GetTke_FreeStream(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " m^2/s^2." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " ft^2/s^2." << endl; - Breakdown_file << "Free-stream specific dissipation: " << config[val_iZone]->GetOmega_FreeStream(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " 1/s." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " 1/s." << endl; - } - } - - if (unsteady) { Breakdown_file << "Total time: " << config[val_iZone]->GetTotal_UnstTime() << " s. Time step: " << config[val_iZone]->GetDelta_UnstTime() << " s." << endl; } - - /*--- Print out reference values. ---*/ - - Breakdown_file <<"-- Reference values:"<< endl; - - if (compressible) { - Breakdown_file << "Reference specific gas constant: " << config[val_iZone]->GetGas_Constant_Ref(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " N.m/kg.K." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " lbf.ft/slug.R." << endl; - } - - Breakdown_file << "Reference pressure: " << config[val_iZone]->GetPressure_Ref(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " Pa." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " psf." << endl; - - if (compressible) { - Breakdown_file << "Reference temperature: " << config[val_iZone]->GetTemperature_Ref(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " K." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " R." << endl; - } - - Breakdown_file << "Reference density: " << config[val_iZone]->GetDensity_Ref(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " kg/m^3." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " slug/ft^3." << endl; - - Breakdown_file << "Reference velocity: " << config[val_iZone]->GetVelocity_Ref(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " m/s." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " ft/s." << endl; - - if (compressible) { - Breakdown_file << "Reference energy per unit mass: " << config[val_iZone]->GetEnergy_Ref(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " m^2/s^2." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " ft^2/s^2." << endl; - } - - if (incompressible || freesurface) { - Breakdown_file << "Reference length: " << config[val_iZone]->GetLength_Ref(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " m." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " in." << endl; - } - - if (viscous) { - Breakdown_file << "Reference viscosity: " << config[val_iZone]->GetViscosity_Ref(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " N.s/m^2." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " lbf.s/ft^2." << endl; - Breakdown_file << "Reference conductivity: " << config[val_iZone]->GetConductivity_Ref(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " W/m^2.K." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " lbf/ft.s.R." << endl; - } - - - if (unsteady) Breakdown_file << "Reference time: " << config[val_iZone]->GetTime_Ref() <<" s." << endl; - - /*--- Print out resulting non-dim values here. ---*/ - - Breakdown_file << "-- Resulting non-dimensional state:" << endl; - Breakdown_file << "Mach number (non-dim): " << config[val_iZone]->GetMach() << endl; - if (viscous) { - Breakdown_file << "Reynolds number (non-dim): " << config[val_iZone]->GetReynolds() <<". Re length: " << config[val_iZone]->GetLength_Reynolds(); - if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " m." << endl; - else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " ft." << endl; - } - if (gravity) { - Breakdown_file << "Froude number (non-dim): " << config[val_iZone]->GetFroude() << endl; - Breakdown_file << "Lenght of the baseline wave (non-dim): " << 2.0*PI_NUMBER*config[val_iZone]->GetFroude()*config[val_iZone]->GetFroude() << endl; - } - - if (compressible) { - Breakdown_file << "Specific gas constant (non-dim): " << config[val_iZone]->GetGas_ConstantND() << endl; - Breakdown_file << "Free-stream temperature (non-dim): " << config[val_iZone]->GetTemperature_FreeStreamND() << endl; - } - - Breakdown_file << "Free-stream pressure (non-dim): " << config[val_iZone]->GetPressure_FreeStreamND() << endl; - - Breakdown_file << "Free-stream density (non-dim): " << config[val_iZone]->GetDensity_FreeStreamND() << endl; - - if (nDim == 2) { - Breakdown_file << "Free-stream velocity (non-dim): (" << config[val_iZone]->GetVelocity_FreeStreamND()[0] << ", "; - Breakdown_file << config[val_iZone]->GetVelocity_FreeStreamND()[1] << "). "; - } else { - Breakdown_file << "Free-stream velocity (non-dim): (" << config[val_iZone]->GetVelocity_FreeStreamND()[0] << ", "; - Breakdown_file << config[val_iZone]->GetVelocity_FreeStreamND()[1] << ", " << config[val_iZone]->GetVelocity_FreeStreamND()[2] << "). "; - } - Breakdown_file << "Magnitude: " << config[val_iZone]->GetModVel_FreeStreamND() << endl; - - if (compressible) - Breakdown_file << "Free-stream total energy per unit mass (non-dim): " << config[val_iZone]->GetEnergy_FreeStreamND() << endl; - - if (viscous) { - Breakdown_file << "Free-stream viscosity (non-dim): " << config[val_iZone]->GetViscosity_FreeStreamND() << endl; - if (turbulent) { - Breakdown_file << "Free-stream turb. kinetic energy (non-dim): " << config[val_iZone]->GetTke_FreeStreamND() << endl; - Breakdown_file << "Free-stream specific dissipation (non-dim): " << config[val_iZone]->GetOmega_FreeStreamND() << endl; - } - } - - if (unsteady) { - Breakdown_file << "Total time (non-dim): " << config[val_iZone]->GetTotal_UnstTimeND() << endl; - Breakdown_file << "Time step (non-dim): " << config[val_iZone]->GetDelta_UnstTimeND() << endl; - } - - Breakdown_file << endl << endl <<"Forces breakdown:" << endl << endl; - - Breakdown_file << "Total CL: "; - Breakdown_file.width(11); Breakdown_file << Total_CLift; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CLift*100.0)/(Total_CLift+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Inv_CLift; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CLift*100.0)/(Total_CLift+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Total_CLift-Inv_CLift << endl; - - Breakdown_file << "Total CD: "; - Breakdown_file.width(11); Breakdown_file << Total_CDrag; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CDrag*100.0)/(Total_CDrag+EPS)) << "%): ";; - Breakdown_file.width(11); Breakdown_file << Inv_CDrag; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CDrag*100.0)/(Total_CDrag+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Total_CDrag-Inv_CDrag << endl; - - if (nDim == 3) { - Breakdown_file << "Total CSF: "; - Breakdown_file.width(11); Breakdown_file << Total_CSideForce; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CSideForce*100.0)/(Total_CSideForce+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Inv_CSideForce; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CSideForce*100.0)/(Total_CSideForce+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Total_CSideForce-Inv_CSideForce << endl; - } - - Breakdown_file << "Total CL/CD: "; - Breakdown_file.width(11); Breakdown_file << Total_CEff; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CEff*100.0)/(Total_CEff+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Inv_CEff; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CEff*100.0)/(Total_CEff+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Total_CEff-Inv_CEff << endl; - - if (nDim == 3) { - Breakdown_file << "Total CMx: "; - Breakdown_file.width(11); Breakdown_file << Total_CMx; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CMx*100.0)/(Total_CMx+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Inv_CMx; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CMx*100.0)/(Total_CMx+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Total_CMx-Inv_CMx << endl; - - Breakdown_file << "Total CMy: "; - Breakdown_file.width(11); Breakdown_file << Total_CMy; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CMy*100.0)/(Total_CMy+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Inv_CMy; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CMy*100.0)/(Total_CMy+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Total_CMy-Inv_CMy << endl; - } - - Breakdown_file << "Total CMz: "; - Breakdown_file.width(11); Breakdown_file << Total_CMz; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CMz*100.0)/(Total_CMz+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Inv_CMz; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CMz*100.0)/(Total_CMz+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Total_CMz-Inv_CMz << endl; - - Breakdown_file << "Total CFx: "; - Breakdown_file.width(11); Breakdown_file << Total_CFx; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CFx*100.0)/(Total_CFx+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Inv_CFx; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CFx*100.0)/(Total_CFx+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Total_CFx-Inv_CFx << endl; - - Breakdown_file << "Total CFy: "; - Breakdown_file.width(11); Breakdown_file << Total_CFy; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CFy*100.0)/(Total_CFy+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Inv_CFy; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CFy*100.0)/(Total_CFy+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Total_CFy-Inv_CFy << endl; - - if (nDim == 3) { - Breakdown_file << "Total CFz: "; - Breakdown_file.width(11); Breakdown_file << Total_CFz; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CFz*100.0)/(Total_CFz+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Inv_CFz; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CFz*100.0)/(Total_CFz+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Total_CFz-Inv_CFz << endl; - } - - Breakdown_file << endl << endl; - - for (iMarker_Monitoring = 0; iMarker_Monitoring < config[val_iZone]->GetnMarker_Monitoring(); iMarker_Monitoring++) { - - Breakdown_file << "Surface name: " << config[val_iZone]->GetMarker_Monitoring(iMarker_Monitoring) << endl << endl; - - Breakdown_file << "Total CL ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CLift[iMarker_Monitoring]*100.0)/(Total_CLift+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CLift[iMarker_Monitoring]; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CLift_Inv[iMarker_Monitoring]*100.0)/(Surface_CLift[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CLift_Inv[iMarker_Monitoring]; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CLift_Inv[iMarker_Monitoring]*100.0)/(Surface_CLift[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CLift[iMarker_Monitoring]-Surface_CLift_Inv[iMarker_Monitoring] << endl; - - Breakdown_file << "Total CD ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CDrag[iMarker_Monitoring]*100.0)/(Total_CDrag+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CDrag[iMarker_Monitoring]; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CDrag_Inv[iMarker_Monitoring]*100.0)/(Surface_CDrag[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CDrag_Inv[iMarker_Monitoring]; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CDrag_Inv[iMarker_Monitoring]*100.0)/(Surface_CDrag[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CDrag[iMarker_Monitoring]-Surface_CDrag_Inv[iMarker_Monitoring] << endl; - - if (nDim == 3) { - Breakdown_file << "Total CSF ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CSideForce[iMarker_Monitoring]*100.0)/(Total_CSideForce+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CSideForce[iMarker_Monitoring]; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CSideForce_Inv[iMarker_Monitoring]*100.0)/(Surface_CSideForce[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CSideForce_Inv[iMarker_Monitoring]; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CSideForce_Inv[iMarker_Monitoring]*100.0)/(Surface_CSideForce[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CSideForce[iMarker_Monitoring]-Surface_CSideForce_Inv[iMarker_Monitoring] << endl; - } - - Breakdown_file << "Total CL/CD ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CEff[iMarker_Monitoring]*100.0)/(Total_CEff+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CEff[iMarker_Monitoring]; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CEff_Inv[iMarker_Monitoring]*100.0)/(Surface_CEff[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CEff_Inv[iMarker_Monitoring]; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CEff_Inv[iMarker_Monitoring]*100.0)/(Surface_CEff[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - - Breakdown_file.width(11); Breakdown_file << Surface_CEff[iMarker_Monitoring]-Surface_CEff_Inv[iMarker_Monitoring] << endl; - - if (nDim == 3) { - - Breakdown_file << "Total CMx ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CMx[iMarker_Monitoring]*100.0)/(Total_CMx+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CMx[iMarker_Monitoring]; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CMx_Inv[iMarker_Monitoring]*100.0)/(Surface_CMx[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CMx_Inv[iMarker_Monitoring]; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CMx_Inv[iMarker_Monitoring]*100.0)/(Surface_CMx[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CMx[iMarker_Monitoring]-Surface_CMx_Inv[iMarker_Monitoring] << endl; - - Breakdown_file << "Total CMy ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CMy[iMarker_Monitoring]*100.0)/(Total_CMy+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CMy[iMarker_Monitoring]; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CMy_Inv[iMarker_Monitoring]*100.0)/(Surface_CMy[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CMy_Inv[iMarker_Monitoring]; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CMy_Inv[iMarker_Monitoring]*100.0)/(Surface_CMy[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CMy[iMarker_Monitoring]-Surface_CMy_Inv[iMarker_Monitoring] << endl; - } - - Breakdown_file << "Total CMz ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CMz[iMarker_Monitoring]*100.0)/(Total_CMz+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CMz[iMarker_Monitoring]; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CMz_Inv[iMarker_Monitoring]*100.0)/(Surface_CMz[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CMz_Inv[iMarker_Monitoring]; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CMz_Inv[iMarker_Monitoring]*100.0)/(Surface_CMz[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CMz[iMarker_Monitoring]-Surface_CMz_Inv[iMarker_Monitoring] << endl; - - Breakdown_file << "Total CFx ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CFx[iMarker_Monitoring]*100.0)/(Total_CFx+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CFx[iMarker_Monitoring]; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CFx_Inv[iMarker_Monitoring]*100.0)/(Surface_CFx[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CFx_Inv[iMarker_Monitoring]; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CFx_Inv[iMarker_Monitoring]*100.0)/(Surface_CFx[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CFx[iMarker_Monitoring]-Surface_CFx_Inv[iMarker_Monitoring] << endl; - - Breakdown_file << "Total CFy ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CFy[iMarker_Monitoring]*100.0)/(Total_CFy+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CFy[iMarker_Monitoring]; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CFy_Inv[iMarker_Monitoring]*100.0)/(Surface_CFy[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CFy_Inv[iMarker_Monitoring]; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CFy_Inv[iMarker_Monitoring]*100.0)/(Surface_CFy[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CFy[iMarker_Monitoring]-Surface_CFy_Inv[iMarker_Monitoring] << endl; - - if (nDim == 3) { - Breakdown_file << "Total CFz ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CFz[iMarker_Monitoring]*100.0)/(Total_CFz+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CFz[iMarker_Monitoring]; - Breakdown_file << " | Pressure Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CFz_Inv[iMarker_Monitoring]*100.0)/(Surface_CFz[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CFz_Inv[iMarker_Monitoring]; - Breakdown_file << " | Friction Component ("; - Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CFz_Inv[iMarker_Monitoring]*100.0)/(Surface_CFz[iMarker_Monitoring]+EPS)); - Breakdown_file << "%): "; - Breakdown_file.width(11); Breakdown_file << Surface_CFz[iMarker_Monitoring]-Surface_CFz_Inv[iMarker_Monitoring] << endl; - } - - Breakdown_file << endl; - - } - - delete [] Surface_CLift; - delete [] Surface_CDrag; - delete [] Surface_CSideForce; - delete [] Surface_CEff; - delete [] Surface_CFx; - delete [] Surface_CFy; - delete [] Surface_CFz; - delete [] Surface_CMx; - delete [] Surface_CMy; - delete [] Surface_CMz; - - delete [] Surface_CLift_Inv; - delete [] Surface_CDrag_Inv; - delete [] Surface_CSideForce_Inv; - delete [] Surface_CEff_Inv; - delete [] Surface_CFx_Inv; - delete [] Surface_CFy_Inv; - delete [] Surface_CFz_Inv; - delete [] Surface_CMx_Inv; - delete [] Surface_CMy_Inv; - delete [] Surface_CMz_Inv; - - Breakdown_file.close(); - - } - -} - -void COutput::SetResult_Files(CSolver ****solver_container, CGeometry ***geometry, CConfig **config, - unsigned long iExtIter, unsigned short val_nZone) { - - int rank = MASTER_NODE; - -#ifdef HAVE_MPI - int size; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - unsigned short iZone; - - for (iZone = 0; iZone < val_nZone; iZone++) { - - /*--- Flags identifying the types of files to be written. ---*/ - - bool Wrt_Vol = config[iZone]->GetWrt_Vol_Sol(); - bool Wrt_Srf = config[iZone]->GetWrt_Srf_Sol(); - -#ifdef HAVE_MPI - /*--- Do not merge the volume solutions if we are running in parallel. - Force the use of SU2_SOL to merge the volume sols in this case. ---*/ - - MPI_Comm_size(MPI_COMM_WORLD, &size); - if (size > SINGLE_NODE) { - Wrt_Vol = false; - Wrt_Srf = false; - } -#endif - - bool Wrt_Csv = config[iZone]->GetWrt_Csv_Sol(); - - if (rank == MASTER_NODE) cout << endl << "Writing comma-separated values (CSV) surface files." << endl; - - switch (config[iZone]->GetKind_Solver()) { - - case EULER : case NAVIER_STOKES : case RANS : - - if (Wrt_Csv) SetSurfaceCSV_Flow(config[iZone], geometry[iZone][MESH_0], solver_container[iZone][MESH_0][FLOW_SOL], iExtIter, iZone); - break; - - case ADJ_EULER : case ADJ_NAVIER_STOKES : case ADJ_RANS : case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: - if (Wrt_Csv) SetSurfaceCSV_Adjoint(config[iZone], geometry[iZone][MESH_0], solver_container[iZone][MESH_0][ADJFLOW_SOL], solver_container[iZone][MESH_0][FLOW_SOL], iExtIter, iZone); - break; - - } - - /*--- Get the file output format ---*/ - - unsigned short FileFormat = config[iZone]->GetOutput_FileFormat(); - - /*--- Merge the node coordinates and connectivity, if necessary. This - is only performed if a volume solution file is requested, and it - is active by default. ---*/ - - if (Wrt_Vol || Wrt_Srf) { - if (rank == MASTER_NODE) cout << "Merging connectivities in the Master node." << endl; - MergeConnectivity(config[iZone], geometry[iZone][MESH_0], iZone); - } - - /*--- Merge coordinates of all grid nodes (excluding ghost points). - The grid coordinates are always merged and included first in the - restart files. ---*/ - - if (rank == MASTER_NODE) cout << "Merging coordinates in the Master node." << endl; - MergeCoordinates(config[iZone], geometry[iZone][MESH_0]); - - if ((rank == MASTER_NODE) && (Wrt_Vol || Wrt_Srf)) { - if (FileFormat == TECPLOT_BINARY) { - if (rank == MASTER_NODE) cout << "Writing Tecplot binary volume and surface mesh files." << endl; - SetTecplotBinary_DomainMesh(config[iZone], geometry[iZone][MESH_0], iZone); - SetTecplotBinary_SurfaceMesh(config[iZone], geometry[iZone][MESH_0], iZone); - if (!wrote_base_file) - DeallocateConnectivity(config[iZone], geometry[iZone][MESH_0], false); - if (!wrote_surf_file) - DeallocateConnectivity(config[iZone], geometry[iZone][MESH_0], wrote_surf_file); - } - } - - /*--- Merge the solution data needed for volume solutions and restarts ---*/ - - if (rank == MASTER_NODE) cout << "Merging solution in the Master node." << endl; - MergeSolution(config[iZone], geometry[iZone][MESH_0], solver_container[iZone][MESH_0], iZone); - - /*--- Write restart, or Tecplot files using the merged data. - This data lives only on the master, and these routines are currently - executed by the master proc alone (as if in serial). ---*/ - - if (rank == MASTER_NODE) { - - /*--- Write a native restart file ---*/ - - if (rank == MASTER_NODE) cout << "Writing SU2 native restart file." << endl; - SetRestart(config[iZone], geometry[iZone][MESH_0], solver_container[iZone][MESH_0] , iZone); - - if (Wrt_Vol) { - - switch (FileFormat) { - - case TECPLOT: - - /*--- Write a Tecplot ASCII file ---*/ - - if (rank == MASTER_NODE) cout << "Writing Tecplot ASCII file volume solution file." << endl; - SetTecplotASCII(config[iZone], geometry[iZone][MESH_0], solver_container[iZone][MESH_0], iZone, val_nZone, false); - DeallocateConnectivity(config[iZone], geometry[iZone][MESH_0], false); - break; - - case FIELDVIEW: - - /*--- Write a FieldView ASCII file ---*/ - - if (rank == MASTER_NODE) cout << "Writing FieldView ASCII file volume solution file." << endl; - SetFieldViewASCII(config[iZone], geometry[iZone][MESH_0], iZone, val_nZone); - DeallocateConnectivity(config[iZone], geometry[iZone][MESH_0], false); - break; - - case TECPLOT_BINARY: - - /*--- Write a Tecplot binary solution file ---*/ - - if (rank == MASTER_NODE) cout << "Writing Tecplot binary volume solution file." << endl; - SetTecplotBinary_DomainSolution(config[iZone], geometry[iZone][MESH_0], iZone); - break; - - case FIELDVIEW_BINARY: - - /*--- Write a FieldView binary file ---*/ - - if (rank == MASTER_NODE) cout << "Writing FieldView binary file volume solution file." << endl; - SetFieldViewBinary(config[iZone], geometry[iZone][MESH_0], iZone, val_nZone); - DeallocateConnectivity(config[iZone], geometry[iZone][MESH_0], false); - break; - - case PARAVIEW: - - /*--- Write a Paraview ASCII file ---*/ - - if (rank == MASTER_NODE) cout << "Writing Paraview ASCII volume solution file." << endl; - SetParaview_ASCII(config[iZone], geometry[iZone][MESH_0], iZone, val_nZone, false); - DeallocateConnectivity(config[iZone], geometry[iZone][MESH_0], false); - break; - - default: - break; - } - - } - - if (Wrt_Srf) { - - switch (FileFormat) { - - case TECPLOT: - - /*--- Write a Tecplot ASCII file ---*/ - - if (rank == MASTER_NODE) cout << "Writing Tecplot ASCII surface solution file." << endl; - SetTecplotASCII(config[iZone], geometry[iZone][MESH_0], solver_container[iZone][MESH_0] , iZone, val_nZone, true); - DeallocateConnectivity(config[iZone], geometry[iZone][MESH_0], true); - break; - - case TECPLOT_BINARY: - - /*--- Write a Tecplot binary solution file ---*/ - - if (rank == MASTER_NODE) cout << "Writing Tecplot binary surface solution file." << endl; - SetTecplotBinary_SurfaceSolution(config[iZone], geometry[iZone][MESH_0], iZone); - break; - - case PARAVIEW: - - /*--- Write a Paraview ASCII file ---*/ - - if (rank == MASTER_NODE) cout << "Writing Paraview ASCII surface solution file." << endl; - SetParaview_ASCII(config[iZone], geometry[iZone][MESH_0], iZone, val_nZone, true); - DeallocateConnectivity(config[iZone], geometry[iZone][MESH_0], true); - break; - - default: - break; - } - - } - - /*--- Release memory needed for merging the solution data. ---*/ - - DeallocateCoordinates(config[iZone], geometry[iZone][MESH_0]); - DeallocateSolution(config[iZone], geometry[iZone][MESH_0]); - - } - - /*--- Final broadcast (informing other procs that the base output - file was written). ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Bcast(&wrote_base_file, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Bcast(&wrote_surf_file, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, MPI_COMM_WORLD); -#endif - - } -} - -void COutput::SetBaselineResult_Files(CSolver **solver, CGeometry **geometry, CConfig **config, - unsigned long iExtIter, unsigned short val_nZone) { - - int rank = MASTER_NODE; - int size = SINGLE_NODE; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); -#endif - - unsigned short iZone; - - for (iZone = 0; iZone < val_nZone; iZone++) { - - /*--- Flags identifying the types of files to be written. ---*/ - - bool Low_MemoryOutput = config[iZone]->GetLow_MemoryOutput(); - bool Wrt_Vol = config[iZone]->GetWrt_Vol_Sol(); - bool Wrt_Srf = config[iZone]->GetWrt_Srf_Sol(); - - /*--- Get the file output format ---*/ - - unsigned short FileFormat = config[iZone]->GetOutput_FileFormat(); - - /*--- Merge the node coordinates and connectivity if necessary. This - is only performed if a volume solution file is requested, and it - is active by default. ---*/ - - if ((Wrt_Vol || Wrt_Srf) && (!Low_MemoryOutput)) { - if (rank == MASTER_NODE) cout << "Merging connectivities in the Master node." << endl; - MergeConnectivity(config[iZone], geometry[iZone], iZone); - } - - /*--- Merge the solution data needed for volume solutions and restarts ---*/ - - if ((Wrt_Vol || Wrt_Srf) && (!Low_MemoryOutput)) { - if (rank == MASTER_NODE) cout << "Merging solution in the Master node." << endl; - MergeBaselineSolution(config[iZone], geometry[iZone], solver[iZone], iZone); - } - - /*--- Write restart, Tecplot or Paraview files using the merged data. - This data lives only on the master, and these routines are currently - executed by the master proc alone (as if in serial). ---*/ - - if (!Low_MemoryOutput) { - - if (rank == MASTER_NODE) { - - if (Wrt_Vol) { - - switch (FileFormat) { - - case TECPLOT: - - /*--- Write a Tecplot ASCII file ---*/ - - if (rank == MASTER_NODE) cout << "Writing Tecplot ASCII file (volume grid)." << endl; - SetTecplotASCII(config[iZone], geometry[iZone], solver, iZone, val_nZone, false); - DeallocateConnectivity(config[iZone], geometry[iZone], false); - break; - - case FIELDVIEW: - - /*--- Write a FieldView ASCII file ---*/ - - if (rank == MASTER_NODE) cout << "Writing FieldView ASCII file (volume grid)." << endl; - SetFieldViewASCII(config[iZone], geometry[iZone], iZone, val_nZone); - DeallocateConnectivity(config[iZone], geometry[iZone], false); - break; - - case TECPLOT_BINARY: - - /*--- Write a Tecplot binary solution file ---*/ - - if (rank == MASTER_NODE) cout << "Writing Tecplot Binary file (volume grid)." << endl; - SetTecplotBinary_DomainMesh(config[iZone], geometry[iZone], iZone); - SetTecplotBinary_DomainSolution(config[iZone], geometry[iZone], iZone); - break; - - case FIELDVIEW_BINARY: - - /*--- Write a binary binary file ---*/ - - if (rank == MASTER_NODE) cout << "Writing FieldView ASCII file (volume grid)." << endl; - SetFieldViewBinary(config[iZone], geometry[iZone], iZone, val_nZone); - DeallocateConnectivity(config[iZone], geometry[iZone], false); - break; - - case PARAVIEW: - - /*--- Write a Paraview ASCII file ---*/ - - if (rank == MASTER_NODE) cout << "Writing Paraview ASCII file (volume grid)." << endl; - SetParaview_ASCII(config[iZone], geometry[iZone], iZone, val_nZone, false); - DeallocateConnectivity(config[iZone], geometry[iZone], false); - break; - - default: - break; - } - - } - - if (Wrt_Srf) { - - switch (FileFormat) { - - case TECPLOT: - - /*--- Write a Tecplot ASCII file ---*/ - - if (rank == MASTER_NODE) cout << "Writing Tecplot ASCII file (surface grid)." << endl; - SetTecplotASCII(config[iZone], geometry[iZone], solver, iZone, val_nZone, true); - DeallocateConnectivity(config[iZone], geometry[iZone], true); - break; - - case TECPLOT_BINARY: - - /*--- Write a Tecplot binary solution file ---*/ - - if (rank == MASTER_NODE) cout << "Writing Tecplot Binary file (surface grid)." << endl; - SetTecplotBinary_SurfaceMesh(config[iZone], geometry[iZone], iZone); - SetTecplotBinary_SurfaceSolution(config[iZone], geometry[iZone], iZone); - break; - - case PARAVIEW: - - /*--- Write a Paraview ASCII file ---*/ - - if (rank == MASTER_NODE) cout << "Writing Paraview ASCII file (surface grid)." << endl; - SetParaview_ASCII(config[iZone], geometry[iZone], iZone, val_nZone, true); - DeallocateConnectivity(config[iZone], geometry[iZone], true); - break; - - default: - break; - } - } - - if (FileFormat == TECPLOT_BINARY) { - if (!wrote_base_file) - DeallocateConnectivity(config[iZone], geometry[iZone], false); - if (!wrote_surf_file) - DeallocateConnectivity(config[iZone], geometry[iZone], wrote_surf_file); - } - - if (Wrt_Vol || Wrt_Srf) - DeallocateSolution(config[iZone], geometry[iZone]); - } - - } - - else { - - if (Wrt_Vol) { - - if (rank == MASTER_NODE) cout << "Writing Tecplot ASCII file (volume grid)." << endl; - char buffer_char[50], out_file[MAX_STRING_SIZE]; - - string filename; - if (!config[iZone]->GetAdjoint()) filename = config[iZone]->GetFlow_FileName(); - else filename = config[iZone]->GetAdj_FileName(); - - if (size > 1) { - SPRINTF (buffer_char, "_%d", SU2_TYPE::Int(rank+1)); - filename = filename + buffer_char; - } - - SPRINTF (buffer_char, ".dat"); - strcpy(out_file, filename.c_str()); strcat(out_file, buffer_char); - SetTecplotASCII_LowMemory(config[iZone], geometry[iZone], solver, out_file, false); - } - - if (Wrt_Srf) { - - if (rank == MASTER_NODE) cout << "Writing Tecplot ASCII file (surface grid)." << endl; - char buffer_char[50], out_file[MAX_STRING_SIZE]; - - string filename; - if (!config[iZone]->GetAdjoint()) filename = config[iZone]->GetSurfFlowCoeff_FileName(); - else filename = config[iZone]->GetSurfAdjCoeff_FileName(); - - if (size > 1) { - SPRINTF (buffer_char, "_%d", SU2_TYPE::Int(rank+1)); - filename = filename + buffer_char; - } - - SPRINTF (buffer_char, ".dat"); - strcpy(out_file, filename.c_str()); strcat(out_file, buffer_char); - SetTecplotASCII_LowMemory(config[iZone], geometry[iZone], solver, out_file, true); - } - - } - - /*--- Final broadcast (informing other procs that the base output - file was written). ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Bcast(&wrote_base_file, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, MPI_COMM_WORLD); -#endif - - } -} - -void COutput::SetMesh_Files(CGeometry **geometry, CConfig **config, unsigned short val_nZone, bool new_file, bool su2_file) { - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - unsigned short iZone; - - for (iZone = 0; iZone < val_nZone; iZone++) { - - /*--- Flags identifying the types of files to be written. ---*/ - - bool Wrt_Vol = config[iZone]->GetWrt_Vol_Sol() && config[iZone]->GetVisualize_Deformation(); - bool Wrt_Srf = config[iZone]->GetWrt_Srf_Sol() && config[iZone]->GetVisualize_Deformation();; - - /*--- Merge the node coordinates and connectivity if necessary. This - is only performed if a volume solution file is requested, and it - is active by default. ---*/ - - if (rank == MASTER_NODE) cout <<"Merging grid connectivity." << endl; - MergeConnectivity(config[iZone], geometry[iZone], iZone); - - /*--- Merge coordinates of all grid nodes (excluding ghost points). - The grid coordinates are always merged and included first in the - restart files. ---*/ - - if (rank == MASTER_NODE) cout <<"Merging grid coordinates." << endl; - MergeCoordinates(config[iZone], geometry[iZone]); - - /*--- Write restart, Tecplot or Paraview files using the merged data. - This data lives only on the master, and these routines are currently - executed by the master proc alone (as if in serial). ---*/ - - if (rank == MASTER_NODE) { - - if (Wrt_Vol) { - - if (rank == MASTER_NODE) cout <<"Writing volume mesh file." << endl; - - /*--- Write a Tecplot ASCII file ---*/ - if (config[iZone]->GetOutput_FileFormat()==PARAVIEW) SetParaview_MeshASCII(config[iZone], geometry[iZone], iZone, val_nZone, false,new_file); - else SetTecplotASCII_Mesh(config[iZone], geometry[iZone], false, new_file); - - } - - if (Wrt_Srf) { - - if (rank == MASTER_NODE) cout <<"Writing surface mesh file." << endl; - - /*--- Write a Tecplot ASCII file ---*/ - if (config[iZone]->GetOutput_FileFormat()==PARAVIEW) SetParaview_MeshASCII(config[iZone], geometry[iZone], iZone, val_nZone, true,new_file); - else SetTecplotASCII_Mesh(config[iZone], geometry[iZone], true, new_file); - - - } - - if (rank == MASTER_NODE) cout <<"Writing .su2 file." << endl; - - /*--- Write a .su2 ASCII file ---*/ - - if (su2_file) SetSU2_MeshASCII(config[iZone], geometry[iZone]); - - /*--- Deallocate connectivity ---*/ - - DeallocateConnectivity(config[iZone], geometry[iZone], true); - - } - - /*--- Final broadcast (informing other procs that the base output - file was written). ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Bcast(&wrote_base_file, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, MPI_COMM_WORLD); -#endif - - } -} - -void COutput::SetMassFlowRate(CSolver *solver_container, CGeometry *geometry, CConfig *config) { - unsigned short iDim, iMarker_monitor, iMarker; - unsigned long iVertex, iPoint; - su2double Vector[3], Total_Mdot=0.0; - unsigned short nDim = geometry->GetnDim(); - - for (iMarker = 0; iMarker< config->GetnMarker_All(); iMarker++) { - iMarker_monitor = config->GetMarker_All_Monitoring(iMarker); - if (iMarker_monitor){ - for (iVertex = 0; iVertex < geometry->nVertex[ iMarker ]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - geometry->vertex[iMarker][iVertex]->GetNormal(Vector); - - for (iDim = 0; iDim < nDim; iDim++) - Total_Mdot -= Vector[iDim]*(solver_container->node[iPoint]->GetSolution(iDim+1)); - } - } - } - } - -#ifdef HAVE_MPI - /*--- Add AllBound information using all the nodes ---*/ - su2double My_Total_Mdot = Total_Mdot; Total_Mdot = 0.0; - SU2_MPI::Allreduce(&My_Total_Mdot, &Total_Mdot, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); -#endif - /*--- Set the output: reusing same variable from OneDimensionalOutput code ---*/ - solver_container->SetOneD_MassFlowRate(Total_Mdot); -} - -void COutput::OneDimensionalOutput(CSolver *solver_container, CGeometry *geometry, CConfig *config) { - - unsigned long iVertex, iPoint; - unsigned short iDim, iMarker, Out1D; - su2double *Normal = NULL, Area = 0.0, UnitNormal[3], - Tot_Pressure, Mach, Temperature, Pressure = 0.0, Velocity2, Enthalpy, RhoUA, U,// local values at each node (Velocity2 = V^2). U = normal velocity - AveragePt = 0.0, AverageMach = 0.0, AverageTemperature = 0.0, MassFlowRate = 0.0, // Area Averaged value ( sum / A ) - VelocityRef = 0.0, EnthalpyRef = 0.0, DensityRef = 0.0, PressureRef = 0.0; // Flux conserved values. TemperatureRef follows ideal gas - su2double TotalArea=0.0; - - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - su2double Gamma = config->GetGamma(); - unsigned short nDim = geometry->GetnDim(); - - - /*--- Loop over the markers ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - Out1D = config->GetMarker_All_Out_1D(iMarker); - - /*--- Loop over the vertices to compute the output ---*/ - - - if (Out1D == YES) { - - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - /*--- Find the normal direction ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - - /*--- Compute area, and unitary normal ---*/ - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); - for (iDim = 0; iDim < nDim; iDim++) UnitNormal[iDim] = -Normal[iDim]/Area; - - if (compressible) Pressure = solver_container->node[iPoint]->GetPressure(); - if (incompressible || freesurface) Pressure = solver_container->node[iPoint]->GetPressureInc(); - - /*-- Find velocity normal to the marked surface/opening --*/ - - U = 0.0; RhoUA = 0.0; - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) { - U += UnitNormal[iDim]*solver_container->node[iPoint]->GetVelocity(iDim); - RhoUA -=Normal[iDim]*solver_container->node[iPoint]->GetSolution(iDim+1); - } - - Enthalpy = solver_container->node[iPoint]->GetEnthalpy(); - Velocity2 = solver_container->node[iPoint]->GetVelocity2(); - Temperature = solver_container->node[iPoint]->GetTemperature(); - - Mach = (sqrt(Velocity2))/ solver_container->node[iPoint]->GetSoundSpeed(); - //Stag_Pressure = Pressure*pow((1.0+((Gamma-1.0)/2.0)*pow(Mach, 2.0)),( Gamma/(Gamma-1.0) ) ); - Tot_Pressure = Pressure + 0.5*solver_container->node[iPoint]->GetDensity()*Velocity2; - - AveragePt += Tot_Pressure * Area; - TotalArea += Area; - AverageMach += Mach*Area; - PressureRef += Pressure * Area; - AverageTemperature += Temperature*Area; - MassFlowRate += RhoUA; // RhoU is rho * vn * Area - VelocityRef+=RhoUA*U*U; // rho u A - EnthalpyRef+=RhoUA*Enthalpy; - - } - } - - } - - } - -#ifdef HAVE_MPI - - /*--- Add AllBound information using all the nodes ---*/ - - su2double My_Area = TotalArea; TotalArea = 0.0; - su2double My_AveragePt = AveragePt; AveragePt = 0.0; - su2double My_AverageMach = AverageMach; AverageMach = 0.0; - su2double My_AverageTemperature = AverageTemperature; AverageTemperature = 0.0; - su2double My_MassFlowRate = MassFlowRate; MassFlowRate = 0.0; - su2double My_PressureRef = PressureRef; PressureRef = 0.0; - su2double My_VelocityRef = VelocityRef; VelocityRef = 0.0; - su2double My_EnthalpyRef = EnthalpyRef; EnthalpyRef = 0.0; - su2double My_DensityRef = DensityRef; DensityRef = 0.0; - - SU2_MPI::Allreduce(&My_Area, &TotalArea, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&My_AveragePt, &AveragePt, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&My_AverageMach, &AverageMach, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&My_AverageTemperature, &AverageTemperature, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&My_MassFlowRate, &MassFlowRate, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&My_PressureRef, &PressureRef, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&My_VelocityRef, &VelocityRef, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&My_EnthalpyRef , &EnthalpyRef , 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&My_DensityRef , &DensityRef , 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - -#endif - - /*--- Set the 1D output ---*/ - /*--- DensityRef depends on the final values of other flux avg variables ---*/ - VelocityRef=sqrt(VelocityRef/MassFlowRate); - PressureRef=PressureRef/TotalArea; - EnthalpyRef=EnthalpyRef/MassFlowRate; - DensityRef =PressureRef*Gamma/(Gamma-1)/(EnthalpyRef-0.5*VelocityRef*VelocityRef); - - /*Area averaged values*/ - solver_container->SetOneD_TotalPress(AveragePt/TotalArea); - solver_container->SetOneD_Mach(AverageMach/TotalArea); - solver_container->SetOneD_Temp(AverageTemperature/TotalArea); - solver_container->SetOneD_MassFlowRate(MassFlowRate); - - /*Flux averaged values*/ - solver_container->SetOneD_FluxAvgPress(PressureRef); - solver_container->SetOneD_FluxAvgDensity(DensityRef); - solver_container->SetOneD_FluxAvgVelocity(VelocityRef); - solver_container->SetOneD_FluxAvgEntalpy(EnthalpyRef); - -} - -void COutput::SetForceSections(CSolver *solver_container, CGeometry *geometry, CConfig *config, unsigned long iExtIter) { - - short iSection, nSection; - unsigned long iVertex, iPoint; - su2double *Plane_P0, *Plane_Normal, MinPlane, MaxPlane, *CPressure, MinXCoord, MaxXCoord, Force[3], ForceInviscid[3], - MomentInviscid[3] = {0.0,0.0,0.0}, MomentDist[3] = {0.0,0.0,0.0}, RefDensity, RefPressure, RefAreaCoeff, *Velocity_Inf, Gas_Constant, Mach2Vel, Mach_Motion, Gamma, RefVel2 = 0.0, factor, NDPressure, *Origin, RefLengthMoment, Alpha, Beta, CDrag_Inv, CLift_Inv, CMy_Inv; - vector Xcoord_Airfoil, Ycoord_Airfoil, Zcoord_Airfoil, Pressure_Airfoil; - string Marker_Tag, Slice_Filename, Slice_Ext; - ofstream Cp_File; - unsigned short iDim; - - bool grid_movement = config->GetGrid_Movement(); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - - Plane_P0 = new su2double [3]; - Plane_Normal = new su2double [3]; - CPressure = new su2double[geometry->GetnPoint()]; - - /*--- Compute some reference quantities and necessary values ---*/ - RefDensity = solver_container->GetDensity_Inf(); - RefPressure = solver_container->GetPressure_Inf(); - RefAreaCoeff = config->GetRefAreaCoeff(); - Velocity_Inf = solver_container->GetVelocity_Inf(); - Gamma = config->GetGamma(); - Origin = config->GetRefOriginMoment(0); - RefLengthMoment = config->GetRefLengthMoment(); - Alpha = config->GetAoA()*PI_NUMBER/180.0; - Beta = config->GetAoS()*PI_NUMBER/180.0; - - if (grid_movement) { - Gas_Constant = config->GetGas_ConstantND(); - Mach2Vel = sqrt(Gamma*Gas_Constant*config->GetTemperature_FreeStreamND()); - Mach_Motion = config->GetMach_Motion(); - RefVel2 = (Mach_Motion*Mach2Vel)*(Mach_Motion*Mach2Vel); - } - else { - RefVel2 = 0.0; - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) - RefVel2 += Velocity_Inf[iDim]*Velocity_Inf[iDim]; - } - factor = 1.0 / (0.5*RefDensity*RefAreaCoeff*RefVel2); - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - if (geometry->GetnDim() == 3) { - - /*--- Copy the pressure to an auxiliar structure ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - if (compressible) { - CPressure[iPoint] = (solver_container->node[iPoint]->GetPressure() - RefPressure)*factor*RefAreaCoeff; - } - if (incompressible || freesurface) { - CPressure[iPoint] = (solver_container->node[iPoint]->GetPressureInc() - RefPressure)*factor*RefAreaCoeff; - } - } - - nSection = config->GetnSections(); - - for (iSection = 0; iSection < nSection; iSection++) { - - /*--- Read the values from the config file ---*/ - - MinPlane = config->GetSection_Location(0); MaxPlane = config->GetSection_Location(1); - MinXCoord = -1E6; MaxXCoord = 1E6; - - Plane_Normal[0] = 0.0; Plane_P0[0] = 0.0; - Plane_Normal[1] = 0.0; Plane_P0[1] = 0.0; - Plane_Normal[2] = 0.0; Plane_P0[2] = 0.0; - - Plane_Normal[config->GetAxis_Orientation()] = 1.0; - Plane_P0[config->GetAxis_Orientation()] = MinPlane + iSection*(MaxPlane - MinPlane)/su2double(nSection-1); - - /*--- Compute the airfoil sections (note that we feed in the Cp) ---*/ - - geometry->ComputeAirfoil_Section(Plane_P0, Plane_Normal, - MinXCoord, MaxXCoord, CPressure, - Xcoord_Airfoil, Ycoord_Airfoil, - Zcoord_Airfoil, Pressure_Airfoil, true, - config); - - if ((rank == MASTER_NODE) && (Xcoord_Airfoil.size() == 0)) { - cout << "Please check the config file, the section "<< iSection+1 <<" has not been detected." << endl; - } - - /*--- Output the pressure on each section (tecplot format) ---*/ - - if ((rank == MASTER_NODE) && (Xcoord_Airfoil.size() != 0)) { - - /*--- Write Cp at each section ---*/ - - ofstream Cp_File; - if (iSection == 0) { - Cp_File.open("cp_sections.dat", ios::out); - Cp_File << "TITLE = \"Airfoil sections\"" << endl; - Cp_File << "VARIABLES = \"X\",\"Y\",\"Z\",\"Cp\"" << endl; - } - else Cp_File.open("cp_sections.dat", ios::app); - - Cp_File << "ZONE T=\"SECTION_"<< (iSection+1) << "\", NODES= "<< Xcoord_Airfoil.size() << ", ELEMENTS= " << Xcoord_Airfoil.size()-1 << ", DATAPACKING= POINT, ZONETYPE= FELINESEG" << endl; - - /*--- Coordinates and pressure value ---*/ - - if (config->GetSystemMeasurements() == SI) { - for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { - Cp_File << Xcoord_Airfoil[iVertex] <<" "<< Ycoord_Airfoil[iVertex] <<" "<< Zcoord_Airfoil[iVertex] <<" "<< Pressure_Airfoil[iVertex] << endl; - } - } - if (config->GetSystemMeasurements() == US) { - for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { - Cp_File << Xcoord_Airfoil[iVertex]*12.0 <<" "<< Ycoord_Airfoil[iVertex]*12.0 <<" "<< Zcoord_Airfoil[iVertex]*12.0 <<" "<< Pressure_Airfoil[iVertex] << endl; - } - } - - /*--- Basic conectivity ---*/ - - for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) { - Cp_File << iVertex << "\t" << iVertex+1 << "\n"; - } - - Cp_File.close(); - - - /*--- Compute load distribution ---*/ - - ForceInviscid[0] = 0.0; ForceInviscid[1] = 0.0; ForceInviscid[2] = 0.0; MomentInviscid[1] = 0.0; - - for (iVertex = 0; iVertex < Xcoord_Airfoil.size()-1; iVertex++) { - - NDPressure = 0.5*(Pressure_Airfoil[iVertex]+Pressure_Airfoil[iVertex+1]); - - Force[0] = -(Zcoord_Airfoil[iVertex+1] - Zcoord_Airfoil[iVertex])*NDPressure; - Force[1] = 0.0; - Force[2] = (Xcoord_Airfoil[iVertex+1] - Xcoord_Airfoil[iVertex])*NDPressure; - - ForceInviscid[0] += Force[0]; - ForceInviscid[1] += Force[1]; - ForceInviscid[2] += Force[2]; - - MomentDist[0] = 0.5*(Xcoord_Airfoil[iVertex] + Xcoord_Airfoil[iVertex+1]) - Origin[0]; - MomentDist[1] = 0.5*(Ycoord_Airfoil[iVertex] + Ycoord_Airfoil[iVertex+1]) - Origin[1]; - MomentDist[2] = 0.5*(Zcoord_Airfoil[iVertex] + Zcoord_Airfoil[iVertex+1]) - Origin[3]; - - MomentInviscid[1] += (Force[0]*MomentDist[2]-Force[2]*MomentDist[0])/RefLengthMoment; - - } - - CLift_Inv = fabs( -ForceInviscid[0]*sin(Alpha) + ForceInviscid[2]*cos(Alpha)); - CDrag_Inv = fabs( ForceInviscid[0]*cos(Alpha)*cos(Beta) + ForceInviscid[1]*sin(Beta) + ForceInviscid[2]*sin(Alpha)*cos(Beta)); - CMy_Inv = MomentInviscid[1]; - - - /*--- Write load distribution ---*/ - - ofstream Load_File; - if (iSection == 0) { - Load_File.open("load_distribution.dat", ios::out); - Load_File << "TITLE = \"Load distribution\"" << endl; - Load_File << "VARIABLES = \"Y\",\"CL\",\"CD\",\"CMy\"" << endl; - Load_File << "ZONE T=\"Wing load distribution\", NODES= "<< nSection << ", ELEMENTS= " << nSection-1 << ", DATAPACKING= POINT, ZONETYPE= FELINESEG" << endl; - } - else Load_File.open("load_distribution.dat", ios::app); - - /*--- Coordinates and pressure value ---*/ - - Load_File << Ycoord_Airfoil[0] <<" "<< CLift_Inv <<" "<< CDrag_Inv <<" "<< CMy_Inv << endl; - - /*--- Basic conectivity ---*/ - - if (iSection == nSection-1) { - for (iSection = 1; iSection < nSection; iSection++) { - Load_File << iSection << "\t" << iSection+1 << "\n"; - } - } - - Load_File.close(); - - - } - - } - - - } - - /*--- Delete dynamically allocated memory ---*/ - - delete [] Plane_P0; - delete [] Plane_Normal; - delete [] CPressure; - -} - -void COutput::SetCp_InverseDesign(CSolver *solver_container, CGeometry *geometry, CConfig *config, unsigned long iExtIter) { - - unsigned short iMarker, icommas, Boundary, iDim; - unsigned long iVertex, iPoint, (*Point2Vertex)[2], nPointLocal = 0, nPointGlobal = 0; - su2double XCoord, YCoord, ZCoord, Pressure, PressureCoeff = 0, Cp, CpTarget, *Normal = NULL, Area, PressDiff; - bool *PointInDomain; - string text_line, surfCp_filename; - ifstream Surface_file; - char buffer[50], cstr[200]; - - - nPointLocal = geometry->GetnPoint(); -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&nPointLocal, &nPointGlobal, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#else - nPointGlobal = nPointLocal; -#endif - - Point2Vertex = new unsigned long[nPointGlobal][2]; - PointInDomain = new bool[nPointGlobal]; - - for (iPoint = 0; iPoint < nPointGlobal; iPoint ++) - PointInDomain[iPoint] = false; - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Boundary = config->GetMarker_All_KindBC(iMarker); - - if ((Boundary == EULER_WALL ) || - (Boundary == HEAT_FLUX ) || - (Boundary == ISOTHERMAL ) || - (Boundary == NEARFIELD_BOUNDARY)) { - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - - /*--- The Pressure file uses the global numbering ---*/ - -#ifndef HAVE_MPI - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); -#else - iPoint = geometry->node[geometry->vertex[iMarker][iVertex]->GetNode()]->GetGlobalIndex(); -#endif - - if (geometry->vertex[iMarker][iVertex]->GetNode() < geometry->GetnPointDomain()) { - Point2Vertex[iPoint][0] = iMarker; - Point2Vertex[iPoint][1] = iVertex; - PointInDomain[iPoint] = true; - solver_container->SetCPressureTarget(iMarker, iVertex, 0.0); - } - - } - } - } - - /*--- Prepare to read the surface pressure files (CSV) ---*/ - - surfCp_filename = "TargetCp"; - strcpy (cstr, surfCp_filename.c_str()); - - /*--- Write file name with extension if unsteady or steady ---*/ - - if ((config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) || - (config->GetUnsteady_Simulation() == TIME_SPECTRAL)) { - if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(iExtIter)); - if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(iExtIter)); - } - else - SPRINTF (buffer, ".dat"); - - strcat (cstr, buffer); - - /*--- Read the surface pressure file ---*/ - - string::size_type position; - - Surface_file.open(cstr, ios::in); - - if (!(Surface_file.fail())) { - - getline(Surface_file, text_line); - - while (getline(Surface_file, text_line)) { - for (icommas = 0; icommas < 50; icommas++) { - position = text_line.find( ",", 0 ); - if (position!=string::npos) text_line.erase (position,1); - } - stringstream point_line(text_line); - - if (geometry->GetnDim() == 2) point_line >> iPoint >> XCoord >> YCoord >> Pressure >> PressureCoeff; - if (geometry->GetnDim() == 3) point_line >> iPoint >> XCoord >> YCoord >> ZCoord >> Pressure >> PressureCoeff; - - if (PointInDomain[iPoint]) { - - /*--- Find the vertex for the Point and Marker ---*/ - - iMarker = Point2Vertex[iPoint][0]; - iVertex = Point2Vertex[iPoint][1]; - - solver_container->SetCPressureTarget(iMarker, iVertex, PressureCoeff); - - } - - } - - Surface_file.close(); - - } - - /*--- Compute the pressure difference ---*/ - - PressDiff = 0.0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Boundary = config->GetMarker_All_KindBC(iMarker); - - if ((Boundary == EULER_WALL ) || - (Boundary == HEAT_FLUX ) || - (Boundary == ISOTHERMAL ) || - (Boundary == NEARFIELD_BOUNDARY)) { - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - - Cp = solver_container->GetCPressure(iMarker, iVertex); - CpTarget = solver_container->GetCPressureTarget(iMarker, iVertex); - - Area = 0.0; - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) - Area += Normal[iDim]*Normal[iDim]; - Area = sqrt(Area); - - PressDiff += Area * (CpTarget - Cp) * (CpTarget - Cp); - } - - } - } - -#ifdef HAVE_MPI - su2double MyPressDiff = PressDiff; PressDiff = 0.0; - SU2_MPI::Allreduce(&MyPressDiff, &PressDiff, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); -#endif - - /*--- Update the total Cp difference coeffient ---*/ - - solver_container->SetTotal_CpDiff(PressDiff); - - delete[] Point2Vertex; - -} - -void COutput::SetHeat_InverseDesign(CSolver *solver_container, CGeometry *geometry, CConfig *config, unsigned long iExtIter) { - - unsigned short iMarker, icommas, Boundary, iDim; - unsigned long iVertex, iPoint, (*Point2Vertex)[2], nPointLocal = 0, nPointGlobal = 0; - su2double XCoord, YCoord, ZCoord, PressureCoeff, HeatFlux = 0.0, HeatFluxDiff, HeatFluxTarget, *Normal = NULL, Area, - Pressure, Cf; - bool *PointInDomain; - string text_line, surfHeatFlux_filename; - ifstream Surface_file; - char buffer[50], cstr[200]; - - - nPointLocal = geometry->GetnPoint(); -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&nPointLocal, &nPointGlobal, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#else - nPointGlobal = nPointLocal; -#endif - - Point2Vertex = new unsigned long[nPointGlobal][2]; - PointInDomain = new bool[nPointGlobal]; - - for (iPoint = 0; iPoint < nPointGlobal; iPoint ++) - PointInDomain[iPoint] = false; - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Boundary = config->GetMarker_All_KindBC(iMarker); - - if ((Boundary == EULER_WALL ) || - (Boundary == HEAT_FLUX ) || - (Boundary == ISOTHERMAL ) || - (Boundary == NEARFIELD_BOUNDARY)) { - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - - /*--- The Pressure file uses the global numbering ---*/ - -#ifndef HAVE_MPI - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); -#else - iPoint = geometry->node[geometry->vertex[iMarker][iVertex]->GetNode()]->GetGlobalIndex(); -#endif - - if (geometry->vertex[iMarker][iVertex]->GetNode() < geometry->GetnPointDomain()) { - Point2Vertex[iPoint][0] = iMarker; - Point2Vertex[iPoint][1] = iVertex; - PointInDomain[iPoint] = true; - solver_container->SetHeatFluxTarget(iMarker, iVertex, 0.0); - } - } - } - } - - /*--- Prepare to read the surface pressure files (CSV) ---*/ - - surfHeatFlux_filename = "TargetHeatFlux"; - strcpy (cstr, surfHeatFlux_filename.c_str()); - - /*--- Write file name with extension if unsteady or steady ---*/ - - if ((config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) || - (config->GetUnsteady_Simulation() == TIME_SPECTRAL)) { - if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(iExtIter)); - if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(iExtIter)); - } - else - SPRINTF (buffer, ".dat"); - - strcat (cstr, buffer); - - /*--- Read the surface pressure file ---*/ - - string::size_type position; - - Surface_file.open(cstr, ios::in); - - if (!(Surface_file.fail())) { - - getline(Surface_file, text_line); - - while (getline(Surface_file, text_line)) { - for (icommas = 0; icommas < 50; icommas++) { - position = text_line.find( ",", 0 ); - if (position!=string::npos) text_line.erase (position,1); - } - stringstream point_line(text_line); - - if (geometry->GetnDim() == 2) point_line >> iPoint >> XCoord >> YCoord >> Pressure >> PressureCoeff >> Cf >> HeatFlux; - if (geometry->GetnDim() == 3) point_line >> iPoint >> XCoord >> YCoord >> ZCoord >> Pressure >> PressureCoeff >> Cf >> HeatFlux; - - if (PointInDomain[iPoint]) { - - /*--- Find the vertex for the Point and Marker ---*/ - - iMarker = Point2Vertex[iPoint][0]; - iVertex = Point2Vertex[iPoint][1]; - - solver_container->SetHeatFluxTarget(iMarker, iVertex, HeatFlux); - - } - - } - - Surface_file.close(); - } - - /*--- Compute the pressure difference ---*/ - - HeatFluxDiff = 0.0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Boundary = config->GetMarker_All_KindBC(iMarker); - - if ((Boundary == EULER_WALL ) || - (Boundary == HEAT_FLUX ) || - (Boundary == ISOTHERMAL ) || - (Boundary == NEARFIELD_BOUNDARY)) { - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - - HeatFlux = solver_container->GetHeatFlux(iMarker, iVertex); - HeatFluxTarget = solver_container->GetHeatFluxTarget(iMarker, iVertex); - - Area = 0.0; - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) - Area += Normal[iDim]*Normal[iDim]; - Area = sqrt(Area); - - HeatFluxDiff += Area * (HeatFluxTarget - HeatFlux) * (HeatFluxTarget - HeatFlux); - - } - - } - } - -#ifdef HAVE_MPI - su2double MyHeatFluxDiff = HeatFluxDiff; HeatFluxDiff = 0.0; - SU2_MPI::Allreduce(&MyHeatFluxDiff, &HeatFluxDiff, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); -#endif - - /*--- Update the total HeatFlux difference coeffient ---*/ - - solver_container->SetTotal_HeatFluxDiff(HeatFluxDiff); - - delete[] Point2Vertex; - -} - -void COutput::SetEquivalentArea(CSolver *solver_container, CGeometry *geometry, CConfig *config, unsigned long iExtIter) { - - ofstream EquivArea_file, FuncGrad_file; - unsigned short iMarker = 0, iDim; - short *AzimuthalAngle = NULL; - su2double Gamma, auxXCoord, auxYCoord, auxZCoord, InverseDesign = 0.0, DeltaX, Coord_i, Coord_j, jp1Coord, *Coord = NULL, MeanFuntion, - *Face_Normal = NULL, auxArea, auxPress, Mach, Beta, R_Plane, Pressure_Inf, - ModVelocity_Inf, Velocity_Inf[3], factor, *Xcoord = NULL, *Ycoord = NULL, *Zcoord = NULL, - *Pressure = NULL, *FaceArea = NULL, *EquivArea = NULL, *TargetArea = NULL, *NearFieldWeight = NULL, - *Weight = NULL, jFunction, jp1Function; - unsigned long jVertex, iVertex, iPoint, nVertex_NearField = 0, auxPoint, - *IdPoint = NULL, *IdDomain = NULL, auxDomain; - unsigned short iPhiAngle; - ofstream NearFieldEA_file; ifstream TargetEA_file; - - su2double XCoordBegin_OF = config->GetEA_IntLimit(0); - su2double XCoordEnd_OF = config->GetEA_IntLimit(1); - - unsigned short nDim = geometry->GetnDim(); - su2double AoA = -(config->GetAoA()*PI_NUMBER/180.0); - su2double EAScaleFactor = config->GetEA_ScaleFactor(); // The EA Obj. Func. should be ~ force based Obj. Func. - - int rank = MESH_0; - - Mach = config->GetMach(); - Gamma = config->GetGamma(); - Beta = sqrt(Mach*Mach-1.0); - R_Plane = fabs(config->GetEA_IntLimit(2)); - Pressure_Inf = config->GetPressure_FreeStreamND(); - Velocity_Inf[0] = config->GetVelocity_FreeStreamND()[0]; - Velocity_Inf[1] = config->GetVelocity_FreeStreamND()[1]; - Velocity_Inf[2] = config->GetVelocity_FreeStreamND()[2]; - ModVelocity_Inf = 0; - for (iDim = 0; iDim < 3; iDim++) - ModVelocity_Inf += Velocity_Inf[iDim] * Velocity_Inf[iDim]; - - factor = 4.0*sqrt(2.0*Beta*R_Plane) / (Gamma*Pressure_Inf*Mach*Mach); - -#ifndef HAVE_MPI - - /*--- Compute the total number of points on the near-field ---*/ - - nVertex_NearField = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Face_Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - Coord = geometry->node[iPoint]->GetCoord(); - - /*--- Using Face_Normal(z), and Coord(z) we identify only a surface, - note that there are 2 NEARFIELD_BOUNDARY surfaces ---*/ - - if ((Face_Normal[nDim-1] > 0.0) && (Coord[nDim-1] < 0.0)) nVertex_NearField ++; - } - - /*--- Create an array with all the coordinates, points, pressures, face area, - equivalent area, and nearfield weight ---*/ - - Xcoord = new su2double[nVertex_NearField]; - Ycoord = new su2double[nVertex_NearField]; - Zcoord = new su2double[nVertex_NearField]; - AzimuthalAngle = new short[nVertex_NearField]; - IdPoint = new unsigned long[nVertex_NearField]; - IdDomain = new unsigned long[nVertex_NearField]; - Pressure = new su2double[nVertex_NearField]; - FaceArea = new su2double[nVertex_NearField]; - EquivArea = new su2double[nVertex_NearField]; - TargetArea = new su2double[nVertex_NearField]; - NearFieldWeight = new su2double[nVertex_NearField]; - Weight = new su2double[nVertex_NearField]; - - /*--- Copy the boundary information to an array ---*/ - - nVertex_NearField = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Face_Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - Coord = geometry->node[iPoint]->GetCoord(); - - if ((Face_Normal[nDim-1] > 0.0) && (Coord[nDim-1] < 0.0)) { - - IdPoint[nVertex_NearField] = iPoint; - Xcoord[nVertex_NearField] = geometry->node[iPoint]->GetCoord(0); - Ycoord[nVertex_NearField] = geometry->node[iPoint]->GetCoord(1); - - if (nDim ==2) { - AzimuthalAngle[nVertex_NearField] = 0; - } - - if (nDim == 3) { - Zcoord[nVertex_NearField] = geometry->node[iPoint]->GetCoord(2); - - /*--- Rotate the nearfield cylinder (AoA) only 3D ---*/ - - su2double YcoordRot = Ycoord[nVertex_NearField]; - su2double ZcoordRot = Xcoord[nVertex_NearField]*sin(AoA) + Zcoord[nVertex_NearField]*cos(AoA); - - /*--- Compute the Azimuthal angle (resolution of degress in the Azimuthal angle)---*/ - - su2double AngleDouble; short AngleInt; - AngleDouble = fabs(atan(-YcoordRot/ZcoordRot)*180.0/PI_NUMBER); - - /*--- Fix an azimuthal line due to misalignments of the near-field ---*/ - - su2double FixAzimuthalLine = config->GetFixAzimuthalLine(); - - if ((AngleDouble >= FixAzimuthalLine - 0.1) && (AngleDouble <= FixAzimuthalLine + 0.1)) AngleDouble = FixAzimuthalLine - 0.1; - - AngleInt = SU2_TYPE::Short(floor(AngleDouble + 0.5)); - if (AngleInt >= 0) AzimuthalAngle[nVertex_NearField] = AngleInt; - else AzimuthalAngle[nVertex_NearField] = 180 + AngleInt; - } - - if (AzimuthalAngle[nVertex_NearField] <= 60) { - Pressure[nVertex_NearField] = solver_container->node[iPoint]->GetPressure(); - FaceArea[nVertex_NearField] = fabs(Face_Normal[nDim-1]); - nVertex_NearField ++; - } - - } - } - -#else - - int nProcessor; - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - unsigned long nLocalVertex_NearField = 0, MaxLocalVertex_NearField = 0; - int iProcessor; - - unsigned long *Buffer_Receive_nVertex = NULL; - if (rank == MASTER_NODE) { - Buffer_Receive_nVertex = new unsigned long [nProcessor]; - } - - /*--- Compute the total number of points of the near-field ghost nodes ---*/ - - nLocalVertex_NearField = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Face_Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - Coord = geometry->node[iPoint]->GetCoord(); - - if (geometry->node[iPoint]->GetDomain()) - if ((Face_Normal[nDim-1] > 0.0) && (Coord[nDim-1] < 0.0)) - nLocalVertex_NearField ++; - } - - unsigned long *Buffer_Send_nVertex = new unsigned long [1]; - Buffer_Send_nVertex[0] = nLocalVertex_NearField; - - /*--- Send Near-Field vertex information --*/ - - SU2_MPI::Allreduce(&nLocalVertex_NearField, &nVertex_NearField, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalVertex_NearField, &MaxLocalVertex_NearField, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); - delete [] Buffer_Send_nVertex; - - su2double *Buffer_Send_Xcoord = new su2double[MaxLocalVertex_NearField]; - su2double *Buffer_Send_Ycoord = new su2double[MaxLocalVertex_NearField]; - su2double *Buffer_Send_Zcoord = new su2double[MaxLocalVertex_NearField]; - unsigned long *Buffer_Send_IdPoint = new unsigned long [MaxLocalVertex_NearField]; - su2double *Buffer_Send_Pressure = new su2double [MaxLocalVertex_NearField]; - su2double *Buffer_Send_FaceArea = new su2double[MaxLocalVertex_NearField]; - - su2double *Buffer_Receive_Xcoord = NULL; - su2double *Buffer_Receive_Ycoord = NULL; - su2double *Buffer_Receive_Zcoord = NULL; - unsigned long *Buffer_Receive_IdPoint = NULL; - su2double *Buffer_Receive_Pressure = NULL; - su2double *Buffer_Receive_FaceArea = NULL; - - if (rank == MASTER_NODE) { - Buffer_Receive_Xcoord = new su2double[nProcessor*MaxLocalVertex_NearField]; - Buffer_Receive_Ycoord = new su2double[nProcessor*MaxLocalVertex_NearField]; - Buffer_Receive_Zcoord = new su2double[nProcessor*MaxLocalVertex_NearField]; - Buffer_Receive_IdPoint = new unsigned long[nProcessor*MaxLocalVertex_NearField]; - Buffer_Receive_Pressure = new su2double[nProcessor*MaxLocalVertex_NearField]; - Buffer_Receive_FaceArea = new su2double[nProcessor*MaxLocalVertex_NearField]; - } - - unsigned long nBuffer_Xcoord = MaxLocalVertex_NearField; - unsigned long nBuffer_Ycoord = MaxLocalVertex_NearField; - unsigned long nBuffer_Zcoord = MaxLocalVertex_NearField; - unsigned long nBuffer_IdPoint = MaxLocalVertex_NearField; - unsigned long nBuffer_Pressure = MaxLocalVertex_NearField; - unsigned long nBuffer_FaceArea = MaxLocalVertex_NearField; - - for (iVertex = 0; iVertex < MaxLocalVertex_NearField; iVertex++) { - Buffer_Send_IdPoint[iVertex] = 0; Buffer_Send_Pressure[iVertex] = 0.0; - Buffer_Send_FaceArea[iVertex] = 0.0; Buffer_Send_Xcoord[iVertex] = 0.0; - Buffer_Send_Ycoord[iVertex] = 0.0; Buffer_Send_Zcoord[iVertex] = 0.0; - } - - /*--- Copy coordinates, index points, and pressures to the auxiliar vector --*/ - - nLocalVertex_NearField = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Face_Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - Coord = geometry->node[iPoint]->GetCoord(); - - if (geometry->node[iPoint]->GetDomain()) - if ((Face_Normal[nDim-1] > 0.0) && (Coord[nDim-1] < 0.0)) { - Buffer_Send_IdPoint[nLocalVertex_NearField] = iPoint; - Buffer_Send_Xcoord[nLocalVertex_NearField] = geometry->node[iPoint]->GetCoord(0); - Buffer_Send_Ycoord[nLocalVertex_NearField] = geometry->node[iPoint]->GetCoord(1); - Buffer_Send_Zcoord[nLocalVertex_NearField] = geometry->node[iPoint]->GetCoord(2); - Buffer_Send_Pressure[nLocalVertex_NearField] = solver_container->node[iPoint]->GetPressure(); - Buffer_Send_FaceArea[nLocalVertex_NearField] = fabs(Face_Normal[nDim-1]); - nLocalVertex_NearField++; - } - } - - /*--- Send all the information --*/ - - SU2_MPI::Gather(Buffer_Send_Xcoord, nBuffer_Xcoord, MPI_DOUBLE, Buffer_Receive_Xcoord, nBuffer_Xcoord, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Ycoord, nBuffer_Ycoord, MPI_DOUBLE, Buffer_Receive_Ycoord, nBuffer_Ycoord, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Zcoord, nBuffer_Zcoord, MPI_DOUBLE, Buffer_Receive_Zcoord, nBuffer_Zcoord, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_IdPoint, nBuffer_IdPoint, MPI_UNSIGNED_LONG, Buffer_Receive_IdPoint, nBuffer_IdPoint, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Pressure, nBuffer_Pressure, MPI_DOUBLE, Buffer_Receive_Pressure, nBuffer_Pressure, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_FaceArea, nBuffer_FaceArea, MPI_DOUBLE, Buffer_Receive_FaceArea, nBuffer_FaceArea, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - delete [] Buffer_Send_Xcoord; - delete [] Buffer_Send_Ycoord; - delete [] Buffer_Send_Zcoord; - delete [] Buffer_Send_IdPoint; - delete [] Buffer_Send_Pressure; - delete [] Buffer_Send_FaceArea; - - if (rank == MASTER_NODE) { - - Xcoord = new su2double[nVertex_NearField]; - Ycoord = new su2double[nVertex_NearField]; - Zcoord = new su2double[nVertex_NearField]; - AzimuthalAngle = new short[nVertex_NearField]; - IdPoint = new unsigned long[nVertex_NearField]; - IdDomain = new unsigned long[nVertex_NearField]; - Pressure = new su2double[nVertex_NearField]; - FaceArea = new su2double[nVertex_NearField]; - EquivArea = new su2double[nVertex_NearField]; - TargetArea = new su2double[nVertex_NearField]; - NearFieldWeight = new su2double[nVertex_NearField]; - Weight = new su2double[nVertex_NearField]; - - nVertex_NearField = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) - for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { - Xcoord[nVertex_NearField] = Buffer_Receive_Xcoord[iProcessor*MaxLocalVertex_NearField+iVertex]; - Ycoord[nVertex_NearField] = Buffer_Receive_Ycoord[iProcessor*MaxLocalVertex_NearField+iVertex]; - - if (nDim == 2) { - AzimuthalAngle[nVertex_NearField] = 0; - } - - if (nDim == 3) { - Zcoord[nVertex_NearField] = Buffer_Receive_Zcoord[iProcessor*MaxLocalVertex_NearField+iVertex]; - - /*--- Rotate the nearfield cylinder ---*/ - - su2double YcoordRot = Ycoord[nVertex_NearField]; - su2double ZcoordRot = Xcoord[nVertex_NearField]*sin(AoA) + Zcoord[nVertex_NearField]*cos(AoA); - - /*--- Compute the Azimuthal angle ---*/ - - su2double AngleDouble; short AngleInt; - AngleDouble = fabs(atan(-YcoordRot/ZcoordRot)*180.0/PI_NUMBER); - - /*--- Fix an azimuthal line due to misalignments of the near-field ---*/ - - su2double FixAzimuthalLine = config->GetFixAzimuthalLine(); - - if ((AngleDouble >= FixAzimuthalLine - 0.1) && (AngleDouble <= FixAzimuthalLine + 0.1)) - AngleDouble = FixAzimuthalLine - 0.1; - - AngleInt = SU2_TYPE::Short(floor(AngleDouble + 0.5)); - - if (AngleInt >= 0) AzimuthalAngle[nVertex_NearField] = AngleInt; - else AzimuthalAngle[nVertex_NearField] = 180 + AngleInt; - } - - if (AzimuthalAngle[nVertex_NearField] <= 60) { - IdPoint[nVertex_NearField] = Buffer_Receive_IdPoint[iProcessor*MaxLocalVertex_NearField+iVertex]; - Pressure[nVertex_NearField] = Buffer_Receive_Pressure[iProcessor*MaxLocalVertex_NearField+iVertex]; - FaceArea[nVertex_NearField] = Buffer_Receive_FaceArea[iProcessor*MaxLocalVertex_NearField+iVertex]; - IdDomain[nVertex_NearField] = iProcessor; - nVertex_NearField++; - } - - } - - delete [] Buffer_Receive_nVertex; - - delete [] Buffer_Receive_Xcoord; - delete [] Buffer_Receive_Ycoord; - delete [] Buffer_Receive_Zcoord; - delete [] Buffer_Receive_IdPoint; - delete [] Buffer_Receive_Pressure; - delete [] Buffer_Receive_FaceArea; - - } - -#endif - - if (rank == MASTER_NODE) { - - vector PhiAngleList; - vector::iterator IterPhiAngleList; - - for (iVertex = 0; iVertex < nVertex_NearField; iVertex++) - PhiAngleList.push_back(AzimuthalAngle[iVertex]); - - sort( PhiAngleList.begin(), PhiAngleList.end()); - IterPhiAngleList = unique( PhiAngleList.begin(), PhiAngleList.end()); - PhiAngleList.resize( IterPhiAngleList - PhiAngleList.begin() ); - - /*--- Create vectors and distribute the values among the different PhiAngle queues ---*/ - - vector > Xcoord_PhiAngle; Xcoord_PhiAngle.resize(PhiAngleList.size()); - vector > Ycoord_PhiAngle; Ycoord_PhiAngle.resize(PhiAngleList.size()); - vector > Zcoord_PhiAngle; Zcoord_PhiAngle.resize(PhiAngleList.size()); - vector > IdPoint_PhiAngle; IdPoint_PhiAngle.resize(PhiAngleList.size()); - vector > IdDomain_PhiAngle; IdDomain_PhiAngle.resize(PhiAngleList.size()); - vector > Pressure_PhiAngle; Pressure_PhiAngle.resize(PhiAngleList.size()); - vector > FaceArea_PhiAngle; FaceArea_PhiAngle.resize(PhiAngleList.size()); - vector > EquivArea_PhiAngle; EquivArea_PhiAngle.resize(PhiAngleList.size()); - vector > TargetArea_PhiAngle; TargetArea_PhiAngle.resize(PhiAngleList.size()); - vector > NearFieldWeight_PhiAngle; NearFieldWeight_PhiAngle.resize(PhiAngleList.size()); - vector > Weight_PhiAngle; Weight_PhiAngle.resize(PhiAngleList.size()); - - /*--- Distribute the values among the different PhiAngles ---*/ - - for (iVertex = 0; iVertex < nVertex_NearField; iVertex++) - for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) - if (AzimuthalAngle[iVertex] == PhiAngleList[iPhiAngle]) { - Xcoord_PhiAngle[iPhiAngle].push_back(Xcoord[iVertex]); - Ycoord_PhiAngle[iPhiAngle].push_back(Ycoord[iVertex]); - Zcoord_PhiAngle[iPhiAngle].push_back(Zcoord[iVertex]); - IdPoint_PhiAngle[iPhiAngle].push_back(IdPoint[iVertex]); - IdDomain_PhiAngle[iPhiAngle].push_back(IdDomain[iVertex]); - Pressure_PhiAngle[iPhiAngle].push_back(Pressure[iVertex]); - FaceArea_PhiAngle[iPhiAngle].push_back(FaceArea[iVertex]); - EquivArea_PhiAngle[iPhiAngle].push_back(EquivArea[iVertex]); - TargetArea_PhiAngle[iPhiAngle].push_back(TargetArea[iVertex]); - NearFieldWeight_PhiAngle[iPhiAngle].push_back(NearFieldWeight[iVertex]); - Weight_PhiAngle[iPhiAngle].push_back(Weight[iVertex]); - } - - /*--- Order the arrays (x Coordinate, Pressure, Point, and Domain) ---*/ - - for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) - for (iVertex = 0; iVertex < Xcoord_PhiAngle[iPhiAngle].size(); iVertex++) - for (jVertex = 0; jVertex < Xcoord_PhiAngle[iPhiAngle].size() - 1 - iVertex; jVertex++) - if (Xcoord_PhiAngle[iPhiAngle][jVertex] > Xcoord_PhiAngle[iPhiAngle][jVertex+1]) { - auxXCoord = Xcoord_PhiAngle[iPhiAngle][jVertex]; Xcoord_PhiAngle[iPhiAngle][jVertex] = Xcoord_PhiAngle[iPhiAngle][jVertex+1]; Xcoord_PhiAngle[iPhiAngle][jVertex+1] = auxXCoord; - auxYCoord = Ycoord_PhiAngle[iPhiAngle][jVertex]; Ycoord_PhiAngle[iPhiAngle][jVertex] = Ycoord_PhiAngle[iPhiAngle][jVertex+1]; Ycoord_PhiAngle[iPhiAngle][jVertex+1] = auxYCoord; - auxZCoord = Zcoord_PhiAngle[iPhiAngle][jVertex]; Zcoord_PhiAngle[iPhiAngle][jVertex] = Zcoord_PhiAngle[iPhiAngle][jVertex+1]; Zcoord_PhiAngle[iPhiAngle][jVertex+1] = auxZCoord; - auxPress = Pressure_PhiAngle[iPhiAngle][jVertex]; Pressure_PhiAngle[iPhiAngle][jVertex] = Pressure_PhiAngle[iPhiAngle][jVertex+1]; Pressure_PhiAngle[iPhiAngle][jVertex+1] = auxPress; - auxArea = FaceArea_PhiAngle[iPhiAngle][jVertex]; FaceArea_PhiAngle[iPhiAngle][jVertex] = FaceArea_PhiAngle[iPhiAngle][jVertex+1]; FaceArea_PhiAngle[iPhiAngle][jVertex+1] = auxArea; - auxPoint = IdPoint_PhiAngle[iPhiAngle][jVertex]; IdPoint_PhiAngle[iPhiAngle][jVertex] = IdPoint_PhiAngle[iPhiAngle][jVertex+1]; IdPoint_PhiAngle[iPhiAngle][jVertex+1] = auxPoint; - auxDomain = IdDomain_PhiAngle[iPhiAngle][jVertex]; IdDomain_PhiAngle[iPhiAngle][jVertex] = IdDomain_PhiAngle[iPhiAngle][jVertex+1]; IdDomain_PhiAngle[iPhiAngle][jVertex+1] = auxDomain; - } - - - /*--- Check that all the azimuth lists have the same size ---*/ - - unsigned short nVertex = Xcoord_PhiAngle[0].size(); - for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) { - unsigned short nVertex_aux = Xcoord_PhiAngle[iPhiAngle].size(); - if (nVertex_aux != nVertex) cout <<"Be careful!!! one azimuth list is shorter than the other"<< endl; - nVertex = min(nVertex, nVertex_aux); - } - - /*--- Compute equivalent area distribution at each azimuth angle ---*/ - - for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) { - EquivArea_PhiAngle[iPhiAngle][0] = 0.0; - for (iVertex = 1; iVertex < EquivArea_PhiAngle[iPhiAngle].size(); iVertex++) { - EquivArea_PhiAngle[iPhiAngle][iVertex] = 0.0; - - Coord_i = Xcoord_PhiAngle[iPhiAngle][iVertex]*cos(AoA) - Zcoord_PhiAngle[iPhiAngle][iVertex]*sin(AoA); - - for (jVertex = 0; jVertex < iVertex-1; jVertex++) { - - Coord_j = Xcoord_PhiAngle[iPhiAngle][jVertex]*cos(AoA) - Zcoord_PhiAngle[iPhiAngle][jVertex]*sin(AoA); - jp1Coord = Xcoord_PhiAngle[iPhiAngle][jVertex+1]*cos(AoA) - Zcoord_PhiAngle[iPhiAngle][jVertex+1]*sin(AoA); - - jFunction = factor*(Pressure_PhiAngle[iPhiAngle][jVertex] - Pressure_Inf)*sqrt(Coord_i-Coord_j); - jp1Function = factor*(Pressure_PhiAngle[iPhiAngle][jVertex+1] - Pressure_Inf)*sqrt(Coord_i-jp1Coord); - - DeltaX = (jp1Coord-Coord_j); - MeanFuntion = 0.5*(jp1Function + jFunction); - EquivArea_PhiAngle[iPhiAngle][iVertex] += DeltaX * MeanFuntion; - } - } - } - - /*--- Create a file with the equivalent area distribution at each azimuthal angle ---*/ - - NearFieldEA_file.precision(15); - NearFieldEA_file.open("Equivalent_Area.dat", ios::out); - NearFieldEA_file << "TITLE = \"Equivalent Area evaluation at each azimuthal angle\"" << endl; - - if (config->GetSystemMeasurements() == US) - NearFieldEA_file << "VARIABLES = \"Height (in) at r="<< R_Plane*12.0 << " in. (cyl. coord. system)\""; - else - NearFieldEA_file << "VARIABLES = \"Height (m) at r="<< R_Plane << " m. (cylindrical coordinate system)\""; - - for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) { - if (config->GetSystemMeasurements() == US) - NearFieldEA_file << ", \"Equivalent Area (ft2), F= " << PhiAngleList[iPhiAngle] << " deg.\""; - else - NearFieldEA_file << ", \"Equivalent Area (m2), F= " << PhiAngleList[iPhiAngle] << " deg.\""; - } - - NearFieldEA_file << endl; - for (iVertex = 0; iVertex < EquivArea_PhiAngle[0].size(); iVertex++) { - - su2double XcoordRot = Xcoord_PhiAngle[0][iVertex]*cos(AoA) - Zcoord_PhiAngle[0][iVertex]*sin(AoA); - su2double XcoordRot_init = Xcoord_PhiAngle[0][0]*cos(AoA) - Zcoord_PhiAngle[0][0]*sin(AoA); - - if (config->GetSystemMeasurements() == US) - NearFieldEA_file << scientific << (XcoordRot - XcoordRot_init) * 12.0; - else - NearFieldEA_file << scientific << (XcoordRot - XcoordRot_init); - - for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) { - NearFieldEA_file << scientific << ", " << EquivArea_PhiAngle[iPhiAngle][iVertex]; - } - - NearFieldEA_file << endl; - - } - NearFieldEA_file.close(); - - /*--- Read target equivalent area from the configuration file, - this first implementation requires a complete table (same as the original - EA table). so... no interpolation. ---*/ - - vector > TargetArea_PhiAngle_Trans; - TargetEA_file.open("TargetEA.dat", ios::in); - - if (TargetEA_file.fail()) { - if (iExtIter == 0) { cout << "There is no Target Equivalent Area file (TargetEA.dat)!!"<< endl; - cout << "Using default parameters (Target Equiv Area = 0.0)" << endl; - } - /*--- Set the table to 0 ---*/ - for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) - for (iVertex = 0; iVertex < TargetArea_PhiAngle[iPhiAngle].size(); iVertex++) - TargetArea_PhiAngle[iPhiAngle][iVertex] = 0.0; - } - else { - - /*--- skip header lines ---*/ - - string line; - getline(TargetEA_file, line); - getline(TargetEA_file, line); - - while (TargetEA_file) { - - string line; - getline(TargetEA_file, line); - istringstream is(line); - vector row; - unsigned short iter = 0; - - while (is.good()) { - string token; - getline(is, token,','); - - istringstream js(token); - - su2double data; - js >> data; - - /*--- The first element in the table is the coordinate (in or m)---*/ - - if (iter != 0) row.push_back(data); - iter++; - - } - TargetArea_PhiAngle_Trans.push_back(row); - } - - for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) - for (iVertex = 0; iVertex < EquivArea_PhiAngle[iPhiAngle].size(); iVertex++) - TargetArea_PhiAngle[iPhiAngle][iVertex] = TargetArea_PhiAngle_Trans[iVertex][iPhiAngle]; - - } - - /*--- Divide by the number of Phi angles in the nearfield ---*/ - - su2double PhiFactor = 1.0/su2double(PhiAngleList.size()); - - /*--- Evaluate the objective function ---*/ - - InverseDesign = 0; - for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) - for (iVertex = 0; iVertex < EquivArea_PhiAngle[iPhiAngle].size(); iVertex++) { - Weight_PhiAngle[iPhiAngle][iVertex] = 1.0; - Coord_i = Xcoord_PhiAngle[iPhiAngle][iVertex]; - - su2double Difference = EquivArea_PhiAngle[iPhiAngle][iVertex]-TargetArea_PhiAngle[iPhiAngle][iVertex]; - su2double percentage = fabs(Difference)*100/fabs(TargetArea_PhiAngle[iPhiAngle][iVertex]); - - if ((percentage < 0.1) || (Coord_i < XCoordBegin_OF) || (Coord_i > XCoordEnd_OF)) Difference = 0.0; - - InverseDesign += EAScaleFactor*PhiFactor*Weight_PhiAngle[iPhiAngle][iVertex]*Difference*Difference; - - } - - /*--- Evaluate the weight of the nearfield pressure (adjoint input) ---*/ - - for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) - for (iVertex = 0; iVertex < EquivArea_PhiAngle[iPhiAngle].size(); iVertex++) { - Coord_i = Xcoord_PhiAngle[iPhiAngle][iVertex]; - NearFieldWeight_PhiAngle[iPhiAngle][iVertex] = 0.0; - for (jVertex = iVertex; jVertex < EquivArea_PhiAngle[iPhiAngle].size(); jVertex++) { - Coord_j = Xcoord_PhiAngle[iPhiAngle][jVertex]; - Weight_PhiAngle[iPhiAngle][iVertex] = 1.0; - - su2double Difference = EquivArea_PhiAngle[iPhiAngle][jVertex]-TargetArea_PhiAngle[iPhiAngle][jVertex]; - su2double percentage = fabs(Difference)*100/fabs(TargetArea_PhiAngle[iPhiAngle][jVertex]); - - if ((percentage < 0.1) || (Coord_j < XCoordBegin_OF) || (Coord_j > XCoordEnd_OF)) Difference = 0.0; - - NearFieldWeight_PhiAngle[iPhiAngle][iVertex] += EAScaleFactor*PhiFactor*Weight_PhiAngle[iPhiAngle][iVertex]*2.0*Difference*factor*sqrt(Coord_j-Coord_i); - } - } - - /*--- Write the Nearfield pressure at each Azimuthal PhiAngle ---*/ - - EquivArea_file.precision(15); - EquivArea_file.open("nearfield_flow.dat", ios::out); - EquivArea_file << "TITLE = \"Equivalent Area evaluation at each azimuthal angle\"" << endl; - - if (config->GetSystemMeasurements() == US) - EquivArea_file << "VARIABLES = \"Height (in) at r="<< R_Plane*12.0 << " in. (cyl. coord. system)\",\"Equivalent Area (ft2)\",\"Target Equivalent Area (ft2)\",\"Cp\"" << endl; - else - EquivArea_file << "VARIABLES = \"Height (m) at r="<< R_Plane << " m. (cylindrical coordinate system)\",\"Equivalent Area (m2)\",\"Target Equivalent Area (m2)\",\"Cp\"" << endl; - - for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) { - EquivArea_file << fixed << "ZONE T= \"F=" << PhiAngleList[iPhiAngle] << " deg.\"" << endl; - for (iVertex = 0; iVertex < Xcoord_PhiAngle[iPhiAngle].size(); iVertex++) { - - su2double XcoordRot = Xcoord_PhiAngle[0][iVertex]*cos(AoA) - Zcoord_PhiAngle[0][iVertex]*sin(AoA); - su2double XcoordRot_init = Xcoord_PhiAngle[0][0]*cos(AoA) - Zcoord_PhiAngle[0][0]*sin(AoA); - - if (config->GetSystemMeasurements() == US) - EquivArea_file << scientific << (XcoordRot - XcoordRot_init) * 12.0; - else - EquivArea_file << scientific << (XcoordRot - XcoordRot_init); - - EquivArea_file << scientific << ", " << EquivArea_PhiAngle[iPhiAngle][iVertex] - << ", " << TargetArea_PhiAngle[iPhiAngle][iVertex] << ", " << (Pressure_PhiAngle[iPhiAngle][iVertex]-Pressure_Inf)/Pressure_Inf << endl; - } - } - - EquivArea_file.close(); - - /*--- Write Weight file for adjoint computation ---*/ - - FuncGrad_file.precision(15); - FuncGrad_file.open("WeightNF.dat", ios::out); - - FuncGrad_file << scientific << "-1.0"; - for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) - FuncGrad_file << scientific << "\t" << PhiAngleList[iPhiAngle]; - FuncGrad_file << endl; - - for (iVertex = 0; iVertex < NearFieldWeight_PhiAngle[0].size(); iVertex++) { - su2double XcoordRot = Xcoord_PhiAngle[0][iVertex]*cos(AoA) - Zcoord_PhiAngle[0][iVertex]*sin(AoA); - FuncGrad_file << scientific << XcoordRot; - for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) - FuncGrad_file << scientific << "\t" << NearFieldWeight_PhiAngle[iPhiAngle][iVertex]; - FuncGrad_file << endl; - } - FuncGrad_file.close(); - - /*--- Delete structures ---*/ - - delete [] Xcoord; delete [] Ycoord; delete [] Zcoord; - delete [] AzimuthalAngle; delete [] IdPoint; delete [] IdDomain; - delete [] Pressure; delete [] FaceArea; - delete [] EquivArea; delete [] TargetArea; - delete [] NearFieldWeight; delete [] Weight; - - } - -#ifndef HAVE_MPI - - /*--- Store the value of the NearField coefficient ---*/ - - solver_container->SetTotal_CEquivArea(InverseDesign); - -#else - - /*--- Send the value of the NearField coefficient to all the processors ---*/ - - SU2_MPI::Bcast(&InverseDesign, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - - /*--- Store the value of the NearField coefficient ---*/ - - solver_container->SetTotal_CEquivArea(InverseDesign); - -#endif - -} - +/*! + * \file output_structure.cpp + * \brief Main subroutines for output solver information + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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_structure.hpp" + +COutput::COutput(void) { + + /*--- Initialize point and connectivity counters to zero. ---*/ + + nGlobal_Poin = 0; + nSurf_Poin = 0; + nGlobal_Elem = 0; + nSurf_Elem = 0; + nGlobal_Tria = 0; + nGlobal_Quad = 0; + nGlobal_Tetr = 0; + nGlobal_Hexa = 0; + nGlobal_Pris = 0; + nGlobal_Pyra = 0; + nGlobal_Line = 0; + nGlobal_BoundTria = 0; + nGlobal_BoundQuad = 0; + + /*--- Initialize CGNS write flag ---*/ + + wrote_base_file = false; + + /*--- Initialize CGNS write flag ---*/ + + wrote_CGNS_base = false; + + /*--- Initialize Tecplot surface flag ---*/ + + wrote_surf_file = false; + + /*--- Initialize Paraview write flag ---*/ + + wrote_Paraview_base = false; + + /*--- Initialize residual ---*/ + + RhoRes_New = EPS; + RhoRes_Old = EPS; + +} + +COutput::~COutput(void) { } + +void COutput::SetSurfaceCSV_Flow(CConfig *config, CGeometry *geometry, + CSolver *FlowSolver, unsigned long iExtIter, + unsigned short val_iZone) { + + unsigned short iMarker; + unsigned long iPoint, iVertex, Global_Index; + su2double PressCoeff = 0.0, SkinFrictionCoeff; + su2double xCoord = 0.0, yCoord = 0.0, zCoord = 0.0, Mach, Pressure; + char cstr[200]; + + unsigned short solver = config->GetKind_Solver(); + unsigned short nDim = geometry->GetnDim(); + +#ifndef HAVE_MPI + + su2double HeatFlux; + char buffer [50]; + ofstream SurfFlow_file; + + /*--- Write file name with extension if unsteady ---*/ + strcpy (cstr, config->GetSurfFlowCoeff_FileName().c_str()); + + if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { + if (SU2_TYPE::Int(val_iZone) < 10) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 10) && (SU2_TYPE::Int(val_iZone) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 100) && (SU2_TYPE::Int(val_iZone) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 1000) && (SU2_TYPE::Int(val_iZone) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(val_iZone)); + if (SU2_TYPE::Int(val_iZone) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(val_iZone)); + + } else if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { + if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(iExtIter)); + if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(iExtIter)); + } + else + SPRINTF (buffer, ".csv"); + + strcat (cstr, buffer); + SurfFlow_file.precision(15); + SurfFlow_file.open(cstr, ios::out); + + SurfFlow_file << "\"Global_Index\", \"x_coord\", \"y_coord\", "; + if (nDim == 3) SurfFlow_file << "\"z_coord\", "; + SurfFlow_file << "\"Pressure\", \"Pressure_Coefficient\", "; + + switch (solver) { + case EULER : SurfFlow_file << "\"Mach_Number\"" << endl; break; + case NAVIER_STOKES: case RANS: SurfFlow_file << "\"Skin_Friction_Coefficient\", \"Heat_Flux\"" << endl; break; + } + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_Plotting(iMarker) == YES) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Global_Index = geometry->node[iPoint]->GetGlobalIndex(); + xCoord = geometry->node[iPoint]->GetCoord(0); + yCoord = geometry->node[iPoint]->GetCoord(1); + if (nDim == 3) zCoord = geometry->node[iPoint]->GetCoord(2); + + /*--- The output should be in inches ---*/ + + if (config->GetSystemMeasurements() == US) { + xCoord *= 12.0; yCoord *= 12.0; + if (nDim == 3) zCoord *= 12.0; + } + + Pressure = FlowSolver->node[iPoint]->GetPressure(); + PressCoeff = FlowSolver->GetCPressure(iMarker, iVertex); + SurfFlow_file << scientific << Global_Index << ", " << xCoord << ", " << yCoord << ", "; + if (nDim == 3) SurfFlow_file << scientific << zCoord << ", "; + SurfFlow_file << scientific << Pressure << ", " << PressCoeff << ", "; + switch (solver) { + case EULER : + Mach = sqrt(FlowSolver->node[iPoint]->GetVelocity2()) / FlowSolver->node[iPoint]->GetSoundSpeed(); + SurfFlow_file << scientific << Mach << endl; + break; + case NAVIER_STOKES: case RANS: + SkinFrictionCoeff = FlowSolver->GetCSkinFriction(iMarker, iVertex); + HeatFlux = FlowSolver->GetHeatFlux(iMarker, iVertex); + SurfFlow_file << scientific << SkinFrictionCoeff << ", " << HeatFlux << endl; + break; + } + } + } + } + + SurfFlow_file.close(); + +#else + + int rank, iProcessor, nProcessor; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); + + unsigned long Buffer_Send_nVertex[1], *Buffer_Recv_nVertex = NULL; + unsigned long nVertex_Surface = 0, nLocalVertex_Surface = 0; + unsigned long MaxLocalVertex_Surface = 0; + + /*--- Find the max number of surface vertices among all + partitions and set up buffers. The master node will handle the + writing of the CSV file after gathering all of the data. ---*/ + + nLocalVertex_Surface = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_Plotting(iMarker) == YES) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if (geometry->node[iPoint]->GetDomain()) nLocalVertex_Surface++; + } + + /*--- Communicate the number of local vertices on each partition + to the master node ---*/ + + Buffer_Send_nVertex[0] = nLocalVertex_Surface; + if (rank == MASTER_NODE) Buffer_Recv_nVertex = new unsigned long [nProcessor]; + + SU2_MPI::Allreduce(&nLocalVertex_Surface, &MaxLocalVertex_Surface, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Gather(&Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Recv_nVertex, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); + + /*--- Send and Recv buffers ---*/ + + su2double *Buffer_Send_Coord_x = new su2double [MaxLocalVertex_Surface]; + su2double *Buffer_Recv_Coord_x = NULL; + + su2double *Buffer_Send_Coord_y = new su2double [MaxLocalVertex_Surface]; + su2double *Buffer_Recv_Coord_y = NULL; + + su2double *Buffer_Send_Coord_z = new su2double [MaxLocalVertex_Surface]; + su2double *Buffer_Recv_Coord_z = NULL; + + su2double *Buffer_Send_Press = new su2double [MaxLocalVertex_Surface]; + su2double *Buffer_Recv_Press = NULL; + + su2double *Buffer_Send_CPress = new su2double [MaxLocalVertex_Surface]; + su2double *Buffer_Recv_CPress = NULL; + + su2double *Buffer_Send_Mach = new su2double [MaxLocalVertex_Surface]; + su2double *Buffer_Recv_Mach = NULL; + + su2double *Buffer_Send_SkinFriction = new su2double [MaxLocalVertex_Surface]; + su2double *Buffer_Recv_SkinFriction = NULL; + + su2double *Buffer_Send_HeatTransfer = new su2double [MaxLocalVertex_Surface]; + su2double *Buffer_Recv_HeatTransfer = NULL; + + unsigned long *Buffer_Send_GlobalIndex = new unsigned long [MaxLocalVertex_Surface]; + unsigned long *Buffer_Recv_GlobalIndex = NULL; + + /*--- Prepare the receive buffers on the master node only. ---*/ + + if (rank == MASTER_NODE) { + Buffer_Recv_Coord_x = new su2double [nProcessor*MaxLocalVertex_Surface]; + Buffer_Recv_Coord_y = new su2double [nProcessor*MaxLocalVertex_Surface]; + if (nDim == 3) Buffer_Recv_Coord_z = new su2double [nProcessor*MaxLocalVertex_Surface]; + Buffer_Recv_Press = new su2double [nProcessor*MaxLocalVertex_Surface]; + Buffer_Recv_CPress = new su2double [nProcessor*MaxLocalVertex_Surface]; + Buffer_Recv_Mach = new su2double [nProcessor*MaxLocalVertex_Surface]; + Buffer_Recv_SkinFriction = new su2double [nProcessor*MaxLocalVertex_Surface]; + Buffer_Recv_HeatTransfer = new su2double [nProcessor*MaxLocalVertex_Surface]; + Buffer_Recv_GlobalIndex = new unsigned long [nProcessor*MaxLocalVertex_Surface]; + } + + /*--- Loop over all vertices in this partition and load the + data of the specified type into the buffer to be sent to + the master node. ---*/ + + nVertex_Surface = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_Plotting(iMarker) == YES) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if (geometry->node[iPoint]->GetDomain()) { + Buffer_Send_Press[nVertex_Surface] = FlowSolver->node[iPoint]->GetPressure(); + Buffer_Send_CPress[nVertex_Surface] = FlowSolver->GetCPressure(iMarker, iVertex); + Buffer_Send_Coord_x[nVertex_Surface] = geometry->node[iPoint]->GetCoord(0); + Buffer_Send_Coord_y[nVertex_Surface] = geometry->node[iPoint]->GetCoord(1); + if (nDim == 3) { Buffer_Send_Coord_z[nVertex_Surface] = geometry->node[iPoint]->GetCoord(2); } + + /*--- If US system, the output should be in inches ---*/ + + if (config->GetSystemMeasurements() == US) { + Buffer_Send_Coord_x[nVertex_Surface] *= 12.0; + Buffer_Send_Coord_y[nVertex_Surface] *= 12.0; + if (nDim == 3) Buffer_Send_Coord_z[nVertex_Surface] *= 12.0; + } + + Buffer_Send_GlobalIndex[nVertex_Surface] = geometry->node[iPoint]->GetGlobalIndex(); + + if (solver == EULER) + Buffer_Send_Mach[nVertex_Surface] = sqrt(FlowSolver->node[iPoint]->GetVelocity2()) / FlowSolver->node[iPoint]->GetSoundSpeed(); + if ((solver == NAVIER_STOKES) || (solver == RANS)) + Buffer_Send_SkinFriction[nVertex_Surface] = FlowSolver->GetCSkinFriction(iMarker, iVertex); + nVertex_Surface++; + } + } + + /*--- Send the information to the master node ---*/ + + SU2_MPI::Gather(Buffer_Send_Coord_x, MaxLocalVertex_Surface, MPI_DOUBLE, Buffer_Recv_Coord_x, MaxLocalVertex_Surface, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Coord_y, MaxLocalVertex_Surface, MPI_DOUBLE, Buffer_Recv_Coord_y, MaxLocalVertex_Surface, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + if (nDim == 3) SU2_MPI::Gather(Buffer_Send_Coord_z, MaxLocalVertex_Surface, MPI_DOUBLE, Buffer_Recv_Coord_z, MaxLocalVertex_Surface, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Press, MaxLocalVertex_Surface, MPI_DOUBLE, Buffer_Recv_Press, MaxLocalVertex_Surface, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_CPress, MaxLocalVertex_Surface, MPI_DOUBLE, Buffer_Recv_CPress, MaxLocalVertex_Surface, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + if (solver == EULER) SU2_MPI::Gather(Buffer_Send_Mach, MaxLocalVertex_Surface, MPI_DOUBLE, Buffer_Recv_Mach, MaxLocalVertex_Surface, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + if ((solver == NAVIER_STOKES) || (solver == RANS)) SU2_MPI::Gather(Buffer_Send_SkinFriction, MaxLocalVertex_Surface, MPI_DOUBLE, Buffer_Recv_SkinFriction, MaxLocalVertex_Surface, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_GlobalIndex, MaxLocalVertex_Surface, MPI_UNSIGNED_LONG, Buffer_Recv_GlobalIndex, MaxLocalVertex_Surface, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); + + /*--- The master node unpacks the data and writes the surface CSV file ---*/ + + if (rank == MASTER_NODE) { + + /*--- Write file name with extension if unsteady ---*/ + char buffer[50]; + string filename = config->GetSurfFlowCoeff_FileName(); + ofstream SurfFlow_file; + + /*--- Write file name with extension if unsteady ---*/ + strcpy (cstr, filename.c_str()); + if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { + if (SU2_TYPE::Int(val_iZone) < 10) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 10) && (SU2_TYPE::Int(val_iZone) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 100) && (SU2_TYPE::Int(val_iZone) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 1000) && (SU2_TYPE::Int(val_iZone) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(val_iZone)); + if (SU2_TYPE::Int(val_iZone) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(val_iZone)); + + } else if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { + if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(iExtIter)); + if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(iExtIter)); + } + else + SPRINTF (buffer, ".csv"); + + strcat (cstr, buffer); + SurfFlow_file.precision(15); + SurfFlow_file.open(cstr, ios::out); + + SurfFlow_file << "\"Global_Index\", \"x_coord\", \"y_coord\", "; + if (nDim == 3) SurfFlow_file << "\"z_coord\", "; + SurfFlow_file << "\"Pressure\", \"Pressure_Coefficient\", "; + + switch (solver) { + case EULER : SurfFlow_file << "\"Mach_Number\"" << endl; break; + case NAVIER_STOKES: case RANS: SurfFlow_file << "\"Skin_Friction_Coefficient\"" << endl; break; + } + + /*--- Loop through all of the collected data and write each node's values ---*/ + + unsigned long Total_Index; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + for (iVertex = 0; iVertex < Buffer_Recv_nVertex[iProcessor]; iVertex++) { + + /*--- Current index position and global index ---*/ + Total_Index = iProcessor*MaxLocalVertex_Surface+iVertex; + Global_Index = Buffer_Recv_GlobalIndex[Total_Index]; + + /*--- Retrieve the merged data for this node ---*/ + xCoord = Buffer_Recv_Coord_x[Total_Index]; + yCoord = Buffer_Recv_Coord_y[Total_Index]; + if (nDim == 3) zCoord = Buffer_Recv_Coord_z[Total_Index]; + Pressure = Buffer_Recv_Press[Total_Index]; + PressCoeff = Buffer_Recv_CPress[Total_Index]; + + /*--- Write the first part of the data ---*/ + SurfFlow_file << scientific << Global_Index << ", " << xCoord << ", " << yCoord << ", "; + if (nDim == 3) SurfFlow_file << scientific << zCoord << ", "; + SurfFlow_file << scientific << Pressure << ", " << PressCoeff << ", "; + + /*--- Write the solver-dependent part of the data ---*/ + switch (solver) { + case EULER : + Mach = Buffer_Recv_Mach[Total_Index]; + SurfFlow_file << scientific << Mach << endl; + break; + case NAVIER_STOKES: case RANS: + SkinFrictionCoeff = Buffer_Recv_SkinFriction[Total_Index]; + SurfFlow_file << scientific << SkinFrictionCoeff << endl; + break; + } + } + } + + /*--- Close the CSV file ---*/ + SurfFlow_file.close(); + + /*--- Release the recv buffers on the master node ---*/ + + delete [] Buffer_Recv_Coord_x; + delete [] Buffer_Recv_Coord_y; + if (nDim == 3) delete [] Buffer_Recv_Coord_z; + delete [] Buffer_Recv_Press; + delete [] Buffer_Recv_CPress; + delete [] Buffer_Recv_Mach; + delete [] Buffer_Recv_SkinFriction; + delete [] Buffer_Recv_HeatTransfer; + delete [] Buffer_Recv_GlobalIndex; + + delete [] Buffer_Recv_nVertex; + + } + + /*--- Release the memory for the remaining buffers and exit ---*/ + + delete [] Buffer_Send_Coord_x; + delete [] Buffer_Send_Coord_y; + delete [] Buffer_Send_Coord_z; + delete [] Buffer_Send_Press; + delete [] Buffer_Send_CPress; + delete [] Buffer_Send_Mach; + delete [] Buffer_Send_SkinFriction; + delete [] Buffer_Send_HeatTransfer; + delete [] Buffer_Send_GlobalIndex; + +#endif + +} + +void COutput::SetSurfaceCSV_Adjoint(CConfig *config, CGeometry *geometry, CSolver *AdjSolver, CSolver *FlowSolution, unsigned long iExtIter, unsigned short val_iZone) { + +#ifndef HAVE_MPI + + unsigned long iPoint, iVertex, Global_Index; + su2double *Solution, xCoord, yCoord, zCoord; + unsigned short iMarker; + char cstr[200], buffer[50]; + ofstream SurfAdj_file; + + /*--- Write file name with extension if unsteady ---*/ + strcpy (cstr, config->GetSurfAdjCoeff_FileName().c_str()); + + if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { + if (SU2_TYPE::Int(val_iZone) < 10) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 10) && (SU2_TYPE::Int(val_iZone) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 100) && (SU2_TYPE::Int(val_iZone) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 1000) && (SU2_TYPE::Int(val_iZone) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(val_iZone)); + if (SU2_TYPE::Int(val_iZone) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(val_iZone)); + + } else if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { + if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(iExtIter)); + if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(iExtIter)); + } + else + SPRINTF (buffer, ".csv"); + + strcat(cstr, buffer); + SurfAdj_file.precision(15); + SurfAdj_file.open(cstr, ios::out); + + if (geometry->GetnDim() == 2) { + SurfAdj_file << "\"Point\",\"Sensitivity\",\"PsiRho\",\"Phi_x\",\"Phi_y\",\"PsiE\",\"x_coord\",\"y_coord\""; + if (config->GetDiscrete_Adjoint()){ + SurfAdj_file << ",\"x_Sens\",\"y_Sens\""; + } + SurfAdj_file << endl; + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_Plotting(iMarker) == YES) + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Global_Index = geometry->node[iPoint]->GetGlobalIndex(); + Solution = AdjSolver->node[iPoint]->GetSolution(); + xCoord = geometry->node[iPoint]->GetCoord(0); + yCoord = geometry->node[iPoint]->GetCoord(1); + + /*--- If US system, the output should be in inches ---*/ + + if (config->GetSystemMeasurements() == US) { + xCoord *= 12.0; + yCoord *= 12.0; + } + + SurfAdj_file << scientific << Global_Index << ", " << AdjSolver->GetCSensitivity(iMarker, iVertex) << ", " << Solution[0] << ", " + << Solution[1] << ", " << Solution[2] << ", " << Solution[3] <<", " << xCoord <<", "<< yCoord; + if (config->GetDiscrete_Adjoint()){ + SurfAdj_file << ", " << AdjSolver->node[iPoint]->GetSensitivity(0) << ", " << AdjSolver->node[iPoint]->GetSensitivity(1); + } + SurfAdj_file << endl; + } + } + } + + if (geometry->GetnDim() == 3) { + SurfAdj_file << "\"Point\",\"Sensitivity\",\"PsiRho\",\"Phi_x\",\"Phi_y\",\"Phi_z\",\"PsiE\",\"x_coord\",\"y_coord\",\"z_coord\""; + if (config->GetDiscrete_Adjoint()){ + SurfAdj_file << ",\"x_Sens\",\"y_Sens\",\"z_Sens\""; + } + SurfAdj_file << endl; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_Plotting(iMarker) == YES) + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Global_Index = geometry->node[iPoint]->GetGlobalIndex(); + Solution = AdjSolver->node[iPoint]->GetSolution(); + + xCoord = geometry->node[iPoint]->GetCoord(0); + yCoord = geometry->node[iPoint]->GetCoord(1); + zCoord = geometry->node[iPoint]->GetCoord(2); + + /*--- If US system, the output should be in inches ---*/ + + if (config->GetSystemMeasurements() == US) { + xCoord *= 12.0; + yCoord *= 12.0; + zCoord *= 12.0; + } + + SurfAdj_file << scientific << Global_Index << ", " << AdjSolver->GetCSensitivity(iMarker, iVertex) << ", " << Solution[0] << ", " + << Solution[1] << ", " << Solution[2] << ", " << Solution[3] << ", " << Solution[4] << ", "<< xCoord <<", "<< yCoord <<", "<< zCoord; + if (config->GetDiscrete_Adjoint()){ + SurfAdj_file << ", " << AdjSolver->node[iPoint]->GetSensitivity(0) << ", " << AdjSolver->node[iPoint]->GetSensitivity(1) + << ", " << AdjSolver->node[iPoint]->GetSensitivity(2); + } + SurfAdj_file << endl; + } + } + } + + SurfAdj_file.close(); + +#else + int rank, iProcessor, nProcessor; + + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); + + unsigned short nDim = geometry->GetnDim(), iMarker; + su2double *Solution, *Coord; + unsigned long Buffer_Send_nVertex[1], iVertex, iPoint, nVertex_Surface = 0, nLocalVertex_Surface = 0, + MaxLocalVertex_Surface = 0, nBuffer_Scalar; + unsigned long *Buffer_Receive_nVertex = NULL; + ofstream SurfAdj_file; + + /*--- Write the surface .csv file ---*/ + nLocalVertex_Surface = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_Plotting(iMarker) == YES) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if (geometry->node[iPoint]->GetDomain()) nLocalVertex_Surface ++; + } + + if (rank == MASTER_NODE) + Buffer_Receive_nVertex = new unsigned long [nProcessor]; + + Buffer_Send_nVertex[0] = nLocalVertex_Surface; + + SU2_MPI::Allreduce(&nLocalVertex_Surface, &MaxLocalVertex_Surface, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Gather(&Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); + + su2double *Buffer_Send_Coord_x = new su2double[MaxLocalVertex_Surface]; + su2double *Buffer_Send_Coord_y= new su2double[MaxLocalVertex_Surface]; + su2double *Buffer_Send_Coord_z= new su2double[MaxLocalVertex_Surface]; + unsigned long *Buffer_Send_GlobalPoint= new unsigned long[MaxLocalVertex_Surface]; + su2double *Buffer_Send_Sensitivity= new su2double[MaxLocalVertex_Surface]; + su2double *Buffer_Send_PsiRho= new su2double[MaxLocalVertex_Surface]; + su2double *Buffer_Send_Phi_x= new su2double[MaxLocalVertex_Surface]; + su2double *Buffer_Send_Phi_y= new su2double[MaxLocalVertex_Surface]; + su2double *Buffer_Send_Phi_z= new su2double[MaxLocalVertex_Surface]; + su2double *Buffer_Send_PsiE= new su2double[MaxLocalVertex_Surface]; + + su2double *Buffer_Send_Sens_x = NULL, *Buffer_Send_Sens_y = NULL, *Buffer_Send_Sens_z = NULL; + + if (config->GetDiscrete_Adjoint()){ + Buffer_Send_Sens_x = new su2double[MaxLocalVertex_Surface]; + Buffer_Send_Sens_y = new su2double[MaxLocalVertex_Surface]; + if (nDim == 3){ + Buffer_Send_Sens_z = new su2double[MaxLocalVertex_Surface]; + } + } + + nVertex_Surface = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_Plotting(iMarker) == YES) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if (geometry->node[iPoint]->GetDomain()) { + Solution = AdjSolver->node[iPoint]->GetSolution(); + //Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + Coord = geometry->node[iPoint]->GetCoord(); + //d = AdjSolver->node[iPoint]->GetForceProj_Vector(); + Buffer_Send_GlobalPoint[nVertex_Surface] = geometry->node[iPoint]->GetGlobalIndex(); + Buffer_Send_Coord_x[nVertex_Surface] = Coord[0]; + Buffer_Send_Coord_y[nVertex_Surface] = Coord[1]; + Buffer_Send_Sensitivity[nVertex_Surface] = AdjSolver->GetCSensitivity(iMarker, iVertex); + Buffer_Send_PsiRho[nVertex_Surface] = Solution[0]; + Buffer_Send_Phi_x[nVertex_Surface] = Solution[1]; + Buffer_Send_Phi_y[nVertex_Surface] = Solution[2]; + if (nDim == 2) Buffer_Send_PsiE[nVertex_Surface] = Solution[3]; + if (nDim == 3) { + Buffer_Send_Coord_z[nVertex_Surface] = Coord[2]; + Buffer_Send_Phi_z[nVertex_Surface] = Solution[3]; + Buffer_Send_PsiE[nVertex_Surface] = Solution[4]; + } + if (config->GetDiscrete_Adjoint()){ + Buffer_Send_Sens_x[nVertex_Surface] = AdjSolver->node[iPoint]->GetSensitivity(0); + Buffer_Send_Sens_y[nVertex_Surface] = AdjSolver->node[iPoint]->GetSensitivity(1); + if (nDim == 3){ + Buffer_Send_Sens_z[nVertex_Surface] = AdjSolver->node[iPoint]->GetSensitivity(2); + } + } + + /*--- If US system, the output should be in inches ---*/ + + if (config->GetSystemMeasurements() == US) { + Buffer_Send_Coord_x[nVertex_Surface] *= 12.0; + Buffer_Send_Coord_y[nVertex_Surface] *= 12.0; + if (nDim == 3) Buffer_Send_Coord_z[nVertex_Surface] *= 12.0; + } + + nVertex_Surface++; + } + } + + su2double *Buffer_Receive_Coord_x = NULL, *Buffer_Receive_Coord_y = NULL, *Buffer_Receive_Coord_z = NULL, *Buffer_Receive_Sensitivity = NULL, + *Buffer_Receive_PsiRho = NULL, *Buffer_Receive_Phi_x = NULL, *Buffer_Receive_Phi_y = NULL, *Buffer_Receive_Phi_z = NULL, + *Buffer_Receive_PsiE = NULL, *Buffer_Receive_Sens_x = NULL, *Buffer_Receive_Sens_y = NULL, *Buffer_Receive_Sens_z = NULL; + unsigned long *Buffer_Receive_GlobalPoint = NULL; + + if (rank == MASTER_NODE) { + Buffer_Receive_Coord_x = new su2double [nProcessor*MaxLocalVertex_Surface]; + Buffer_Receive_Coord_y = new su2double [nProcessor*MaxLocalVertex_Surface]; + if (nDim == 3) Buffer_Receive_Coord_z = new su2double [nProcessor*MaxLocalVertex_Surface]; + Buffer_Receive_GlobalPoint = new unsigned long [nProcessor*MaxLocalVertex_Surface]; + Buffer_Receive_Sensitivity = new su2double [nProcessor*MaxLocalVertex_Surface]; + Buffer_Receive_PsiRho = new su2double [nProcessor*MaxLocalVertex_Surface]; + Buffer_Receive_Phi_x = new su2double [nProcessor*MaxLocalVertex_Surface]; + Buffer_Receive_Phi_y = new su2double [nProcessor*MaxLocalVertex_Surface]; + if (nDim == 3) Buffer_Receive_Phi_z = new su2double [nProcessor*MaxLocalVertex_Surface]; + Buffer_Receive_PsiE = new su2double [nProcessor*MaxLocalVertex_Surface]; + if (config->GetDiscrete_Adjoint()){ + Buffer_Receive_Sens_x = new su2double[nProcessor*MaxLocalVertex_Surface]; + Buffer_Receive_Sens_y = new su2double[nProcessor*MaxLocalVertex_Surface]; + if (nDim == 3){ + Buffer_Receive_Sens_z = new su2double[nProcessor*MaxLocalVertex_Surface]; + } + } + } + + nBuffer_Scalar = MaxLocalVertex_Surface; + + /*--- Send the information to the Master node ---*/ + SU2_MPI::Gather(Buffer_Send_Coord_x, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Coord_x, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Coord_y, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Coord_y, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + if (nDim == 3) SU2_MPI::Gather(Buffer_Send_Coord_z, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Coord_z, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_GlobalPoint, nBuffer_Scalar, MPI_UNSIGNED_LONG, Buffer_Receive_GlobalPoint, nBuffer_Scalar, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Sensitivity, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Sensitivity, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_PsiRho, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_PsiRho, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Phi_x, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Phi_x, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Phi_y, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Phi_y, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + if (nDim == 3) SU2_MPI::Gather(Buffer_Send_Phi_z, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Phi_z, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_PsiE, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_PsiE, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + if (config->GetDiscrete_Adjoint()){ + SU2_MPI::Gather(Buffer_Send_Sens_x, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Sens_x, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Sens_y, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Sens_y, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + if (nDim == 3){ + SU2_MPI::Gather(Buffer_Send_Sens_z, nBuffer_Scalar, MPI_DOUBLE, Buffer_Receive_Sens_z, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + } + } + + /*--- The master node is the one who writes the surface files ---*/ + if (rank == MASTER_NODE) { + unsigned long iVertex, GlobalPoint, position; + char cstr[200], buffer[50]; + ofstream SurfAdj_file; + string filename = config->GetSurfAdjCoeff_FileName(); + + /*--- Write file name with extension if unsteady ---*/ + strcpy (cstr, filename.c_str()); + + if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { + if (SU2_TYPE::Int(val_iZone) < 10) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 10) && (SU2_TYPE::Int(val_iZone) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 100) && (SU2_TYPE::Int(val_iZone) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 1000) && (SU2_TYPE::Int(val_iZone) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(val_iZone)); + if (SU2_TYPE::Int(val_iZone) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(val_iZone)); + + } else if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { + if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(iExtIter)); + if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(iExtIter)); + } + else + SPRINTF (buffer, ".csv"); + + strcat (cstr, buffer); + SurfAdj_file.open(cstr, ios::out); + SurfAdj_file.precision(15); + + /*--- Write the 2D surface flow coefficient file ---*/ + if (geometry->GetnDim() == 2) { + + SurfAdj_file << "\"Point\",\"Sensitivity\",\"PsiRho\",\"Phi_x\",\"Phi_y\",\"PsiE\",\"x_coord\",\"y_coord\""; + if (config->GetDiscrete_Adjoint()){ + SurfAdj_file << ",\" x_Sens\",\"y_Sens\""; + } + SurfAdj_file << endl; + + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) + for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { + + position = iProcessor*MaxLocalVertex_Surface+iVertex; + GlobalPoint = Buffer_Receive_GlobalPoint[position]; + + SurfAdj_file << scientific << GlobalPoint << + ", " << Buffer_Receive_Sensitivity[position] << ", " << Buffer_Receive_PsiRho[position] << + ", " << Buffer_Receive_Phi_x[position] << ", " << Buffer_Receive_Phi_y[position] << + ", " << Buffer_Receive_PsiE[position] << ", " << Buffer_Receive_Coord_x[position] << + ", "<< Buffer_Receive_Coord_y[position]; + if (config->GetDiscrete_Adjoint()){ + SurfAdj_file << ", " << Buffer_Receive_Sens_x[position] << ", " << Buffer_Receive_Sens_y[position]; + } + SurfAdj_file << endl; + } + } + + /*--- Write the 3D surface flow coefficient file ---*/ + if (geometry->GetnDim() == 3) { + + SurfAdj_file << "\"Point\",\"Sensitivity\",\"PsiRho\",\"Phi_x\",\"Phi_y\",\"Phi_z\",\"PsiE\",\"x_coord\",\"y_coord\",\"z_coord\"" << endl; + if (config->GetDiscrete_Adjoint()){ + SurfAdj_file << ",\"x_Sens\",\"y_Sens\",\"z_Sens\""; + } + SurfAdj_file << endl; + + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) + for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { + position = iProcessor*MaxLocalVertex_Surface+iVertex; + GlobalPoint = Buffer_Receive_GlobalPoint[position]; + + SurfAdj_file << scientific << GlobalPoint << + ", " << Buffer_Receive_Sensitivity[position] << ", " << Buffer_Receive_PsiRho[position] << + ", " << Buffer_Receive_Phi_x[position] << ", " << Buffer_Receive_Phi_y[position] << ", " << Buffer_Receive_Phi_z[position] << + ", " << Buffer_Receive_PsiE[position] <<", "<< Buffer_Receive_Coord_x[position] << + ", "<< Buffer_Receive_Coord_y[position] <<", "<< Buffer_Receive_Coord_z[position]; + if (config->GetDiscrete_Adjoint()){ + SurfAdj_file << ", " << Buffer_Receive_Sens_x[position] << ", " << Buffer_Receive_Sens_y[position] << ", " << Buffer_Receive_Sens_z[position]; + } + SurfAdj_file << endl; + } + } + + } + + if (rank == MASTER_NODE) { + delete [] Buffer_Receive_nVertex; + delete [] Buffer_Receive_Coord_x; + delete [] Buffer_Receive_Coord_y; + if (nDim == 3) delete [] Buffer_Receive_Coord_z; + delete [] Buffer_Receive_Sensitivity; + delete [] Buffer_Receive_PsiRho; + delete [] Buffer_Receive_Phi_x; + delete [] Buffer_Receive_Phi_y; + if (nDim == 3) delete [] Buffer_Receive_Phi_z; + delete [] Buffer_Receive_PsiE; + delete [] Buffer_Receive_GlobalPoint; + if (config->GetDiscrete_Adjoint()){ + delete [] Buffer_Receive_Sens_x; + delete [] Buffer_Receive_Sens_y; + if (nDim == 3){ + delete [] Buffer_Receive_Sens_z; + } + } + } + + delete [] Buffer_Send_Coord_x; + delete [] Buffer_Send_Coord_y; + delete [] Buffer_Send_Coord_z; + delete [] Buffer_Send_GlobalPoint; + delete [] Buffer_Send_Sensitivity; + delete [] Buffer_Send_PsiRho; + delete [] Buffer_Send_Phi_x; + delete [] Buffer_Send_Phi_y; + delete [] Buffer_Send_Phi_z; + delete [] Buffer_Send_PsiE; + if (Buffer_Send_Sens_x != NULL) delete [] Buffer_Send_Sens_x; + if (Buffer_Send_Sens_y != NULL) delete [] Buffer_Send_Sens_y; + if (Buffer_Send_Sens_z != NULL) delete [] Buffer_Send_Sens_z; + + SurfAdj_file.close(); + +#endif +} + +void COutput::MergeConnectivity(CConfig *config, CGeometry *geometry, unsigned short val_iZone) { + + int rank = MASTER_NODE; + int size = SINGLE_NODE; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); +#endif + + /*--- Flags identifying the types of files to be written. ---*/ + + bool Wrt_Vol = config->GetWrt_Vol_Sol(); + bool Wrt_Srf = config->GetWrt_Srf_Sol(); + + /*--- Merge connectivity for each type of element (excluding halos). Note + that we only need to merge the connectivity once, as it does not change + during computation. Check whether the base file has been written. ---*/ + + /*--- Merge volumetric grid. ---*/ + + if (Wrt_Vol) { + + if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_Tria != 0)) + cout <<"Merging volumetric triangle grid connectivity." << endl; + MergeVolumetricConnectivity(config, geometry, TRIANGLE ); + + if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_Quad != 0)) + cout <<"Merging volumetric quadrilateral grid connectivity." << endl; + MergeVolumetricConnectivity(config, geometry, QUADRILATERAL ); + + if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_Tetr != 0)) + cout <<"Merging volumetric tetrahedron grid connectivity." << endl; + MergeVolumetricConnectivity(config, geometry, TETRAHEDRON ); + + if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_Hexa != 0)) + cout <<"Merging volumetric hexahedron grid connectivity." << endl; + MergeVolumetricConnectivity(config, geometry, HEXAHEDRON ); + + if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_Pris != 0)) + cout <<"Merging volumetric prism grid connectivity." << endl; + MergeVolumetricConnectivity(config, geometry, PRISM ); + + if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_Pyra != 0)) + cout <<"Merging volumetric pyramid grid connectivity." << endl; + MergeVolumetricConnectivity(config, geometry, PYRAMID ); + + } + + /*--- Merge surface grid. ---*/ + + if (Wrt_Srf) { + + if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_Line != 0)) + cout <<"Merging surface line grid connectivity." << endl; + MergeSurfaceConnectivity(config, geometry, LINE); + + if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_BoundTria != 0)) + cout <<"Merging surface triangle grid connectivity." << endl; + MergeSurfaceConnectivity(config, geometry, TRIANGLE); + + if ((rank == MASTER_NODE) && (size != SINGLE_NODE) && (nGlobal_BoundQuad != 0)) + cout <<"Merging surface quadrilateral grid connectivity." << endl; + MergeSurfaceConnectivity(config, geometry, QUADRILATERAL); + + } + + /*--- Update total number of volume elements after merge. ---*/ + + nGlobal_Elem = nGlobal_Tria + nGlobal_Quad + nGlobal_Tetr + + nGlobal_Hexa + nGlobal_Pyra + nGlobal_Pris; + + /*--- Update total number of surface elements after merge. ---*/ + + nSurf_Elem = nGlobal_Line + nGlobal_BoundTria + nGlobal_BoundQuad; + +} + +void COutput::MergeCoordinates(CConfig *config, CGeometry *geometry) { + + /*--- Local variables needed on all processors ---*/ + + unsigned short iDim, nDim = geometry->GetnDim(); + unsigned long iPoint; + +#ifndef HAVE_MPI + + /*--- In serial, the single process has access to all geometry, so simply + load the coordinates into the data structure. ---*/ + + unsigned short iMarker; + unsigned long iVertex, nTotalPoints = 0; + int SendRecv; + + /*--- First, create a structure to locate any periodic halo nodes ---*/ + int *Local_Halo = new int[geometry->GetnPoint()]; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + Local_Halo[iPoint] = !geometry->node[iPoint]->GetDomain(); + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { + SendRecv = config->GetMarker_All_SendRecv(iMarker); + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && + (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 1) && + (SendRecv < 0)) { + Local_Halo[iPoint] = false; + } + } + + } + } + + /*--- Total number of points in the mesh (this might include periodic points). ---*/ + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + if (!Local_Halo[iPoint]) nTotalPoints++; + + nGlobal_Poin = nTotalPoints; + nGlobal_Doma = geometry->GetnPointDomain(); + + /*--- Allocate the coordinates data structure. ---*/ + + Coords = new su2double*[nDim]; + for (iDim = 0; iDim < nDim; iDim++) { + Coords[iDim] = new su2double[nGlobal_Poin]; + } + + /*--- Loop over the mesh to collect the coords of the local points ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check if the node belongs to the domain (i.e, not a halo node). + Sort by the global index, even in serial there is a renumbering (e.g. RCM). ---*/ + + if (!Local_Halo[iPoint]) { + + /*--- Retrieve the current coordinates at this node. ---*/ + + unsigned long iGlobal_Index = geometry->node[iPoint]->GetGlobalIndex(); + + for (iDim = 0; iDim < nDim; iDim++) { + Coords[iDim][iGlobal_Index] = geometry->node[iPoint]->GetCoord(iDim); + + /*--- If US system, the output should be in inches ---*/ + + if ((config->GetSystemMeasurements() == US) && (config->GetKind_SU2() != SU2_DEF)) { + Coords[iDim][iGlobal_Index] *= 12.0; + } + + } + + } + } + + + delete [] Local_Halo; + +#else + + /*--- MPI preprocessing ---*/ + int iProcessor, nProcessor, rank; + unsigned long jPoint; + + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); + + bool Wrt_Halo = config->GetWrt_Halo(), isPeriodic; + + /*--- Local variables needed for merging the geometry with MPI. ---*/ + + unsigned long iVertex, iMarker; + unsigned long Buffer_Send_nPoin[1], *Buffer_Recv_nPoin = NULL; + unsigned long nLocalPoint = 0, MaxLocalPoint = 0; + unsigned long iGlobal_Index = 0, nBuffer_Scalar = 0; + + if (rank == MASTER_NODE) Buffer_Recv_nPoin = new unsigned long[nProcessor]; + + int *Local_Halo = new int[geometry->GetnPoint()]; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + Local_Halo[iPoint] = !geometry->node[iPoint]->GetDomain(); + + /*--- Search all send/recv boundaries on this partition for any periodic + nodes that were part of the original domain. We want to recover these + for visualization purposes. ---*/ + + if (Wrt_Halo) { + nLocalPoint = geometry->GetnPoint(); + } else { + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { + + /*--- Checking for less than or equal to the rank, because there may + be some periodic halo nodes that send info to the same rank. ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + isPeriodic = ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && + (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 1)); + if (isPeriodic) Local_Halo[iPoint] = false; + } + } + } + + /*--- Sum total number of nodes that belong to the domain ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + if (Local_Halo[iPoint] == false) + nLocalPoint++; + } + Buffer_Send_nPoin[0] = nLocalPoint; + + /*--- Communicate the total number of nodes on this domain. ---*/ + + SU2_MPI::Gather(&Buffer_Send_nPoin, 1, MPI_UNSIGNED_LONG, + Buffer_Recv_nPoin, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&nLocalPoint, &MaxLocalPoint, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + + if (rank == MASTER_NODE) { + nGlobal_Doma = 0; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + nGlobal_Doma += Buffer_Recv_nPoin[iProcessor]; + } + } + nBuffer_Scalar = MaxLocalPoint; + + /*--- Send and Recv buffers. ---*/ + + su2double *Buffer_Send_X = new su2double[MaxLocalPoint]; + su2double *Buffer_Recv_X = NULL; + + su2double *Buffer_Send_Y = new su2double[MaxLocalPoint]; + su2double *Buffer_Recv_Y = NULL; + + su2double *Buffer_Send_Z = NULL, *Buffer_Recv_Z = NULL; + if (nDim == 3) Buffer_Send_Z = new su2double[MaxLocalPoint]; + + unsigned long *Buffer_Send_GlobalIndex = new unsigned long[MaxLocalPoint]; + unsigned long *Buffer_Recv_GlobalIndex = NULL; + + /*--- Prepare the receive buffers in the master node only. ---*/ + + if (rank == MASTER_NODE) { + + Buffer_Recv_X = new su2double[nProcessor*MaxLocalPoint]; + Buffer_Recv_Y = new su2double[nProcessor*MaxLocalPoint]; + if (nDim == 3) Buffer_Recv_Z = new su2double[nProcessor*MaxLocalPoint]; + Buffer_Recv_GlobalIndex = new unsigned long[nProcessor*MaxLocalPoint]; + + /*--- Sum total number of nodes to be written and allocate arrays ---*/ + nGlobal_Poin = 0; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + nGlobal_Poin += Buffer_Recv_nPoin[iProcessor]; + } + Coords = new su2double*[nDim]; + for (iDim = 0; iDim < nDim; iDim++) { + Coords[iDim] = new su2double[nGlobal_Poin]; + } + } + + /*--- Main communication routine. Loop over each coordinate and perform + the MPI comm. Temporary 1-D buffers are used to send the coordinates at + all nodes on each partition to the master node. These are then unpacked + by the master and sorted by global index in one large n-dim. array. ---*/ + + /*--- Loop over this partition to collect the coords of the local points. ---*/ + su2double *Coords_Local; jPoint = 0; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check for halos and write only if requested ---*/ + if (!Local_Halo[iPoint] || Wrt_Halo) { + + /*--- Retrieve local coordinates at this node. ---*/ + Coords_Local = geometry->node[iPoint]->GetCoord(); + + /*--- Load local coords into the temporary send buffer. ---*/ + Buffer_Send_X[jPoint] = Coords_Local[0]; + Buffer_Send_Y[jPoint] = Coords_Local[1]; + if (nDim == 3) Buffer_Send_Z[jPoint] = Coords_Local[2]; + + /*--- If US system, the output should be in inches ---*/ + + if ((config->GetSystemMeasurements() == US) && (config->GetKind_SU2() != SU2_DEF)) { + Buffer_Send_X[jPoint] *= 12.0; + Buffer_Send_Y[jPoint] *= 12.0; + if (nDim == 3) Buffer_Send_Z[jPoint] *= 12.0; + } + + /*--- Store the global index for this local node. ---*/ + Buffer_Send_GlobalIndex[jPoint] = geometry->node[iPoint]->GetGlobalIndex(); + + /*--- Increment jPoint as the counter. We need this because iPoint + may include halo nodes that we skip over during this loop. ---*/ + jPoint++; + } + } + + /*--- Gather the coordinate data on the master node using MPI. ---*/ + + SU2_MPI::Gather(Buffer_Send_X, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_X, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Y, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Y, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + if (nDim == 3) { + SU2_MPI::Gather(Buffer_Send_Z, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Z, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + } + SU2_MPI::Gather(Buffer_Send_GlobalIndex, nBuffer_Scalar, MPI_UNSIGNED_LONG, Buffer_Recv_GlobalIndex, nBuffer_Scalar, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); + + /*--- The master node unpacks and sorts this variable by global index ---*/ + + if (rank == MASTER_NODE) { + jPoint = 0; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoin[iProcessor]; iPoint++) { + /*--- Get global index, then loop over each variable and store ---*/ + iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; + Coords[0][iGlobal_Index] = Buffer_Recv_X[jPoint]; + Coords[1][iGlobal_Index] = Buffer_Recv_Y[jPoint]; + if (nDim == 3) Coords[2][iGlobal_Index] = Buffer_Recv_Z[jPoint]; + jPoint++; + } + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + jPoint = (iProcessor+1)*nBuffer_Scalar; + } + } + + /*--- Immediately release the temporary data buffers. ---*/ + + delete [] Local_Halo; + delete [] Buffer_Send_X; + delete [] Buffer_Send_Y; + if (Buffer_Send_Z != NULL) delete [] Buffer_Send_Z; + delete [] Buffer_Send_GlobalIndex; + if (rank == MASTER_NODE) { + delete [] Buffer_Recv_X; + delete [] Buffer_Recv_Y; + if (Buffer_Recv_Z != NULL) delete [] Buffer_Recv_Z; + delete [] Buffer_Recv_GlobalIndex; + delete [] Buffer_Recv_nPoin; + } + +#endif + +} + +void COutput::MergeVolumetricConnectivity(CConfig *config, CGeometry *geometry, unsigned short Elem_Type) { + + int iProcessor; + unsigned short NODES_PER_ELEMENT; + unsigned long iPoint, iNode, jNode; + unsigned long iElem = 0; + unsigned long nLocalElem = 0, nElem_Total = 0; + + unsigned long iVertex, iMarker; + unsigned long jElem; + int SendRecv, RecvFrom; + + unsigned long Buffer_Send_nElem[1], *Buffer_Recv_nElem = NULL; + unsigned long nBuffer_Scalar = 0; + unsigned long kNode = 0, kElem = 0; + unsigned long MaxLocalElem = 0, iGlobal_Index, jPoint, kPoint; + + bool Wrt_Halo = config->GetWrt_Halo(); + bool *Write_Elem = NULL, notPeriodic, notHalo, addedPeriodic; + + int *Conn_Elem = NULL; + + int rank = MASTER_NODE; + int size = SINGLE_NODE; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); +#endif + + + /*--- Store the local number of this element type and the number of nodes + per this element type. In serial, this will be the total number of this + element type in the entire mesh. In parallel, it is the number on only + the current partition. ---*/ + + switch (Elem_Type) { + case TRIANGLE: + nLocalElem = geometry->GetnElemTria(); + NODES_PER_ELEMENT = N_POINTS_TRIANGLE; + break; + case QUADRILATERAL: + nLocalElem = geometry->GetnElemQuad(); + NODES_PER_ELEMENT = N_POINTS_QUADRILATERAL; + break; + case TETRAHEDRON: + nLocalElem = geometry->GetnElemTetr(); + NODES_PER_ELEMENT = N_POINTS_TETRAHEDRON; + break; + case HEXAHEDRON: + nLocalElem = geometry->GetnElemHexa(); + NODES_PER_ELEMENT = N_POINTS_HEXAHEDRON; + break; + case PRISM: + nLocalElem = geometry->GetnElemPris(); + NODES_PER_ELEMENT = N_POINTS_PRISM; + break; + case PYRAMID: + nLocalElem = geometry->GetnElemPyra(); + NODES_PER_ELEMENT = N_POINTS_PYRAMID; + break; + default: + cout << "Error: Unrecognized element type \n"; + exit(EXIT_FAILURE); break; + } + + /*--- Find the max number of this element type among all + partitions and set up buffers. ---*/ + + Buffer_Send_nElem[0] = nLocalElem; + if (rank == MASTER_NODE) Buffer_Recv_nElem = new unsigned long[size]; + +#ifdef HAVE_MPI + SU2_MPI::Allreduce(&nLocalElem, &MaxLocalElem, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Gather(&Buffer_Send_nElem, 1, MPI_UNSIGNED_LONG, Buffer_Recv_nElem, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); +#else + MaxLocalElem = nLocalElem; + Buffer_Recv_nElem[0] = Buffer_Send_nElem[0]; +#endif + + nBuffer_Scalar = MaxLocalElem*NODES_PER_ELEMENT; + + /*--- Send and Recv buffers ---*/ + + unsigned long *Buffer_Send_Elem = new unsigned long[nBuffer_Scalar]; + unsigned long *Buffer_Recv_Elem = NULL; + + unsigned short *Buffer_Send_Halo = new unsigned short[MaxLocalElem]; + unsigned short *Buffer_Recv_Halo = NULL; + + /*--- Prepare the receive buffers on the master node only. ---*/ + + if (rank == MASTER_NODE) { + Buffer_Recv_Elem = new unsigned long[size*nBuffer_Scalar]; + Buffer_Recv_Halo = new unsigned short[size*MaxLocalElem]; + Conn_Elem = new int[size*MaxLocalElem*NODES_PER_ELEMENT]; + } + + /*--- Force the removal of all added periodic elements (use global index). + First, we isolate and create a list of all added periodic points, excluding + those that we part of the original domain (we want these to be in the + output files). ---*/ + + vector Added_Periodic; + Added_Periodic.clear(); + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { + SendRecv = config->GetMarker_All_SendRecv(iMarker); + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && + (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 0) && + (SendRecv < 0)) { + Added_Periodic.push_back(geometry->node[iPoint]->GetGlobalIndex()); + } + } + } + } + + /*--- Now we communicate this information to all processors, so that they + can force the removal of these particular nodes by flagging them as halo + points. In general, this should be a small percentage of the total mesh, + so the communication/storage costs here shouldn't be prohibitive. ---*/ + + /*--- First communicate the number of points that each rank has found ---*/ + unsigned long nAddedPeriodic = 0, maxAddedPeriodic = 0; + unsigned long Buffer_Send_nAddedPeriodic[1], *Buffer_Recv_nAddedPeriodic = NULL; + Buffer_Recv_nAddedPeriodic = new unsigned long[size]; + + nAddedPeriodic = Added_Periodic.size(); + Buffer_Send_nAddedPeriodic[0] = nAddedPeriodic; + +#ifdef HAVE_MPI + SU2_MPI::Allreduce(&nAddedPeriodic, &maxAddedPeriodic, 1, MPI_UNSIGNED_LONG, + MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allgather(&Buffer_Send_nAddedPeriodic, 1, MPI_UNSIGNED_LONG, + Buffer_Recv_nAddedPeriodic, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); +#else + maxAddedPeriodic = nAddedPeriodic; + Buffer_Recv_nAddedPeriodic[0] = Buffer_Send_nAddedPeriodic[0]; +#endif + + /*--- Communicate the global index values of all added periodic nodes. ---*/ + unsigned long *Buffer_Send_AddedPeriodic = new unsigned long[maxAddedPeriodic]; + unsigned long *Buffer_Recv_AddedPeriodic = new unsigned long[size*maxAddedPeriodic]; + + for (iPoint = 0; iPoint < Added_Periodic.size(); iPoint++) { + Buffer_Send_AddedPeriodic[iPoint] = Added_Periodic[iPoint]; + } + + /*--- Gather the element connectivity information. All processors will now + have a copy of the global index values for all added periodic points. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Allgather(Buffer_Send_AddedPeriodic, maxAddedPeriodic, MPI_UNSIGNED_LONG, + Buffer_Recv_AddedPeriodic, maxAddedPeriodic, MPI_UNSIGNED_LONG, + MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < maxAddedPeriodic; iPoint++) Buffer_Recv_AddedPeriodic[iPoint] = Buffer_Send_AddedPeriodic[iPoint]; +#endif + + /*--- Search all send/recv boundaries on this partition for halo cells. In + particular, consider only the recv conditions (these are the true halo + nodes). Check the ranks of the processors that are communicating and + choose to keep only the halo cells from the higher rank processor. Here, + we are also choosing to keep periodic nodes that were part of the original + domain. We will check the communicated list of added periodic points. ---*/ + + int *Local_Halo = new int[geometry->GetnPoint()]; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + Local_Halo[iPoint] = !geometry->node[iPoint]->GetDomain(); + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { + SendRecv = config->GetMarker_All_SendRecv(iMarker); + RecvFrom = abs(SendRecv)-1; + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + iGlobal_Index = geometry->node[iPoint]->GetGlobalIndex(); + + /*--- We need to keep one copy of overlapping halo cells. ---*/ + notHalo = ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() == 0) && + (SendRecv < 0) && (rank > RecvFrom)); + + /*--- We want to keep the periodic nodes that were part of the original domain ---*/ + notPeriodic = ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && + (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 1) && + (SendRecv < 0)); + + /*--- Lastly, check that this isn't an added periodic point that + we will forcibly remove. Use the communicated list of these points. ---*/ + addedPeriodic = false; kPoint = 0; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (jPoint = 0; jPoint < Buffer_Recv_nAddedPeriodic[iProcessor]; jPoint++) { + if (iGlobal_Index == Buffer_Recv_AddedPeriodic[kPoint+jPoint]) + addedPeriodic = true; + } + /*--- Adjust jNode to index of next proc's data in the buffers. ---*/ + kPoint = (iProcessor+1)*maxAddedPeriodic; + } + + /*--- If we found either of these types of nodes, flag them to be kept. ---*/ + if ((notHalo || notPeriodic) && !addedPeriodic) { + Local_Halo[iPoint] = false; + } + } + } + } + + /*--- Loop over all elements in this partition and load the + elements of the current type into the buffer to be sent to + the master node. ---*/ + + jNode = 0; jElem = 0; + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + if (geometry->elem[iElem]->GetVTK_Type() == Elem_Type) { + + /*--- Loop over all nodes in this element and load the + connectivity into the send buffer. ---*/ + + Buffer_Send_Halo[jElem] = false; + for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) { + + /*--- Store the global index values directly. ---*/ + + iPoint = geometry->elem[iElem]->GetNode(iNode); + Buffer_Send_Elem[jNode] = geometry->node[iPoint]->GetGlobalIndex(); + + /*--- Check if this is a halo node. If so, flag this element + as a halo cell. We will use this later to sort and remove + any duplicates from the connectivity list. ---*/ + + if (Local_Halo[iPoint]) { + Buffer_Send_Halo[jElem] = true; + } + + /*--- Increment jNode as the counter. We need this because iElem + may include other elements that we skip over during this loop. ---*/ + + jNode++; + } + jElem++; + } + } + + /*--- Gather the element connectivity information. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Elem, nBuffer_Scalar, MPI_UNSIGNED_LONG, Buffer_Recv_Elem, nBuffer_Scalar, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Halo, MaxLocalElem, MPI_UNSIGNED_SHORT, Buffer_Recv_Halo, MaxLocalElem, MPI_UNSIGNED_SHORT, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Elem[iPoint] = Buffer_Send_Elem[iPoint]; + for (iPoint = 0; iPoint < MaxLocalElem; iPoint++) Buffer_Recv_Halo[iPoint] = Buffer_Send_Halo[iPoint]; +#endif + + /*--- The master node unpacks and sorts the connectivity. ---*/ + + if (rank == MASTER_NODE) { + + /*--- We need to remove any duplicate elements (halo cells) that + exist on multiple partitions. Start by initializing all elements + to the "write" state by using a boolean array. ---*/ + + Write_Elem = new bool[size*MaxLocalElem]; + for (iElem = 0; iElem < size*MaxLocalElem; iElem++) { + Write_Elem[iElem] = true; + } + + /*--- Remove the rind layer from the solution only if requested ---*/ + + if (!Wrt_Halo) { + + /*--- Loop for flagging duplicate elements so that they are not + included in the final connectivity list. ---*/ + + kElem = 0; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iElem = 0; iElem < Buffer_Recv_nElem[iProcessor]; iElem++) { + + /*--- Check if this element was marked as a halo. ---*/ + if (Buffer_Recv_Halo[kElem+iElem]) + Write_Elem[kElem+iElem] = false; + + } + kElem = (iProcessor+1)*MaxLocalElem; + } + } + + /*--- Store the unique connectivity list for this element type. ---*/ + + jNode = 0; kNode = 0; jElem = 0; nElem_Total = 0; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iElem = 0; iElem < Buffer_Recv_nElem[iProcessor]; iElem++) { + + /*--- Only write the elements that were flagged for it. ---*/ + if (Write_Elem[jElem+iElem]) { + + /*--- Increment total count for this element type ---*/ + nElem_Total++; + + /*--- Get global index, then loop over each variable and store. + Note that we are adding one to the index value because CGNS/Tecplot + use 1-based indexing.---*/ + + for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) { + Conn_Elem[kNode] = (int)Buffer_Recv_Elem[jNode+iElem*NODES_PER_ELEMENT+iNode] + 1; + kNode++; + } + } + } + /*--- Adjust jNode to index of next proc's data in the buffers. ---*/ + jElem = (iProcessor+1)*MaxLocalElem; + jNode = (iProcessor+1)*nBuffer_Scalar; + } + } + + /*--- Immediately release the temporary buffers. ---*/ + delete [] Buffer_Send_Elem; + delete [] Buffer_Send_Halo; + delete [] Buffer_Recv_nAddedPeriodic; + delete [] Buffer_Send_AddedPeriodic; + delete [] Buffer_Recv_AddedPeriodic; + delete [] Local_Halo; + if (rank == MASTER_NODE) { + delete [] Buffer_Recv_nElem; + delete [] Buffer_Recv_Elem; + delete [] Buffer_Recv_Halo; + delete [] Write_Elem; + } + + /*--- Store the particular global element count in the class data, + and set the class data pointer to the connectivity array. ---*/ + + if (rank == MASTER_NODE) { + switch (Elem_Type) { + case TRIANGLE: + nGlobal_Tria = nElem_Total; + if (nGlobal_Tria > 0) Conn_Tria = Conn_Elem; + break; + case QUADRILATERAL: + nGlobal_Quad = nElem_Total; + if (nGlobal_Quad > 0) Conn_Quad = Conn_Elem; + break; + case TETRAHEDRON: + nGlobal_Tetr = nElem_Total; + if (nGlobal_Tetr > 0) Conn_Tetr = Conn_Elem; + break; + case HEXAHEDRON: + nGlobal_Hexa = nElem_Total; + if (nGlobal_Hexa > 0) Conn_Hexa = Conn_Elem; + break; + case PRISM: + nGlobal_Pris = nElem_Total; + if (nGlobal_Pris > 0) Conn_Pris = Conn_Elem; + break; + case PYRAMID: + nGlobal_Pyra = nElem_Total; + if (nGlobal_Pyra > 0) Conn_Pyra = Conn_Elem; + break; + default: + cout << "Error: Unrecognized element type \n"; + exit(EXIT_FAILURE); break; + } + } + +} + +void COutput::MergeSurfaceConnectivity(CConfig *config, CGeometry *geometry, unsigned short Elem_Type) { + + unsigned short NODES_PER_ELEMENT; + + unsigned short iMarker; + unsigned long iPoint, iNode, jNode; + unsigned long iElem = 0; + unsigned long nLocalElem = 0, nElem_Total = 0; + + int iProcessor; + unsigned long jElem; + + unsigned long iVertex; + + int SendRecv, RecvFrom; + + unsigned long Buffer_Send_nElem[1], *Buffer_Recv_nElem = NULL; + unsigned long nBuffer_Scalar = 0; + unsigned long kNode = 0, kElem = 0; + unsigned long MaxLocalElem = 0, iGlobal_Index, jPoint, kPoint; + + bool Wrt_Halo = config->GetWrt_Halo(); + bool *Write_Elem = NULL, notPeriodic, notHalo, addedPeriodic; + + + int *Conn_Elem = NULL; + + int rank = MASTER_NODE; + int size = SINGLE_NODE; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); +#endif + + /*--- Store the local number of this element type and the number of nodes + per this element type. In serial, this will be the total number of this + element type in the entire mesh. In parallel, it is the number on only + the current partition. ---*/ + + nLocalElem = 0; + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_Plotting(iMarker) == YES) { + for (iElem = 0; iElem < geometry->GetnElem_Bound(iMarker); iElem++) { + if (geometry->bound[iMarker][iElem]->GetVTK_Type() == Elem_Type) { + nLocalElem++; + } + } + } + } + + switch (Elem_Type) { + case LINE: + NODES_PER_ELEMENT = N_POINTS_LINE; + break; + case TRIANGLE: + NODES_PER_ELEMENT = N_POINTS_TRIANGLE; + break; + case QUADRILATERAL: + NODES_PER_ELEMENT = N_POINTS_QUADRILATERAL; + break; + default: + cout << "Error: Unrecognized element type \n"; + exit(EXIT_FAILURE); break; + } + + /*--- Find the max number of this element type among all + partitions and set up buffers. ---*/ + + Buffer_Send_nElem[0] = nLocalElem; + if (rank == MASTER_NODE) Buffer_Recv_nElem = new unsigned long[size]; + +#ifdef HAVE_MPI + SU2_MPI::Allreduce(&nLocalElem, &MaxLocalElem, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Gather(&Buffer_Send_nElem, 1, MPI_UNSIGNED_LONG, Buffer_Recv_nElem, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); +#else + MaxLocalElem = nLocalElem; + Buffer_Recv_nElem[0] = Buffer_Send_nElem[0]; +#endif + + nBuffer_Scalar = MaxLocalElem*NODES_PER_ELEMENT; + + /*--- Send and Recv buffers ---*/ + + unsigned long *Buffer_Send_Elem = new unsigned long[nBuffer_Scalar]; + unsigned long *Buffer_Recv_Elem = NULL; + + unsigned short *Buffer_Send_Halo = new unsigned short[MaxLocalElem]; + unsigned short *Buffer_Recv_Halo = NULL; + + /*--- Prepare the receive buffers on the master node only. ---*/ + + if (rank == MASTER_NODE) { + Buffer_Recv_Elem = new unsigned long[size*nBuffer_Scalar]; + Buffer_Recv_Halo = new unsigned short[size*MaxLocalElem]; + Conn_Elem = new int[size*MaxLocalElem*NODES_PER_ELEMENT]; + } + + /*--- Force the removal of all added periodic elements (use global index). + First, we isolate and create a list of all added periodic points, excluding + those that we part of the original domain (we want these to be in the + output files). ---*/ + + vector Added_Periodic; + Added_Periodic.clear(); + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { + SendRecv = config->GetMarker_All_SendRecv(iMarker); + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && + (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 0) && + (SendRecv < 0)) { + Added_Periodic.push_back(geometry->node[iPoint]->GetGlobalIndex()); + } + } + } + } + + /*--- Now we communicate this information to all processors, so that they + can force the removal of these particular nodes by flagging them as halo + points. In general, this should be a small percentage of the total mesh, + so the communication/storage costs here shouldn't be prohibitive. ---*/ + + /*--- First communicate the number of points that each rank has found ---*/ + unsigned long nAddedPeriodic = 0, maxAddedPeriodic = 0; + unsigned long Buffer_Send_nAddedPeriodic[1], *Buffer_Recv_nAddedPeriodic = NULL; + Buffer_Recv_nAddedPeriodic = new unsigned long[size]; + + nAddedPeriodic = Added_Periodic.size(); + Buffer_Send_nAddedPeriodic[0] = nAddedPeriodic; + +#ifdef HAVE_MPI + SU2_MPI::Allreduce(&nAddedPeriodic, &maxAddedPeriodic, 1, MPI_UNSIGNED_LONG, + MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allgather(&Buffer_Send_nAddedPeriodic, 1, MPI_UNSIGNED_LONG, + Buffer_Recv_nAddedPeriodic, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); +#else + maxAddedPeriodic = nAddedPeriodic; + Buffer_Recv_nAddedPeriodic[0] = Buffer_Send_nAddedPeriodic[0]; +#endif + + /*--- Communicate the global index values of all added periodic nodes. ---*/ + unsigned long *Buffer_Send_AddedPeriodic = new unsigned long[maxAddedPeriodic]; + unsigned long *Buffer_Recv_AddedPeriodic = new unsigned long[size*maxAddedPeriodic]; + + for (iPoint = 0; iPoint < Added_Periodic.size(); iPoint++) { + Buffer_Send_AddedPeriodic[iPoint] = Added_Periodic[iPoint]; + } + + /*--- Gather the element connectivity information. All processors will now + have a copy of the global index values for all added periodic points. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Allgather(Buffer_Send_AddedPeriodic, maxAddedPeriodic, MPI_UNSIGNED_LONG, + Buffer_Recv_AddedPeriodic, maxAddedPeriodic, MPI_UNSIGNED_LONG, + MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < maxAddedPeriodic; iPoint++) Buffer_Recv_AddedPeriodic[iPoint] = Buffer_Send_AddedPeriodic[iPoint]; +#endif + + /*--- Search all send/recv boundaries on this partition for halo cells. In + particular, consider only the recv conditions (these are the true halo + nodes). Check the ranks of the processors that are communicating and + choose to keep only the halo cells from the higher rank processor. Here, + we are also choosing to keep periodic nodes that were part of the original + domain. We will check the communicated list of added periodic points. ---*/ + + int *Local_Halo = new int[geometry->GetnPoint()]; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + Local_Halo[iPoint] = !geometry->node[iPoint]->GetDomain(); + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { + SendRecv = config->GetMarker_All_SendRecv(iMarker); + RecvFrom = abs(SendRecv)-1; + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + iGlobal_Index = geometry->node[iPoint]->GetGlobalIndex(); + + /*--- We need to keep one copy of overlapping halo cells. ---*/ + notHalo = ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() == 0) && + (SendRecv < 0) && (rank > RecvFrom)); + + /*--- We want to keep the periodic nodes that were part of the original domain ---*/ + notPeriodic = ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && + (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 1) && + (SendRecv < 0)); + + /*--- Lastly, check that this isn't an added periodic point that + we will forcibly remove. Use the communicated list of these points. ---*/ + addedPeriodic = false; kPoint = 0; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (jPoint = 0; jPoint < Buffer_Recv_nAddedPeriodic[iProcessor]; jPoint++) { + if (iGlobal_Index == Buffer_Recv_AddedPeriodic[kPoint+jPoint]) + addedPeriodic = true; + } + /*--- Adjust jNode to index of next proc's data in the buffers. ---*/ + kPoint = (iProcessor+1)*maxAddedPeriodic; + } + + /*--- If we found either of these types of nodes, flag them to be kept. ---*/ + if ((notHalo || notPeriodic) && !addedPeriodic) { + Local_Halo[iPoint] = false; + } + } + } + } + + /*--- Loop over all elements in this partition and load the + elements of the current type into the buffer to be sent to + the master node. ---*/ + jNode = 0; jElem = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_Plotting(iMarker) == YES) + for (iElem = 0; iElem < geometry->GetnElem_Bound(iMarker); iElem++) { + + if (geometry->bound[iMarker][iElem]->GetVTK_Type() == Elem_Type) { + + /*--- Loop over all nodes in this element and load the + connectivity into the send buffer. ---*/ + + Buffer_Send_Halo[jElem] = false; + for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) { + + /*--- Store the global index values directly. ---*/ + + iPoint = geometry->bound[iMarker][iElem]->GetNode(iNode); + Buffer_Send_Elem[jNode] = geometry->node[iPoint]->GetGlobalIndex(); + + /*--- Check if this is a halo node. If so, flag this element + as a halo cell. We will use this later to sort and remove + any duplicates from the connectivity list. ---*/ + + if (Local_Halo[iPoint]) + Buffer_Send_Halo[jElem] = true; + + /*--- Increment jNode as the counter. We need this because iElem + may include other elements that we skip over during this loop. ---*/ + + jNode++; + } + jElem++; + } + } + + /*--- Gather the element connectivity information. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Elem, nBuffer_Scalar, MPI_UNSIGNED_LONG, Buffer_Recv_Elem, nBuffer_Scalar, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Halo, MaxLocalElem, MPI_UNSIGNED_SHORT, Buffer_Recv_Halo, MaxLocalElem, MPI_UNSIGNED_SHORT, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Elem[iPoint] = Buffer_Send_Elem[iPoint]; + for (iPoint = 0; iPoint < MaxLocalElem; iPoint++) Buffer_Recv_Halo[iPoint] = Buffer_Send_Halo[iPoint]; +#endif + + /*--- The master node unpacks and sorts the connectivity. ---*/ + + if (rank == MASTER_NODE) { + + /*--- We need to remove any duplicate elements (halo cells) that + exist on multiple partitions. Start by initializing all elements + to the "write" state by using a boolean array. ---*/ + + Write_Elem = new bool[size*MaxLocalElem]; + for (iElem = 0; iElem < size*MaxLocalElem; iElem++) { + Write_Elem[iElem] = true; + } + + /*--- Remove the rind layer from the solution only if requested ---*/ + + if (!Wrt_Halo) { + + /*--- Loop for flagging duplicate elements so that they are not + included in the final connectivity list. ---*/ + + kElem = 0; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iElem = 0; iElem < Buffer_Recv_nElem[iProcessor]; iElem++) { + + /*--- Check if this element was marked as a halo. ---*/ + if (Buffer_Recv_Halo[kElem+iElem]) + Write_Elem[kElem+iElem] = false; + + } + kElem = (iProcessor+1)*MaxLocalElem; + } + } + + /*--- Store the unique connectivity list for this element type. ---*/ + + jNode = 0; kNode = 0; jElem = 0; nElem_Total = 0; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iElem = 0; iElem < Buffer_Recv_nElem[iProcessor]; iElem++) { + + /*--- Only write the elements that were flagged for it. ---*/ + if (Write_Elem[jElem+iElem]) { + + /*--- Increment total count for this element type ---*/ + nElem_Total++; + + /*--- Get global index, then loop over each variable and store. + Note that we are adding one to the index value because CGNS/Tecplot + use 1-based indexing.---*/ + + for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) { + Conn_Elem[kNode] = (int)Buffer_Recv_Elem[jNode+iElem*NODES_PER_ELEMENT+iNode] + 1; + kNode++; + } + } + } + /*--- Adjust jNode to index of next proc's data in the buffers. ---*/ + jElem = (iProcessor+1)*MaxLocalElem; + jNode = (iProcessor+1)*nBuffer_Scalar; + } + } + + /*--- Immediately release the temporary buffers. ---*/ + delete [] Buffer_Send_Elem; + delete [] Buffer_Send_Halo; + delete [] Buffer_Recv_nAddedPeriodic; + delete [] Buffer_Send_AddedPeriodic; + delete [] Buffer_Recv_AddedPeriodic; + delete [] Local_Halo; + if (rank == MASTER_NODE) { + delete [] Buffer_Recv_nElem; + delete [] Buffer_Recv_Elem; + delete [] Buffer_Recv_Halo; + delete [] Write_Elem; + } + + /*--- Store the particular global element count in the class data, + and set the class data pointer to the connectivity array. ---*/ + + if (rank == MASTER_NODE) { + switch (Elem_Type) { + case LINE: + nGlobal_Line = nElem_Total; + if (nGlobal_Line > 0) Conn_Line = Conn_Elem; + break; + case TRIANGLE: + nGlobal_BoundTria = nElem_Total; + if (nGlobal_BoundTria > 0) Conn_BoundTria = Conn_Elem; + break; + case QUADRILATERAL: + nGlobal_BoundQuad = nElem_Total; + if (nGlobal_BoundQuad > 0) Conn_BoundQuad = Conn_Elem; + break; + default: + cout << "Error: Unrecognized element type \n"; + exit(EXIT_FAILURE); break; + } + } + +} + +void COutput::MergeSolution(CConfig *config, CGeometry *geometry, CSolver **solver, unsigned short val_iZone) { + + unsigned short Kind_Solver = config->GetKind_Solver(); + unsigned short iVar = 0, jVar = 0, FirstIndex = NONE, SecondIndex = NONE, ThirdIndex = NONE; + unsigned short nVar_First = 0, nVar_Second = 0, nVar_Third = 0; + unsigned short iVar_GridVel = 0, iVar_PressCp = 0, iVar_Density = 0, iVar_Lam = 0, iVar_MachMean = 0, + iVar_ViscCoeffs = 0, iVar_Sens = 0, iVar_Extra = 0, iVar_Eddy = 0, iVar_Sharp = 0, + iVar_FEA_Stress = 0, iVar_FEA_Stress_3D = 0, iVar_FEA_Extra = 0, iVar_SensDim = 0; + + unsigned long iPoint = 0, jPoint = 0, iVertex = 0, iMarker = 0; + su2double Gas_Constant, Mach2Vel, Mach_Motion, RefDensity, RefPressure = 0.0, factor = 0.0; + + su2double *Aux_Frict = NULL, *Aux_Heat = NULL, *Aux_yPlus = NULL, *Aux_Sens = NULL; + + unsigned short CurrentIndex; + int *Local_Halo; + unsigned long Buffer_Send_nPoint[1], *Buffer_Recv_nPoint = NULL; + unsigned long nLocalPoint = 0, MaxLocalPoint = 0; + unsigned long iGlobal_Index = 0, nBuffer_Scalar = 0; + bool Wrt_Halo = config->GetWrt_Halo(), isPeriodic; + + int iProcessor; + int rank = MASTER_NODE; + int size = SINGLE_NODE; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); +#endif + + bool grid_movement = (config->GetGrid_Movement()); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool transition = (config->GetKind_Trans_Model() == LM); + bool flow = (( config->GetKind_Solver() == EULER ) || + ( config->GetKind_Solver() == NAVIER_STOKES ) || + ( config->GetKind_Solver() == RANS ) || + ( config->GetKind_Solver() == ADJ_EULER ) || + ( config->GetKind_Solver() == ADJ_NAVIER_STOKES ) || + ( config->GetKind_Solver() == ADJ_RANS ) ); + + unsigned short iDim; + unsigned short nDim = geometry->GetnDim(); + su2double RefAreaCoeff = config->GetRefAreaCoeff(); + su2double Gamma = config->GetGamma(); + su2double RefVel2, *Normal, Area; + + /*--- Set the non-dimensionalization ---*/ + if (flow) { + if (grid_movement) { + Gas_Constant = config->GetGas_ConstantND(); + Mach2Vel = sqrt(Gamma*Gas_Constant*config->GetTemperature_FreeStreamND()); + Mach_Motion = config->GetMach_Motion(); + RefVel2 = (Mach_Motion*Mach2Vel)*(Mach_Motion*Mach2Vel); + } + else { + RefVel2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + RefVel2 += solver[FLOW_SOL]->GetVelocity_Inf(iDim)*solver[FLOW_SOL]->GetVelocity_Inf(iDim); + } + RefDensity = solver[FLOW_SOL]->GetDensity_Inf(); + RefPressure = solver[FLOW_SOL]->GetPressure_Inf(); + factor = 1.0 / (0.5*RefDensity*RefAreaCoeff*RefVel2); + } + + /*--- Prepare send buffers for the conservative variables. Need to + find the total number of conservative variables and also the + index for their particular solution container. ---*/ + + switch (Kind_Solver) { + case EULER : case NAVIER_STOKES: FirstIndex = FLOW_SOL; SecondIndex = NONE; ThirdIndex = NONE; break; + case RANS : FirstIndex = FLOW_SOL; SecondIndex = TURB_SOL; if (transition) ThirdIndex=TRANS_SOL; else ThirdIndex = NONE; break; + case POISSON_EQUATION: FirstIndex = POISSON_SOL; SecondIndex = NONE; ThirdIndex = NONE; break; + case WAVE_EQUATION: FirstIndex = WAVE_SOL; SecondIndex = NONE; ThirdIndex = NONE; break; + case HEAT_EQUATION: FirstIndex = HEAT_SOL; SecondIndex = NONE; ThirdIndex = NONE; break; + case LINEAR_ELASTICITY: FirstIndex = FEA_SOL; SecondIndex = NONE; ThirdIndex = NONE; break; + case ADJ_EULER : case ADJ_NAVIER_STOKES : FirstIndex = ADJFLOW_SOL; SecondIndex = NONE; ThirdIndex = NONE; break; + case ADJ_RANS : FirstIndex = ADJFLOW_SOL; if (config->GetFrozen_Visc()) SecondIndex = NONE; else SecondIndex = ADJTURB_SOL; ThirdIndex = NONE; break; + case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: FirstIndex = ADJFLOW_SOL; SecondIndex = NONE; ThirdIndex = NONE; break; + case DISC_ADJ_RANS: FirstIndex = ADJFLOW_SOL; SecondIndex = ADJTURB_SOL; ThirdIndex = NONE; break; + default: SecondIndex = NONE; ThirdIndex = NONE; break; + } + + nVar_First = solver[FirstIndex]->GetnVar(); + if (SecondIndex != NONE) nVar_Second = solver[SecondIndex]->GetnVar(); + if (ThirdIndex != NONE) nVar_Third = solver[ThirdIndex]->GetnVar(); + nVar_Consv = nVar_First + nVar_Second + nVar_Third; + nVar_Total = nVar_Consv; + + if (!config->GetLow_MemoryOutput()) { + + /*--- Add the limiters ---*/ + + if (config->GetWrt_Limiters()) nVar_Total += nVar_Consv; + + /*--- Add the residuals ---*/ + + if (config->GetWrt_Residuals()) nVar_Total += nVar_Consv; + + /*--- Add the grid velocity to the restart file for the unsteady adjoint ---*/ + + if (grid_movement) { + iVar_GridVel = nVar_Total; + if (geometry->GetnDim() == 2) nVar_Total += 2; + else if (geometry->GetnDim() == 3) nVar_Total += 3; + } + + /*--- Add density to the restart file ---*/ + + if ((config->GetKind_Regime() == FREESURFACE)) { + iVar_Density = nVar_Total; nVar_Total += 1; + } + + /*--- Add Pressure, Temperature, Cp, Mach to the restart file ---*/ + + if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + iVar_PressCp = nVar_Total; nVar_Total += 3; + iVar_MachMean = nVar_Total; nVar_Total += 1; + } + + /*--- Add Laminar Viscosity, Skin Friction, Heat Flux, & yPlus to the restart file ---*/ + + if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + iVar_Lam = nVar_Total; nVar_Total += 1; + iVar_ViscCoeffs = nVar_Total; nVar_Total += 3; + } + + /*--- Add Eddy Viscosity to the restart file ---*/ + + if (Kind_Solver == RANS) { + iVar_Eddy = nVar_Total; nVar_Total += 1; + } + + /*--- Add Sharp edges to the restart file ---*/ + + if (config->GetWrt_SharpEdges()) { + if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + iVar_Sharp = nVar_Total; nVar_Total += 1; + } + } + + //if (Kind_Solver == POISSON_EQUATION) { + // iVar_EF = nVar_Total; nVar_Total += geometry->GetnDim(); + //} + + if (( Kind_Solver == ADJ_EULER ) || ( Kind_Solver == ADJ_NAVIER_STOKES ) || + ( Kind_Solver == ADJ_RANS )) { + iVar_Sens = nVar_Total; nVar_Total += 2; + } + + if (Kind_Solver == LINEAR_ELASTICITY) { + iVar_FEA_Stress = nVar_Total; nVar_Total += 3; + if (geometry->GetnDim() == 3) {iVar_FEA_Stress_3D = nVar_Total; nVar_Total += 3;} + iVar_FEA_Extra = nVar_Total; nVar_Total += 2; + } + + if ((Kind_Solver == DISC_ADJ_EULER) || + (Kind_Solver == DISC_ADJ_NAVIER_STOKES) || + (Kind_Solver == DISC_ADJ_RANS)){ + iVar_Sens = nVar_Total; nVar_Total += 1; + iVar_SensDim = nVar_Total; nVar_Total += nDim; + } + + if (config->GetExtraOutput()) { + if (Kind_Solver == RANS) { + iVar_Extra = nVar_Total; nVar_Extra = solver[TURB_SOL]->GetnOutputVariables(); nVar_Total += nVar_Extra; + } + } + + } + + Local_Halo = new int[geometry->GetnPoint()]; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + Local_Halo[iPoint] = !geometry->node[iPoint]->GetDomain(); + + /*--- Search all send/recv boundaries on this partition for any periodic + nodes that were part of the original domain. We want to recover these + for visualization purposes. ---*/ + + if (Wrt_Halo) { + nLocalPoint = geometry->GetnPoint(); + } else { + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { + + /*--- Checking for less than or equal to the rank, because there may + be some periodic halo nodes that send info to the same rank. ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + isPeriodic = ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && + (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 1)); + if (isPeriodic) Local_Halo[iPoint] = false; + } + } + } + + /*--- Sum total number of nodes that belong to the domain ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + if (Local_Halo[iPoint] == false) + nLocalPoint++; + + } + Buffer_Send_nPoint[0] = nLocalPoint; + + /*--- Each processor sends its local number of nodes to the master. ---*/ + + if (rank == MASTER_NODE) Buffer_Recv_nPoint = new unsigned long[size]; + +#ifdef HAVE_MPI + SU2_MPI::Allreduce(&nLocalPoint, &MaxLocalPoint, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Gather(&Buffer_Send_nPoint, 1, MPI_UNSIGNED_LONG, Buffer_Recv_nPoint, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); +#else + MaxLocalPoint = nLocalPoint; + Buffer_Recv_nPoint[0] = Buffer_Send_nPoint[0]; +#endif + + nBuffer_Scalar = MaxLocalPoint; + + /*--- Send and Recv buffers. ---*/ + + su2double *Buffer_Send_Var = new su2double[MaxLocalPoint]; + su2double *Buffer_Recv_Var = NULL; + + su2double *Buffer_Send_Res = new su2double[MaxLocalPoint]; + su2double *Buffer_Recv_Res = NULL; + + su2double *Buffer_Send_Vol = new su2double[MaxLocalPoint]; + su2double *Buffer_Recv_Vol = NULL; + + unsigned long *Buffer_Send_GlobalIndex = new unsigned long[MaxLocalPoint]; + unsigned long *Buffer_Recv_GlobalIndex = NULL; + + /*--- Auxiliary vectors for surface coefficients ---*/ + + if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + Aux_Frict = new su2double[geometry->GetnPoint()]; + Aux_Heat = new su2double[geometry->GetnPoint()]; + Aux_yPlus = new su2double[geometry->GetnPoint()]; + } + + if ((Kind_Solver == ADJ_EULER) || + (Kind_Solver == ADJ_NAVIER_STOKES) || + (Kind_Solver == ADJ_RANS) || + (Kind_Solver == DISC_ADJ_EULER) || + (Kind_Solver == DISC_ADJ_NAVIER_STOKES) || + (Kind_Solver == DISC_ADJ_RANS)) { + Aux_Sens = new su2double[geometry->GetnPoint()]; + } + + /*--- Prepare the receive buffers in the master node only. ---*/ + + if (rank == MASTER_NODE) { + + Buffer_Recv_Var = new su2double[size*MaxLocalPoint]; + Buffer_Recv_Res = new su2double[size*MaxLocalPoint]; + Buffer_Recv_Vol = new su2double[size*MaxLocalPoint]; + Buffer_Recv_GlobalIndex = new unsigned long[size*MaxLocalPoint]; + + /*--- Sum total number of nodes to be written and allocate arrays ---*/ + nGlobal_Poin = 0; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + nGlobal_Poin += Buffer_Recv_nPoint[iProcessor]; + } + Data = new su2double*[nVar_Total]; + for (iVar = 0; iVar < nVar_Total; iVar++) { + Data[iVar] = new su2double[nGlobal_Poin]; + } + } + + /*--- Main communication routine. Loop over each variable that has + been requested by the user and perform the MPI comm. Temporary + 1-D buffers are used to send the solution for each variable at all + nodes on each partition to the master node. These are then unpacked + by the master and sorted by global index in one large n-dim. array. ---*/ + + for (iVar = 0; iVar < nVar_Consv; iVar++) { + + /*--- Logic for which solution class to draw from. ---*/ + + jVar = iVar; + CurrentIndex = FirstIndex; + if ((SecondIndex != NONE) && (iVar > nVar_First-1)) { + jVar = iVar - nVar_First; + CurrentIndex = SecondIndex; + } + if ((SecondIndex != NONE) && (ThirdIndex != NONE) && (iVar > (nVar_First + nVar_Second-1))) { + jVar = iVar - nVar_First - nVar_Second; + CurrentIndex = ThirdIndex; + } + + /*--- Loop over this partition to collect the current variable ---*/ + + jPoint = 0; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check for halos & write only if requested ---*/ + + if (!Local_Halo[iPoint] || Wrt_Halo) { + + /*--- Get this variable into the temporary send buffer. ---*/ + + Buffer_Send_Var[jPoint] = solver[CurrentIndex]->node[iPoint]->GetSolution(jVar); + + if (!config->GetLow_MemoryOutput()) { + + if (config->GetWrt_Limiters()) { + Buffer_Send_Vol[jPoint] = solver[CurrentIndex]->node[iPoint]->GetLimiter_Primitive(jVar); + } + + if (config->GetWrt_Residuals()) { + Buffer_Send_Res[jPoint] = solver[CurrentIndex]->LinSysRes.GetBlock(iPoint, jVar); + } + + } + + /*--- Only send/recv the volumes & global indices during the first loop ---*/ + + if (iVar == 0) { + Buffer_Send_GlobalIndex[jPoint] = geometry->node[iPoint]->GetGlobalIndex(); + } + + jPoint++; + + } + } + + /*--- Gather the data on the master node. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; +#endif + if (!config->GetLow_MemoryOutput()) { + + if (config->GetWrt_Limiters()) { +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Vol, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Vol, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Vol[iPoint] = Buffer_Send_Vol[iPoint]; +#endif + } + + if (config->GetWrt_Residuals()) { +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; +#endif + } + + } + + if (iVar == 0) { +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_GlobalIndex, nBuffer_Scalar, MPI_UNSIGNED_LONG, Buffer_Recv_GlobalIndex, nBuffer_Scalar, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_GlobalIndex[iPoint] = Buffer_Send_GlobalIndex[iPoint]; +#endif + } + + /*--- The master node unpacks and sorts this variable by global index ---*/ + + if (rank == MASTER_NODE) { + jPoint = 0; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { + + /*--- Get global index, then loop over each variable and store ---*/ + + iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; + + Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; + + if (!config->GetLow_MemoryOutput()) { + + if (config->GetWrt_Limiters()) { + Data[iVar+nVar_Consv][iGlobal_Index] = Buffer_Recv_Vol[jPoint]; + } + + if (config->GetWrt_Residuals()) { + unsigned short ExtraIndex; + ExtraIndex = nVar_Consv; + if (config->GetWrt_Limiters()) ExtraIndex = 2*nVar_Consv; + Data[iVar+ExtraIndex][iGlobal_Index] = Buffer_Recv_Res[jPoint]; + } + + } + + jPoint++; + } + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + jPoint = (iProcessor+1)*nBuffer_Scalar; + } + } + + } + + if (!config->GetLow_MemoryOutput()) { + + /*--- Additional communication routine for the grid velocity. Note that + we are reusing the same temporary buffers from above for efficiency. + Also, in the future more routines like this could be used to write + an arbitrary number of additional variables to the file. ---*/ + + if (grid_movement) { + + /*--- Loop over this partition to collect the current variable ---*/ + + jPoint = 0; su2double *Grid_Vel; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check for halos & write only if requested ---*/ + + if (!Local_Halo[iPoint] || Wrt_Halo) { + + /*--- Load buffers with the three grid velocity components. ---*/ + + Grid_Vel = geometry->node[iPoint]->GetGridVel(); + Buffer_Send_Var[jPoint] = Grid_Vel[0]; + Buffer_Send_Res[jPoint] = Grid_Vel[1]; + if (geometry->GetnDim() == 3) Buffer_Send_Vol[jPoint] = Grid_Vel[2]; + jPoint++; + } + } + + /*--- Gather the data on the master node. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + if (geometry->GetnDim() == 3) { + SU2_MPI::Gather(Buffer_Send_Vol, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Vol, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + } +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; + if (geometry->GetnDim() == 3) { + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Vol[iPoint] = Buffer_Send_Vol[iPoint]; + } +#endif + + /*--- The master node unpacks and sorts this variable by global index ---*/ + + if (rank == MASTER_NODE) { + jPoint = 0; iVar = iVar_GridVel; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { + + /*--- Get global index, then loop over each variable and store ---*/ + + iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; + Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; + Data[iVar+1][iGlobal_Index] = Buffer_Recv_Res[jPoint]; + if (geometry->GetnDim() == 3) + Data[iVar+2][iGlobal_Index] = Buffer_Recv_Vol[jPoint]; + jPoint++; + } + + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + + jPoint = (iProcessor+1)*nBuffer_Scalar; + } + } + } + + /*--- Communicate the Density in Free-surface problems ---*/ + + if (config->GetKind_Regime() == FREESURFACE) { + + /*--- Loop over this partition to collect the current variable ---*/ + + jPoint = 0; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check for halos & write only if requested ---*/ + + if (!Local_Halo[iPoint] || Wrt_Halo) { + + /*--- Load buffers with the pressure and mach variables. ---*/ + Buffer_Send_Var[jPoint] = solver[FLOW_SOL]->node[iPoint]->GetDensityInc(); + jPoint++; + } + } + + /*--- Gather the data on the master node. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; +#endif + + /*--- The master node unpacks and sorts this variable by global index ---*/ + + if (rank == MASTER_NODE) { + jPoint = 0; iVar = iVar_Density; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { + + /*--- Get global index, then loop over each variable and store ---*/ + + iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; + Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; + jPoint++; + } + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + + jPoint = (iProcessor+1)*nBuffer_Scalar; + } + } + + } + + /*--- Communicate Pressure, Cp, and Mach ---*/ + + if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + + /*--- First, loop through the mesh in order to find and store the + value of the coefficient of pressure at any surface nodes. They + will be placed in an auxiliary vector and then communicated like + all other volumetric variables. ---*/ + + /*--- Loop over this partition to collect the current variable ---*/ + + jPoint = 0; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check for halos & write only if requested ---*/ + + if (!Local_Halo[iPoint] || Wrt_Halo) { + + /*--- Load buffers with the pressure, Cp, and mach variables. ---*/ + + if (compressible) { + Buffer_Send_Var[jPoint] = solver[FLOW_SOL]->node[iPoint]->GetPressure(); + Buffer_Send_Res[jPoint] = solver[FLOW_SOL]->node[iPoint]->GetTemperature(); + Buffer_Send_Vol[jPoint] = (solver[FLOW_SOL]->node[iPoint]->GetPressure() - RefPressure)*factor*RefAreaCoeff; + } + if (incompressible || freesurface) { + Buffer_Send_Var[jPoint] = solver[FLOW_SOL]->node[iPoint]->GetPressureInc(); + Buffer_Send_Res[jPoint] = 0.0; + Buffer_Send_Vol[jPoint] = (solver[FLOW_SOL]->node[iPoint]->GetPressureInc() - RefPressure)*factor*RefAreaCoeff; + } + jPoint++; + } + } + + /*--- Gather the data on the master node. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Vol, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Vol, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Vol[iPoint] = Buffer_Send_Vol[iPoint]; +#endif + + /*--- The master node unpacks and sorts this variable by global index ---*/ + + if (rank == MASTER_NODE) { + jPoint = 0; iVar = iVar_PressCp; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { + + /*--- Get global index, then loop over each variable and store ---*/ + + iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; + Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; + Data[iVar+1][iGlobal_Index] = Buffer_Recv_Res[jPoint]; + Data[iVar+2][iGlobal_Index] = Buffer_Recv_Vol[jPoint]; + jPoint++; + } + + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + + jPoint = (iProcessor+1)*nBuffer_Scalar; + } + } + } + + /*--- Communicate Mach---*/ + + if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + + /*--- Loop over this partition to collect the current variable ---*/ + + jPoint = 0; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check for halos & write only if requested ---*/ + + if (!Local_Halo[iPoint] || Wrt_Halo) { + + /*--- Load buffers with the temperature and laminar viscosity variables. ---*/ + + if (compressible) { + Buffer_Send_Var[jPoint] = sqrt(solver[FLOW_SOL]->node[iPoint]->GetVelocity2())/ + solver[FLOW_SOL]->node[iPoint]->GetSoundSpeed(); + } + if (incompressible || freesurface) { + Buffer_Send_Var[jPoint] = sqrt(solver[FLOW_SOL]->node[iPoint]->GetVelocity2())*config->GetVelocity_Ref()/ + sqrt(config->GetBulk_Modulus()/(solver[FLOW_SOL]->node[iPoint]->GetDensityInc()*config->GetDensity_Ref())); + } + jPoint++; + } + } + + /*--- Gather the data on the master node. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; +#endif + + /*--- The master node unpacks and sorts this variable by global index ---*/ + + if (rank == MASTER_NODE) { + jPoint = 0; iVar = iVar_MachMean; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { + + /*--- Get global index, then loop over each variable and store ---*/ + + iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; + Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; + jPoint++; + } + + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + + jPoint = (iProcessor+1)*nBuffer_Scalar; + } + } + } + + /*--- Laminar Viscosity ---*/ + + if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + + /*--- Loop over this partition to collect the current variable ---*/ + + jPoint = 0; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check for halos & write only if requested ---*/ + + if (!Local_Halo[iPoint] || Wrt_Halo) { + + /*--- Load buffers with the temperature and laminar viscosity variables. ---*/ + + if (compressible) { + Buffer_Send_Res[jPoint] = solver[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); + } + if (incompressible || freesurface) { + Buffer_Send_Res[jPoint] = solver[FLOW_SOL]->node[iPoint]->GetLaminarViscosityInc(); + } + jPoint++; + } + } + + /*--- Gather the data on the master node. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; +#endif + + /*--- The master node unpacks and sorts this variable by global index ---*/ + + if (rank == MASTER_NODE) { + jPoint = 0; iVar = iVar_Lam; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { + + /*--- Get global index, then loop over each variable and store ---*/ + + iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; + Data[iVar][iGlobal_Index] = Buffer_Recv_Res[jPoint]; + jPoint++; + } + + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + + jPoint = (iProcessor+1)*nBuffer_Scalar; + } + } + + /*--- Communicate skin friction, heat transfer, y+ ---*/ + + /*--- First, loop through the mesh in order to find and store the + value of the viscous coefficients at any surface nodes. They + will be placed in an auxiliary vector and then communicated like + all other volumetric variables. ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + Aux_Frict[iPoint] = 0.0; + Aux_Heat[iPoint] = 0.0; + Aux_yPlus[iPoint] = 0.0; + } + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_Plotting(iMarker) == YES) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Aux_Frict[iPoint] = solver[FLOW_SOL]->GetCSkinFriction(iMarker, iVertex); + Aux_Heat[iPoint] = solver[FLOW_SOL]->GetHeatFlux(iMarker, iVertex); + Aux_yPlus[iPoint] = solver[FLOW_SOL]->GetYPlus(iMarker, iVertex); + } + } + + /*--- Loop over this partition to collect the current variable ---*/ + + jPoint = 0; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check for halos & write only if requested ---*/ + + + if (!Local_Halo[iPoint] || Wrt_Halo) { + + /*--- Load buffers with the skin friction, heat transfer, y+ variables. ---*/ + + if (compressible) { + Buffer_Send_Var[jPoint] = Aux_Frict[iPoint]; + Buffer_Send_Res[jPoint] = Aux_Heat[iPoint]; + Buffer_Send_Vol[jPoint] = Aux_yPlus[iPoint]; + } + if (incompressible || freesurface) { + Buffer_Send_Var[jPoint] = Aux_Frict[iPoint]; + Buffer_Send_Res[jPoint] = Aux_Heat[iPoint]; + Buffer_Send_Vol[jPoint] = Aux_yPlus[iPoint]; + } + jPoint++; + } + } + + /*--- Gather the data on the master node. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Vol, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Vol, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Vol[iPoint] = Buffer_Send_Vol[iPoint]; +#endif + + /*--- The master node unpacks and sorts this variable by global index ---*/ + + if (rank == MASTER_NODE) { + jPoint = 0; iVar = iVar_ViscCoeffs; + + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { + + /*--- Get global index, then loop over each variable and store ---*/ + + iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; + Data[iVar+0][iGlobal_Index] = Buffer_Recv_Var[jPoint]; + Data[iVar+1][iGlobal_Index] = Buffer_Recv_Res[jPoint]; + Data[iVar+2][iGlobal_Index] = Buffer_Recv_Vol[jPoint]; + jPoint++; + } + + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + + jPoint = (iProcessor+1)*nBuffer_Scalar; + } + } + } + + /*--- Communicate the Eddy Viscosity ---*/ + + if (Kind_Solver == RANS) { + + /*--- Loop over this partition to collect the current variable ---*/ + + jPoint = 0; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check for halos & write only if requested ---*/ + + if (!Local_Halo[iPoint] || Wrt_Halo) { + + /*--- Load buffers with the pressure and mach variables. ---*/ + + if (compressible) { + Buffer_Send_Var[jPoint] = solver[FLOW_SOL]->node[iPoint]->GetEddyViscosity(); + } + if (incompressible || freesurface) { + Buffer_Send_Var[jPoint] = solver[FLOW_SOL]->node[iPoint]->GetEddyViscosityInc(); + } + jPoint++; + } + } + + /*--- Gather the data on the master node. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; +#endif + + /*--- The master node unpacks and sorts this variable by global index ---*/ + + if (rank == MASTER_NODE) { + jPoint = 0; iVar = iVar_Eddy; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { + + /*--- Get global index, then loop over each variable and store ---*/ + + iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; + Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; + jPoint++; + } + + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + + jPoint = (iProcessor+1)*nBuffer_Scalar; + } + } + + } + + /*--- Communicate the Sharp Edges ---*/ + + if (config->GetWrt_SharpEdges()) { + + if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + + /*--- Loop over this partition to collect the current variable ---*/ + jPoint = 0; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check for halos & write only if requested ---*/ + + if (!Local_Halo[iPoint] || Wrt_Halo) { + + /*--- Load buffers with the pressure and mach variables. ---*/ + + Buffer_Send_Var[jPoint] = geometry->node[iPoint]->GetSharpEdge_Distance(); + jPoint++; + } + } + + /*--- Gather the data on the master node. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; +#endif + + /*--- The master node unpacks and sorts this variable by global index ---*/ + + if (rank == MASTER_NODE) { + jPoint = 0; iVar = iVar_Sharp; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { + + /*--- Get global index, then loop over each variable and store ---*/ + + iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; + Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; + jPoint++; + } + + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + + jPoint = (iProcessor+1)*nBuffer_Scalar; + } + } + } + } + + /*--- Communicate the surface sensitivity ---*/ + + if ((Kind_Solver == ADJ_EULER) || + (Kind_Solver == ADJ_NAVIER_STOKES) || + (Kind_Solver == ADJ_RANS) || + (Kind_Solver == DISC_ADJ_EULER) || + (Kind_Solver == DISC_ADJ_NAVIER_STOKES) || + (Kind_Solver == DISC_ADJ_RANS)) { + + /*--- First, loop through the mesh in order to find and store the + value of the surface sensitivity at any surface nodes. They + will be placed in an auxiliary vector and then communicated like + all other volumetric variables. ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) Aux_Sens[iPoint] = 0.0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_Plotting(iMarker) == YES) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; + Area = sqrt (Area); + Aux_Sens[iPoint] = solver[ADJFLOW_SOL]->GetCSensitivity(iMarker, iVertex)/Area; + } + } + + /*--- Loop over this partition to collect the current variable ---*/ + + jPoint = 0; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check for halos & write only if requested ---*/ + + if (!Local_Halo[iPoint] || Wrt_Halo) { + + /*--- Load buffers with the skin friction, heat transfer, y+ variables. ---*/ + + Buffer_Send_Var[jPoint] = Aux_Sens[iPoint]; + if ((config->GetKind_ConvNumScheme() == SPACE_CENTERED) && (!config->GetDiscrete_Adjoint())) + Buffer_Send_Res[jPoint] = solver[ADJFLOW_SOL]->node[iPoint]->GetSensor(iPoint); + if ((config->GetKind_ConvNumScheme() == SPACE_UPWIND) && (!config->GetDiscrete_Adjoint())) + Buffer_Send_Res[jPoint] = solver[ADJFLOW_SOL]->node[iPoint]->GetLimiter(0); + + jPoint++; + } + } + + /*--- Gather the data on the master node. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + if (!config->GetDiscrete_Adjoint()) + SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; + if (!config->GetDiscrete_Adjoint()) + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; +#endif + + /*--- The master node unpacks and sorts this variable by global index ---*/ + + if (rank == MASTER_NODE) { + jPoint = 0; iVar = iVar_Sens; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { + + /*--- Get global index, then loop over each variable and store ---*/ + + iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; + Data[iVar+0][iGlobal_Index] = Buffer_Recv_Var[jPoint]; + if (!config->GetDiscrete_Adjoint()) + Data[iVar+1][iGlobal_Index] = Buffer_Recv_Res[jPoint]; + jPoint++; + } + + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + + jPoint = (iProcessor+1)*nBuffer_Scalar; + } + } + } + + if ((Kind_Solver == DISC_ADJ_EULER) || + (Kind_Solver == DISC_ADJ_NAVIER_STOKES) || + (Kind_Solver == DISC_ADJ_RANS)) { + /*--- Loop over this partition to collect the current variable ---*/ + + jPoint = 0; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check for halos & write only if requested ---*/ + + if (!Local_Halo[iPoint] || Wrt_Halo) { + + /*--- Load buffers with the skin friction, heat transfer, y+ variables. ---*/ + + Buffer_Send_Var[jPoint] = solver[ADJFLOW_SOL]->node[iPoint]->GetSensitivity(0); + Buffer_Send_Res[jPoint] = solver[ADJFLOW_SOL]->node[iPoint]->GetSensitivity(1); + if (nDim == 3) + Buffer_Send_Vol[jPoint] = solver[ADJFLOW_SOL]->node[iPoint]->GetSensitivity(2); + jPoint++; + } + } + + /*--- Gather the data on the master node. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + if (nDim == 3) + SU2_MPI::Gather(Buffer_Send_Vol, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Vol, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; + if (nDim == 3) + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Vol[iPoint] = Buffer_Send_Vol[iPoint]; +#endif + + /*--- The master node unpacks and sorts this variable by global index ---*/ + + if (rank == MASTER_NODE) { + jPoint = 0; iVar = iVar_SensDim; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { + + /*--- Get global index, then loop over each variable and store ---*/ + + iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; + Data[iVar+0][iGlobal_Index] = Buffer_Recv_Var[jPoint]; + Data[iVar+1][iGlobal_Index] = Buffer_Recv_Res[jPoint]; + if (nDim == 3) + Data[iVar+2][iGlobal_Index] = Buffer_Recv_Vol[jPoint]; + jPoint++; + } + + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + + jPoint = (iProcessor+1)*nBuffer_Scalar; + } + } + } + + /*--- Communicate the Linear elasticity stresses (2D) ---*/ + + if (Kind_Solver == LINEAR_ELASTICITY) { + + /*--- Loop over this partition to collect the current variable ---*/ + + jPoint = 0; su2double **Stress; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check for halos & write only if requested ---*/ + + if (!Local_Halo[iPoint] || Wrt_Halo) { + + /*--- Load buffers with the three grid velocity components. ---*/ + + Stress = solver[FEA_SOL]->node[iPoint]->GetStress(); + /*--- Sigma xx ---*/ + Buffer_Send_Var[jPoint] = Stress[0][0]; + /*--- Sigma yy ---*/ + Buffer_Send_Res[jPoint] = Stress[1][1]; + /*--- Sigma xy ---*/ + Buffer_Send_Vol[jPoint] = Stress[0][1]; + jPoint++; + } + } + + /*--- Gather the data on the master node. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Vol, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Vol, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Vol[iPoint] = Buffer_Send_Vol[iPoint]; +#endif + + /*--- The master node unpacks and sorts this variable by global index ---*/ + + if (rank == MASTER_NODE) { + jPoint = 0; iVar = iVar_FEA_Stress; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { + + /*--- Get global index, then loop over each variable and store ---*/ + + iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; + Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; + Data[iVar+1][iGlobal_Index] = Buffer_Recv_Res[jPoint]; + Data[iVar+2][iGlobal_Index] = Buffer_Recv_Vol[jPoint]; + jPoint++; + } + + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + + jPoint = (iProcessor+1)*nBuffer_Scalar; + } + } + } + + /*--- Communicate the Linear elasticity stresses (3D) ---*/ + + if ((Kind_Solver == LINEAR_ELASTICITY) && (geometry->GetnDim() == 3)) { + + /*--- Loop over this partition to collect the current variable ---*/ + + jPoint = 0; su2double **Stress; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check for halos & write only if requested ---*/ + + if (!Local_Halo[iPoint] || Wrt_Halo) { + + /*--- Load buffers with the three grid velocity components. ---*/ + + Stress = solver[FEA_SOL]->node[iPoint]->GetStress(); + /*--- Sigma zz ---*/ + Buffer_Send_Var[jPoint] = Stress[2][2]; + /*--- Sigma xz ---*/ + Buffer_Send_Res[jPoint] = Stress[0][2]; + /*--- Sigma yz ---*/ + Buffer_Send_Vol[jPoint] = Stress[1][2]; + jPoint++; + } + } + + /*--- Gather the data on the master node. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Vol, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Vol, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Vol[iPoint] = Buffer_Send_Vol[iPoint]; + +#endif + + /*--- The master node unpacks and sorts this variable by global index ---*/ + + if (rank == MASTER_NODE) { + jPoint = 0; iVar = iVar_FEA_Stress_3D; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { + + /*--- Get global index, then loop over each variable and store ---*/ + + iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; + Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; + Data[iVar+1][iGlobal_Index] = Buffer_Recv_Res[jPoint]; + Data[iVar+2][iGlobal_Index] = Buffer_Recv_Vol[jPoint]; + jPoint++; + } + + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + + jPoint = (iProcessor+1)*nBuffer_Scalar; + } + } + } + + + /*--- Communicate the Linear elasticity ---*/ + + if ( Kind_Solver == LINEAR_ELASTICITY ) { + + /*--- Loop over this partition to collect the current variable ---*/ + jPoint = 0; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check for halos & write only if requested ---*/ + + if (!Local_Halo[iPoint] || Wrt_Halo) { + + /*--- Load buffers with the temperature and laminar viscosity variables. ---*/ + + Buffer_Send_Var[jPoint] = solver[FEA_SOL]->node[iPoint]->GetVonMises_Stress(); + Buffer_Send_Res[jPoint] = solver[FEA_SOL]->node[iPoint]->GetFlow_Pressure(); + jPoint++; + } + } + + /*--- Gather the data on the master node. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; +#endif + + /*--- The master node unpacks and sorts this variable by global index ---*/ + + if (rank == MASTER_NODE) { + jPoint = 0; iVar = iVar_FEA_Extra; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { + + /*--- Get global index, then loop over each variable and store ---*/ + + iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; + Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; + Data[iVar+1][iGlobal_Index] = Buffer_Recv_Res[jPoint]; + jPoint++; + } + + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + + jPoint = (iProcessor+1)*nBuffer_Scalar; + } + } + } + + if (config->GetExtraOutput()) { + + for (jVar = 0; jVar < nVar_Extra; jVar++) { + + /*--- Loop over this partition to collect the current variable ---*/ + + jPoint = 0; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check for halos & write only if requested ---*/ + + if (!Local_Halo[iPoint] || Wrt_Halo) { + + /*--- Get this variable into the temporary send buffer. ---*/ + + if (Kind_Solver == RANS) { + Buffer_Send_Var[jPoint] = solver[TURB_SOL]->OutputVariables[iPoint*nVar_Extra+jVar]; + } + jPoint++; + + } + } + + /*--- Gather the data on the master node. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); +#else + for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; +#endif + + /*--- The master node unpacks and sorts this variable by global index ---*/ + + if (rank == MASTER_NODE) { + jPoint = 0; iVar = iVar_Extra; + for (iProcessor = 0; iProcessor < size; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { + + /*--- Get global index, then loop over each variable and store ---*/ + + iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; + Data[iVar+jVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; + jPoint++; + } + + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + + jPoint = (iProcessor+1)*nBuffer_Scalar; + } + } + } + } + + } + + /*--- Immediately release the temporary buffers. ---*/ + + delete [] Buffer_Send_Var; + delete [] Buffer_Send_Res; + delete [] Buffer_Send_Vol; + delete [] Buffer_Send_GlobalIndex; + if (rank == MASTER_NODE) { + delete [] Buffer_Recv_Var; + delete [] Buffer_Recv_Res; + delete [] Buffer_Recv_Vol; + delete [] Buffer_Recv_GlobalIndex; + } + + /*--- Release memory needed for surface coefficients ---*/ + + delete [] Local_Halo; + + if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + delete [] Aux_Frict; delete [] Aux_Heat; delete [] Aux_yPlus; + } + if (( Kind_Solver == ADJ_EULER ) || + ( Kind_Solver == ADJ_NAVIER_STOKES ) || + ( Kind_Solver == ADJ_RANS ) || + ( Kind_Solver == DISC_ADJ_EULER ) || + ( Kind_Solver == DISC_ADJ_NAVIER_STOKES ) || + ( Kind_Solver == DISC_ADJ_RANS )) { + delete [] Aux_Sens; + } + +} + +void COutput::MergeBaselineSolution(CConfig *config, CGeometry *geometry, CSolver *solver, unsigned short val_iZone) { + + /*--- Local variables needed on all processors ---*/ + unsigned short iVar; + unsigned long iPoint = 0, jPoint = 0; + + nVar_Total = config->fields.size() - 1; + + /*--- Merge the solution either in serial or parallel. ---*/ + +#ifndef HAVE_MPI + + /*--- In serial, the single process has access to all solution data, + so it is simple to retrieve and store inside Solution_Data. ---*/ + + unsigned short iMarker; + unsigned long iVertex, nTotalPoints = 0; + int SendRecv; + + /*--- First, create a structure to locate any periodic halo nodes ---*/ + int *Local_Halo = new int[geometry->GetnPoint()]; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + Local_Halo[iPoint] = !geometry->node[iPoint]->GetDomain(); + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { + SendRecv = config->GetMarker_All_SendRecv(iMarker); + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && + (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 1) && + (SendRecv < 0)) { + Local_Halo[iPoint] = false; + } + } + + } + } + + /*--- Total number of points in the mesh (this might include periodic points). ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + if (!Local_Halo[iPoint]) nTotalPoints++; + + nGlobal_Poin = nTotalPoints; + Data = new su2double*[nVar_Total]; + for (iVar = 0; iVar < nVar_Total; iVar++) { + Data[iVar] = new su2double[nGlobal_Poin]; + } + + /*--- Loop over all points in the mesh, but only write data + for nodes in the domain (ignore periodic halo nodes). ---*/ + + jPoint = 0; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + if (!Local_Halo[iPoint]) { + + /*--- Solution (first, and second system of equations) ---*/ + + unsigned short jVar = 0; + for (iVar = 0; iVar < nVar_Total; iVar++) { + Data[jVar][jPoint] = solver->node[iPoint]->GetSolution(iVar); + jVar++; + } + } + + /*--- Increment jPoint as the counter. We need this because iPoint + may include halo nodes that we skip over during this loop. ---*/ + + jPoint++; + + } + +#else + + /*--- MPI preprocessing ---*/ + + int rank, nProcessor, iProcessor; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); + + /*--- Local variables needed for merging with MPI ---*/ + + unsigned long iVertex, iMarker; + unsigned long Buffer_Send_nPoint[1], *Buffer_Recv_nPoint = NULL; + unsigned long nLocalPoint = 0, MaxLocalPoint = 0; + unsigned long iGlobal_Index = 0, nBuffer_Scalar = 0; + + int *Local_Halo = new int[geometry->GetnPoint()]; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + Local_Halo[iPoint] = !geometry->node[iPoint]->GetDomain(); + + bool Wrt_Halo = config->GetWrt_Halo(), isPeriodic; + + /*--- Search all send/recv boundaries on this partition for any periodic + nodes that were part of the original domain. We want to recover these + for visualization purposes. ---*/ + + if (Wrt_Halo) { + nLocalPoint = geometry->GetnPoint(); + } else { + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { + + /*--- Checking for less than or equal to the rank, because there may + be some periodic halo nodes that send info to the same rank. ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + isPeriodic = ((geometry->vertex[iMarker][iVertex]->GetRotation_Type() > 0) && + (geometry->vertex[iMarker][iVertex]->GetRotation_Type() % 2 == 1)); + if (isPeriodic) Local_Halo[iPoint] = false; + } + } + } + + /*--- Sum total number of nodes that belong to the domain ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + if (Local_Halo[iPoint] == false) + nLocalPoint++; + + } + Buffer_Send_nPoint[0] = nLocalPoint; + + if (rank == MASTER_NODE) Buffer_Recv_nPoint = new unsigned long[nProcessor]; + + SU2_MPI::Allreduce(&nLocalPoint, &MaxLocalPoint, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Gather(&Buffer_Send_nPoint, 1, MPI_UNSIGNED_LONG, Buffer_Recv_nPoint, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); + + nBuffer_Scalar = MaxLocalPoint; + + /*--- Send and Recv buffers. ---*/ + + su2double *Buffer_Send_Var = new su2double[MaxLocalPoint]; + su2double *Buffer_Recv_Var = NULL; + + unsigned long *Buffer_Send_GlobalIndex = new unsigned long[MaxLocalPoint]; + unsigned long *Buffer_Recv_GlobalIndex = NULL; + + /*--- Prepare the receive buffers in the master node only. ---*/ + if (rank == MASTER_NODE) { + + Buffer_Recv_Var = new su2double[nProcessor*MaxLocalPoint]; + Buffer_Recv_GlobalIndex = new unsigned long[nProcessor*MaxLocalPoint]; + + /*--- Sum total number of nodes to be written and allocate arrays ---*/ + nGlobal_Poin = 0; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + nGlobal_Poin += Buffer_Recv_nPoint[iProcessor]; + } + Data = new su2double*[nVar_Total]; + for (iVar = 0; iVar < nVar_Total; iVar++) { + Data[iVar] = new su2double[nGlobal_Poin]; + } + + } + + /*--- Main communication routine. Loop over each variable that has + been requested by the user and perform the MPI comm. Temporary + 1-D buffers are used to send the solution for each variable at all + nodes on each partition to the master node. These are then unpacked + by the master and sorted by global index in one large n-dim. array. ---*/ + + for (iVar = 0; iVar < nVar_Total; iVar++) { + + /*--- Loop over this partition to collect the current variable ---*/ + jPoint = 0; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Check for halos and write only if requested ---*/ + if (!Local_Halo[iPoint] || Wrt_Halo) { + + /*--- Get this variable into the temporary send buffer. ---*/ + Buffer_Send_Var[jPoint] = solver->node[iPoint]->GetSolution(iVar); + + /*--- Only send/recv the volumes & global indices during the first loop ---*/ + if (iVar == 0) { + Buffer_Send_GlobalIndex[jPoint] = geometry->node[iPoint]->GetGlobalIndex(); + } + jPoint++; + } + } + + /*--- Gather the data on the master node. ---*/ + + SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + if (iVar == 0) { + SU2_MPI::Gather(Buffer_Send_GlobalIndex, nBuffer_Scalar, MPI_UNSIGNED_LONG, Buffer_Recv_GlobalIndex, nBuffer_Scalar, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); + } + + /*--- The master node unpacks and sorts this variable by global index ---*/ + if (rank == MASTER_NODE) { + jPoint = 0; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { + + /*--- Get global index, then loop over each variable and store ---*/ + iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; + Data[iVar][iGlobal_Index] = Buffer_Recv_Var[jPoint]; + jPoint++; + } + /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ + jPoint = (iProcessor+1)*nBuffer_Scalar; + } + } + } + + /*--- Immediately release the temporary buffers. ---*/ + + delete [] Buffer_Send_Var; + delete [] Buffer_Send_GlobalIndex; + if (rank == MASTER_NODE) { + delete [] Buffer_Recv_Var; + delete [] Buffer_Recv_GlobalIndex; + } + +#endif + + delete [] Local_Halo; + +} + +void COutput::SetRestart(CConfig *config, CGeometry *geometry, CSolver **solver, unsigned short val_iZone) { + + /*--- Local variables ---*/ + + unsigned short Kind_Solver = config->GetKind_Solver(); + unsigned short iVar, iDim, nDim = geometry->GetnDim(); + unsigned long iPoint, iExtIter = config->GetExtIter(); + bool grid_movement = config->GetGrid_Movement(); + ofstream restart_file; + string filename; + + /*--- Retrieve filename from config ---*/ + + if ((config->GetAdjoint()) || (config->GetDiscrete_Adjoint())) { + filename = config->GetRestart_AdjFileName(); + filename = config->GetObjFunc_Extension(filename); + } else { + filename = config->GetRestart_FlowFileName(); + filename = config->GetRestart_FlowFileName(filename, val_iZone); + } + + /*--- Unsteady problems require an iteration number to be appended. ---*/ + + if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { + filename = config->GetUnsteady_FileName(filename, SU2_TYPE::Int(val_iZone)); + } else if (config->GetWrt_Unsteady()) { + filename = config->GetUnsteady_FileName(filename, SU2_TYPE::Int(iExtIter)); + } + + /*--- Open the restart file and write the solution. ---*/ + + restart_file.open(filename.c_str(), ios::out); + restart_file.precision(15); + + /*--- Write the header line based on the particular solver ----*/ + + restart_file << "\"PointID\""; + + /*--- Mesh coordinates are always written to the restart first ---*/ + + if (nDim == 2) { + restart_file << "\t\"x\"\t\"y\""; + } else { + restart_file << "\t\"x\"\t\"y\"\t\"z\""; + } + + for (iVar = 0; iVar < nVar_Consv; iVar++) { + if ( Kind_Solver == LINEAR_ELASTICITY ) + restart_file << "\t\"Displacement_" << iVar+1<<"\""; + else + restart_file << "\t\"Conservative_" << iVar+1<<"\""; + } + + if (!config->GetLow_MemoryOutput()) { + + if (config->GetWrt_Limiters()) { + for (iVar = 0; iVar < nVar_Consv; iVar++) { + restart_file << "\t\"Limiter_" << iVar+1<<"\""; + } + } + if (config->GetWrt_Residuals()) { + for (iVar = 0; iVar < nVar_Consv; iVar++) { + restart_file << "\t\"Residual_" << iVar+1<<"\""; + } + } + + /*--- Mesh velocities for dynamic mesh cases ---*/ + + if (grid_movement) { + if (nDim == 2) { + restart_file << "\t\"Grid_Velx\"\t\"Grid_Vely\""; + } else { + restart_file << "\t\"Grid_Velx\"\t\"Grid_Vely\"\t\"Grid_Velz\""; + } + } + + /*--- Solver specific output variables ---*/ + + if (config->GetKind_Regime() == FREESURFACE) { + restart_file << "\t\"Density\""; + } + + if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + restart_file << "\t\"Pressure\"\t\"Temperature\"\t\"Pressure_Coefficient\"\t\"Mach\""; + } + + if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + restart_file << "\t\"Laminar_Viscosity\"\t\"Skin_Friction_Coefficient\"\t\"Heat_Flux\"\t\"Y_Plus\""; + } + + if (Kind_Solver == RANS) { + restart_file << "\t\"Eddy_Viscosity\""; + } + + if (config->GetWrt_SharpEdges()) { + if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + restart_file << "\t\"Sharp_Edge_Dist\""; + } + } + + if (Kind_Solver == POISSON_EQUATION) { + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) + restart_file << "\t\"poissonField_" << iDim+1 << "\""; + } + + if ((Kind_Solver == ADJ_EULER ) || + (Kind_Solver == ADJ_NAVIER_STOKES ) || + (Kind_Solver == ADJ_RANS ) ) { + restart_file << "\t\"Surface_Sensitivity\"\t\"Solution_Sensor\""; + } + if (( Kind_Solver == DISC_ADJ_EULER ) || + ( Kind_Solver == DISC_ADJ_NAVIER_STOKES ) || + ( Kind_Solver == DISC_ADJ_RANS )) { + restart_file << "\t\"Surface_Sensitivity\"\t\"Sensitivity_x\"\t\"Sensitivity_y\""; + if (geometry->GetnDim() == 3){ + restart_file << "\t\"Sensitivity_z\""; + } + } + + if ((Kind_Solver == LINEAR_ELASTICITY) && (geometry->GetnDim() == 2)) { + restart_file << "\t\"Sxx\"\t\"Syy\"\t\"Sxy\"\t\"Von_Mises_Stress\"\t\"Flow_Pressure\""; + } + + if ((Kind_Solver == LINEAR_ELASTICITY) && (geometry->GetnDim() == 3)) { + restart_file << "\t\"Sxx\"\t\"Syy\"\t\"Sxy\"\t\"Szz\"\t\"Sxz\"\t\"Syz\"\t\"Von_Mises_Stress\"\t\"Flow_Pressure\""; + } + + if (config->GetExtraOutput()) { + string *headings = NULL; + //if (Kind_Solver == RANS) { + headings = solver[TURB_SOL]->OutputHeadingNames; + //} + + for (iVar = 0; iVar < nVar_Extra; iVar++) { + if (headings == NULL) { + restart_file << "\t\"ExtraOutput_" << iVar+1<<"\""; + } else{ + restart_file << "\t\""<< headings[iVar] <<"\""; + } + } + } + } + + restart_file << endl; + + /*--- Write the restart file ---*/ + + for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) { + + /*--- Index of the point ---*/ + restart_file << iPoint << "\t"; + + /*--- Write the grid coordinates first ---*/ + for (iDim = 0; iDim < nDim; iDim++) { + restart_file << scientific << Coords[iDim][iPoint] << "\t"; + } + + /*--- Loop over the variables and write the values to file ---*/ + for (iVar = 0; iVar < nVar_Total; iVar++) { + restart_file << scientific << Data[iVar][iPoint] << "\t"; + } + restart_file << endl; + } + + restart_file.close(); + +} + +void COutput::DeallocateCoordinates(CConfig *config, CGeometry *geometry) { + + unsigned short iDim, nDim = geometry->GetnDim(); + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- The master node alone owns all data found in this routine. ---*/ + + if (rank == MASTER_NODE) { + + /*--- Deallocate memory for coordinate data ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + delete [] Coords[iDim]; + } + delete [] Coords; + + } +} + +void COutput::DeallocateConnectivity(CConfig *config, CGeometry *geometry, bool surf_sol) { + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- The master node alone owns all data found in this routine. ---*/ + if (rank == MASTER_NODE) { + + /*--- Deallocate memory for connectivity data ---*/ + if (surf_sol) { + if (nGlobal_Line > 0) delete [] Conn_Line; + if (nGlobal_BoundTria > 0) delete [] Conn_BoundTria; + if (nGlobal_BoundQuad > 0) delete [] Conn_BoundQuad; + } + else { + if (nGlobal_Tria > 0) delete [] Conn_Tria; + if (nGlobal_Quad > 0) delete [] Conn_Quad; + if (nGlobal_Tetr > 0) delete [] Conn_Tetr; + if (nGlobal_Hexa > 0) delete [] Conn_Hexa; + if (nGlobal_Pris > 0) delete [] Conn_Pris; + if (nGlobal_Pyra > 0) delete [] Conn_Pyra; + } + + } +} + +void COutput::DeallocateSolution(CConfig *config, CGeometry *geometry) { + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- The master node alone owns all data found in this routine. ---*/ + if (rank == MASTER_NODE) { + + /*--- Deallocate memory for solution data ---*/ + for (unsigned short iVar = 0; iVar < nVar_Total; iVar++) { + delete [] Data[iVar]; + } + delete [] Data; + + } +} + +void COutput::SetConvHistory_Header(ofstream *ConvHist_file, CConfig *config) { + char cstr[200], buffer[50], turb_resid[1000]; + unsigned short iMarker, iMarker_Monitoring; + string Monitoring_Tag, monitoring_coeff, aeroelastic_coeff; + + bool rotating_frame = config->GetRotating_Frame(); + bool aeroelastic = config->GetAeroelastic_Simulation(); + bool equiv_area = config->GetEquivArea(); + bool turbulent = ((config->GetKind_Solver() == RANS) || (config->GetKind_Solver() == ADJ_RANS) || + (config->GetKind_Solver() == DISC_ADJ_RANS)); + bool frozen_turb = config->GetFrozen_Visc(); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool inv_design = (config->GetInvDesign_Cp() || config->GetInvDesign_HeatFlux()); + bool output_1d = config->GetWrt_1D_Output(); + bool output_per_surface = false; + bool output_massflow = (config->GetKind_ObjFunc() == MASS_FLOW_RATE); + if (config->GetnMarker_Monitoring() > 1) output_per_surface = true; + + unsigned short direct_diff = config->GetDirectDiff(); + + bool isothermal = false; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if ((config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL )) + isothermal = true; + + /*--- Write file name with extension ---*/ + + string filename = config->GetConv_FileName(); + strcpy (cstr, filename.data()); + + if (config->GetWrt_Unsteady() && config->GetRestart()) { + long iExtIter = config->GetUnst_RestartIter(); + if (SU2_TYPE::Int(iExtIter) < 10) SPRINTF (buffer, "_0000%d", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d", SU2_TYPE::Int(iExtIter)); + if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d", SU2_TYPE::Int(iExtIter)); + strcat(cstr, buffer); + } + + if ((config->GetOutput_FileFormat() == TECPLOT) || + (config->GetOutput_FileFormat() == FIELDVIEW)) SPRINTF (buffer, ".dat"); + else if ((config->GetOutput_FileFormat() == TECPLOT_BINARY) || + (config->GetOutput_FileFormat() == FIELDVIEW_BINARY)) SPRINTF (buffer, ".plt"); + else if (config->GetOutput_FileFormat() == PARAVIEW) SPRINTF (buffer, ".csv"); + strcat(cstr, buffer); + + ConvHist_file->open(cstr, ios::out); + ConvHist_file->precision(15); + + /*--- Begin of the header ---*/ + + char begin[]= "\"Iteration\""; + + /*--- Header for the coefficients ---*/ + + char flow_coeff[]= ",\"CLift\",\"CDrag\",\"CSideForce\",\"CMx\",\"CMy\",\"CMz\",\"CFx\",\"CFy\",\"CFz\",\"CL/CD\""; + char heat_coeff[]= ",\"HeatFlux_Total\",\"HeatFlux_Maximum\""; + char equivalent_area_coeff[]= ",\"CEquivArea\",\"CNearFieldOF\""; + char rotating_frame_coeff[]= ",\"CMerit\",\"CT\",\"CQ\""; + char free_surface_coeff[]= ",\"CFreeSurface\""; + char wave_coeff[]= ",\"CWave\""; + char fea_coeff[]= ",\"CFEA\""; + char adj_coeff[]= ",\"Sens_Geo\",\"Sens_Mach\",\"Sens_AoA\",\"Sens_Press\",\"Sens_Temp\",\"Sens_AoS\",\"Sens_BPress\""; + char oneD_outputs[]= ",\"Avg_TotalPress\",\"Avg_Mach\",\"Avg_Temperature\",\"MassFlowRate\",\"FluxAvg_Pressure\",\"FluxAvg_Density\",\"FluxAvg_Velocity\",\"FluxAvg_Enthalpy\""; + char Cp_inverse_design[]= ",\"Cp_Diff\""; + char Heat_inverse_design[]= ",\"HeatFlux_Diff\""; + char mass_flow_rate[] = ",\"MassFlowRate\""; + char d_flow_coeff[] = ",\"D(CLift)\",\"D(CDrag)\",\"D(CSideForce)\",\"D(CMx)\",\"D(CMy)\",\"D(CMz)\",\"D(CFx)\",\"D(CFy)\",\"D(CFz)\",\"D(CL/CD)\""; + + /* Find the markers being monitored and create a header for them */ + for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { + Monitoring_Tag = config->GetMarker_Monitoring(iMarker_Monitoring); + monitoring_coeff += ",\"CLift_" + Monitoring_Tag + "\""; + monitoring_coeff += ",\"CDrag_" + Monitoring_Tag + "\""; + monitoring_coeff += ",\"CSideForce_" + Monitoring_Tag + "\""; + monitoring_coeff += ",\"CL/CD_" + Monitoring_Tag + "\""; + monitoring_coeff += ",\"CFx_" + Monitoring_Tag + "\""; + monitoring_coeff += ",\"CFy_" + Monitoring_Tag + "\""; + monitoring_coeff += ",\"CFz_" + Monitoring_Tag + "\""; + monitoring_coeff += ",\"CMx_" + Monitoring_Tag + "\""; + monitoring_coeff += ",\"CMy_" + Monitoring_Tag + "\""; + monitoring_coeff += ",\"CMz_" + Monitoring_Tag + "\""; + aeroelastic_coeff += ",\"plunge_" + Monitoring_Tag + "\""; + aeroelastic_coeff += ",\"pitch_" + Monitoring_Tag + "\""; + } + + /*--- Header for the residuals ---*/ + + char flow_resid[]= ",\"Res_Flow[0]\",\"Res_Flow[1]\",\"Res_Flow[2]\",\"Res_Flow[3]\",\"Res_Flow[4]\""; + char adj_flow_resid[]= ",\"Res_AdjFlow[0]\",\"Res_AdjFlow[1]\",\"Res_AdjFlow[2]\",\"Res_AdjFlow[3]\",\"Res_AdjFlow[4]\""; + switch (config->GetKind_Turb_Model()) { + case SA: SPRINTF (turb_resid, ",\"Res_Turb[0]\""); break; + case SA_NEG: SPRINTF (turb_resid, ",\"Res_Turb[0]\""); break; + case SST: SPRINTF (turb_resid, ",\"Res_Turb[0]\",\"Res_Turb[1]\""); break; + } + char adj_turb_resid[]= ",\"Res_AdjTurb[0]\""; + char levelset_resid[]= ",\"Res_LevelSet\""; + char adj_levelset_resid[]= ",\"Res_AdjLevelSet\""; + char wave_resid[]= ",\"Res_Wave[0]\",\"Res_Wave[1]\""; + char fea_resid[]= ",\"Res_FEA\""; + char heat_resid[]= ",\"Res_Heat\""; + + /*--- End of the header ---*/ + + char end[]= ",\"Linear_Solver_Iterations\",\"CFL_Number\",\"Time(min)\"\n"; + + if ((config->GetOutput_FileFormat() == TECPLOT) || + (config->GetOutput_FileFormat() == TECPLOT_BINARY) || + (config->GetOutput_FileFormat() == FIELDVIEW) || + (config->GetOutput_FileFormat() == FIELDVIEW_BINARY)) { + ConvHist_file[0] << "TITLE = \"SU2 Simulation\"" << endl; + ConvHist_file[0] << "VARIABLES = "; + } + + /*--- Write the header, case depending ---*/ + switch (config->GetKind_Solver()) { + + case EULER : case NAVIER_STOKES: case RANS : + ConvHist_file[0] << begin << flow_coeff; + if (isothermal) ConvHist_file[0] << heat_coeff; + if (equiv_area) ConvHist_file[0] << equivalent_area_coeff; + if (inv_design) { + ConvHist_file[0] << Cp_inverse_design; + if (isothermal) ConvHist_file[0] << Heat_inverse_design; + } + if (rotating_frame) ConvHist_file[0] << rotating_frame_coeff; + ConvHist_file[0] << flow_resid; + if (turbulent) ConvHist_file[0] << turb_resid; + if (aeroelastic) ConvHist_file[0] << aeroelastic_coeff; + if (output_per_surface) ConvHist_file[0] << monitoring_coeff; + if (output_1d) ConvHist_file[0] << oneD_outputs; + if (output_massflow and !output_1d) ConvHist_file[0]<< mass_flow_rate; + if (direct_diff != NO_DERIVATIVE) ConvHist_file[0] << d_flow_coeff; + ConvHist_file[0] << end; + if (freesurface) { + ConvHist_file[0] << begin << flow_coeff << free_surface_coeff; + ConvHist_file[0] << flow_resid << levelset_resid << end; + } + + break; + + case ADJ_EULER : case ADJ_NAVIER_STOKES : case ADJ_RANS: + case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: + ConvHist_file[0] << begin << adj_coeff << adj_flow_resid; + if ((turbulent) && (!frozen_turb)) ConvHist_file[0] << adj_turb_resid; + ConvHist_file[0] << end; + if (freesurface) { + ConvHist_file[0] << begin << adj_coeff << adj_flow_resid << adj_levelset_resid << end; + } + break; + + case WAVE_EQUATION: + ConvHist_file[0] << begin << wave_coeff; + ConvHist_file[0] << wave_resid << end; + break; + + case HEAT_EQUATION: + ConvHist_file[0] << begin << heat_coeff; + ConvHist_file[0] << heat_resid << end; + break; + + case LINEAR_ELASTICITY: + ConvHist_file[0] << begin << fea_coeff; + ConvHist_file[0] << fea_resid << end; + break; + + } + + if (config->GetOutput_FileFormat() == TECPLOT || + config->GetOutput_FileFormat() == TECPLOT_BINARY || + config->GetOutput_FileFormat() == FIELDVIEW || + config->GetOutput_FileFormat() == FIELDVIEW_BINARY) { + ConvHist_file[0] << "ZONE T= \"Convergence history\"" << endl; + } + +} + + +void COutput::SetConvHistory_Body(ofstream *ConvHist_file, + CGeometry ***geometry, + CSolver ****solver_container, + CConfig **config, + CIntegration ***integration, + bool DualTime_Iteration, + su2double timeused, + unsigned short val_iZone) { + + bool output_1d = config[val_iZone]->GetWrt_1D_Output(); + bool output_massflow = (config[val_iZone]->GetKind_ObjFunc() == MASS_FLOW_RATE); + unsigned short FinestMesh = config[val_iZone]->GetFinestMesh(); + + int rank; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#else + rank = MASTER_NODE; +#endif + + /*--- If 1-D outputs requested, calculated them. Requires info from all nodes, + Get area-averaged and flux-averaged values at the specified surface ---*/ + + if (output_1d) { + switch (config[val_iZone]->GetKind_Solver()) { + case EULER: case NAVIER_STOKES: case RANS: + case ADJ_EULER: case ADJ_NAVIER_STOKES: case ADJ_RANS: + OneDimensionalOutput(solver_container[val_iZone][FinestMesh][FLOW_SOL], geometry[val_iZone][FinestMesh], config[val_iZone]); + break; + } + } + if (output_massflow and !output_1d) { + switch (config[val_iZone]->GetKind_Solver()) { + case EULER: case NAVIER_STOKES: case RANS: + case ADJ_EULER: case ADJ_NAVIER_STOKES: case ADJ_RANS: + SetMassFlowRate(solver_container[val_iZone][FinestMesh][FLOW_SOL], geometry[val_iZone][FinestMesh], config[val_iZone]); + break; + } + } + + /*--- Output using only the master node ---*/ + if (rank == MASTER_NODE) { + + unsigned long iIntIter = config[val_iZone]->GetIntIter(); + unsigned long iExtIter = config[val_iZone]->GetExtIter(); + + /*--- WARNING: These buffers have hard-coded lengths. Note that you + may have to adjust them to be larger if adding more entries. ---*/ + char begin[1000], direct_coeff[1000], surface_coeff[1000], aeroelastic_coeff[1000], monitoring_coeff[10000], + adjoint_coeff[1000], flow_resid[1000], adj_flow_resid[1000], turb_resid[1000], trans_resid[1000], + adj_turb_resid[1000], levelset_resid[1000], adj_levelset_resid[1000], wave_coeff[1000], + heat_coeff[1000], fea_coeff[1000], wave_resid[1000], heat_resid[1000], fea_resid[1000], end[1000], + oneD_outputs[1000], massflow_outputs[1000], d_direct_coeff[1000]; + + su2double dummy = 0.0, *Coord; + unsigned short iVar, iMarker, iMarker_Monitoring; + + unsigned long LinSolvIter = 0, iPointMaxResid; + su2double timeiter = timeused/su2double(iExtIter+1); + + unsigned short nDim = geometry[val_iZone][FinestMesh]->GetnDim(); + + bool compressible = (config[val_iZone]->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config[val_iZone]->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config[val_iZone]->GetKind_Regime() == FREESURFACE); + + bool rotating_frame = config[val_iZone]->GetRotating_Frame(); + bool aeroelastic = config[val_iZone]->GetAeroelastic_Simulation(); + bool equiv_area = config[val_iZone]->GetEquivArea(); + bool inv_design = (config[val_iZone]->GetInvDesign_Cp() || config[val_iZone]->GetInvDesign_HeatFlux()); + bool transition = (config[val_iZone]->GetKind_Trans_Model() == LM); + bool isothermal = false; + for (iMarker = 0; iMarker < config[val_iZone]->GetnMarker_All(); iMarker++) + if ((config[val_iZone]->GetMarker_All_KindBC(iMarker) == ISOTHERMAL)) + isothermal = true; + bool turbulent = ((config[val_iZone]->GetKind_Solver() == RANS) || (config[val_iZone]->GetKind_Solver() == ADJ_RANS) || + (config[val_iZone]->GetKind_Solver() == DISC_ADJ_RANS)); + bool adjoint = config[val_iZone]->GetAdjoint() || config[val_iZone]->GetDiscrete_Adjoint(); + bool disc_adj = config[val_iZone]->GetDiscrete_Adjoint(); + bool wave = (config[val_iZone]->GetKind_Solver() == WAVE_EQUATION); + bool heat = (config[val_iZone]->GetKind_Solver() == HEAT_EQUATION); + bool fea = (config[val_iZone]->GetKind_Solver() == LINEAR_ELASTICITY); + bool flow = (config[val_iZone]->GetKind_Solver() == EULER) || (config[val_iZone]->GetKind_Solver() == NAVIER_STOKES) || + (config[val_iZone]->GetKind_Solver() == RANS) || (config[val_iZone]->GetKind_Solver() == ADJ_EULER) || + (config[val_iZone]->GetKind_Solver() == ADJ_NAVIER_STOKES) || (config[val_iZone]->GetKind_Solver() == ADJ_RANS); + + bool turbo = config[val_iZone]->GetBoolTurboPerf(); + string inMarker_Tag, outMarker_Tag; + + bool output_per_surface = false; + if (config[val_iZone]->GetnMarker_Monitoring() > 1) output_per_surface = true; + + unsigned short direct_diff = config[val_iZone]->GetDirectDiff(); + + + /*--- Initialize variables to store information from all domains (direct solution) ---*/ + su2double Total_CLift = 0.0, Total_CDrag = 0.0, Total_CSideForce = 0.0, Total_CMx = 0.0, Total_CMy = 0.0, Total_CMz = 0.0, Total_CEff = 0.0, + Total_CEquivArea = 0.0, Total_CNearFieldOF = 0.0, Total_CFx = 0.0, Total_CFy = 0.0, Total_CFz = 0.0, Total_CMerit = 0.0, + Total_CT = 0.0, Total_CQ = 0.0, Total_CFreeSurface = 0.0, Total_CWave = 0.0, Total_CHeat = 0.0, Total_CpDiff = 0.0, Total_HeatFluxDiff = 0.0, + Total_CFEA = 0.0, Total_Heat = 0.0, Total_MaxHeat = 0.0, Total_Mdot = 0.0; + su2double OneD_AvgStagPress = 0.0, OneD_AvgMach = 0.0, OneD_AvgTemp = 0.0, OneD_MassFlowRate = 0.0, + OneD_FluxAvgPress = 0.0, OneD_FluxAvgDensity = 0.0, OneD_FluxAvgVelocity = 0.0, OneD_FluxAvgEntalpy = 0.0; + + /*--- Initialize variables to store information from all zone for turboperformance (direct solution) ---*/ + su2double *TotalStaticEfficiency = NULL, + *TotalTotalEfficiency = NULL, + *KineticEnergyLoss = NULL, + *TotalPressureLoss = NULL, + *MassFlowIn = NULL, + *MassFlowOut = NULL, + *FlowAngleIn = NULL, + *FlowAngleOut = NULL, + *EulerianWork = NULL, + *TotalEnthalpyIn = NULL, + *PressureRatio = NULL, + *PressureOut = NULL, + *EnthalpyOut = NULL, + *MachIn = NULL, + *MachOut = NULL, + *NormalMachIn = NULL, + *NormalMachOut = NULL, + *VelocityOutIs = NULL; + + + + /*--- Initialize variables to store information from all domains (adjoint solution) ---*/ + su2double Total_Sens_Geo = 0.0, Total_Sens_Mach = 0.0, Total_Sens_AoA = 0.0; + su2double Total_Sens_Press = 0.0, Total_Sens_Temp = 0.0, Total_Sens_BPress=0.0; + + /*--- Initialize variables to store information from all domains (direct differentiation) ---*/ + su2double D_Total_CLift = 0.0, D_Total_CDrag = 0.0, D_Total_CSideForce = 0.0, D_Total_CMx = 0.0, D_Total_CMy = 0.0, D_Total_CMz = 0.0, D_Total_CEff = 0.0, D_Total_CFx = 0.0, D_Total_CFy = 0.0, D_Total_CFz = 0.0; + + /*--- Residual arrays ---*/ + su2double *residual_flow = NULL, + *residual_turbulent = NULL, + *residual_transition = NULL, + *residual_levelset = NULL; + su2double *residual_adjflow = NULL, + *residual_adjturbulent = NULL, + *residual_adjlevelset = NULL; + su2double *residual_wave = NULL; + su2double *residual_fea = NULL; + su2double *residual_heat = NULL; + + /*--- Coefficients Monitored arrays ---*/ + su2double *aeroelastic_plunge = NULL, + *aeroelastic_pitch = NULL, + *Surface_CLift = NULL, + *Surface_CDrag = NULL, + *Surface_CSideForce = NULL, + *Surface_CEff = NULL, + *Surface_CFx = NULL, + *Surface_CFy = NULL, + *Surface_CFz = NULL, + *Surface_CMx = NULL, + *Surface_CMy = NULL, + *Surface_CMz = NULL; + + /*--- Initialize number of variables ---*/ + unsigned short nVar_Flow = 0, nVar_LevelSet = 0, nVar_Turb = 0, + nVar_Trans = 0, nVar_Wave = 0, nVar_Heat = 0, nVar_FEA = 0, + nVar_AdjFlow = 0, nVar_AdjLevelSet = 0, nVar_AdjTurb = 0; + + /*--- Direct problem variables ---*/ + if (compressible) nVar_Flow = nDim+2; else nVar_Flow = nDim+1; + if (turbulent) { + switch (config[val_iZone]->GetKind_Turb_Model()) { + case SA: nVar_Turb = 1; break; + case SA_NEG: nVar_Turb = 1; break; + case SST: nVar_Turb = 2; break; + } + } + if (transition) nVar_Trans = 2; + if (wave) nVar_Wave = 2; + if (fea) nVar_FEA = nDim; + if (heat) nVar_Heat = 1; + if (freesurface) nVar_LevelSet = 1; + + /*--- Adjoint problem variables ---*/ + if (compressible) nVar_AdjFlow = nDim+2; else nVar_AdjFlow = nDim+1; + if (turbulent) { + switch (config[val_iZone]->GetKind_Turb_Model()) { + case SA: nVar_AdjTurb = 1; break; + case SA_NEG: nVar_AdjTurb = 1; break; + case SST: nVar_AdjTurb = 2; break; + } + } + if (freesurface) nVar_AdjLevelSet = 1; + + /*--- Allocate memory for the residual ---*/ + residual_flow = new su2double[nVar_Flow]; + residual_turbulent = new su2double[nVar_Turb]; + residual_transition = new su2double[nVar_Trans]; + residual_levelset = new su2double[nVar_LevelSet]; + residual_wave = new su2double[nVar_Wave]; + residual_fea = new su2double[nVar_FEA]; + residual_heat = new su2double[nVar_Heat]; + + residual_adjflow = new su2double[nVar_AdjFlow]; + residual_adjturbulent = new su2double[nVar_AdjTurb]; + residual_adjlevelset = new su2double[nVar_AdjLevelSet]; + + /*--- Allocate memory for the coefficients being monitored ---*/ + aeroelastic_plunge = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + aeroelastic_pitch = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CLift = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CDrag = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CSideForce = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CEff = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CFx = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CFy = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CFz = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CMx = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CMy = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CMz = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + + /*--- Allocate memory for the turboperformace ---*/ + TotalStaticEfficiency = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + TotalTotalEfficiency = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + KineticEnergyLoss = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + TotalPressureLoss = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + MassFlowIn = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + MassFlowOut = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + FlowAngleIn = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + FlowAngleOut = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + EulerianWork = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + TotalEnthalpyIn = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + PressureRatio = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + PressureOut = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + EnthalpyOut = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + MachIn = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + MachOut = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + NormalMachIn = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + NormalMachOut = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + VelocityOutIs = new su2double[config[ZONE_0]->Get_nMarkerTurboPerf()]; + + + + + + /*--- Write information from nodes ---*/ + switch (config[val_iZone]->GetKind_Solver()) { + + case EULER: case NAVIER_STOKES: case RANS: + case ADJ_EULER: case ADJ_NAVIER_STOKES: case ADJ_RANS: + case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: + + /*--- Flow solution coefficients ---*/ + Total_CLift = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CLift(); + Total_CDrag = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CDrag(); + Total_CSideForce = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CSideForce(); + Total_CEff = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CEff(); + Total_CMx = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CMx(); + Total_CMy = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CMy(); + Total_CMz = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CMz(); + Total_CFx = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CFx(); + Total_CFy = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CFy(); + Total_CFz = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CFz(); + + if (direct_diff != NO_DERIVATIVE){ + D_Total_CLift = SU2_TYPE::GetDerivative(Total_CLift); + D_Total_CDrag = SU2_TYPE::GetDerivative(Total_CDrag); + D_Total_CSideForce = SU2_TYPE::GetDerivative(Total_CSideForce); + D_Total_CEff = SU2_TYPE::GetDerivative(Total_CEff); + D_Total_CMx = SU2_TYPE::GetDerivative(Total_CMx); + D_Total_CMy = SU2_TYPE::GetDerivative(Total_CMy); + D_Total_CMz = SU2_TYPE::GetDerivative(Total_CMz); + D_Total_CFx = SU2_TYPE::GetDerivative(Total_CFx); + D_Total_CFy = SU2_TYPE::GetDerivative(Total_CFy); + D_Total_CFz = SU2_TYPE::GetDerivative(Total_CFz); + } + + if (freesurface) { + Total_CFreeSurface = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CFreeSurface(); + } + + if (isothermal) { + Total_Heat = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_HeatFlux(); + Total_MaxHeat = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_MaxHeatFlux(); + } + + if (equiv_area) { + Total_CEquivArea = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CEquivArea(); + Total_CNearFieldOF = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CNearFieldOF(); + + /*--- Note that there is a redefinition of the nearfield based functionals ---*/ + Total_CEquivArea = config[val_iZone]->GetWeightCd()*Total_CDrag + (1.0-config[val_iZone]->GetWeightCd())*Total_CEquivArea; + Total_CNearFieldOF = config[val_iZone]->GetWeightCd()*Total_CDrag + (1.0-config[val_iZone]->GetWeightCd())*Total_CNearFieldOF; + } + + if (inv_design) { + Total_CpDiff = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CpDiff(); + if (isothermal) { + Total_HeatFluxDiff = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_HeatFluxDiff(); + } + } + + if (rotating_frame) { + Total_CT = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CT(); + Total_CQ = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CQ(); + Total_CMerit = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CMerit(); + } + + if (aeroelastic) { + /*--- Look over the markers being monitored and get the desired values ---*/ + for (iMarker_Monitoring = 0; iMarker_Monitoring < config[ZONE_0]->GetnMarker_Monitoring(); iMarker_Monitoring++) { + aeroelastic_plunge[iMarker_Monitoring] = config[val_iZone]->GetAeroelastic_plunge(iMarker_Monitoring); + aeroelastic_pitch[iMarker_Monitoring] = config[val_iZone]->GetAeroelastic_pitch(iMarker_Monitoring); + } + } + + if (output_per_surface) { + /*--- Look over the markers being monitored and get the desired values ---*/ + for (iMarker_Monitoring = 0; iMarker_Monitoring < config[ZONE_0]->GetnMarker_Monitoring(); iMarker_Monitoring++) { + Surface_CLift[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CLift(iMarker_Monitoring); + Surface_CDrag[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CDrag(iMarker_Monitoring); + Surface_CSideForce[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CSideForce(iMarker_Monitoring); + Surface_CEff[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CEff(iMarker_Monitoring); + Surface_CFx[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFx(iMarker_Monitoring); + Surface_CFy[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFy(iMarker_Monitoring); + Surface_CFz[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFz(iMarker_Monitoring); + Surface_CMx[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMx(iMarker_Monitoring); + Surface_CMy[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMy(iMarker_Monitoring); + Surface_CMz[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMz(iMarker_Monitoring); + } + } + + if (turbo) { + /*--- Loop over the nMarker of turboperformance and get the desired values ---*/ + for (iMarker_Monitoring = 0; iMarker_Monitoring < config[ZONE_0]->Get_nMarkerTurboPerf(); iMarker_Monitoring++) { + TotalStaticEfficiency[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotalStaticEfficiency(iMarker_Monitoring); + TotalTotalEfficiency[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotalTotalEfficiency(iMarker_Monitoring); + KineticEnergyLoss[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetKineticEnergyLoss(iMarker_Monitoring); + TotalPressureLoss[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotalPressureLoss(iMarker_Monitoring); + MassFlowIn[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetMassFlowIn(iMarker_Monitoring); + MassFlowOut[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetMassFlowOut(iMarker_Monitoring); + FlowAngleIn[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetFlowAngleIn(iMarker_Monitoring); + FlowAngleOut[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetFlowAngleOut(iMarker_Monitoring); + EulerianWork[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetEulerianWork(iMarker_Monitoring); + TotalEnthalpyIn[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotalEnthalpyIn(iMarker_Monitoring); + PressureRatio[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetPressureRatio(iMarker_Monitoring); + PressureOut[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetPressureOut(iMarker_Monitoring); + EnthalpyOut[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetEnthalpyOut(iMarker_Monitoring); + MachIn[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetMachIn(iMarker_Monitoring); + MachOut[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetMachOut(iMarker_Monitoring); + NormalMachIn[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetNormalMachIn(iMarker_Monitoring); + NormalMachOut[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetNormalMachOut(iMarker_Monitoring); + VelocityOutIs[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetVelocityOutIs(iMarker_Monitoring); + } + } + + +// if (fluid_structure) { +// Total_CFEA = solver_container[ZONE_0][FinestMesh][FEA_SOL]->GetTotal_CFEA(); +// } + + if (output_1d) { + + /*--- Get area-averaged and flux-averaged values at the specified surface ---*/ + + OneD_AvgStagPress = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_TotalPress(); + OneD_AvgMach = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_Mach(); + OneD_AvgTemp = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_Temp(); + OneD_MassFlowRate = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_MassFlowRate(); + + OneD_FluxAvgPress = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_FluxAvgPress(); + OneD_FluxAvgDensity = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_FluxAvgDensity(); + OneD_FluxAvgVelocity = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_FluxAvgVelocity(); + OneD_FluxAvgEntalpy = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_FluxAvgEntalpy(); + + } + /*--- Get Mass Flow at the Monitored Markers ---*/ + + + if (output_massflow) { + Total_Mdot = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOneD_MassFlowRate(); + } + + /*--- Flow Residuals ---*/ + + for (iVar = 0; iVar < nVar_Flow; iVar++) + residual_flow[iVar] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetRes_RMS(iVar); + + /*--- Turbulent residual ---*/ + + if (turbulent) { + for (iVar = 0; iVar < nVar_Turb; iVar++) + residual_turbulent[iVar] = solver_container[val_iZone][FinestMesh][TURB_SOL]->GetRes_RMS(iVar); + } + + /*--- Transition residual ---*/ + + if (transition) { + for (iVar = 0; iVar < nVar_Trans; iVar++) + residual_transition[iVar] = solver_container[val_iZone][FinestMesh][TRANS_SOL]->GetRes_RMS(iVar); + } + + /*--- Free Surface residual ---*/ + + if (freesurface) { + for (iVar = 0; iVar < nVar_LevelSet; iVar++) + residual_levelset[iVar] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetRes_RMS(nDim+1); + } + + /*--- FEA residual ---*/ +// if (fluid_structure) { +// for (iVar = 0; iVar < nVar_FEA; iVar++) +// residual_fea[iVar] = solver_container[ZONE_0][FinestMesh][FEA_SOL]->GetRes_RMS(iVar); +// } + + /*--- Iterations of the linear solver ---*/ + + LinSolvIter = (unsigned long) solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetIterLinSolver(); + + /*--- Adjoint solver ---*/ + + if (adjoint) { + + /*--- Adjoint solution coefficients ---*/ + + Total_Sens_Geo = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetTotal_Sens_Geo(); + Total_Sens_Mach = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetTotal_Sens_Mach(); + Total_Sens_AoA = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetTotal_Sens_AoA(); + Total_Sens_Press = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetTotal_Sens_Press(); + Total_Sens_Temp = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetTotal_Sens_Temp(); + Total_Sens_BPress = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetTotal_Sens_BPress(); + + /*--- Adjoint flow residuals ---*/ + + for (iVar = 0; iVar < nVar_AdjFlow; iVar++) { + residual_adjflow[iVar] = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetRes_RMS(iVar); + } + + /*--- Adjoint turbulent residuals ---*/ + + if (turbulent) { + if (!config[val_iZone]->GetFrozen_Visc()) { + for (iVar = 0; iVar < nVar_AdjTurb; iVar++) + residual_adjturbulent[iVar] = solver_container[val_iZone][FinestMesh][ADJTURB_SOL]->GetRes_RMS(iVar); + } + } + + /*--- Adjoint level set residuals ---*/ + + if (freesurface) { + for (iVar = 0; iVar < nVar_AdjLevelSet; iVar++) + residual_adjlevelset[iVar] = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetRes_RMS(nDim+1); + } + + } + + break; + + case WAVE_EQUATION: + + /*--- Wave coefficients ---*/ + + Total_CWave = solver_container[val_iZone][FinestMesh][WAVE_SOL]->GetTotal_CWave(); + + /*--- Wave Residuals ---*/ + + for (iVar = 0; iVar < nVar_Wave; iVar++) { + residual_wave[iVar] = solver_container[val_iZone][FinestMesh][WAVE_SOL]->GetRes_RMS(iVar); + } + + break; + + case HEAT_EQUATION: + + /*--- Heat coefficients ---*/ + + Total_CHeat = solver_container[val_iZone][FinestMesh][HEAT_SOL]->GetTotal_CHeat(); + + /*--- Wave Residuals ---*/ + + for (iVar = 0; iVar < nVar_Heat; iVar++) { + residual_heat[iVar] = solver_container[val_iZone][FinestMesh][HEAT_SOL]->GetRes_RMS(iVar); + } + + break; + + case LINEAR_ELASTICITY: + + /*--- FEA coefficients ---*/ + + Total_CFEA = solver_container[val_iZone][FinestMesh][FEA_SOL]->GetTotal_CFEA(); + + /*--- Plasma Residuals ---*/ + + for (iVar = 0; iVar < nVar_FEA; iVar++) { + residual_fea[iVar] = solver_container[val_iZone][FinestMesh][FEA_SOL]->GetRes_RMS(iVar); + } + + break; + + } + + /*--- Header frequency ---*/ + + bool Unsteady = ((config[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config[val_iZone]->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + bool In_NoDualTime = (!DualTime_Iteration && (iExtIter % config[val_iZone]->GetWrt_Con_Freq() == 0)); + bool In_DualTime_0 = (DualTime_Iteration && (iIntIter % config[val_iZone]->GetWrt_Con_Freq_DualTime() == 0)); + bool In_DualTime_1 = (!DualTime_Iteration && Unsteady); + bool In_DualTime_2 = (Unsteady && DualTime_Iteration && (iExtIter % config[val_iZone]->GetWrt_Con_Freq() == 0)); + bool In_DualTime_3 = (Unsteady && !DualTime_Iteration && (iExtIter % config[val_iZone]->GetWrt_Con_Freq() == 0)); + + bool write_heads; + if (Unsteady) write_heads = (iIntIter == 0); + else write_heads = (((iExtIter % (config[val_iZone]->GetWrt_Con_Freq()*40)) == 0)); + bool write_turbo = (((iExtIter % (config[val_iZone]->GetWrt_Con_Freq()*200)) == 0)); + if ((In_NoDualTime || In_DualTime_0 || In_DualTime_1) && (In_NoDualTime || In_DualTime_2 || In_DualTime_3)) { + + /*--- Prepare the history file output, note that the dual + time output don't write to the history file ---*/ + if (!DualTime_Iteration) { + + /*--- Write the begining of the history file ---*/ + SPRINTF (begin, "%12d", SU2_TYPE::Int(iExtIter)); + + /*--- Write the end of the history file ---*/ + SPRINTF (end, ", %12.10f, %12.10f, %12.10f\n", su2double(LinSolvIter), config[val_iZone]->GetCFL(MESH_0), timeused/60.0); + + /*--- Write the solution and residual of the history file ---*/ + switch (config[val_iZone]->GetKind_Solver()) { + + case EULER : case NAVIER_STOKES: case RANS: + case ADJ_EULER: case ADJ_NAVIER_STOKES: case ADJ_RANS: case DISC_ADJ_EULER: + case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: + + /*--- Direct coefficients ---*/ + SPRINTF (direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", + Total_CLift, Total_CDrag, Total_CSideForce, Total_CMx, Total_CMy, Total_CMz, Total_CFx, Total_CFy, + Total_CFz, Total_CEff); + if (direct_diff != NO_DERIVATIVE){ + SPRINTF (d_direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", + D_Total_CLift, D_Total_CDrag, D_Total_CSideForce, D_Total_CMx, D_Total_CMy, D_Total_CMz, D_Total_CFx, D_Total_CFy, + D_Total_CFz, D_Total_CEff); + } + if (isothermal) + SPRINTF (direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", Total_CLift, Total_CDrag, Total_CSideForce, Total_CMx, Total_CMy, + Total_CMz, Total_CFx, Total_CFy, Total_CFz, Total_CEff, Total_Heat, Total_MaxHeat); + if (equiv_area) + SPRINTF (direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", Total_CLift, Total_CDrag, Total_CSideForce, Total_CMx, Total_CMy, Total_CMz, Total_CFx, Total_CFy, Total_CFz, Total_CEff, Total_CEquivArea, Total_CNearFieldOF); + if (inv_design) { + SPRINTF (direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", Total_CLift, Total_CDrag, Total_CSideForce, Total_CMx, Total_CMy, Total_CMz, Total_CFx, Total_CFy, Total_CFz, Total_CEff, Total_CpDiff); + Total_CpDiff = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CpDiff(); + if (isothermal) { + SPRINTF (direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", Total_CLift, Total_CDrag, Total_CSideForce, Total_CMx, Total_CMy, Total_CMz, Total_CFx, Total_CFy, Total_CFz, Total_CEff, Total_Heat, Total_MaxHeat, Total_CpDiff, Total_HeatFluxDiff); + } + } + if (rotating_frame) + SPRINTF (direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", Total_CLift, Total_CDrag, Total_CSideForce, Total_CMx, + Total_CMy, Total_CMz, Total_CFx, Total_CFy, Total_CFz, Total_CEff, Total_CMerit, Total_CT, Total_CQ); + + if (freesurface) { + SPRINTF (direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", Total_CLift, Total_CDrag, Total_CSideForce, Total_CMx, Total_CMy, Total_CMz, Total_CFx, Total_CFy, + Total_CFz, Total_CEff, Total_CFreeSurface); + } +// if (fluid_structure) +// SPRINTF (direct_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", Total_CLift, Total_CDrag, Total_CSideForce, Total_CMx, Total_CMy, Total_CMz, +// Total_CFx, Total_CFy, Total_CFz, Total_CEff, Total_CFEA); + + if (aeroelastic) { + for (iMarker_Monitoring = 0; iMarker_Monitoring < config[ZONE_0]->GetnMarker_Monitoring(); iMarker_Monitoring++) { + //Append one by one the surface coeff to aeroelastic coeff. (Think better way do this, maybe use string) + if (iMarker_Monitoring == 0) { + SPRINTF(aeroelastic_coeff, ", %12.10f", aeroelastic_plunge[iMarker_Monitoring]); + } + else { + SPRINTF(surface_coeff, ", %12.10f", aeroelastic_plunge[iMarker_Monitoring]); + strcat(aeroelastic_coeff, surface_coeff); + } + SPRINTF(surface_coeff, ", %12.10f", aeroelastic_pitch[iMarker_Monitoring]); + strcat(aeroelastic_coeff, surface_coeff); + } + } + + if (output_per_surface) { + for (iMarker_Monitoring = 0; iMarker_Monitoring < config[ZONE_0]->GetnMarker_Monitoring(); iMarker_Monitoring++) { + //Append one by one the surface coeff to monitoring coeff. (Think better way do this, maybe use string) + if (iMarker_Monitoring == 0) { + SPRINTF(monitoring_coeff, ", %12.10f", Surface_CLift[iMarker_Monitoring]); + } + else { + SPRINTF(surface_coeff, ", %12.10f", Surface_CLift[iMarker_Monitoring]); + strcat(monitoring_coeff, surface_coeff); + } + SPRINTF(surface_coeff, ", %12.10f", Surface_CDrag[iMarker_Monitoring]); + strcat(monitoring_coeff, surface_coeff); + SPRINTF(surface_coeff, ", %12.10f", Surface_CSideForce[iMarker_Monitoring]); + strcat(monitoring_coeff, surface_coeff); + SPRINTF(surface_coeff, ", %12.10f", Surface_CEff[iMarker_Monitoring]); + strcat(monitoring_coeff, surface_coeff); + SPRINTF(surface_coeff, ", %12.10f", Surface_CFx[iMarker_Monitoring]); + strcat(monitoring_coeff, surface_coeff); + SPRINTF(surface_coeff, ", %12.10f", Surface_CFy[iMarker_Monitoring]); + strcat(monitoring_coeff, surface_coeff); + SPRINTF(surface_coeff, ", %12.10f", Surface_CFz[iMarker_Monitoring]); + strcat(monitoring_coeff, surface_coeff); + SPRINTF(surface_coeff, ", %12.10f", Surface_CMx[iMarker_Monitoring]); + strcat(monitoring_coeff, surface_coeff); + SPRINTF(surface_coeff, ", %12.10f", Surface_CMy[iMarker_Monitoring]); + strcat(monitoring_coeff, surface_coeff); + SPRINTF(surface_coeff, ", %12.10f", Surface_CMz[iMarker_Monitoring]); + strcat(monitoring_coeff, surface_coeff); + } + } + + + /*--- Flow residual ---*/ + if (nDim == 2) { + if (compressible) SPRINTF (flow_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", log10 (residual_flow[0]), log10 (residual_flow[1]), log10 (residual_flow[2]), log10 (residual_flow[3]), dummy); + if (incompressible || freesurface) SPRINTF (flow_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", log10 (residual_flow[0]), log10 (residual_flow[1]), log10 (residual_flow[2]), dummy, dummy); + } + else { + if (compressible) SPRINTF (flow_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", log10 (residual_flow[0]), log10 (residual_flow[1]), log10 (residual_flow[2]), log10 (residual_flow[3]), log10 (residual_flow[4]) ); + if (incompressible || freesurface) SPRINTF (flow_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", log10 (residual_flow[0]), log10 (residual_flow[1]), log10 (residual_flow[2]), log10 (residual_flow[3]), dummy); + } + + /*--- Turbulent residual ---*/ + if (turbulent) { + switch(nVar_Turb) { + case 1: SPRINTF (turb_resid, ", %12.10f", log10 (residual_turbulent[0])); break; + case 2: SPRINTF (turb_resid, ", %12.10f, %12.10f", log10(residual_turbulent[0]), log10(residual_turbulent[1])); break; + } + } + /*---- Averaged stagnation pressure at an exit ----*/ + if (output_1d) { + SPRINTF( oneD_outputs, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", OneD_AvgStagPress, OneD_AvgMach, OneD_AvgTemp, OneD_MassFlowRate, OneD_FluxAvgPress, OneD_FluxAvgDensity, OneD_FluxAvgVelocity, OneD_FluxAvgEntalpy); + } + if (output_massflow && !output_1d) { + SPRINTF(massflow_outputs,", %12.10f", Total_Mdot); + } + + + /*--- Transition residual ---*/ + if (transition) { + SPRINTF (trans_resid, ", %12.10f, %12.10f", log10(residual_transition[0]), log10(residual_transition[1])); + } + + /*--- Free surface residual ---*/ + if (freesurface) { + SPRINTF (levelset_resid, ", %12.10f", log10 (residual_levelset[0])); + } + + /*--- Fluid structure residual ---*/ +// if (fluid_structure) { +// if (nDim == 2) SPRINTF (levelset_resid, ", %12.10f, %12.10f, 0.0", log10 (residual_fea[0]), log10 (residual_fea[1])); +// else SPRINTF (levelset_resid, ", %12.10f, %12.10f, %12.10f", log10 (residual_fea[0]), log10 (residual_fea[1]), log10 (residual_fea[2])); +// } + + if (adjoint) { + + /*--- Adjoint coefficients ---*/ + SPRINTF (adjoint_coeff, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f, 0.0, %12.10f", Total_Sens_Geo, Total_Sens_Mach, Total_Sens_AoA, Total_Sens_Press, Total_Sens_Temp, Total_Sens_BPress); + + /*--- Adjoint flow residuals ---*/ + if (nDim == 2) { + if (compressible) SPRINTF (adj_flow_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, 0.0", log10 (residual_adjflow[0]), log10 (residual_adjflow[1]), log10 (residual_adjflow[2]), log10 (residual_adjflow[3]) ); + if (incompressible || freesurface) SPRINTF (adj_flow_resid, ", %12.10f, %12.10f, %12.10f, 0.0, 0.0", log10 (residual_adjflow[0]), log10 (residual_adjflow[1]), log10 (residual_adjflow[2]) ); + } + else { + if (compressible) SPRINTF (adj_flow_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", log10 (residual_adjflow[0]), log10 (residual_adjflow[1]), log10 (residual_adjflow[2]), log10 (residual_adjflow[3]), log10 (residual_adjflow[4]) ); + if (incompressible || freesurface) SPRINTF (adj_flow_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, 0.0", log10 (residual_adjflow[0]), log10 (residual_adjflow[1]), log10 (residual_adjflow[2]), log10 (residual_adjflow[3]) ); + } + + /*--- Adjoint turbulent residuals ---*/ + if (turbulent) + if (!config[val_iZone]->GetFrozen_Visc()) + SPRINTF (adj_turb_resid, ", %12.10f", log10 (residual_adjturbulent[0])); + + /*--- Adjoint free surface residuals ---*/ + if (freesurface) SPRINTF (adj_levelset_resid, ", %12.10f", log10 (residual_adjlevelset[0])); + } + + break; + + case WAVE_EQUATION: + + SPRINTF (direct_coeff, ", %12.10f", Total_CWave); + SPRINTF (wave_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", log10 (residual_wave[0]), log10 (residual_wave[1]), dummy, dummy, dummy ); + + break; + + case HEAT_EQUATION: + + SPRINTF (direct_coeff, ", %12.10f", Total_CHeat); + SPRINTF (heat_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", log10 (residual_heat[0]), dummy, dummy, dummy, dummy ); + + break; + + case LINEAR_ELASTICITY: + + SPRINTF (direct_coeff, ", %12.10f", Total_CFEA); + SPRINTF (fea_resid, ", %12.10f, %12.10f, %12.10f, %12.10f, %12.10f", log10 (residual_fea[0]), dummy, dummy, dummy, dummy ); + + break; + + } + } + + /*--- Write the screen header---*/ + if ((write_heads) && !(!DualTime_Iteration && Unsteady)) { + + if (!Unsteady) { + switch (config[val_iZone]->GetKind_Solver()) { + case EULER : case NAVIER_STOKES: case RANS: + case ADJ_EULER : case ADJ_NAVIER_STOKES: case ADJ_RANS: + + cout << endl << "---------------------- Local Time Stepping Summary ----------------------" << endl; + + for (unsigned short iMesh = FinestMesh; iMesh <= config[val_iZone]->GetnMGLevels(); iMesh++) + cout << "MG level: "<< iMesh << " -> Min. DT: " << solver_container[val_iZone][iMesh][FLOW_SOL]->GetMin_Delta_Time()<< + ". Max. DT: " << solver_container[val_iZone][iMesh][FLOW_SOL]->GetMax_Delta_Time() << + ". CFL: " << config[val_iZone]->GetCFL(iMesh) << "." << endl; + + cout << "-------------------------------------------------------------------------" << endl; + + if (direct_diff != NO_DERIVATIVE){ + cout << endl << "---------------------- Direct Differentiation Summary -------------------" << endl; + cout << "Coefficients are differentiated with respect to "; + switch (direct_diff) { + case D_MACH: + cout << "Mach number." << endl; + break; + case D_AOA: + cout << "AoA." << endl; + break; + case D_SIDESLIP: + cout << "AoS." << endl; + break; + case D_REYNOLDS: + cout << "Reynolds number." << endl; + break; + case D_TURB2LAM: + cout << "Turb/Lam ratio." << endl; + break; + case D_PRESSURE: + cout << "Freestream Pressure." << endl; + break; + case D_TEMPERATURE: + cout << "Freestream Temperature." << endl; + break; + case D_DENSITY: + cout << "Freestream Density." << endl; + break; + case D_VISCOSITY: + cout << "Freestream Viscosity." << endl; + break; + case D_DESIGN: + cout << "Design Variables." << endl; + break; + default: + break; + } + + cout << " D_CLift(Total)" << " D_CDrag(Total)" << " D_CMz(Total)" <<" D_CEff(Total)" << endl; + cout.width(18); cout << D_Total_CLift; + cout.width(18); cout << D_Total_CDrag; + cout.width(18); cout << D_Total_CMz; + cout.width(18); cout << D_Total_CEff; + cout << endl << "-------------------------------------------------------------------------" << endl; + cout << endl; + } + if (turbo && write_turbo){ + cout << endl << "---------------------- Turbo Performance Summary -------------------" << endl; + for (iMarker_Monitoring = 0; iMarker_Monitoring < config[ZONE_0]->Get_nMarkerTurboPerf(); iMarker_Monitoring++){ + inMarker_Tag = config[ZONE_0]->GetMarker_TurboPerf_BoundIn(iMarker_Monitoring); + outMarker_Tag = config[ZONE_0]->GetMarker_TurboPerf_BoundOut(iMarker_Monitoring); + switch (config[ZONE_0]->GetKind_TurboPerf(iMarker_Monitoring)) { + case BLADE: + cout << "Blade performance between boundaries " << inMarker_Tag << " and "<< outMarker_Tag << " : "<GetWrt_Sol_Freq() << " iterations): "; + cout.precision(4); + cout.setf(ios::scientific, ios::floatfield); + cout << Total_Sens_Geo; + cout << endl << "-------------------------------------------------------------------------" << endl; + break; + + } + } + else { + if (flow) { + cout << endl << "Min DT: " << solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetMin_Delta_Time()<< + ".Max DT: " << solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetMax_Delta_Time() << + ".Dual Time step: " << config[val_iZone]->GetDelta_UnstTimeND() << "."; + } + else { + cout << endl << "Dual Time step: " << config[val_iZone]->GetDelta_UnstTimeND() << "."; + } + } + + switch (config[val_iZone]->GetKind_Solver()) { + case EULER : case NAVIER_STOKES: + + /*--- Visualize the maximum residual ---*/ + iPointMaxResid = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetPoint_Max(0); + Coord = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetPoint_Max_Coord(0); + + cout << endl << "----------------------- Residual Evolution Summary ----------------------" << endl; + + cout << "log10[Maximum residual]: " << log10(solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetRes_Max(0)) << "." << endl; + + if (config[val_iZone]->GetSystemMeasurements() == SI) { + cout <<"Maximum residual point " << iPointMaxResid << ", located at (" << Coord[0] << ", " << Coord[1]; + if (nDim == 3) cout << ", " << Coord[2]; + cout << ")." << endl; + } + else { + cout <<"Maximum residual point " << iPointMaxResid << ", located at (" << Coord[0]*12.0 << ", " << Coord[1]*12.0; + if (nDim == 3) cout << ", " << Coord[2]*12.0; + cout << ")." << endl; + } + + /*--- Print out the number of non-physical points and reconstructions ---*/ + + if (config[val_iZone]->GetNonphysical_Points() > 0) + cout << "There are " << config[val_iZone]->GetNonphysical_Points() << " non-physical points in the solution." << endl; + if (config[val_iZone]->GetNonphysical_Reconstr() > 0) + cout << "There are " << config[val_iZone]->GetNonphysical_Reconstr() << " non-physical states in the upwind reconstruction." << endl; + + cout << "-------------------------------------------------------------------------" << endl; + + if (!Unsteady) cout << endl << " Iter" << " Time(s)"; + else cout << endl << " IntIter" << " ExtIter"; + +// if (!fluid_structure) { + if (incompressible) cout << " Res[Press]" << " Res[Velx]" << " CLift(Total)" << " CDrag(Total)" << endl; + else if (freesurface) cout << " Res[Press]" << " Res[Dist]" << " CLift(Total)" << " CLevelSet" << endl; + else if (rotating_frame && nDim == 3) cout << " Res[Rho]" << " Res[RhoE]" << " CThrust(Total)" << " CTorque(Total)" << endl; + else if (aeroelastic) cout << " Res[Rho]" << " Res[RhoE]" << " CLift(Total)" << " CDrag(Total)" << " plunge" << " pitch" << endl; + else if (equiv_area) cout << " Res[Rho]" << " CLift(Total)" << " CDrag(Total)" << " CPress(N-F)" << endl; + else if (turbo) + switch (config[ZONE_0]->GetKind_TurboPerf(0)) { + case BLADE: + cout << " Res[Rho]" << " Res[RhoE]" << " KineticLoss(%)" << " D_MassFlow(%)" << endl; + break; + case STAGE: case TURBINE: + cout << " Res[Rho]" << " Res[RhoE]" << " TSEfficiency(%)" << " Outlet Pressure" << endl; + break; + default: + break; + } + else cout << " Res[Rho]" << " Res[RhoE]" << " CLift(Total)" << " CDrag(Total)" << endl; +// } +// else if (fluid_structure) cout << " Res[Rho]" << " Res[Displx]" << " CLift(Total)" << " CDrag(Total)" << endl; + + break; + + case RANS : + + /*--- Visualize the maximum residual ---*/ + iPointMaxResid = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetPoint_Max(0); + Coord = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetPoint_Max_Coord(0); + + cout << endl << "----------------------- Residual Evolution Summary ----------------------" << endl; + + cout << "log10[Maximum residual]: " << log10(solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetRes_Max(0)) << "." << endl; + if (config[val_iZone]->GetSystemMeasurements() == SI) { + cout <<"Maximum residual point " << iPointMaxResid << ", located at (" << Coord[0] << ", " << Coord[1]; + if (nDim == 3) cout << ", " << Coord[2]; + cout << ")." << endl; + } + else { + cout <<"Maximum residual point " << iPointMaxResid << ", located at (" << Coord[0]*12.0 << ", " << Coord[1]*12.0; + if (nDim == 3) cout << ", " << Coord[2]*12.0; + cout << ")." << endl; + } + cout <<"Maximum Omega " << solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetOmega_Max() << ", maximum Strain Rate " << solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetStrainMag_Max() << "." << endl; + + /*--- Print out the number of non-physical points and reconstructions ---*/ + if (config[val_iZone]->GetNonphysical_Points() > 0) + cout << "There are " << config[val_iZone]->GetNonphysical_Points() << " non-physical points in the solution." << endl; + if (config[val_iZone]->GetNonphysical_Reconstr() > 0) + cout << "There are " << config[val_iZone]->GetNonphysical_Reconstr() << " non-physical states in the upwind reconstruction." << endl; + + cout << "-------------------------------------------------------------------------" << endl; + + if (!Unsteady) cout << endl << " Iter" << " Time(s)"; + else cout << endl << " IntIter" << " ExtIter"; + if (incompressible || freesurface) cout << " Res[Press]"; + else cout << " Res[Rho]";//, cout << " Res[RhoE]"; + + switch (config[val_iZone]->GetKind_Turb_Model()) { + case SA: cout << " Res[nu]"; break; + case SA_NEG: cout << " Res[nu]"; break; + case SST: cout << " Res[kine]" << " Res[omega]"; break; + } + + if (transition) { cout << " Res[Int]" << " Res[Re]"; } + else if (rotating_frame && nDim == 3 ) cout << " CThrust(Total)" << " CTorque(Total)" << endl; + else if (aeroelastic) cout << " CLift(Total)" << " CDrag(Total)" << " plunge" << " pitch" << endl; + else if (equiv_area) cout << " CLift(Total)" << " CDrag(Total)" << " CPress(N-F)" << endl; + else if (turbo) + switch (config[ZONE_0]->GetKind_TurboPerf(0)) { + case BLADE: + cout << " KineticLoss(%)" << " D_MassFlow(%)" << endl; + break; + case STAGE: case TURBINE: + cout << " TSEfficiency(%)" << " Outlet Pressure" << endl; + break; + default: + break; + } + + else cout << " CLift(Total)" << " CDrag(Total)" << endl; + + break; + + case WAVE_EQUATION : + if (!Unsteady) cout << endl << " Iter" << " Time(s)"; + else cout << endl << " IntIter" << " ExtIter"; + + cout << " Res[Wave]" << " CWave(Total)"<< endl; + break; + + case HEAT_EQUATION : + if (!Unsteady) cout << endl << " Iter" << " Time(s)"; + else cout << endl << " IntIter" << " ExtIter"; + + cout << " Res[Heat]" << " CHeat(Total)"<< endl; + break; + + case LINEAR_ELASTICITY : + if (!Unsteady) cout << endl << " Iter" << " Time(s)"; + else cout << endl << " IntIter" << " ExtIter"; + + if (nDim == 2) cout << " Res[Displx]" << " Res[Disply]" << " CFEA(Total)"<< endl; + if (nDim == 3) cout << " Res[Displx]" << " Res[Disply]" << " Res[Displz]" << " CFEA(Total)"<< endl; + break; + + case ADJ_EULER : case ADJ_NAVIER_STOKES : + case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: + + /*--- Visualize the maximum residual ---*/ + iPointMaxResid = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetPoint_Max(0); + Coord = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetPoint_Max_Coord(0); + cout << endl << "log10[Maximum residual]: " << log10(solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetRes_Max(0)) << "." << endl; + if (config[val_iZone]->GetSystemMeasurements() == SI) { + cout <<"Maximum residual point " << iPointMaxResid << ", located at (" << Coord[0] << ", " << Coord[1]; + if (nDim == 3) cout << ", " << Coord[2]; + cout << ")." << endl; + } + else { + cout <<"Maximum residual point " << iPointMaxResid << ", located at (" << Coord[0]*12.0 << ", " << Coord[1]*12.0; + if (nDim == 3) cout << ", " << Coord[2]*12.0; + cout << ")." << endl; + } + + /*--- Print out the number of non-physical points and reconstructions ---*/ + if (config[val_iZone]->GetNonphysical_Points() > 0) + cout << "There are " << config[val_iZone]->GetNonphysical_Points() << " non-physical points in the solution." << endl; + + if (!Unsteady) cout << endl << " Iter" << " Time(s)"; + else cout << endl << " IntIter" << " ExtIter"; + + if (incompressible || freesurface) cout << " Res[Psi_Press]" << " Res[Psi_Velx]"; + else cout << " Res[Psi_Rho]" << " Res[Psi_E]"; + if (disc_adj){ + cout << " Sens_Press" << " Sens_Mach" << endl; + } else { + if (output_1d) + cout << " Sens_Geo" << " Sens_BPress" << endl; + else + cout << " Sens_Geo" << " Sens_Mach" << endl; + } + if (freesurface) { + cout << " Res[Psi_Press]" << " Res[Psi_Dist]" << " Sens_Geo"; + if (output_1d) + cout << " Sens_BPress" << endl; + else + cout << " Sens_Mach" << endl; + } + break; + + case ADJ_RANS : case DISC_ADJ_RANS: + + /*--- Visualize the maximum residual ---*/ + iPointMaxResid = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetPoint_Max(0); + Coord = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetPoint_Max_Coord(0); + cout << endl << "log10[Maximum residual]: " << log10(solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetRes_Max(0)) << "." << endl; + if (config[val_iZone]->GetSystemMeasurements() == SI) { + cout <<"Maximum residual point " << iPointMaxResid << ", located at (" << Coord[0] << ", " << Coord[1]; + if (nDim == 3) cout << ", " << Coord[2]; + cout << ")." << endl; + } + else { + cout <<"Maximum residual point " << iPointMaxResid << ", located at (" << Coord[0]*12.0 << ", " << Coord[1]*12.0; + if (nDim == 3) cout << ", " << Coord[2]*12.0; + cout << ")." << endl; + } + + /*--- Print out the number of non-physical points and reconstructions ---*/ + if (config[val_iZone]->GetNonphysical_Points() > 0) + cout << "There are " << config[val_iZone]->GetNonphysical_Points() << " non-physical points in the solution." << endl; + + if (!Unsteady) cout << endl << " Iter" << " Time(s)"; + else cout << endl << " IntIter" << " ExtIter"; + + if (incompressible || freesurface) cout << " Res[Psi_Press]"; + else cout << " Res[Psi_Rho]"; + + if (!config[val_iZone]->GetFrozen_Visc()) { + cout << " Res[Psi_nu]"; + } + else { + if (incompressible || freesurface) cout << " Res[Psi_Velx]"; + else cout << " Res[Psi_E]"; + } + if (disc_adj){ + cout << " Sens_Press" << " Sens_Mach" << endl; + } else { + if (output_1d) + cout << " Sens_Geo" << " Sens_BPress" << endl; + else + cout << " Sens_Geo" << " Sens_Mach" << endl; + } + if (freesurface) { + cout << " Res[Psi_Press]" << " Res[Psi_Dist]" << " Sens_Geo"; + if (output_1d) + cout << " Sens_BPress" << endl; + else + cout << " Sens_Mach" << endl; + } + break; + + } + + } + + /*--- Write the solution on the screen and history file ---*/ + cout.precision(6); + cout.setf(ios::fixed, ios::floatfield); + + if (!Unsteady) { + cout.width(5); cout << iExtIter; + cout.width(11); cout << timeiter; + + } else { + cout.width(8); cout << iIntIter; + cout.width(8); cout << iExtIter; + } + + switch (config[val_iZone]->GetKind_Solver()) { + case EULER : case NAVIER_STOKES: + + if (!DualTime_Iteration) { + if (compressible) ConvHist_file[0] << begin << direct_coeff << flow_resid; + if (incompressible) ConvHist_file[0] << begin << direct_coeff << flow_resid; + if (freesurface) ConvHist_file[0] << begin << direct_coeff << flow_resid << levelset_resid << end; +// if (fluid_structure) ConvHist_file[0] << fea_resid; + if (aeroelastic) ConvHist_file[0] << aeroelastic_coeff; + if (output_per_surface) ConvHist_file[0] << monitoring_coeff; + if (output_1d) ConvHist_file[0] << oneD_outputs; + if (output_massflow and !output_1d) ConvHist_file[0] << massflow_outputs; + if (direct_diff != NO_DERIVATIVE) ConvHist_file[0] << d_direct_coeff; + ConvHist_file[0] << end; + ConvHist_file[0].flush(); + } + + cout.precision(6); + cout.setf(ios::fixed, ios::floatfield); + cout.width(13); cout << log10(residual_flow[0]); +// if (!fluid_structure && !equiv_area) { + if (!equiv_area) { + if (compressible) { + if (nDim == 2 ) { cout.width(14); cout << log10(residual_flow[3]); } + else { cout.width(14); cout << log10(residual_flow[4]); } + } + if (incompressible) { cout.width(14); cout << log10(residual_flow[1]); } + if (freesurface) { cout.width(14); cout << log10(residual_levelset[0]); } + } +// else if (fluid_structure) { cout.width(14); cout << log10(residual_fea[0]); } + + if (rotating_frame && nDim == 3 ) { + cout.setf(ios::scientific, ios::floatfield); + cout.width(15); cout << Total_CT; + cout.width(15); cout << Total_CQ; + cout.unsetf(ios_base::floatfield); + } + else if (equiv_area) { cout.width(15); cout << min(10000.0, max(-10000.0, Total_CLift)); cout.width(15); cout << min(10000.0, max(-10000.0, Total_CDrag)); cout.width(15); + cout.precision(4); + cout.setf(ios::scientific, ios::floatfield); + cout << Total_CNearFieldOF; } + else if (freesurface) { cout.width(15); cout << Total_CLift; cout.width(15); cout << Total_CFreeSurface; } + else if (turbo) { + cout.setf(ios::scientific, ios::floatfield); + switch (config[ZONE_0]->GetKind_TurboPerf(0)) { + case BLADE: + cout.width(15); cout << KineticEnergyLoss[0]*100.0; + cout.width(15); cout << abs((MassFlowIn[0] + MassFlowOut[0])/MassFlowIn[0])*100.0; + break; + case STAGE: case TURBINE: + cout.width(15); cout << TotalStaticEfficiency[0]*100.0; + cout.width(15); cout << PressureOut[0]; + break; + default: + break; + } + cout.unsetf(ios_base::floatfield); + } + else { cout.width(15); cout << min(10000.0, max(-10000.0, Total_CLift)); cout.width(15); cout << min(10000.0, max(-10000.0, Total_CDrag)); } + if (aeroelastic) { + cout.setf(ios::scientific, ios::floatfield); + cout.width(15); cout << aeroelastic_plunge[0]; //Only output the first marker being monitored to the console. + cout.width(15); cout << aeroelastic_pitch[0]; + cout.unsetf(ios_base::floatfield); + } + cout << endl; + + break; + + case RANS : + + if (!DualTime_Iteration) { + ConvHist_file[0] << begin << direct_coeff << flow_resid << turb_resid; + if (aeroelastic) ConvHist_file[0] << aeroelastic_coeff; + if (output_per_surface) ConvHist_file[0] << monitoring_coeff; + if (output_1d) ConvHist_file[0] << oneD_outputs; + if (output_massflow and !output_1d) ConvHist_file[0] << massflow_outputs; + if (direct_diff != NO_DERIVATIVE) ConvHist_file[0] << d_direct_coeff; + ConvHist_file[0] << end; + ConvHist_file[0].flush(); + } + + cout.precision(6); + cout.setf(ios::fixed, ios::floatfield); + + if (incompressible || freesurface) cout.width(13); + else cout.width(14); + cout << log10(residual_flow[0]); +// else cout.width(14), +// cout << log10(residual_flow[0]), +// cout.width(14); +// if ( nDim==2 ) cout << log10(residual_flow[3]); +// if ( nDim==3 ) cout << log10(residual_flow[4]); + + switch(nVar_Turb) { + case 1: cout.width(14); cout << log10(residual_turbulent[0]); break; + case 2: cout.width(14); cout << log10(residual_turbulent[0]); + cout.width(15); cout << log10(residual_turbulent[1]); break; + } + + if (transition) { cout.width(14); cout << log10(residual_transition[0]); cout.width(14); cout << log10(residual_transition[1]); } + + if (rotating_frame && nDim == 3 ) { + cout.setf(ios::scientific, ios::floatfield); + cout.width(15); cout << Total_CT; cout.width(15); + cout << Total_CQ; + cout.unsetf(ios_base::floatfield); + } + else if (equiv_area) { cout.width(15); cout << min(10000.0, max(-10000.0, Total_CLift)); cout.width(15); cout << min(10000.0, max(-10000.0, Total_CDrag)); cout.width(15); + cout.precision(4); + cout.setf(ios::scientific, ios::floatfield); + cout << Total_CNearFieldOF; } + else if (turbo) { + cout.setf(ios::scientific, ios::floatfield); + switch (config[ZONE_0]->GetKind_TurboPerf(0)) { + case BLADE: + cout.width(15); cout << KineticEnergyLoss[0]*100.0; + cout.width(15); cout << abs((MassFlowIn[0] + MassFlowOut[0])/MassFlowIn[0])*100.0; + break; + case STAGE: case TURBINE: + cout.width(15); cout << TotalStaticEfficiency[0]*100.0; + cout.width(15); cout << PressureOut[0]; + break; + default: + break; + } + cout.unsetf(ios_base::floatfield); + } + else { cout.width(15); cout << min(10000.0, max(-10000.0, Total_CLift)); cout.width(15); cout << min(10000.0, max(-10000.0, Total_CDrag)); } + + if (aeroelastic) { + cout.setf(ios::scientific, ios::floatfield); + cout.width(15); cout << aeroelastic_plunge[0]; //Only output the first marker being monitored to the console. + cout.width(15); cout << aeroelastic_pitch[0]; + cout.unsetf(ios_base::floatfield); + } + cout << endl; + + if (freesurface) { + if (!DualTime_Iteration) { + ConvHist_file[0] << begin << direct_coeff << flow_resid << levelset_resid << end; + ConvHist_file[0].flush(); + } + + cout.precision(6); + cout.setf(ios::fixed, ios::floatfield); + cout.width(13); cout << log10(residual_flow[0]); + cout.width(14); cout << log10(residual_levelset[0]); + cout.width(15); cout << Total_CLift; + cout.width(14); cout << Total_CFreeSurface; + + cout << endl; + } + + break; + + case WAVE_EQUATION: + + if (!DualTime_Iteration) { + ConvHist_file[0] << begin << wave_coeff << wave_resid << end; + ConvHist_file[0].flush(); + } + + cout.precision(6); + cout.setf(ios::fixed, ios::floatfield); + cout.width(14); cout << log10(residual_wave[0]); + cout.width(14); cout << Total_CWave; + cout << endl; + break; + + case HEAT_EQUATION: + + if (!DualTime_Iteration) { + ConvHist_file[0] << begin << heat_coeff << heat_resid << end; + ConvHist_file[0].flush(); + } + + cout.precision(6); + cout.setf(ios::fixed, ios::floatfield); + cout.width(14); cout << log10(residual_heat[0]); + cout.width(14); cout << Total_CHeat; + cout << endl; + break; + + case LINEAR_ELASTICITY: + + if (!DualTime_Iteration) { + ConvHist_file[0] << begin << fea_coeff << fea_resid << end; + ConvHist_file[0].flush(); + } + + cout.precision(6); + cout.setf(ios::fixed, ios::floatfield); + cout.width(15); cout << log10(residual_fea[0]); + cout.width(15); cout << log10(residual_fea[1]); + if (nDim == 3) { cout.width(15); cout << log10(residual_fea[2]); } + cout.precision(4); + cout.setf(ios::scientific, ios::floatfield); + cout.width(14); cout << Total_CFEA; + cout << endl; + break; + + case ADJ_EULER : case ADJ_NAVIER_STOKES : + case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: + + if (!DualTime_Iteration) { + ConvHist_file[0] << begin << adjoint_coeff << adj_flow_resid << end; + ConvHist_file[0].flush(); + } + + cout.precision(6); + cout.setf(ios::fixed, ios::floatfield); + if (compressible) { + cout.width(15); cout << log10(residual_adjflow[0]); + cout.width(15); cout << log10(residual_adjflow[nDim+1]); + } + if (incompressible || freesurface) { + cout.width(17); cout << log10(residual_adjflow[0]); + cout.width(16); cout << log10(residual_adjflow[1]); + } + + if (disc_adj){ + cout.precision(4); + cout.setf(ios::scientific, ios::floatfield); + cout.width(14); cout << Total_Sens_Press; + cout.width(14); cout << Total_Sens_Mach; + }else{ + cout.precision(4); + cout.setf(ios::scientific, ios::floatfield); + cout.width(14); cout << Total_Sens_Geo; + if (output_1d){ + cout.width(14); cout << Total_Sens_BPress; + } + else{ + cout.width(14); cout << Total_Sens_Mach; + } + } + cout << endl; + cout.unsetf(ios_base::floatfield); + + if (freesurface) { + if (!DualTime_Iteration) { + ConvHist_file[0] << begin << adjoint_coeff << adj_flow_resid << adj_levelset_resid << end; + ConvHist_file[0].flush(); + } + + cout.precision(6); + cout.setf(ios::fixed, ios::floatfield); + cout.width(17); cout << log10(residual_adjflow[0]); + cout.width(16); cout << log10(residual_adjlevelset[0]); + cout.precision(3); + cout.setf(ios::scientific, ios::floatfield); + cout.width(12); cout << Total_Sens_Geo; + if (output_1d){ + cout.width(12); cout << Total_Sens_BPress; + } + else{ + cout.width(12); cout << Total_Sens_Mach; + } + cout.unsetf(ios_base::floatfield); + cout << endl; + } + + break; + + case ADJ_RANS : case DISC_ADJ_RANS: + + if (!DualTime_Iteration) { + ConvHist_file[0] << begin << adjoint_coeff << adj_flow_resid; + if (!config[val_iZone]->GetFrozen_Visc()) + ConvHist_file[0] << adj_turb_resid; + ConvHist_file[0] << end; + ConvHist_file[0].flush(); + } + + cout.precision(6); + cout.setf(ios::fixed, ios::floatfield); + cout.width(17); cout << log10(residual_adjflow[0]); + if (!config[val_iZone]->GetFrozen_Visc()) { + cout.width(17); cout << log10(residual_adjturbulent[0]); + } + else { + if (compressible) { + if (geometry[val_iZone][FinestMesh]->GetnDim() == 2 ) { cout.width(15); cout << log10(residual_adjflow[3]); } + else { cout.width(15); cout << log10(residual_adjflow[4]); } + } + if (incompressible || freesurface) { + cout.width(15); cout << log10(residual_adjflow[1]); + } + } + if (disc_adj){ + cout.precision(4); + cout.setf(ios::scientific, ios::floatfield); + cout.width(14); cout << Total_Sens_Press; + cout.width(14); cout << Total_Sens_Mach; + }else{ + cout.precision(4); + cout.setf(ios::scientific, ios::floatfield); + cout.width(14); cout << Total_Sens_Geo; + if (output_1d){ + cout.width(14); cout << Total_Sens_BPress; + } + else{ + cout.width(14); cout << Total_Sens_Mach; + } + } + cout << endl; + cout.unsetf(ios_base::floatfield); + if (freesurface) { + if (!DualTime_Iteration) { + ConvHist_file[0] << begin << adjoint_coeff << adj_flow_resid << adj_levelset_resid; + ConvHist_file[0] << end; + ConvHist_file[0].flush(); + } + + cout.precision(6); + cout.setf(ios::fixed, ios::floatfield); + cout.width(17); cout << log10(residual_adjflow[0]); + cout.width(16); cout << log10(residual_adjlevelset[0]); + + cout.precision(4); + cout.setf(ios::scientific, ios::floatfield); + cout.width(12); cout << Total_Sens_Geo; + if (output_1d){ + cout.width(14); cout << Total_Sens_BPress; + } + else{ + cout.width(14); cout << Total_Sens_Mach; + } + cout << endl; + cout.unsetf(ios_base::floatfield); + } + + break; + + } + cout.unsetf(ios::fixed); + + delete [] residual_flow; + delete [] residual_turbulent; + delete [] residual_transition; + delete [] residual_levelset; + delete [] residual_wave; + delete [] residual_fea; + delete [] residual_heat; + + delete [] residual_adjflow; + delete [] residual_adjturbulent; + delete [] residual_adjlevelset; + + delete [] Surface_CLift; + delete [] Surface_CDrag; + delete [] Surface_CSideForce; + delete [] Surface_CEff; + delete [] Surface_CFx; + delete [] Surface_CFy; + delete [] Surface_CFz; + delete [] Surface_CMx; + delete [] Surface_CMy; + delete [] Surface_CMz; + delete [] aeroelastic_pitch; + delete [] aeroelastic_plunge; + + delete [] TotalStaticEfficiency; + delete [] TotalTotalEfficiency; + delete [] KineticEnergyLoss; + delete [] TotalPressureLoss; + delete [] MassFlowIn; + delete [] MassFlowOut; + delete [] FlowAngleIn; + delete [] FlowAngleOut; + delete [] EulerianWork; + delete [] TotalEnthalpyIn; + delete [] PressureRatio; + delete [] PressureOut; + delete [] EnthalpyOut; + delete [] MachIn; + delete [] MachOut; + delete [] NormalMachIn; + delete [] NormalMachOut; + delete [] VelocityOutIs; + } + } +} + +void COutput::SetCFL_Number(CSolver ****solver_container, CConfig **config, unsigned short val_iZone) { + + su2double CFLFactor = 1.0, power = 1.0, CFL = 0.0, CFLMin = 0.0, CFLMax = 0.0, Div = 1.0, Diff = 0.0, MGFactor[100]; + unsigned short iMesh; + + unsigned short FinestMesh = config[val_iZone]->GetFinestMesh(); + unsigned long ExtIter = config[val_iZone]->GetExtIter(); + + RhoRes_New = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetRes_RMS(0); + switch( config[val_iZone]->GetKind_Solver()){ + case ADJ_EULER : case ADJ_NAVIER_STOKES: case ADJ_RANS: + RhoRes_New = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetRes_RMS(0); + break; + } + + if (RhoRes_New < EPS) RhoRes_New = EPS; + if (RhoRes_Old < EPS) RhoRes_Old = RhoRes_New; + + Div = RhoRes_Old/RhoRes_New; + Diff = RhoRes_New-RhoRes_Old; + + /*--- Compute MG factor ---*/ + + for (iMesh = 0; iMesh <= config[val_iZone]->GetnMGLevels(); iMesh++) { + if (iMesh == MESH_0) MGFactor[iMesh] = 1.0; + else MGFactor[iMesh] = MGFactor[iMesh-1] * config[val_iZone]->GetCFL(iMesh)/config[val_iZone]->GetCFL(iMesh-1); + } + + if (Div < 1.0) power = config[val_iZone]->GetCFL_AdaptParam(0); + else power = config[val_iZone]->GetCFL_AdaptParam(1); + + /*--- Detect a stall in the residual ---*/ + + if ((fabs(Diff) <= RhoRes_New*1E-8) && (ExtIter != 0)) { Div = 0.1; power = config[val_iZone]->GetCFL_AdaptParam(1); } + + CFLMin = config[val_iZone]->GetCFL_AdaptParam(2); + CFLMax = config[val_iZone]->GetCFL_AdaptParam(3); + + CFLFactor = pow(Div, power); + + for (iMesh = 0; iMesh <= config[val_iZone]->GetnMGLevels(); iMesh++) { + CFL = config[val_iZone]->GetCFL(iMesh); + CFL *= CFLFactor; + + if ((iMesh == MESH_0) && (CFL <= CFLMin)) { + for (iMesh = 0; iMesh <= config[val_iZone]->GetnMGLevels(); iMesh++) { + config[val_iZone]->SetCFL(iMesh, 1.001*CFLMin*MGFactor[iMesh]); + } + break; + } + if ((iMesh == MESH_0) && (CFL >= CFLMax)) { + for (iMesh = 0; iMesh <= config[val_iZone]->GetnMGLevels(); iMesh++) + config[val_iZone]->SetCFL(iMesh, 0.999*CFLMax*MGFactor[iMesh]); + break; + } + + config[val_iZone]->SetCFL(iMesh, CFL); + + } + + RhoRes_Old = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetRes_RMS(0); + switch( config[val_iZone]->GetKind_Solver()){ + case ADJ_EULER : case ADJ_NAVIER_STOKES: case ADJ_RANS: + RhoRes_Old = solver_container[val_iZone][FinestMesh][ADJFLOW_SOL]->GetRes_RMS(0); + break; + } + +} + + +void COutput::SetForces_Breakdown(CGeometry ***geometry, + CSolver ****solver_container, + CConfig **config, + CIntegration ***integration, + unsigned short val_iZone) { + + char cstr[200]; + unsigned short iMarker_Monitoring; + ofstream Breakdown_file; + + int rank = MASTER_NODE; + bool compressible = (config[val_iZone]->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config[val_iZone]->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config[val_iZone]->GetKind_Regime() == FREESURFACE); + bool unsteady = (config[val_iZone]->GetUnsteady_Simulation() != NO); + bool viscous = config[val_iZone]->GetViscous(); + bool grid_movement = config[val_iZone]->GetGrid_Movement(); + bool gravity = config[val_iZone]->GetGravityForce(); + bool turbulent = config[val_iZone]->GetKind_Solver() == RANS; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + unsigned short FinestMesh = config[val_iZone]->GetFinestMesh(); + unsigned short nDim = geometry[val_iZone][FinestMesh]->GetnDim(); + bool flow = ((config[val_iZone]->GetKind_Solver() == EULER) || (config[val_iZone]->GetKind_Solver() == NAVIER_STOKES) || + (config[val_iZone]->GetKind_Solver() == RANS)); + + /*--- Output the mean flow solution using only the master node ---*/ + + if ((rank == MASTER_NODE) && (flow)) { + + cout << "Writing the forces breakdown file." << endl; + + /*--- Initialize variables to store information from all domains (direct solution) ---*/ + + su2double Total_CLift = 0.0, Total_CDrag = 0.0, Total_CSideForce = 0.0, Total_CMx = 0.0, Total_CMy = 0.0, Total_CMz = 0.0, Total_CEff = 0.0, Total_CFx = 0.0, Total_CFy = 0.0, Total_CFz = 0.0, + Inv_CLift = 0.0, Inv_CDrag = 0.0, Inv_CSideForce = 0.0, Inv_CMx = 0.0, Inv_CMy = 0.0, Inv_CMz = 0.0, Inv_CEff = 0.0, Inv_CFx = 0.0, Inv_CFy = 0.0, Inv_CFz = 0.0, + *Surface_CLift = NULL, *Surface_CDrag = NULL, *Surface_CSideForce = NULL, *Surface_CEff = NULL, *Surface_CFx = NULL, *Surface_CFy = NULL, *Surface_CFz = NULL, *Surface_CMx = NULL, *Surface_CMy = NULL, *Surface_CMz = NULL, + *Surface_CLift_Inv = NULL, *Surface_CDrag_Inv = NULL, *Surface_CSideForce_Inv = NULL, *Surface_CEff_Inv = NULL, *Surface_CFx_Inv = NULL, *Surface_CFy_Inv = NULL, *Surface_CFz_Inv = NULL, *Surface_CMx_Inv = NULL, *Surface_CMy_Inv = NULL, *Surface_CMz_Inv = NULL; + time_t now = time(0); + string dt = ctime(&now); dt[24] = '.'; + + /*--- Allocate memory for the coefficients being monitored ---*/ + + Surface_CLift = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CDrag = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CSideForce = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CEff = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CFx = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CFy = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CFz = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CMx = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CMy = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CMz = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + + Surface_CLift_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CDrag_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CSideForce_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CEff_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CFx_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CFy_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CFz_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CMx_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CMy_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + Surface_CMz_Inv = new su2double[config[ZONE_0]->GetnMarker_Monitoring()]; + + /*--- Flow solution coefficients ---*/ + + Total_CLift = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CLift(); + Total_CDrag = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CDrag(); + Total_CSideForce = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CSideForce(); + Total_CEff = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CEff(); + Total_CMx = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CMx(); + Total_CMy = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CMy(); + Total_CMz = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CMz(); + Total_CFx = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CFx(); + Total_CFy = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CFy(); + Total_CFz = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetTotal_CFz(); + + /*--- Flow inviscid solution coefficients ---*/ + + Inv_CLift = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CLift_Inv(); + Inv_CDrag = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CDrag_Inv(); + Inv_CSideForce = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CSideForce_Inv(); + Inv_CEff = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CEff_Inv(); + Inv_CMx = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CMx_Inv(); + Inv_CMy = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CMy_Inv(); + Inv_CMz = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CMz_Inv(); + Inv_CFx = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CFx_Inv(); + Inv_CFy = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CFy_Inv(); + Inv_CFz = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetAllBound_CFz_Inv(); + + /*--- Look over the markers being monitored and get the desired values ---*/ + + for (iMarker_Monitoring = 0; iMarker_Monitoring < config[ZONE_0]->GetnMarker_Monitoring(); iMarker_Monitoring++) { + Surface_CLift[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CLift(iMarker_Monitoring); + Surface_CDrag[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CDrag(iMarker_Monitoring); + Surface_CSideForce[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CSideForce(iMarker_Monitoring); + Surface_CEff[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CEff(iMarker_Monitoring); + Surface_CFx[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFx(iMarker_Monitoring); + Surface_CFy[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFy(iMarker_Monitoring); + Surface_CFz[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFz(iMarker_Monitoring); + Surface_CMx[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMx(iMarker_Monitoring); + Surface_CMy[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMy(iMarker_Monitoring); + Surface_CMz[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMz(iMarker_Monitoring); + + Surface_CLift_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CLift_Inv(iMarker_Monitoring); + Surface_CDrag_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CDrag_Inv(iMarker_Monitoring); + Surface_CSideForce_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CSideForce_Inv(iMarker_Monitoring); + Surface_CEff_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CEff_Inv(iMarker_Monitoring); + Surface_CFx_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFx_Inv(iMarker_Monitoring); + Surface_CFy_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFy_Inv(iMarker_Monitoring); + Surface_CFz_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CFz_Inv(iMarker_Monitoring); + Surface_CMx_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMx_Inv(iMarker_Monitoring); + Surface_CMy_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMy_Inv(iMarker_Monitoring); + Surface_CMz_Inv[iMarker_Monitoring] = solver_container[val_iZone][FinestMesh][FLOW_SOL]->GetSurface_CMz_Inv(iMarker_Monitoring); + } + + /*--- Write file name with extension ---*/ + + string filename = config[val_iZone]->GetBreakdown_FileName(); + strcpy (cstr, filename.data()); + + Breakdown_file.open(cstr, ios::out); + + Breakdown_file << endl <<"-------------------------------------------------------------------------" << endl; + Breakdown_file <<"| ___ _ _ ___ |" << endl; + Breakdown_file <<"| / __| | | |_ ) Release 4.0.1 \"Cardinal\" |" << endl; + Breakdown_file <<"| \\__ \\ |_| |/ / |" << endl; + Breakdown_file <<"| |___/\\___//___| Suite (Computational Fluid Dynamics Code) |" << endl; + Breakdown_file << "| |" << endl; + Breakdown_file << "| Local date and time: " << dt << " |" << endl; + Breakdown_file <<"-------------------------------------------------------------------------" << endl; + Breakdown_file << "| SU2 Lead Dev.: Dr. Francisco Palacios, Francisco.D.Palacios@boeing.com|" << endl; + Breakdown_file << "| Dr. Thomas D. Economon, economon@stanford.edu |" << endl; + Breakdown_file <<"-------------------------------------------------------------------------" << endl; + Breakdown_file << "| SU2 Developers: |" << endl; + Breakdown_file << "| - Prof. Juan J. Alonso's group at Stanford University. |" << endl; + Breakdown_file << "| - Prof. Piero Colonna's group at Delft University of Technology. |" << endl; + Breakdown_file << "| - Prof. Nicolas R. Gauger's group at Kaiserslautern U. of Technology. |" << endl; + Breakdown_file << "| - Prof. Alberto Guardone's group at Polytechnic University of Milan. |" << endl; + Breakdown_file << "| - Prof. Rafael Palacios' group at Imperial College London. |" << endl; + Breakdown_file <<"-------------------------------------------------------------------------" << endl; + Breakdown_file << "| Copyright (C) 2012-2015 SU2, the open-source CFD code. |" << endl; + Breakdown_file << "| |" << endl; + Breakdown_file << "| SU2 is free software; you can redistribute it and/or |" << endl; + Breakdown_file << "| modify it under the terms of the GNU Lesser General Public |" << endl; + Breakdown_file << "| License as published by the Free Software Foundation; either |" << endl; + Breakdown_file << "| version 2.1 of the License, or (at your option) any later version. |" << endl; + Breakdown_file << "| |" << endl; + Breakdown_file << "| SU2 is distributed in the hope that it will be useful, |" << endl; + Breakdown_file << "| but WITHOUT ANY WARRANTY; without even the implied warranty of |" << endl; + Breakdown_file << "| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |" << endl; + Breakdown_file << "| Lesser General Public License for more details. |" << endl; + Breakdown_file << "| |" << endl; + Breakdown_file << "| You should have received a copy of the GNU Lesser General Public |" << endl; + Breakdown_file << "| License along with SU2. If not, see . |" << endl; + Breakdown_file <<"-------------------------------------------------------------------------" << endl; + + Breakdown_file.precision(6); + + Breakdown_file << endl << endl <<"Problem definition:" << endl << endl; + + if (compressible) { + if (viscous) { + Breakdown_file << "Viscous flow: Computing pressure using the ideal gas law" << endl; + Breakdown_file << "based on the free-stream temperature and a density computed" << endl; + Breakdown_file << "from the Reynolds number." << endl; + } else { + Breakdown_file << "Inviscid flow: Computing density based on free-stream" << endl; + Breakdown_file << "temperature and pressure using the ideal gas law." << endl; + } + } + + if (grid_movement) Breakdown_file << "Force coefficients computed using MACH_MOTION." << endl; + else Breakdown_file << "Force coefficients computed using free-stream values." << endl; + + if (incompressible || freesurface) { + Breakdown_file << "Viscous and Inviscid flow: rho_ref, and vel_ref" << endl; + Breakdown_file << "are based on the free-stream values, p_ref = rho_ref*vel_ref^2." << endl; + Breakdown_file << "The free-stream value of the pressure is 0." << endl; + Breakdown_file << "Mach number: "<< config[val_iZone]->GetMach() << ", computed using the Bulk modulus." << endl; + Breakdown_file << "Angle of attack (deg): "<< config[val_iZone]->GetAoA() << ", computed using the the free-stream velocity." << endl; + Breakdown_file << "Side slip angle (deg): "<< config[val_iZone]->GetAoS() << ", computed using the the free-stream velocity." << endl; + if (viscous) Breakdown_file << "Reynolds number: " << config[val_iZone]->GetReynolds() << ", computed using free-stream values."<< endl; + Breakdown_file << "Only dimensional computation, the grid should be dimensional." << endl; + } + + Breakdown_file <<"-- Input conditions:"<< endl; + + if (compressible) { + switch (config[val_iZone]->GetKind_FluidModel()) { + + case STANDARD_AIR: + Breakdown_file << "Fluid Model: STANDARD_AIR "<< endl; + Breakdown_file << "Specific gas constant: " << config[val_iZone]->GetGas_Constant(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " N.m/kg.K." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " lbf.ft/slug.R." << endl; + Breakdown_file << "Specific gas constant (non-dim): " << config[val_iZone]->GetGas_ConstantND()<< endl; + Breakdown_file << "Specific Heat Ratio: 1.4000 "<< endl; + break; + + case IDEAL_GAS: + Breakdown_file << "Fluid Model: IDEAL_GAS "<< endl; + Breakdown_file << "Specific gas constant: " << config[val_iZone]->GetGas_Constant() << " N.m/kg.K." << endl; + Breakdown_file << "Specific gas constant (non-dim): " << config[val_iZone]->GetGas_ConstantND()<< endl; + Breakdown_file << "Specific Heat Ratio: "<< config[val_iZone]->GetGamma() << endl; + break; + + case VW_GAS: + Breakdown_file << "Fluid Model: Van der Waals "<< endl; + Breakdown_file << "Specific gas constant: " << config[val_iZone]->GetGas_Constant() << " N.m/kg.K." << endl; + Breakdown_file << "Specific gas constant (non-dim): " << config[val_iZone]->GetGas_ConstantND()<< endl; + Breakdown_file << "Specific Heat Ratio: "<< config[val_iZone]->GetGamma() << endl; + Breakdown_file << "Critical Pressure: " << config[val_iZone]->GetPressure_Critical() << " Pa." << endl; + Breakdown_file << "Critical Temperature: " << config[val_iZone]->GetTemperature_Critical() << " K." << endl; + Breakdown_file << "Critical Pressure (non-dim): " << config[val_iZone]->GetPressure_Critical() /config[val_iZone]->GetPressure_Ref() << endl; + Breakdown_file << "Critical Temperature (non-dim) : " << config[val_iZone]->GetTemperature_Critical() /config[val_iZone]->GetTemperature_Ref() << endl; + break; + + case PR_GAS: + Breakdown_file << "Fluid Model: Peng-Robinson "<< endl; + Breakdown_file << "Specific gas constant: " << config[val_iZone]->GetGas_Constant() << " N.m/kg.K." << endl; + Breakdown_file << "Specific gas constant(non-dim): " << config[val_iZone]->GetGas_ConstantND()<< endl; + Breakdown_file << "Specific Heat Ratio: "<< config[val_iZone]->GetGamma() << endl; + Breakdown_file << "Critical Pressure: " << config[val_iZone]->GetPressure_Critical() << " Pa." << endl; + Breakdown_file << "Critical Temperature: " << config[val_iZone]->GetTemperature_Critical() << " K." << endl; + Breakdown_file << "Critical Pressure (non-dim): " << config[val_iZone]->GetPressure_Critical() /config[val_iZone]->GetPressure_Ref() << endl; + Breakdown_file << "Critical Temperature (non-dim) : " << config[val_iZone]->GetTemperature_Critical() /config[val_iZone]->GetTemperature_Ref() << endl; + break; + } + + if (viscous) { + + switch (config[val_iZone]->GetKind_ViscosityModel()) { + + case CONSTANT_VISCOSITY: + Breakdown_file << "Viscosity Model: CONSTANT_VISCOSITY "<< endl; + Breakdown_file << "Laminar Viscosity: " << config[val_iZone]->GetMu_ConstantND()*config[val_iZone]->GetViscosity_Ref(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " N.s/m^2." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " lbf.s/ft^2." << endl; + Breakdown_file << "Laminar Viscosity (non-dim): " << config[val_iZone]->GetMu_ConstantND()<< endl; + break; + + case SUTHERLAND: + Breakdown_file << "Viscosity Model: SUTHERLAND "<< endl; + Breakdown_file << "Ref. Laminar Viscosity: " << config[val_iZone]->GetMu_RefND()*config[val_iZone]->GetViscosity_Ref(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " N.s/m^2." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " lbf.s/ft^2." << endl; + Breakdown_file << "Ref. Temperature: " << config[val_iZone]->GetMu_Temperature_RefND()*config[val_iZone]->GetTemperature_Ref(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " K." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " R." << endl; + Breakdown_file << "Sutherland Constant: "<< config[val_iZone]->GetMu_SND()*config[val_iZone]->GetTemperature_Ref(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " K." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " R." << endl; + Breakdown_file << "Laminar Viscosity (non-dim): " << config[val_iZone]->GetMu_ConstantND()<< endl; + Breakdown_file << "Ref. Temperature (non-dim): " << config[val_iZone]->GetMu_Temperature_RefND()<< endl; + Breakdown_file << "Sutherland constant (non-dim): "<< config[val_iZone]->GetMu_SND()<< endl; + break; + + } + switch (config[val_iZone]->GetKind_ConductivityModel()) { + + case CONSTANT_PRANDTL: + Breakdown_file << "Conductivity Model: CONSTANT_PRANDTL "<< endl; + Breakdown_file << "Prandtl: " << config[val_iZone]->GetPrandtl_Lam()<< endl; + break; + + case CONSTANT_CONDUCTIVITY: + Breakdown_file << "Conductivity Model: CONSTANT_CONDUCTIVITY "<< endl; + Breakdown_file << "Molecular Conductivity: " << config[val_iZone]->GetKt_ConstantND()*config[val_iZone]->GetConductivity_Ref()<< " W/m^2.K." << endl; + Breakdown_file << "Molecular Conductivity (non-dim): " << config[val_iZone]->GetKt_ConstantND()<< endl; + break; + + } + } + } + + if (incompressible || freesurface) { + Breakdown_file << "Bulk modulus: " << config[val_iZone]->GetBulk_Modulus(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " Pa." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " psf." << endl; + Breakdown_file << "Artificial compressibility factor: " << config[val_iZone]->GetArtComp_Factor(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " Pa." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " psf." << endl; + } + + Breakdown_file << "Free-stream static pressure: " << config[val_iZone]->GetPressure_FreeStream(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " Pa." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " psf." << endl; + + Breakdown_file << "Free-stream total pressure: " << config[val_iZone]->GetPressure_FreeStream() * pow( 1.0+config[val_iZone]->GetMach()*config[val_iZone]->GetMach()*0.5*(config[val_iZone]->GetGamma()-1.0), config[val_iZone]->GetGamma()/(config[val_iZone]->GetGamma()-1.0) ); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " Pa." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " psf." << endl; + + if (compressible) { + Breakdown_file << "Free-stream temperature: " << config[val_iZone]->GetTemperature_FreeStream(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " K." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " R." << endl; + } + + Breakdown_file << "Free-stream density: " << config[val_iZone]->GetDensity_FreeStream(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " kg/m^3." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " slug/ft^3." << endl; + + if (nDim == 2) { + Breakdown_file << "Free-stream velocity: (" << config[val_iZone]->GetVelocity_FreeStream()[0] << ", "; + Breakdown_file << config[val_iZone]->GetVelocity_FreeStream()[1] << ")"; + } + if (nDim == 3) { + Breakdown_file << "Free-stream velocity: (" << config[val_iZone]->GetVelocity_FreeStream()[0] << ", "; + Breakdown_file << config[val_iZone]->GetVelocity_FreeStream()[1] << ", " << config[val_iZone]->GetVelocity_FreeStream()[2] << ")"; + } + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " m/s. "; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " ft/s. "; + + Breakdown_file << "Magnitude: " << config[val_iZone]->GetModVel_FreeStream(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " m/s." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " ft/s." << endl; + + if (compressible) { + Breakdown_file << "Free-stream total energy per unit mass: " << config[val_iZone]->GetEnergy_FreeStream(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " m^2/s^2." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " ft^2/s^2." << endl; + } + + if (viscous) { + Breakdown_file << "Free-stream viscosity: " << config[val_iZone]->GetViscosity_FreeStream(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " N.s/m^2." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " lbf.s/ft^2." << endl; + if (turbulent) { + Breakdown_file << "Free-stream turb. kinetic energy per unit mass: " << config[val_iZone]->GetTke_FreeStream(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " m^2/s^2." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " ft^2/s^2." << endl; + Breakdown_file << "Free-stream specific dissipation: " << config[val_iZone]->GetOmega_FreeStream(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " 1/s." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " 1/s." << endl; + } + } + + if (unsteady) { Breakdown_file << "Total time: " << config[val_iZone]->GetTotal_UnstTime() << " s. Time step: " << config[val_iZone]->GetDelta_UnstTime() << " s." << endl; } + + /*--- Print out reference values. ---*/ + + Breakdown_file <<"-- Reference values:"<< endl; + + if (compressible) { + Breakdown_file << "Reference specific gas constant: " << config[val_iZone]->GetGas_Constant_Ref(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " N.m/kg.K." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " lbf.ft/slug.R." << endl; + } + + Breakdown_file << "Reference pressure: " << config[val_iZone]->GetPressure_Ref(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " Pa." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " psf." << endl; + + if (compressible) { + Breakdown_file << "Reference temperature: " << config[val_iZone]->GetTemperature_Ref(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " K." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " R." << endl; + } + + Breakdown_file << "Reference density: " << config[val_iZone]->GetDensity_Ref(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " kg/m^3." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " slug/ft^3." << endl; + + Breakdown_file << "Reference velocity: " << config[val_iZone]->GetVelocity_Ref(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " m/s." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " ft/s." << endl; + + if (compressible) { + Breakdown_file << "Reference energy per unit mass: " << config[val_iZone]->GetEnergy_Ref(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " m^2/s^2." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " ft^2/s^2." << endl; + } + + if (incompressible || freesurface) { + Breakdown_file << "Reference length: " << config[val_iZone]->GetLength_Ref(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " m." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " in." << endl; + } + + if (viscous) { + Breakdown_file << "Reference viscosity: " << config[val_iZone]->GetViscosity_Ref(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " N.s/m^2." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " lbf.s/ft^2." << endl; + Breakdown_file << "Reference conductivity: " << config[val_iZone]->GetConductivity_Ref(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " W/m^2.K." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " lbf/ft.s.R." << endl; + } + + + if (unsteady) Breakdown_file << "Reference time: " << config[val_iZone]->GetTime_Ref() <<" s." << endl; + + /*--- Print out resulting non-dim values here. ---*/ + + Breakdown_file << "-- Resulting non-dimensional state:" << endl; + Breakdown_file << "Mach number (non-dim): " << config[val_iZone]->GetMach() << endl; + if (viscous) { + Breakdown_file << "Reynolds number (non-dim): " << config[val_iZone]->GetReynolds() <<". Re length: " << config[val_iZone]->GetLength_Reynolds(); + if (config[val_iZone]->GetSystemMeasurements() == SI) Breakdown_file << " m." << endl; + else if (config[val_iZone]->GetSystemMeasurements() == US) Breakdown_file << " ft." << endl; + } + if (gravity) { + Breakdown_file << "Froude number (non-dim): " << config[val_iZone]->GetFroude() << endl; + Breakdown_file << "Lenght of the baseline wave (non-dim): " << 2.0*PI_NUMBER*config[val_iZone]->GetFroude()*config[val_iZone]->GetFroude() << endl; + } + + if (compressible) { + Breakdown_file << "Specific gas constant (non-dim): " << config[val_iZone]->GetGas_ConstantND() << endl; + Breakdown_file << "Free-stream temperature (non-dim): " << config[val_iZone]->GetTemperature_FreeStreamND() << endl; + } + + Breakdown_file << "Free-stream pressure (non-dim): " << config[val_iZone]->GetPressure_FreeStreamND() << endl; + + Breakdown_file << "Free-stream density (non-dim): " << config[val_iZone]->GetDensity_FreeStreamND() << endl; + + if (nDim == 2) { + Breakdown_file << "Free-stream velocity (non-dim): (" << config[val_iZone]->GetVelocity_FreeStreamND()[0] << ", "; + Breakdown_file << config[val_iZone]->GetVelocity_FreeStreamND()[1] << "). "; + } else { + Breakdown_file << "Free-stream velocity (non-dim): (" << config[val_iZone]->GetVelocity_FreeStreamND()[0] << ", "; + Breakdown_file << config[val_iZone]->GetVelocity_FreeStreamND()[1] << ", " << config[val_iZone]->GetVelocity_FreeStreamND()[2] << "). "; + } + Breakdown_file << "Magnitude: " << config[val_iZone]->GetModVel_FreeStreamND() << endl; + + if (compressible) + Breakdown_file << "Free-stream total energy per unit mass (non-dim): " << config[val_iZone]->GetEnergy_FreeStreamND() << endl; + + if (viscous) { + Breakdown_file << "Free-stream viscosity (non-dim): " << config[val_iZone]->GetViscosity_FreeStreamND() << endl; + if (turbulent) { + Breakdown_file << "Free-stream turb. kinetic energy (non-dim): " << config[val_iZone]->GetTke_FreeStreamND() << endl; + Breakdown_file << "Free-stream specific dissipation (non-dim): " << config[val_iZone]->GetOmega_FreeStreamND() << endl; + } + } + + if (unsteady) { + Breakdown_file << "Total time (non-dim): " << config[val_iZone]->GetTotal_UnstTimeND() << endl; + Breakdown_file << "Time step (non-dim): " << config[val_iZone]->GetDelta_UnstTimeND() << endl; + } + + Breakdown_file << endl << endl <<"Forces breakdown:" << endl << endl; + + Breakdown_file << "Total CL: "; + Breakdown_file.width(11); Breakdown_file << Total_CLift; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CLift*100.0)/(Total_CLift+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Inv_CLift; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CLift*100.0)/(Total_CLift+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Total_CLift-Inv_CLift << endl; + + Breakdown_file << "Total CD: "; + Breakdown_file.width(11); Breakdown_file << Total_CDrag; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CDrag*100.0)/(Total_CDrag+EPS)) << "%): ";; + Breakdown_file.width(11); Breakdown_file << Inv_CDrag; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CDrag*100.0)/(Total_CDrag+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Total_CDrag-Inv_CDrag << endl; + + if (nDim == 3) { + Breakdown_file << "Total CSF: "; + Breakdown_file.width(11); Breakdown_file << Total_CSideForce; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CSideForce*100.0)/(Total_CSideForce+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Inv_CSideForce; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CSideForce*100.0)/(Total_CSideForce+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Total_CSideForce-Inv_CSideForce << endl; + } + + Breakdown_file << "Total CL/CD: "; + Breakdown_file.width(11); Breakdown_file << Total_CEff; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CEff*100.0)/(Total_CEff+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Inv_CEff; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CEff*100.0)/(Total_CEff+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Total_CEff-Inv_CEff << endl; + + if (nDim == 3) { + Breakdown_file << "Total CMx: "; + Breakdown_file.width(11); Breakdown_file << Total_CMx; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CMx*100.0)/(Total_CMx+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Inv_CMx; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CMx*100.0)/(Total_CMx+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Total_CMx-Inv_CMx << endl; + + Breakdown_file << "Total CMy: "; + Breakdown_file.width(11); Breakdown_file << Total_CMy; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CMy*100.0)/(Total_CMy+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Inv_CMy; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CMy*100.0)/(Total_CMy+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Total_CMy-Inv_CMy << endl; + } + + Breakdown_file << "Total CMz: "; + Breakdown_file.width(11); Breakdown_file << Total_CMz; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CMz*100.0)/(Total_CMz+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Inv_CMz; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CMz*100.0)/(Total_CMz+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Total_CMz-Inv_CMz << endl; + + Breakdown_file << "Total CFx: "; + Breakdown_file.width(11); Breakdown_file << Total_CFx; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CFx*100.0)/(Total_CFx+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Inv_CFx; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CFx*100.0)/(Total_CFx+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Total_CFx-Inv_CFx << endl; + + Breakdown_file << "Total CFy: "; + Breakdown_file.width(11); Breakdown_file << Total_CFy; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CFy*100.0)/(Total_CFy+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Inv_CFy; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CFy*100.0)/(Total_CFy+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Total_CFy-Inv_CFy << endl; + + if (nDim == 3) { + Breakdown_file << "Total CFz: "; + Breakdown_file.width(11); Breakdown_file << Total_CFz; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Inv_CFz*100.0)/(Total_CFz+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Inv_CFz; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Inv_CFz*100.0)/(Total_CFz+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Total_CFz-Inv_CFz << endl; + } + + Breakdown_file << endl << endl; + + for (iMarker_Monitoring = 0; iMarker_Monitoring < config[val_iZone]->GetnMarker_Monitoring(); iMarker_Monitoring++) { + + Breakdown_file << "Surface name: " << config[val_iZone]->GetMarker_Monitoring(iMarker_Monitoring) << endl << endl; + + Breakdown_file << "Total CL ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CLift[iMarker_Monitoring]*100.0)/(Total_CLift+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CLift[iMarker_Monitoring]; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CLift_Inv[iMarker_Monitoring]*100.0)/(Surface_CLift[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CLift_Inv[iMarker_Monitoring]; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CLift_Inv[iMarker_Monitoring]*100.0)/(Surface_CLift[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CLift[iMarker_Monitoring]-Surface_CLift_Inv[iMarker_Monitoring] << endl; + + Breakdown_file << "Total CD ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CDrag[iMarker_Monitoring]*100.0)/(Total_CDrag+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CDrag[iMarker_Monitoring]; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CDrag_Inv[iMarker_Monitoring]*100.0)/(Surface_CDrag[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CDrag_Inv[iMarker_Monitoring]; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CDrag_Inv[iMarker_Monitoring]*100.0)/(Surface_CDrag[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CDrag[iMarker_Monitoring]-Surface_CDrag_Inv[iMarker_Monitoring] << endl; + + if (nDim == 3) { + Breakdown_file << "Total CSF ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CSideForce[iMarker_Monitoring]*100.0)/(Total_CSideForce+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CSideForce[iMarker_Monitoring]; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CSideForce_Inv[iMarker_Monitoring]*100.0)/(Surface_CSideForce[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CSideForce_Inv[iMarker_Monitoring]; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CSideForce_Inv[iMarker_Monitoring]*100.0)/(Surface_CSideForce[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CSideForce[iMarker_Monitoring]-Surface_CSideForce_Inv[iMarker_Monitoring] << endl; + } + + Breakdown_file << "Total CL/CD ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CEff[iMarker_Monitoring]*100.0)/(Total_CEff+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CEff[iMarker_Monitoring]; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CEff_Inv[iMarker_Monitoring]*100.0)/(Surface_CEff[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CEff_Inv[iMarker_Monitoring]; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CEff_Inv[iMarker_Monitoring]*100.0)/(Surface_CEff[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + + Breakdown_file.width(11); Breakdown_file << Surface_CEff[iMarker_Monitoring]-Surface_CEff_Inv[iMarker_Monitoring] << endl; + + if (nDim == 3) { + + Breakdown_file << "Total CMx ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CMx[iMarker_Monitoring]*100.0)/(Total_CMx+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CMx[iMarker_Monitoring]; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CMx_Inv[iMarker_Monitoring]*100.0)/(Surface_CMx[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CMx_Inv[iMarker_Monitoring]; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CMx_Inv[iMarker_Monitoring]*100.0)/(Surface_CMx[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CMx[iMarker_Monitoring]-Surface_CMx_Inv[iMarker_Monitoring] << endl; + + Breakdown_file << "Total CMy ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CMy[iMarker_Monitoring]*100.0)/(Total_CMy+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CMy[iMarker_Monitoring]; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CMy_Inv[iMarker_Monitoring]*100.0)/(Surface_CMy[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CMy_Inv[iMarker_Monitoring]; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CMy_Inv[iMarker_Monitoring]*100.0)/(Surface_CMy[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CMy[iMarker_Monitoring]-Surface_CMy_Inv[iMarker_Monitoring] << endl; + } + + Breakdown_file << "Total CMz ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CMz[iMarker_Monitoring]*100.0)/(Total_CMz+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CMz[iMarker_Monitoring]; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CMz_Inv[iMarker_Monitoring]*100.0)/(Surface_CMz[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CMz_Inv[iMarker_Monitoring]; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CMz_Inv[iMarker_Monitoring]*100.0)/(Surface_CMz[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CMz[iMarker_Monitoring]-Surface_CMz_Inv[iMarker_Monitoring] << endl; + + Breakdown_file << "Total CFx ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CFx[iMarker_Monitoring]*100.0)/(Total_CFx+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CFx[iMarker_Monitoring]; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CFx_Inv[iMarker_Monitoring]*100.0)/(Surface_CFx[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CFx_Inv[iMarker_Monitoring]; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CFx_Inv[iMarker_Monitoring]*100.0)/(Surface_CFx[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CFx[iMarker_Monitoring]-Surface_CFx_Inv[iMarker_Monitoring] << endl; + + Breakdown_file << "Total CFy ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CFy[iMarker_Monitoring]*100.0)/(Total_CFy+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CFy[iMarker_Monitoring]; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CFy_Inv[iMarker_Monitoring]*100.0)/(Surface_CFy[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CFy_Inv[iMarker_Monitoring]; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CFy_Inv[iMarker_Monitoring]*100.0)/(Surface_CFy[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CFy[iMarker_Monitoring]-Surface_CFy_Inv[iMarker_Monitoring] << endl; + + if (nDim == 3) { + Breakdown_file << "Total CFz ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CFz[iMarker_Monitoring]*100.0)/(Total_CFz+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CFz[iMarker_Monitoring]; + Breakdown_file << " | Pressure Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int((Surface_CFz_Inv[iMarker_Monitoring]*100.0)/(Surface_CFz[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CFz_Inv[iMarker_Monitoring]; + Breakdown_file << " | Friction Component ("; + Breakdown_file.width(5); Breakdown_file << SU2_TYPE::Int(100.0-(Surface_CFz_Inv[iMarker_Monitoring]*100.0)/(Surface_CFz[iMarker_Monitoring]+EPS)); + Breakdown_file << "%): "; + Breakdown_file.width(11); Breakdown_file << Surface_CFz[iMarker_Monitoring]-Surface_CFz_Inv[iMarker_Monitoring] << endl; + } + + Breakdown_file << endl; + + } + + delete [] Surface_CLift; + delete [] Surface_CDrag; + delete [] Surface_CSideForce; + delete [] Surface_CEff; + delete [] Surface_CFx; + delete [] Surface_CFy; + delete [] Surface_CFz; + delete [] Surface_CMx; + delete [] Surface_CMy; + delete [] Surface_CMz; + + delete [] Surface_CLift_Inv; + delete [] Surface_CDrag_Inv; + delete [] Surface_CSideForce_Inv; + delete [] Surface_CEff_Inv; + delete [] Surface_CFx_Inv; + delete [] Surface_CFy_Inv; + delete [] Surface_CFz_Inv; + delete [] Surface_CMx_Inv; + delete [] Surface_CMy_Inv; + delete [] Surface_CMz_Inv; + + Breakdown_file.close(); + + } + +} + +void COutput::SetResult_Files(CSolver ****solver_container, CGeometry ***geometry, CConfig **config, + unsigned long iExtIter, unsigned short val_nZone) { + + int rank = MASTER_NODE; + +#ifdef HAVE_MPI + int size; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + unsigned short iZone; + + for (iZone = 0; iZone < val_nZone; iZone++) { + + /*--- Flags identifying the types of files to be written. ---*/ + + bool Wrt_Vol = config[iZone]->GetWrt_Vol_Sol(); + bool Wrt_Srf = config[iZone]->GetWrt_Srf_Sol(); + +#ifdef HAVE_MPI + /*--- Do not merge the volume solutions if we are running in parallel. + Force the use of SU2_SOL to merge the volume sols in this case. ---*/ + + MPI_Comm_size(MPI_COMM_WORLD, &size); + if (size > SINGLE_NODE) { + Wrt_Vol = false; + Wrt_Srf = false; + } +#endif + + bool Wrt_Csv = config[iZone]->GetWrt_Csv_Sol(); + + if (rank == MASTER_NODE) cout << endl << "Writing comma-separated values (CSV) surface files." << endl; + + switch (config[iZone]->GetKind_Solver()) { + + case EULER : case NAVIER_STOKES : case RANS : + + if (Wrt_Csv) SetSurfaceCSV_Flow(config[iZone], geometry[iZone][MESH_0], solver_container[iZone][MESH_0][FLOW_SOL], iExtIter, iZone); + break; + + case ADJ_EULER : case ADJ_NAVIER_STOKES : case ADJ_RANS : case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: + if (Wrt_Csv) SetSurfaceCSV_Adjoint(config[iZone], geometry[iZone][MESH_0], solver_container[iZone][MESH_0][ADJFLOW_SOL], solver_container[iZone][MESH_0][FLOW_SOL], iExtIter, iZone); + break; + + } + + /*--- Get the file output format ---*/ + + unsigned short FileFormat = config[iZone]->GetOutput_FileFormat(); + + /*--- Merge the node coordinates and connectivity, if necessary. This + is only performed if a volume solution file is requested, and it + is active by default. ---*/ + + if (Wrt_Vol || Wrt_Srf) { + if (rank == MASTER_NODE) cout << "Merging connectivities in the Master node." << endl; + MergeConnectivity(config[iZone], geometry[iZone][MESH_0], iZone); + } + + /*--- Merge coordinates of all grid nodes (excluding ghost points). + The grid coordinates are always merged and included first in the + restart files. ---*/ + + if (rank == MASTER_NODE) cout << "Merging coordinates in the Master node." << endl; + MergeCoordinates(config[iZone], geometry[iZone][MESH_0]); + + if ((rank == MASTER_NODE) && (Wrt_Vol || Wrt_Srf)) { + if (FileFormat == TECPLOT_BINARY) { + if (rank == MASTER_NODE) cout << "Writing Tecplot binary volume and surface mesh files." << endl; + SetTecplotBinary_DomainMesh(config[iZone], geometry[iZone][MESH_0], iZone); + SetTecplotBinary_SurfaceMesh(config[iZone], geometry[iZone][MESH_0], iZone); + if (!wrote_base_file) + DeallocateConnectivity(config[iZone], geometry[iZone][MESH_0], false); + if (!wrote_surf_file) + DeallocateConnectivity(config[iZone], geometry[iZone][MESH_0], wrote_surf_file); + } + } + + /*--- Merge the solution data needed for volume solutions and restarts ---*/ + + if (rank == MASTER_NODE) cout << "Merging solution in the Master node." << endl; + MergeSolution(config[iZone], geometry[iZone][MESH_0], solver_container[iZone][MESH_0], iZone); + + /*--- Write restart, or Tecplot files using the merged data. + This data lives only on the master, and these routines are currently + executed by the master proc alone (as if in serial). ---*/ + + if (rank == MASTER_NODE) { + + /*--- Write a native restart file ---*/ + + if (rank == MASTER_NODE) cout << "Writing SU2 native restart file." << endl; + SetRestart(config[iZone], geometry[iZone][MESH_0], solver_container[iZone][MESH_0] , iZone); + + if (Wrt_Vol) { + + switch (FileFormat) { + + case TECPLOT: + + /*--- Write a Tecplot ASCII file ---*/ + + if (rank == MASTER_NODE) cout << "Writing Tecplot ASCII file volume solution file." << endl; + SetTecplotASCII(config[iZone], geometry[iZone][MESH_0], solver_container[iZone][MESH_0], iZone, val_nZone, false); + DeallocateConnectivity(config[iZone], geometry[iZone][MESH_0], false); + break; + + case FIELDVIEW: + + /*--- Write a FieldView ASCII file ---*/ + + if (rank == MASTER_NODE) cout << "Writing FieldView ASCII file volume solution file." << endl; + SetFieldViewASCII(config[iZone], geometry[iZone][MESH_0], iZone, val_nZone); + DeallocateConnectivity(config[iZone], geometry[iZone][MESH_0], false); + break; + + case TECPLOT_BINARY: + + /*--- Write a Tecplot binary solution file ---*/ + + if (rank == MASTER_NODE) cout << "Writing Tecplot binary volume solution file." << endl; + SetTecplotBinary_DomainSolution(config[iZone], geometry[iZone][MESH_0], iZone); + break; + + case FIELDVIEW_BINARY: + + /*--- Write a FieldView binary file ---*/ + + if (rank == MASTER_NODE) cout << "Writing FieldView binary file volume solution file." << endl; + SetFieldViewBinary(config[iZone], geometry[iZone][MESH_0], iZone, val_nZone); + DeallocateConnectivity(config[iZone], geometry[iZone][MESH_0], false); + break; + + case PARAVIEW: + + /*--- Write a Paraview ASCII file ---*/ + + if (rank == MASTER_NODE) cout << "Writing Paraview ASCII volume solution file." << endl; + SetParaview_ASCII(config[iZone], geometry[iZone][MESH_0], iZone, val_nZone, false); + DeallocateConnectivity(config[iZone], geometry[iZone][MESH_0], false); + break; + + default: + break; + } + + } + + if (Wrt_Srf) { + + switch (FileFormat) { + + case TECPLOT: + + /*--- Write a Tecplot ASCII file ---*/ + + if (rank == MASTER_NODE) cout << "Writing Tecplot ASCII surface solution file." << endl; + SetTecplotASCII(config[iZone], geometry[iZone][MESH_0], solver_container[iZone][MESH_0] , iZone, val_nZone, true); + DeallocateConnectivity(config[iZone], geometry[iZone][MESH_0], true); + break; + + case TECPLOT_BINARY: + + /*--- Write a Tecplot binary solution file ---*/ + + if (rank == MASTER_NODE) cout << "Writing Tecplot binary surface solution file." << endl; + SetTecplotBinary_SurfaceSolution(config[iZone], geometry[iZone][MESH_0], iZone); + break; + + case PARAVIEW: + + /*--- Write a Paraview ASCII file ---*/ + + if (rank == MASTER_NODE) cout << "Writing Paraview ASCII surface solution file." << endl; + SetParaview_ASCII(config[iZone], geometry[iZone][MESH_0], iZone, val_nZone, true); + DeallocateConnectivity(config[iZone], geometry[iZone][MESH_0], true); + break; + + default: + break; + } + + } + + /*--- Release memory needed for merging the solution data. ---*/ + + DeallocateCoordinates(config[iZone], geometry[iZone][MESH_0]); + DeallocateSolution(config[iZone], geometry[iZone][MESH_0]); + + } + + /*--- Final broadcast (informing other procs that the base output + file was written). ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Bcast(&wrote_base_file, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Bcast(&wrote_surf_file, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, MPI_COMM_WORLD); +#endif + + } +} + +void COutput::SetBaselineResult_Files(CSolver **solver, CGeometry **geometry, CConfig **config, + unsigned long iExtIter, unsigned short val_nZone) { + + int rank = MASTER_NODE; + int size = SINGLE_NODE; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); +#endif + + unsigned short iZone; + + for (iZone = 0; iZone < val_nZone; iZone++) { + + /*--- Flags identifying the types of files to be written. ---*/ + + bool Low_MemoryOutput = config[iZone]->GetLow_MemoryOutput(); + bool Wrt_Vol = config[iZone]->GetWrt_Vol_Sol(); + bool Wrt_Srf = config[iZone]->GetWrt_Srf_Sol(); + + /*--- Get the file output format ---*/ + + unsigned short FileFormat = config[iZone]->GetOutput_FileFormat(); + + /*--- Merge the node coordinates and connectivity if necessary. This + is only performed if a volume solution file is requested, and it + is active by default. ---*/ + + if ((Wrt_Vol || Wrt_Srf) && (!Low_MemoryOutput)) { + if (rank == MASTER_NODE) cout << "Merging connectivities in the Master node." << endl; + MergeConnectivity(config[iZone], geometry[iZone], iZone); + } + + /*--- Merge the solution data needed for volume solutions and restarts ---*/ + + if ((Wrt_Vol || Wrt_Srf) && (!Low_MemoryOutput)) { + if (rank == MASTER_NODE) cout << "Merging solution in the Master node." << endl; + MergeBaselineSolution(config[iZone], geometry[iZone], solver[iZone], iZone); + } + + /*--- Write restart, Tecplot or Paraview files using the merged data. + This data lives only on the master, and these routines are currently + executed by the master proc alone (as if in serial). ---*/ + + if (!Low_MemoryOutput) { + + if (rank == MASTER_NODE) { + + if (Wrt_Vol) { + + switch (FileFormat) { + + case TECPLOT: + + /*--- Write a Tecplot ASCII file ---*/ + + if (rank == MASTER_NODE) cout << "Writing Tecplot ASCII file (volume grid)." << endl; + SetTecplotASCII(config[iZone], geometry[iZone], solver, iZone, val_nZone, false); + DeallocateConnectivity(config[iZone], geometry[iZone], false); + break; + + case FIELDVIEW: + + /*--- Write a FieldView ASCII file ---*/ + + if (rank == MASTER_NODE) cout << "Writing FieldView ASCII file (volume grid)." << endl; + SetFieldViewASCII(config[iZone], geometry[iZone], iZone, val_nZone); + DeallocateConnectivity(config[iZone], geometry[iZone], false); + break; + + case TECPLOT_BINARY: + + /*--- Write a Tecplot binary solution file ---*/ + + if (rank == MASTER_NODE) cout << "Writing Tecplot Binary file (volume grid)." << endl; + SetTecplotBinary_DomainMesh(config[iZone], geometry[iZone], iZone); + SetTecplotBinary_DomainSolution(config[iZone], geometry[iZone], iZone); + break; + + case FIELDVIEW_BINARY: + + /*--- Write a binary binary file ---*/ + + if (rank == MASTER_NODE) cout << "Writing FieldView ASCII file (volume grid)." << endl; + SetFieldViewBinary(config[iZone], geometry[iZone], iZone, val_nZone); + DeallocateConnectivity(config[iZone], geometry[iZone], false); + break; + + case PARAVIEW: + + /*--- Write a Paraview ASCII file ---*/ + + if (rank == MASTER_NODE) cout << "Writing Paraview ASCII file (volume grid)." << endl; + SetParaview_ASCII(config[iZone], geometry[iZone], iZone, val_nZone, false); + DeallocateConnectivity(config[iZone], geometry[iZone], false); + break; + + default: + break; + } + + } + + if (Wrt_Srf) { + + switch (FileFormat) { + + case TECPLOT: + + /*--- Write a Tecplot ASCII file ---*/ + + if (rank == MASTER_NODE) cout << "Writing Tecplot ASCII file (surface grid)." << endl; + SetTecplotASCII(config[iZone], geometry[iZone], solver, iZone, val_nZone, true); + DeallocateConnectivity(config[iZone], geometry[iZone], true); + break; + + case TECPLOT_BINARY: + + /*--- Write a Tecplot binary solution file ---*/ + + if (rank == MASTER_NODE) cout << "Writing Tecplot Binary file (surface grid)." << endl; + SetTecplotBinary_SurfaceMesh(config[iZone], geometry[iZone], iZone); + SetTecplotBinary_SurfaceSolution(config[iZone], geometry[iZone], iZone); + break; + + case PARAVIEW: + + /*--- Write a Paraview ASCII file ---*/ + + if (rank == MASTER_NODE) cout << "Writing Paraview ASCII file (surface grid)." << endl; + SetParaview_ASCII(config[iZone], geometry[iZone], iZone, val_nZone, true); + DeallocateConnectivity(config[iZone], geometry[iZone], true); + break; + + default: + break; + } + } + + if (FileFormat == TECPLOT_BINARY) { + if (!wrote_base_file) + DeallocateConnectivity(config[iZone], geometry[iZone], false); + if (!wrote_surf_file) + DeallocateConnectivity(config[iZone], geometry[iZone], wrote_surf_file); + } + + if (Wrt_Vol || Wrt_Srf) + DeallocateSolution(config[iZone], geometry[iZone]); + } + + } + + else { + + if (Wrt_Vol) { + + if (rank == MASTER_NODE) cout << "Writing Tecplot ASCII file (volume grid)." << endl; + char buffer_char[50], out_file[MAX_STRING_SIZE]; + + string filename; + if (!config[iZone]->GetAdjoint()) filename = config[iZone]->GetFlow_FileName(); + else filename = config[iZone]->GetAdj_FileName(); + + if (size > 1) { + SPRINTF (buffer_char, "_%d", SU2_TYPE::Int(rank+1)); + filename = filename + buffer_char; + } + + SPRINTF (buffer_char, ".dat"); + strcpy(out_file, filename.c_str()); strcat(out_file, buffer_char); + SetTecplotASCII_LowMemory(config[iZone], geometry[iZone], solver, out_file, false); + } + + if (Wrt_Srf) { + + if (rank == MASTER_NODE) cout << "Writing Tecplot ASCII file (surface grid)." << endl; + char buffer_char[50], out_file[MAX_STRING_SIZE]; + + string filename; + if (!config[iZone]->GetAdjoint()) filename = config[iZone]->GetSurfFlowCoeff_FileName(); + else filename = config[iZone]->GetSurfAdjCoeff_FileName(); + + if (size > 1) { + SPRINTF (buffer_char, "_%d", SU2_TYPE::Int(rank+1)); + filename = filename + buffer_char; + } + + SPRINTF (buffer_char, ".dat"); + strcpy(out_file, filename.c_str()); strcat(out_file, buffer_char); + SetTecplotASCII_LowMemory(config[iZone], geometry[iZone], solver, out_file, true); + } + + } + + /*--- Final broadcast (informing other procs that the base output + file was written). ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Bcast(&wrote_base_file, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, MPI_COMM_WORLD); +#endif + + } +} + +void COutput::SetMesh_Files(CGeometry **geometry, CConfig **config, unsigned short val_nZone, bool new_file, bool su2_file) { + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + unsigned short iZone; + + for (iZone = 0; iZone < val_nZone; iZone++) { + + /*--- Flags identifying the types of files to be written. ---*/ + + bool Wrt_Vol = config[iZone]->GetWrt_Vol_Sol() && config[iZone]->GetVisualize_Deformation(); + bool Wrt_Srf = config[iZone]->GetWrt_Srf_Sol() && config[iZone]->GetVisualize_Deformation();; + + /*--- Merge the node coordinates and connectivity if necessary. This + is only performed if a volume solution file is requested, and it + is active by default. ---*/ + + if (rank == MASTER_NODE) cout <<"Merging grid connectivity." << endl; + MergeConnectivity(config[iZone], geometry[iZone], iZone); + + /*--- Merge coordinates of all grid nodes (excluding ghost points). + The grid coordinates are always merged and included first in the + restart files. ---*/ + + if (rank == MASTER_NODE) cout <<"Merging grid coordinates." << endl; + MergeCoordinates(config[iZone], geometry[iZone]); + + /*--- Write restart, Tecplot or Paraview files using the merged data. + This data lives only on the master, and these routines are currently + executed by the master proc alone (as if in serial). ---*/ + + if (rank == MASTER_NODE) { + + if (Wrt_Vol) { + + if (rank == MASTER_NODE) cout <<"Writing volume mesh file." << endl; + + /*--- Write a Tecplot ASCII file ---*/ + if (config[iZone]->GetOutput_FileFormat()==PARAVIEW) SetParaview_MeshASCII(config[iZone], geometry[iZone], iZone, val_nZone, false,new_file); + else SetTecplotASCII_Mesh(config[iZone], geometry[iZone], false, new_file); + + } + + if (Wrt_Srf) { + + if (rank == MASTER_NODE) cout <<"Writing surface mesh file." << endl; + + /*--- Write a Tecplot ASCII file ---*/ + if (config[iZone]->GetOutput_FileFormat()==PARAVIEW) SetParaview_MeshASCII(config[iZone], geometry[iZone], iZone, val_nZone, true,new_file); + else SetTecplotASCII_Mesh(config[iZone], geometry[iZone], true, new_file); + + + } + + if (rank == MASTER_NODE) cout <<"Writing .su2 file." << endl; + + /*--- Write a .su2 ASCII file ---*/ + + if (su2_file) SetSU2_MeshASCII(config[iZone], geometry[iZone]); + + /*--- Deallocate connectivity ---*/ + + DeallocateConnectivity(config[iZone], geometry[iZone], true); + + } + + /*--- Final broadcast (informing other procs that the base output + file was written). ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Bcast(&wrote_base_file, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, MPI_COMM_WORLD); +#endif + + } +} + +void COutput::SetMassFlowRate(CSolver *solver_container, CGeometry *geometry, CConfig *config) { + unsigned short iDim, iMarker_monitor, iMarker; + unsigned long iVertex, iPoint; + su2double Vector[3], Total_Mdot=0.0; + unsigned short nDim = geometry->GetnDim(); + + for (iMarker = 0; iMarker< config->GetnMarker_All(); iMarker++) { + iMarker_monitor = config->GetMarker_All_Monitoring(iMarker); + if (iMarker_monitor){ + for (iVertex = 0; iVertex < geometry->nVertex[ iMarker ]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + geometry->vertex[iMarker][iVertex]->GetNormal(Vector); + + for (iDim = 0; iDim < nDim; iDim++) + Total_Mdot -= Vector[iDim]*(solver_container->node[iPoint]->GetSolution(iDim+1)); + } + } + } + } + +#ifdef HAVE_MPI + /*--- Add AllBound information using all the nodes ---*/ + su2double My_Total_Mdot = Total_Mdot; Total_Mdot = 0.0; + SU2_MPI::Allreduce(&My_Total_Mdot, &Total_Mdot, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); +#endif + /*--- Set the output: reusing same variable from OneDimensionalOutput code ---*/ + solver_container->SetOneD_MassFlowRate(Total_Mdot); +} + +void COutput::OneDimensionalOutput(CSolver *solver_container, CGeometry *geometry, CConfig *config) { + + unsigned long iVertex, iPoint; + unsigned short iDim, iMarker, Out1D; + su2double *Normal = NULL, Area = 0.0, UnitNormal[3], + Tot_Pressure, Mach, Temperature, Pressure = 0.0, Velocity2, Enthalpy, RhoUA, U,// local values at each node (Velocity2 = V^2). U = normal velocity + AveragePt = 0.0, AverageMach = 0.0, AverageTemperature = 0.0, MassFlowRate = 0.0, // Area Averaged value ( sum / A ) + VelocityRef = 0.0, EnthalpyRef = 0.0, DensityRef = 0.0, PressureRef = 0.0; // Flux conserved values. TemperatureRef follows ideal gas + su2double TotalArea=0.0; + + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + su2double Gamma = config->GetGamma(); + unsigned short nDim = geometry->GetnDim(); + + + /*--- Loop over the markers ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + Out1D = config->GetMarker_All_Out_1D(iMarker); + + /*--- Loop over the vertices to compute the output ---*/ + + + if (Out1D == YES) { + + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + /*--- Find the normal direction ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + + /*--- Compute area, and unitary normal ---*/ + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); + for (iDim = 0; iDim < nDim; iDim++) UnitNormal[iDim] = -Normal[iDim]/Area; + + if (compressible) Pressure = solver_container->node[iPoint]->GetPressure(); + if (incompressible || freesurface) Pressure = solver_container->node[iPoint]->GetPressureInc(); + + /*-- Find velocity normal to the marked surface/opening --*/ + + U = 0.0; RhoUA = 0.0; + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) { + U += UnitNormal[iDim]*solver_container->node[iPoint]->GetVelocity(iDim); + RhoUA -=Normal[iDim]*solver_container->node[iPoint]->GetSolution(iDim+1); + } + + Enthalpy = solver_container->node[iPoint]->GetEnthalpy(); + Velocity2 = solver_container->node[iPoint]->GetVelocity2(); + Temperature = solver_container->node[iPoint]->GetTemperature(); + + Mach = (sqrt(Velocity2))/ solver_container->node[iPoint]->GetSoundSpeed(); + //Stag_Pressure = Pressure*pow((1.0+((Gamma-1.0)/2.0)*pow(Mach, 2.0)),( Gamma/(Gamma-1.0) ) ); + Tot_Pressure = Pressure + 0.5*solver_container->node[iPoint]->GetDensity()*Velocity2; + + AveragePt += Tot_Pressure * Area; + TotalArea += Area; + AverageMach += Mach*Area; + PressureRef += Pressure * Area; + AverageTemperature += Temperature*Area; + MassFlowRate += RhoUA; // RhoU is rho * vn * Area + VelocityRef+=RhoUA*U*U; // rho u A + EnthalpyRef+=RhoUA*Enthalpy; + + } + } + + } + + } + +#ifdef HAVE_MPI + + /*--- Add AllBound information using all the nodes ---*/ + + su2double My_Area = TotalArea; TotalArea = 0.0; + su2double My_AveragePt = AveragePt; AveragePt = 0.0; + su2double My_AverageMach = AverageMach; AverageMach = 0.0; + su2double My_AverageTemperature = AverageTemperature; AverageTemperature = 0.0; + su2double My_MassFlowRate = MassFlowRate; MassFlowRate = 0.0; + su2double My_PressureRef = PressureRef; PressureRef = 0.0; + su2double My_VelocityRef = VelocityRef; VelocityRef = 0.0; + su2double My_EnthalpyRef = EnthalpyRef; EnthalpyRef = 0.0; + su2double My_DensityRef = DensityRef; DensityRef = 0.0; + + SU2_MPI::Allreduce(&My_Area, &TotalArea, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&My_AveragePt, &AveragePt, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&My_AverageMach, &AverageMach, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&My_AverageTemperature, &AverageTemperature, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&My_MassFlowRate, &MassFlowRate, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&My_PressureRef, &PressureRef, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&My_VelocityRef, &VelocityRef, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&My_EnthalpyRef , &EnthalpyRef , 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&My_DensityRef , &DensityRef , 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + +#endif + + /*--- Set the 1D output ---*/ + /*--- DensityRef depends on the final values of other flux avg variables ---*/ + VelocityRef=sqrt(VelocityRef/MassFlowRate); + PressureRef=PressureRef/TotalArea; + EnthalpyRef=EnthalpyRef/MassFlowRate; + DensityRef =PressureRef*Gamma/(Gamma-1)/(EnthalpyRef-0.5*VelocityRef*VelocityRef); + + /*Area averaged values*/ + solver_container->SetOneD_TotalPress(AveragePt/TotalArea); + solver_container->SetOneD_Mach(AverageMach/TotalArea); + solver_container->SetOneD_Temp(AverageTemperature/TotalArea); + solver_container->SetOneD_MassFlowRate(MassFlowRate); + + /*Flux averaged values*/ + solver_container->SetOneD_FluxAvgPress(PressureRef); + solver_container->SetOneD_FluxAvgDensity(DensityRef); + solver_container->SetOneD_FluxAvgVelocity(VelocityRef); + solver_container->SetOneD_FluxAvgEntalpy(EnthalpyRef); + +} + +void COutput::SetForceSections(CSolver *solver_container, CGeometry *geometry, CConfig *config, unsigned long iExtIter) { + + short iSection, nSection; + unsigned long iVertex, iPoint; + su2double *Plane_P0, *Plane_Normal, MinPlane, MaxPlane, *CPressure, MinXCoord, MaxXCoord, Force[3], ForceInviscid[3], + MomentInviscid[3] = {0.0,0.0,0.0}, MomentDist[3] = {0.0,0.0,0.0}, RefDensity, RefPressure, RefAreaCoeff, *Velocity_Inf, Gas_Constant, Mach2Vel, Mach_Motion, Gamma, RefVel2 = 0.0, factor, NDPressure, *Origin, RefLengthMoment, Alpha, Beta, CDrag_Inv, CLift_Inv, CMy_Inv; + vector Xcoord_Airfoil, Ycoord_Airfoil, Zcoord_Airfoil, Pressure_Airfoil; + string Marker_Tag, Slice_Filename, Slice_Ext; + ofstream Cp_File; + unsigned short iDim; + + bool grid_movement = config->GetGrid_Movement(); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + + Plane_P0 = new su2double [3]; + Plane_Normal = new su2double [3]; + CPressure = new su2double[geometry->GetnPoint()]; + + /*--- Compute some reference quantities and necessary values ---*/ + RefDensity = solver_container->GetDensity_Inf(); + RefPressure = solver_container->GetPressure_Inf(); + RefAreaCoeff = config->GetRefAreaCoeff(); + Velocity_Inf = solver_container->GetVelocity_Inf(); + Gamma = config->GetGamma(); + Origin = config->GetRefOriginMoment(0); + RefLengthMoment = config->GetRefLengthMoment(); + Alpha = config->GetAoA()*PI_NUMBER/180.0; + Beta = config->GetAoS()*PI_NUMBER/180.0; + + if (grid_movement) { + Gas_Constant = config->GetGas_ConstantND(); + Mach2Vel = sqrt(Gamma*Gas_Constant*config->GetTemperature_FreeStreamND()); + Mach_Motion = config->GetMach_Motion(); + RefVel2 = (Mach_Motion*Mach2Vel)*(Mach_Motion*Mach2Vel); + } + else { + RefVel2 = 0.0; + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) + RefVel2 += Velocity_Inf[iDim]*Velocity_Inf[iDim]; + } + factor = 1.0 / (0.5*RefDensity*RefAreaCoeff*RefVel2); + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + if (geometry->GetnDim() == 3) { + + /*--- Copy the pressure to an auxiliar structure ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + if (compressible) { + CPressure[iPoint] = (solver_container->node[iPoint]->GetPressure() - RefPressure)*factor*RefAreaCoeff; + } + if (incompressible || freesurface) { + CPressure[iPoint] = (solver_container->node[iPoint]->GetPressureInc() - RefPressure)*factor*RefAreaCoeff; + } + } + + nSection = config->GetnSections(); + + for (iSection = 0; iSection < nSection; iSection++) { + + /*--- Read the values from the config file ---*/ + + MinPlane = config->GetSection_Location(0); MaxPlane = config->GetSection_Location(1); + MinXCoord = -1E6; MaxXCoord = 1E6; + + Plane_Normal[0] = 0.0; Plane_P0[0] = 0.0; + Plane_Normal[1] = 0.0; Plane_P0[1] = 0.0; + Plane_Normal[2] = 0.0; Plane_P0[2] = 0.0; + + Plane_Normal[config->GetAxis_Orientation()] = 1.0; + Plane_P0[config->GetAxis_Orientation()] = MinPlane + iSection*(MaxPlane - MinPlane)/su2double(nSection-1); + + /*--- Compute the airfoil sections (note that we feed in the Cp) ---*/ + + geometry->ComputeAirfoil_Section(Plane_P0, Plane_Normal, + MinXCoord, MaxXCoord, CPressure, + Xcoord_Airfoil, Ycoord_Airfoil, + Zcoord_Airfoil, Pressure_Airfoil, true, + config); + + if ((rank == MASTER_NODE) && (Xcoord_Airfoil.size() == 0)) { + cout << "Please check the config file, the section "<< iSection+1 <<" has not been detected." << endl; + } + + /*--- Output the pressure on each section (tecplot format) ---*/ + + if ((rank == MASTER_NODE) && (Xcoord_Airfoil.size() != 0)) { + + /*--- Write Cp at each section ---*/ + + ofstream Cp_File; + if (iSection == 0) { + Cp_File.open("cp_sections.dat", ios::out); + Cp_File << "TITLE = \"Airfoil sections\"" << endl; + Cp_File << "VARIABLES = \"X\",\"Y\",\"Z\",\"Cp\"" << endl; + } + else Cp_File.open("cp_sections.dat", ios::app); + + Cp_File << "ZONE T=\"SECTION_"<< (iSection+1) << "\", NODES= "<< Xcoord_Airfoil.size() << ", ELEMENTS= " << Xcoord_Airfoil.size()-1 << ", DATAPACKING= POINT, ZONETYPE= FELINESEG" << endl; + + /*--- Coordinates and pressure value ---*/ + + if (config->GetSystemMeasurements() == SI) { + for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { + Cp_File << Xcoord_Airfoil[iVertex] <<" "<< Ycoord_Airfoil[iVertex] <<" "<< Zcoord_Airfoil[iVertex] <<" "<< Pressure_Airfoil[iVertex] << endl; + } + } + if (config->GetSystemMeasurements() == US) { + for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { + Cp_File << Xcoord_Airfoil[iVertex]*12.0 <<" "<< Ycoord_Airfoil[iVertex]*12.0 <<" "<< Zcoord_Airfoil[iVertex]*12.0 <<" "<< Pressure_Airfoil[iVertex] << endl; + } + } + + /*--- Basic conectivity ---*/ + + for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) { + Cp_File << iVertex << "\t" << iVertex+1 << "\n"; + } + + Cp_File.close(); + + + /*--- Compute load distribution ---*/ + + ForceInviscid[0] = 0.0; ForceInviscid[1] = 0.0; ForceInviscid[2] = 0.0; MomentInviscid[1] = 0.0; + + for (iVertex = 0; iVertex < Xcoord_Airfoil.size()-1; iVertex++) { + + NDPressure = 0.5*(Pressure_Airfoil[iVertex]+Pressure_Airfoil[iVertex+1]); + + Force[0] = -(Zcoord_Airfoil[iVertex+1] - Zcoord_Airfoil[iVertex])*NDPressure; + Force[1] = 0.0; + Force[2] = (Xcoord_Airfoil[iVertex+1] - Xcoord_Airfoil[iVertex])*NDPressure; + + ForceInviscid[0] += Force[0]; + ForceInviscid[1] += Force[1]; + ForceInviscid[2] += Force[2]; + + MomentDist[0] = 0.5*(Xcoord_Airfoil[iVertex] + Xcoord_Airfoil[iVertex+1]) - Origin[0]; + MomentDist[1] = 0.5*(Ycoord_Airfoil[iVertex] + Ycoord_Airfoil[iVertex+1]) - Origin[1]; + MomentDist[2] = 0.5*(Zcoord_Airfoil[iVertex] + Zcoord_Airfoil[iVertex+1]) - Origin[3]; + + MomentInviscid[1] += (Force[0]*MomentDist[2]-Force[2]*MomentDist[0])/RefLengthMoment; + + } + + CLift_Inv = fabs( -ForceInviscid[0]*sin(Alpha) + ForceInviscid[2]*cos(Alpha)); + CDrag_Inv = fabs( ForceInviscid[0]*cos(Alpha)*cos(Beta) + ForceInviscid[1]*sin(Beta) + ForceInviscid[2]*sin(Alpha)*cos(Beta)); + CMy_Inv = MomentInviscid[1]; + + + /*--- Write load distribution ---*/ + + ofstream Load_File; + if (iSection == 0) { + Load_File.open("load_distribution.dat", ios::out); + Load_File << "TITLE = \"Load distribution\"" << endl; + Load_File << "VARIABLES = \"Y\",\"CL\",\"CD\",\"CMy\"" << endl; + Load_File << "ZONE T=\"Wing load distribution\", NODES= "<< nSection << ", ELEMENTS= " << nSection-1 << ", DATAPACKING= POINT, ZONETYPE= FELINESEG" << endl; + } + else Load_File.open("load_distribution.dat", ios::app); + + /*--- Coordinates and pressure value ---*/ + + Load_File << Ycoord_Airfoil[0] <<" "<< CLift_Inv <<" "<< CDrag_Inv <<" "<< CMy_Inv << endl; + + /*--- Basic conectivity ---*/ + + if (iSection == nSection-1) { + for (iSection = 1; iSection < nSection; iSection++) { + Load_File << iSection << "\t" << iSection+1 << "\n"; + } + } + + Load_File.close(); + + + } + + } + + + } + + /*--- Delete dynamically allocated memory ---*/ + + delete [] Plane_P0; + delete [] Plane_Normal; + delete [] CPressure; + +} + +void COutput::SetCp_InverseDesign(CSolver *solver_container, CGeometry *geometry, CConfig *config, unsigned long iExtIter) { + + unsigned short iMarker, icommas, Boundary, iDim; + unsigned long iVertex, iPoint, (*Point2Vertex)[2], nPointLocal = 0, nPointGlobal = 0; + su2double XCoord, YCoord, ZCoord, Pressure, PressureCoeff = 0, Cp, CpTarget, *Normal = NULL, Area, PressDiff; + bool *PointInDomain; + string text_line, surfCp_filename; + ifstream Surface_file; + char buffer[50], cstr[200]; + + + nPointLocal = geometry->GetnPoint(); +#ifdef HAVE_MPI + SU2_MPI::Allreduce(&nPointLocal, &nPointGlobal, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); +#else + nPointGlobal = nPointLocal; +#endif + + Point2Vertex = new unsigned long[nPointGlobal][2]; + PointInDomain = new bool[nPointGlobal]; + + for (iPoint = 0; iPoint < nPointGlobal; iPoint ++) + PointInDomain[iPoint] = false; + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + Boundary = config->GetMarker_All_KindBC(iMarker); + + if ((Boundary == EULER_WALL ) || + (Boundary == HEAT_FLUX ) || + (Boundary == ISOTHERMAL ) || + (Boundary == NEARFIELD_BOUNDARY)) { + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + + /*--- The Pressure file uses the global numbering ---*/ + +#ifndef HAVE_MPI + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); +#else + iPoint = geometry->node[geometry->vertex[iMarker][iVertex]->GetNode()]->GetGlobalIndex(); +#endif + + if (geometry->vertex[iMarker][iVertex]->GetNode() < geometry->GetnPointDomain()) { + Point2Vertex[iPoint][0] = iMarker; + Point2Vertex[iPoint][1] = iVertex; + PointInDomain[iPoint] = true; + solver_container->SetCPressureTarget(iMarker, iVertex, 0.0); + } + + } + } + } + + /*--- Prepare to read the surface pressure files (CSV) ---*/ + + surfCp_filename = "TargetCp"; + strcpy (cstr, surfCp_filename.c_str()); + + /*--- Write file name with extension if unsteady or steady ---*/ + + if ((config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) || + (config->GetUnsteady_Simulation() == TIME_SPECTRAL)) { + if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(iExtIter)); + if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(iExtIter)); + } + else + SPRINTF (buffer, ".dat"); + + strcat (cstr, buffer); + + /*--- Read the surface pressure file ---*/ + + string::size_type position; + + Surface_file.open(cstr, ios::in); + + if (!(Surface_file.fail())) { + + getline(Surface_file, text_line); + + while (getline(Surface_file, text_line)) { + for (icommas = 0; icommas < 50; icommas++) { + position = text_line.find( ",", 0 ); + if (position!=string::npos) text_line.erase (position,1); + } + stringstream point_line(text_line); + + if (geometry->GetnDim() == 2) point_line >> iPoint >> XCoord >> YCoord >> Pressure >> PressureCoeff; + if (geometry->GetnDim() == 3) point_line >> iPoint >> XCoord >> YCoord >> ZCoord >> Pressure >> PressureCoeff; + + if (PointInDomain[iPoint]) { + + /*--- Find the vertex for the Point and Marker ---*/ + + iMarker = Point2Vertex[iPoint][0]; + iVertex = Point2Vertex[iPoint][1]; + + solver_container->SetCPressureTarget(iMarker, iVertex, PressureCoeff); + + } + + } + + Surface_file.close(); + + } + + /*--- Compute the pressure difference ---*/ + + PressDiff = 0.0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + Boundary = config->GetMarker_All_KindBC(iMarker); + + if ((Boundary == EULER_WALL ) || + (Boundary == HEAT_FLUX ) || + (Boundary == ISOTHERMAL ) || + (Boundary == NEARFIELD_BOUNDARY)) { + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + + Cp = solver_container->GetCPressure(iMarker, iVertex); + CpTarget = solver_container->GetCPressureTarget(iMarker, iVertex); + + Area = 0.0; + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) + Area += Normal[iDim]*Normal[iDim]; + Area = sqrt(Area); + + PressDiff += Area * (CpTarget - Cp) * (CpTarget - Cp); + } + + } + } + +#ifdef HAVE_MPI + su2double MyPressDiff = PressDiff; PressDiff = 0.0; + SU2_MPI::Allreduce(&MyPressDiff, &PressDiff, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); +#endif + + /*--- Update the total Cp difference coeffient ---*/ + + solver_container->SetTotal_CpDiff(PressDiff); + + delete[] Point2Vertex; + +} + +void COutput::SetHeat_InverseDesign(CSolver *solver_container, CGeometry *geometry, CConfig *config, unsigned long iExtIter) { + + unsigned short iMarker, icommas, Boundary, iDim; + unsigned long iVertex, iPoint, (*Point2Vertex)[2], nPointLocal = 0, nPointGlobal = 0; + su2double XCoord, YCoord, ZCoord, PressureCoeff, HeatFlux = 0.0, HeatFluxDiff, HeatFluxTarget, *Normal = NULL, Area, + Pressure, Cf; + bool *PointInDomain; + string text_line, surfHeatFlux_filename; + ifstream Surface_file; + char buffer[50], cstr[200]; + + + nPointLocal = geometry->GetnPoint(); +#ifdef HAVE_MPI + SU2_MPI::Allreduce(&nPointLocal, &nPointGlobal, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); +#else + nPointGlobal = nPointLocal; +#endif + + Point2Vertex = new unsigned long[nPointGlobal][2]; + PointInDomain = new bool[nPointGlobal]; + + for (iPoint = 0; iPoint < nPointGlobal; iPoint ++) + PointInDomain[iPoint] = false; + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + Boundary = config->GetMarker_All_KindBC(iMarker); + + if ((Boundary == EULER_WALL ) || + (Boundary == HEAT_FLUX ) || + (Boundary == ISOTHERMAL ) || + (Boundary == NEARFIELD_BOUNDARY)) { + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + + /*--- The Pressure file uses the global numbering ---*/ + +#ifndef HAVE_MPI + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); +#else + iPoint = geometry->node[geometry->vertex[iMarker][iVertex]->GetNode()]->GetGlobalIndex(); +#endif + + if (geometry->vertex[iMarker][iVertex]->GetNode() < geometry->GetnPointDomain()) { + Point2Vertex[iPoint][0] = iMarker; + Point2Vertex[iPoint][1] = iVertex; + PointInDomain[iPoint] = true; + solver_container->SetHeatFluxTarget(iMarker, iVertex, 0.0); + } + } + } + } + + /*--- Prepare to read the surface pressure files (CSV) ---*/ + + surfHeatFlux_filename = "TargetHeatFlux"; + strcpy (cstr, surfHeatFlux_filename.c_str()); + + /*--- Write file name with extension if unsteady or steady ---*/ + + if ((config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) || + (config->GetUnsteady_Simulation() == TIME_SPECTRAL)) { + if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(iExtIter)); + if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(iExtIter)); + } + else + SPRINTF (buffer, ".dat"); + + strcat (cstr, buffer); + + /*--- Read the surface pressure file ---*/ + + string::size_type position; + + Surface_file.open(cstr, ios::in); + + if (!(Surface_file.fail())) { + + getline(Surface_file, text_line); + + while (getline(Surface_file, text_line)) { + for (icommas = 0; icommas < 50; icommas++) { + position = text_line.find( ",", 0 ); + if (position!=string::npos) text_line.erase (position,1); + } + stringstream point_line(text_line); + + if (geometry->GetnDim() == 2) point_line >> iPoint >> XCoord >> YCoord >> Pressure >> PressureCoeff >> Cf >> HeatFlux; + if (geometry->GetnDim() == 3) point_line >> iPoint >> XCoord >> YCoord >> ZCoord >> Pressure >> PressureCoeff >> Cf >> HeatFlux; + + if (PointInDomain[iPoint]) { + + /*--- Find the vertex for the Point and Marker ---*/ + + iMarker = Point2Vertex[iPoint][0]; + iVertex = Point2Vertex[iPoint][1]; + + solver_container->SetHeatFluxTarget(iMarker, iVertex, HeatFlux); + + } + + } + + Surface_file.close(); + } + + /*--- Compute the pressure difference ---*/ + + HeatFluxDiff = 0.0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + Boundary = config->GetMarker_All_KindBC(iMarker); + + if ((Boundary == EULER_WALL ) || + (Boundary == HEAT_FLUX ) || + (Boundary == ISOTHERMAL ) || + (Boundary == NEARFIELD_BOUNDARY)) { + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + + HeatFlux = solver_container->GetHeatFlux(iMarker, iVertex); + HeatFluxTarget = solver_container->GetHeatFluxTarget(iMarker, iVertex); + + Area = 0.0; + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) + Area += Normal[iDim]*Normal[iDim]; + Area = sqrt(Area); + + HeatFluxDiff += Area * (HeatFluxTarget - HeatFlux) * (HeatFluxTarget - HeatFlux); + + } + + } + } + +#ifdef HAVE_MPI + su2double MyHeatFluxDiff = HeatFluxDiff; HeatFluxDiff = 0.0; + SU2_MPI::Allreduce(&MyHeatFluxDiff, &HeatFluxDiff, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); +#endif + + /*--- Update the total HeatFlux difference coeffient ---*/ + + solver_container->SetTotal_HeatFluxDiff(HeatFluxDiff); + + delete[] Point2Vertex; + +} + +void COutput::SetEquivalentArea(CSolver *solver_container, CGeometry *geometry, CConfig *config, unsigned long iExtIter) { + + ofstream EquivArea_file, FuncGrad_file; + unsigned short iMarker = 0, iDim; + short *AzimuthalAngle = NULL; + su2double Gamma, auxXCoord, auxYCoord, auxZCoord, InverseDesign = 0.0, DeltaX, Coord_i, Coord_j, jp1Coord, *Coord = NULL, MeanFuntion, + *Face_Normal = NULL, auxArea, auxPress, Mach, Beta, R_Plane, Pressure_Inf, + ModVelocity_Inf, Velocity_Inf[3], factor, *Xcoord = NULL, *Ycoord = NULL, *Zcoord = NULL, + *Pressure = NULL, *FaceArea = NULL, *EquivArea = NULL, *TargetArea = NULL, *NearFieldWeight = NULL, + *Weight = NULL, jFunction, jp1Function; + unsigned long jVertex, iVertex, iPoint, nVertex_NearField = 0, auxPoint, + *IdPoint = NULL, *IdDomain = NULL, auxDomain; + unsigned short iPhiAngle; + ofstream NearFieldEA_file; ifstream TargetEA_file; + + su2double XCoordBegin_OF = config->GetEA_IntLimit(0); + su2double XCoordEnd_OF = config->GetEA_IntLimit(1); + + unsigned short nDim = geometry->GetnDim(); + su2double AoA = -(config->GetAoA()*PI_NUMBER/180.0); + su2double EAScaleFactor = config->GetEA_ScaleFactor(); // The EA Obj. Func. should be ~ force based Obj. Func. + + int rank = MESH_0; + + Mach = config->GetMach(); + Gamma = config->GetGamma(); + Beta = sqrt(Mach*Mach-1.0); + R_Plane = fabs(config->GetEA_IntLimit(2)); + Pressure_Inf = config->GetPressure_FreeStreamND(); + Velocity_Inf[0] = config->GetVelocity_FreeStreamND()[0]; + Velocity_Inf[1] = config->GetVelocity_FreeStreamND()[1]; + Velocity_Inf[2] = config->GetVelocity_FreeStreamND()[2]; + ModVelocity_Inf = 0; + for (iDim = 0; iDim < 3; iDim++) + ModVelocity_Inf += Velocity_Inf[iDim] * Velocity_Inf[iDim]; + + factor = 4.0*sqrt(2.0*Beta*R_Plane) / (Gamma*Pressure_Inf*Mach*Mach); + +#ifndef HAVE_MPI + + /*--- Compute the total number of points on the near-field ---*/ + + nVertex_NearField = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Face_Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + Coord = geometry->node[iPoint]->GetCoord(); + + /*--- Using Face_Normal(z), and Coord(z) we identify only a surface, + note that there are 2 NEARFIELD_BOUNDARY surfaces ---*/ + + if ((Face_Normal[nDim-1] > 0.0) && (Coord[nDim-1] < 0.0)) nVertex_NearField ++; + } + + /*--- Create an array with all the coordinates, points, pressures, face area, + equivalent area, and nearfield weight ---*/ + + Xcoord = new su2double[nVertex_NearField]; + Ycoord = new su2double[nVertex_NearField]; + Zcoord = new su2double[nVertex_NearField]; + AzimuthalAngle = new short[nVertex_NearField]; + IdPoint = new unsigned long[nVertex_NearField]; + IdDomain = new unsigned long[nVertex_NearField]; + Pressure = new su2double[nVertex_NearField]; + FaceArea = new su2double[nVertex_NearField]; + EquivArea = new su2double[nVertex_NearField]; + TargetArea = new su2double[nVertex_NearField]; + NearFieldWeight = new su2double[nVertex_NearField]; + Weight = new su2double[nVertex_NearField]; + + /*--- Copy the boundary information to an array ---*/ + + nVertex_NearField = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Face_Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + Coord = geometry->node[iPoint]->GetCoord(); + + if ((Face_Normal[nDim-1] > 0.0) && (Coord[nDim-1] < 0.0)) { + + IdPoint[nVertex_NearField] = iPoint; + Xcoord[nVertex_NearField] = geometry->node[iPoint]->GetCoord(0); + Ycoord[nVertex_NearField] = geometry->node[iPoint]->GetCoord(1); + + if (nDim ==2) { + AzimuthalAngle[nVertex_NearField] = 0; + } + + if (nDim == 3) { + Zcoord[nVertex_NearField] = geometry->node[iPoint]->GetCoord(2); + + /*--- Rotate the nearfield cylinder (AoA) only 3D ---*/ + + su2double YcoordRot = Ycoord[nVertex_NearField]; + su2double ZcoordRot = Xcoord[nVertex_NearField]*sin(AoA) + Zcoord[nVertex_NearField]*cos(AoA); + + /*--- Compute the Azimuthal angle (resolution of degress in the Azimuthal angle)---*/ + + su2double AngleDouble; short AngleInt; + AngleDouble = fabs(atan(-YcoordRot/ZcoordRot)*180.0/PI_NUMBER); + + /*--- Fix an azimuthal line due to misalignments of the near-field ---*/ + + su2double FixAzimuthalLine = config->GetFixAzimuthalLine(); + + if ((AngleDouble >= FixAzimuthalLine - 0.1) && (AngleDouble <= FixAzimuthalLine + 0.1)) AngleDouble = FixAzimuthalLine - 0.1; + + AngleInt = SU2_TYPE::Short(floor(AngleDouble + 0.5)); + if (AngleInt >= 0) AzimuthalAngle[nVertex_NearField] = AngleInt; + else AzimuthalAngle[nVertex_NearField] = 180 + AngleInt; + } + + if (AzimuthalAngle[nVertex_NearField] <= 60) { + Pressure[nVertex_NearField] = solver_container->node[iPoint]->GetPressure(); + FaceArea[nVertex_NearField] = fabs(Face_Normal[nDim-1]); + nVertex_NearField ++; + } + + } + } + +#else + + int nProcessor; + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + unsigned long nLocalVertex_NearField = 0, MaxLocalVertex_NearField = 0; + int iProcessor; + + unsigned long *Buffer_Receive_nVertex = NULL; + if (rank == MASTER_NODE) { + Buffer_Receive_nVertex = new unsigned long [nProcessor]; + } + + /*--- Compute the total number of points of the near-field ghost nodes ---*/ + + nLocalVertex_NearField = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Face_Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + Coord = geometry->node[iPoint]->GetCoord(); + + if (geometry->node[iPoint]->GetDomain()) + if ((Face_Normal[nDim-1] > 0.0) && (Coord[nDim-1] < 0.0)) + nLocalVertex_NearField ++; + } + + unsigned long *Buffer_Send_nVertex = new unsigned long [1]; + Buffer_Send_nVertex[0] = nLocalVertex_NearField; + + /*--- Send Near-Field vertex information --*/ + + SU2_MPI::Allreduce(&nLocalVertex_NearField, &nVertex_NearField, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&nLocalVertex_NearField, &MaxLocalVertex_NearField, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); + delete [] Buffer_Send_nVertex; + + su2double *Buffer_Send_Xcoord = new su2double[MaxLocalVertex_NearField]; + su2double *Buffer_Send_Ycoord = new su2double[MaxLocalVertex_NearField]; + su2double *Buffer_Send_Zcoord = new su2double[MaxLocalVertex_NearField]; + unsigned long *Buffer_Send_IdPoint = new unsigned long [MaxLocalVertex_NearField]; + su2double *Buffer_Send_Pressure = new su2double [MaxLocalVertex_NearField]; + su2double *Buffer_Send_FaceArea = new su2double[MaxLocalVertex_NearField]; + + su2double *Buffer_Receive_Xcoord = NULL; + su2double *Buffer_Receive_Ycoord = NULL; + su2double *Buffer_Receive_Zcoord = NULL; + unsigned long *Buffer_Receive_IdPoint = NULL; + su2double *Buffer_Receive_Pressure = NULL; + su2double *Buffer_Receive_FaceArea = NULL; + + if (rank == MASTER_NODE) { + Buffer_Receive_Xcoord = new su2double[nProcessor*MaxLocalVertex_NearField]; + Buffer_Receive_Ycoord = new su2double[nProcessor*MaxLocalVertex_NearField]; + Buffer_Receive_Zcoord = new su2double[nProcessor*MaxLocalVertex_NearField]; + Buffer_Receive_IdPoint = new unsigned long[nProcessor*MaxLocalVertex_NearField]; + Buffer_Receive_Pressure = new su2double[nProcessor*MaxLocalVertex_NearField]; + Buffer_Receive_FaceArea = new su2double[nProcessor*MaxLocalVertex_NearField]; + } + + unsigned long nBuffer_Xcoord = MaxLocalVertex_NearField; + unsigned long nBuffer_Ycoord = MaxLocalVertex_NearField; + unsigned long nBuffer_Zcoord = MaxLocalVertex_NearField; + unsigned long nBuffer_IdPoint = MaxLocalVertex_NearField; + unsigned long nBuffer_Pressure = MaxLocalVertex_NearField; + unsigned long nBuffer_FaceArea = MaxLocalVertex_NearField; + + for (iVertex = 0; iVertex < MaxLocalVertex_NearField; iVertex++) { + Buffer_Send_IdPoint[iVertex] = 0; Buffer_Send_Pressure[iVertex] = 0.0; + Buffer_Send_FaceArea[iVertex] = 0.0; Buffer_Send_Xcoord[iVertex] = 0.0; + Buffer_Send_Ycoord[iVertex] = 0.0; Buffer_Send_Zcoord[iVertex] = 0.0; + } + + /*--- Copy coordinates, index points, and pressures to the auxiliar vector --*/ + + nLocalVertex_NearField = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Face_Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + Coord = geometry->node[iPoint]->GetCoord(); + + if (geometry->node[iPoint]->GetDomain()) + if ((Face_Normal[nDim-1] > 0.0) && (Coord[nDim-1] < 0.0)) { + Buffer_Send_IdPoint[nLocalVertex_NearField] = iPoint; + Buffer_Send_Xcoord[nLocalVertex_NearField] = geometry->node[iPoint]->GetCoord(0); + Buffer_Send_Ycoord[nLocalVertex_NearField] = geometry->node[iPoint]->GetCoord(1); + Buffer_Send_Zcoord[nLocalVertex_NearField] = geometry->node[iPoint]->GetCoord(2); + Buffer_Send_Pressure[nLocalVertex_NearField] = solver_container->node[iPoint]->GetPressure(); + Buffer_Send_FaceArea[nLocalVertex_NearField] = fabs(Face_Normal[nDim-1]); + nLocalVertex_NearField++; + } + } + + /*--- Send all the information --*/ + + SU2_MPI::Gather(Buffer_Send_Xcoord, nBuffer_Xcoord, MPI_DOUBLE, Buffer_Receive_Xcoord, nBuffer_Xcoord, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Ycoord, nBuffer_Ycoord, MPI_DOUBLE, Buffer_Receive_Ycoord, nBuffer_Ycoord, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Zcoord, nBuffer_Zcoord, MPI_DOUBLE, Buffer_Receive_Zcoord, nBuffer_Zcoord, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_IdPoint, nBuffer_IdPoint, MPI_UNSIGNED_LONG, Buffer_Receive_IdPoint, nBuffer_IdPoint, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_Pressure, nBuffer_Pressure, MPI_DOUBLE, Buffer_Receive_Pressure, nBuffer_Pressure, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Gather(Buffer_Send_FaceArea, nBuffer_FaceArea, MPI_DOUBLE, Buffer_Receive_FaceArea, nBuffer_FaceArea, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + delete [] Buffer_Send_Xcoord; + delete [] Buffer_Send_Ycoord; + delete [] Buffer_Send_Zcoord; + delete [] Buffer_Send_IdPoint; + delete [] Buffer_Send_Pressure; + delete [] Buffer_Send_FaceArea; + + if (rank == MASTER_NODE) { + + Xcoord = new su2double[nVertex_NearField]; + Ycoord = new su2double[nVertex_NearField]; + Zcoord = new su2double[nVertex_NearField]; + AzimuthalAngle = new short[nVertex_NearField]; + IdPoint = new unsigned long[nVertex_NearField]; + IdDomain = new unsigned long[nVertex_NearField]; + Pressure = new su2double[nVertex_NearField]; + FaceArea = new su2double[nVertex_NearField]; + EquivArea = new su2double[nVertex_NearField]; + TargetArea = new su2double[nVertex_NearField]; + NearFieldWeight = new su2double[nVertex_NearField]; + Weight = new su2double[nVertex_NearField]; + + nVertex_NearField = 0; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) + for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { + Xcoord[nVertex_NearField] = Buffer_Receive_Xcoord[iProcessor*MaxLocalVertex_NearField+iVertex]; + Ycoord[nVertex_NearField] = Buffer_Receive_Ycoord[iProcessor*MaxLocalVertex_NearField+iVertex]; + + if (nDim == 2) { + AzimuthalAngle[nVertex_NearField] = 0; + } + + if (nDim == 3) { + Zcoord[nVertex_NearField] = Buffer_Receive_Zcoord[iProcessor*MaxLocalVertex_NearField+iVertex]; + + /*--- Rotate the nearfield cylinder ---*/ + + su2double YcoordRot = Ycoord[nVertex_NearField]; + su2double ZcoordRot = Xcoord[nVertex_NearField]*sin(AoA) + Zcoord[nVertex_NearField]*cos(AoA); + + /*--- Compute the Azimuthal angle ---*/ + + su2double AngleDouble; short AngleInt; + AngleDouble = fabs(atan(-YcoordRot/ZcoordRot)*180.0/PI_NUMBER); + + /*--- Fix an azimuthal line due to misalignments of the near-field ---*/ + + su2double FixAzimuthalLine = config->GetFixAzimuthalLine(); + + if ((AngleDouble >= FixAzimuthalLine - 0.1) && (AngleDouble <= FixAzimuthalLine + 0.1)) + AngleDouble = FixAzimuthalLine - 0.1; + + AngleInt = SU2_TYPE::Short(floor(AngleDouble + 0.5)); + + if (AngleInt >= 0) AzimuthalAngle[nVertex_NearField] = AngleInt; + else AzimuthalAngle[nVertex_NearField] = 180 + AngleInt; + } + + if (AzimuthalAngle[nVertex_NearField] <= 60) { + IdPoint[nVertex_NearField] = Buffer_Receive_IdPoint[iProcessor*MaxLocalVertex_NearField+iVertex]; + Pressure[nVertex_NearField] = Buffer_Receive_Pressure[iProcessor*MaxLocalVertex_NearField+iVertex]; + FaceArea[nVertex_NearField] = Buffer_Receive_FaceArea[iProcessor*MaxLocalVertex_NearField+iVertex]; + IdDomain[nVertex_NearField] = iProcessor; + nVertex_NearField++; + } + + } + + delete [] Buffer_Receive_nVertex; + + delete [] Buffer_Receive_Xcoord; + delete [] Buffer_Receive_Ycoord; + delete [] Buffer_Receive_Zcoord; + delete [] Buffer_Receive_IdPoint; + delete [] Buffer_Receive_Pressure; + delete [] Buffer_Receive_FaceArea; + + } + +#endif + + if (rank == MASTER_NODE) { + + vector PhiAngleList; + vector::iterator IterPhiAngleList; + + for (iVertex = 0; iVertex < nVertex_NearField; iVertex++) + PhiAngleList.push_back(AzimuthalAngle[iVertex]); + + sort( PhiAngleList.begin(), PhiAngleList.end()); + IterPhiAngleList = unique( PhiAngleList.begin(), PhiAngleList.end()); + PhiAngleList.resize( IterPhiAngleList - PhiAngleList.begin() ); + + /*--- Create vectors and distribute the values among the different PhiAngle queues ---*/ + + vector > Xcoord_PhiAngle; Xcoord_PhiAngle.resize(PhiAngleList.size()); + vector > Ycoord_PhiAngle; Ycoord_PhiAngle.resize(PhiAngleList.size()); + vector > Zcoord_PhiAngle; Zcoord_PhiAngle.resize(PhiAngleList.size()); + vector > IdPoint_PhiAngle; IdPoint_PhiAngle.resize(PhiAngleList.size()); + vector > IdDomain_PhiAngle; IdDomain_PhiAngle.resize(PhiAngleList.size()); + vector > Pressure_PhiAngle; Pressure_PhiAngle.resize(PhiAngleList.size()); + vector > FaceArea_PhiAngle; FaceArea_PhiAngle.resize(PhiAngleList.size()); + vector > EquivArea_PhiAngle; EquivArea_PhiAngle.resize(PhiAngleList.size()); + vector > TargetArea_PhiAngle; TargetArea_PhiAngle.resize(PhiAngleList.size()); + vector > NearFieldWeight_PhiAngle; NearFieldWeight_PhiAngle.resize(PhiAngleList.size()); + vector > Weight_PhiAngle; Weight_PhiAngle.resize(PhiAngleList.size()); + + /*--- Distribute the values among the different PhiAngles ---*/ + + for (iVertex = 0; iVertex < nVertex_NearField; iVertex++) + for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) + if (AzimuthalAngle[iVertex] == PhiAngleList[iPhiAngle]) { + Xcoord_PhiAngle[iPhiAngle].push_back(Xcoord[iVertex]); + Ycoord_PhiAngle[iPhiAngle].push_back(Ycoord[iVertex]); + Zcoord_PhiAngle[iPhiAngle].push_back(Zcoord[iVertex]); + IdPoint_PhiAngle[iPhiAngle].push_back(IdPoint[iVertex]); + IdDomain_PhiAngle[iPhiAngle].push_back(IdDomain[iVertex]); + Pressure_PhiAngle[iPhiAngle].push_back(Pressure[iVertex]); + FaceArea_PhiAngle[iPhiAngle].push_back(FaceArea[iVertex]); + EquivArea_PhiAngle[iPhiAngle].push_back(EquivArea[iVertex]); + TargetArea_PhiAngle[iPhiAngle].push_back(TargetArea[iVertex]); + NearFieldWeight_PhiAngle[iPhiAngle].push_back(NearFieldWeight[iVertex]); + Weight_PhiAngle[iPhiAngle].push_back(Weight[iVertex]); + } + + /*--- Order the arrays (x Coordinate, Pressure, Point, and Domain) ---*/ + + for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) + for (iVertex = 0; iVertex < Xcoord_PhiAngle[iPhiAngle].size(); iVertex++) + for (jVertex = 0; jVertex < Xcoord_PhiAngle[iPhiAngle].size() - 1 - iVertex; jVertex++) + if (Xcoord_PhiAngle[iPhiAngle][jVertex] > Xcoord_PhiAngle[iPhiAngle][jVertex+1]) { + auxXCoord = Xcoord_PhiAngle[iPhiAngle][jVertex]; Xcoord_PhiAngle[iPhiAngle][jVertex] = Xcoord_PhiAngle[iPhiAngle][jVertex+1]; Xcoord_PhiAngle[iPhiAngle][jVertex+1] = auxXCoord; + auxYCoord = Ycoord_PhiAngle[iPhiAngle][jVertex]; Ycoord_PhiAngle[iPhiAngle][jVertex] = Ycoord_PhiAngle[iPhiAngle][jVertex+1]; Ycoord_PhiAngle[iPhiAngle][jVertex+1] = auxYCoord; + auxZCoord = Zcoord_PhiAngle[iPhiAngle][jVertex]; Zcoord_PhiAngle[iPhiAngle][jVertex] = Zcoord_PhiAngle[iPhiAngle][jVertex+1]; Zcoord_PhiAngle[iPhiAngle][jVertex+1] = auxZCoord; + auxPress = Pressure_PhiAngle[iPhiAngle][jVertex]; Pressure_PhiAngle[iPhiAngle][jVertex] = Pressure_PhiAngle[iPhiAngle][jVertex+1]; Pressure_PhiAngle[iPhiAngle][jVertex+1] = auxPress; + auxArea = FaceArea_PhiAngle[iPhiAngle][jVertex]; FaceArea_PhiAngle[iPhiAngle][jVertex] = FaceArea_PhiAngle[iPhiAngle][jVertex+1]; FaceArea_PhiAngle[iPhiAngle][jVertex+1] = auxArea; + auxPoint = IdPoint_PhiAngle[iPhiAngle][jVertex]; IdPoint_PhiAngle[iPhiAngle][jVertex] = IdPoint_PhiAngle[iPhiAngle][jVertex+1]; IdPoint_PhiAngle[iPhiAngle][jVertex+1] = auxPoint; + auxDomain = IdDomain_PhiAngle[iPhiAngle][jVertex]; IdDomain_PhiAngle[iPhiAngle][jVertex] = IdDomain_PhiAngle[iPhiAngle][jVertex+1]; IdDomain_PhiAngle[iPhiAngle][jVertex+1] = auxDomain; + } + + + /*--- Check that all the azimuth lists have the same size ---*/ + + unsigned short nVertex = Xcoord_PhiAngle[0].size(); + for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) { + unsigned short nVertex_aux = Xcoord_PhiAngle[iPhiAngle].size(); + if (nVertex_aux != nVertex) cout <<"Be careful!!! one azimuth list is shorter than the other"<< endl; + nVertex = min(nVertex, nVertex_aux); + } + + /*--- Compute equivalent area distribution at each azimuth angle ---*/ + + for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) { + EquivArea_PhiAngle[iPhiAngle][0] = 0.0; + for (iVertex = 1; iVertex < EquivArea_PhiAngle[iPhiAngle].size(); iVertex++) { + EquivArea_PhiAngle[iPhiAngle][iVertex] = 0.0; + + Coord_i = Xcoord_PhiAngle[iPhiAngle][iVertex]*cos(AoA) - Zcoord_PhiAngle[iPhiAngle][iVertex]*sin(AoA); + + for (jVertex = 0; jVertex < iVertex-1; jVertex++) { + + Coord_j = Xcoord_PhiAngle[iPhiAngle][jVertex]*cos(AoA) - Zcoord_PhiAngle[iPhiAngle][jVertex]*sin(AoA); + jp1Coord = Xcoord_PhiAngle[iPhiAngle][jVertex+1]*cos(AoA) - Zcoord_PhiAngle[iPhiAngle][jVertex+1]*sin(AoA); + + jFunction = factor*(Pressure_PhiAngle[iPhiAngle][jVertex] - Pressure_Inf)*sqrt(Coord_i-Coord_j); + jp1Function = factor*(Pressure_PhiAngle[iPhiAngle][jVertex+1] - Pressure_Inf)*sqrt(Coord_i-jp1Coord); + + DeltaX = (jp1Coord-Coord_j); + MeanFuntion = 0.5*(jp1Function + jFunction); + EquivArea_PhiAngle[iPhiAngle][iVertex] += DeltaX * MeanFuntion; + } + } + } + + /*--- Create a file with the equivalent area distribution at each azimuthal angle ---*/ + + NearFieldEA_file.precision(15); + NearFieldEA_file.open("Equivalent_Area.dat", ios::out); + NearFieldEA_file << "TITLE = \"Equivalent Area evaluation at each azimuthal angle\"" << endl; + + if (config->GetSystemMeasurements() == US) + NearFieldEA_file << "VARIABLES = \"Height (in) at r="<< R_Plane*12.0 << " in. (cyl. coord. system)\""; + else + NearFieldEA_file << "VARIABLES = \"Height (m) at r="<< R_Plane << " m. (cylindrical coordinate system)\""; + + for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) { + if (config->GetSystemMeasurements() == US) + NearFieldEA_file << ", \"Equivalent Area (ft2), F= " << PhiAngleList[iPhiAngle] << " deg.\""; + else + NearFieldEA_file << ", \"Equivalent Area (m2), F= " << PhiAngleList[iPhiAngle] << " deg.\""; + } + + NearFieldEA_file << endl; + for (iVertex = 0; iVertex < EquivArea_PhiAngle[0].size(); iVertex++) { + + su2double XcoordRot = Xcoord_PhiAngle[0][iVertex]*cos(AoA) - Zcoord_PhiAngle[0][iVertex]*sin(AoA); + su2double XcoordRot_init = Xcoord_PhiAngle[0][0]*cos(AoA) - Zcoord_PhiAngle[0][0]*sin(AoA); + + if (config->GetSystemMeasurements() == US) + NearFieldEA_file << scientific << (XcoordRot - XcoordRot_init) * 12.0; + else + NearFieldEA_file << scientific << (XcoordRot - XcoordRot_init); + + for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) { + NearFieldEA_file << scientific << ", " << EquivArea_PhiAngle[iPhiAngle][iVertex]; + } + + NearFieldEA_file << endl; + + } + NearFieldEA_file.close(); + + /*--- Read target equivalent area from the configuration file, + this first implementation requires a complete table (same as the original + EA table). so... no interpolation. ---*/ + + vector > TargetArea_PhiAngle_Trans; + TargetEA_file.open("TargetEA.dat", ios::in); + + if (TargetEA_file.fail()) { + if (iExtIter == 0) { cout << "There is no Target Equivalent Area file (TargetEA.dat)!!"<< endl; + cout << "Using default parameters (Target Equiv Area = 0.0)" << endl; + } + /*--- Set the table to 0 ---*/ + for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) + for (iVertex = 0; iVertex < TargetArea_PhiAngle[iPhiAngle].size(); iVertex++) + TargetArea_PhiAngle[iPhiAngle][iVertex] = 0.0; + } + else { + + /*--- skip header lines ---*/ + + string line; + getline(TargetEA_file, line); + getline(TargetEA_file, line); + + while (TargetEA_file) { + + string line; + getline(TargetEA_file, line); + istringstream is(line); + vector row; + unsigned short iter = 0; + + while (is.good()) { + string token; + getline(is, token,','); + + istringstream js(token); + + su2double data; + js >> data; + + /*--- The first element in the table is the coordinate (in or m)---*/ + + if (iter != 0) row.push_back(data); + iter++; + + } + TargetArea_PhiAngle_Trans.push_back(row); + } + + for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) + for (iVertex = 0; iVertex < EquivArea_PhiAngle[iPhiAngle].size(); iVertex++) + TargetArea_PhiAngle[iPhiAngle][iVertex] = TargetArea_PhiAngle_Trans[iVertex][iPhiAngle]; + + } + + /*--- Divide by the number of Phi angles in the nearfield ---*/ + + su2double PhiFactor = 1.0/su2double(PhiAngleList.size()); + + /*--- Evaluate the objective function ---*/ + + InverseDesign = 0; + for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) + for (iVertex = 0; iVertex < EquivArea_PhiAngle[iPhiAngle].size(); iVertex++) { + Weight_PhiAngle[iPhiAngle][iVertex] = 1.0; + Coord_i = Xcoord_PhiAngle[iPhiAngle][iVertex]; + + su2double Difference = EquivArea_PhiAngle[iPhiAngle][iVertex]-TargetArea_PhiAngle[iPhiAngle][iVertex]; + su2double percentage = fabs(Difference)*100/fabs(TargetArea_PhiAngle[iPhiAngle][iVertex]); + + if ((percentage < 0.1) || (Coord_i < XCoordBegin_OF) || (Coord_i > XCoordEnd_OF)) Difference = 0.0; + + InverseDesign += EAScaleFactor*PhiFactor*Weight_PhiAngle[iPhiAngle][iVertex]*Difference*Difference; + + } + + /*--- Evaluate the weight of the nearfield pressure (adjoint input) ---*/ + + for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) + for (iVertex = 0; iVertex < EquivArea_PhiAngle[iPhiAngle].size(); iVertex++) { + Coord_i = Xcoord_PhiAngle[iPhiAngle][iVertex]; + NearFieldWeight_PhiAngle[iPhiAngle][iVertex] = 0.0; + for (jVertex = iVertex; jVertex < EquivArea_PhiAngle[iPhiAngle].size(); jVertex++) { + Coord_j = Xcoord_PhiAngle[iPhiAngle][jVertex]; + Weight_PhiAngle[iPhiAngle][iVertex] = 1.0; + + su2double Difference = EquivArea_PhiAngle[iPhiAngle][jVertex]-TargetArea_PhiAngle[iPhiAngle][jVertex]; + su2double percentage = fabs(Difference)*100/fabs(TargetArea_PhiAngle[iPhiAngle][jVertex]); + + if ((percentage < 0.1) || (Coord_j < XCoordBegin_OF) || (Coord_j > XCoordEnd_OF)) Difference = 0.0; + + NearFieldWeight_PhiAngle[iPhiAngle][iVertex] += EAScaleFactor*PhiFactor*Weight_PhiAngle[iPhiAngle][iVertex]*2.0*Difference*factor*sqrt(Coord_j-Coord_i); + } + } + + /*--- Write the Nearfield pressure at each Azimuthal PhiAngle ---*/ + + EquivArea_file.precision(15); + EquivArea_file.open("nearfield_flow.dat", ios::out); + EquivArea_file << "TITLE = \"Equivalent Area evaluation at each azimuthal angle\"" << endl; + + if (config->GetSystemMeasurements() == US) + EquivArea_file << "VARIABLES = \"Height (in) at r="<< R_Plane*12.0 << " in. (cyl. coord. system)\",\"Equivalent Area (ft2)\",\"Target Equivalent Area (ft2)\",\"Cp\"" << endl; + else + EquivArea_file << "VARIABLES = \"Height (m) at r="<< R_Plane << " m. (cylindrical coordinate system)\",\"Equivalent Area (m2)\",\"Target Equivalent Area (m2)\",\"Cp\"" << endl; + + for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) { + EquivArea_file << fixed << "ZONE T= \"F=" << PhiAngleList[iPhiAngle] << " deg.\"" << endl; + for (iVertex = 0; iVertex < Xcoord_PhiAngle[iPhiAngle].size(); iVertex++) { + + su2double XcoordRot = Xcoord_PhiAngle[0][iVertex]*cos(AoA) - Zcoord_PhiAngle[0][iVertex]*sin(AoA); + su2double XcoordRot_init = Xcoord_PhiAngle[0][0]*cos(AoA) - Zcoord_PhiAngle[0][0]*sin(AoA); + + if (config->GetSystemMeasurements() == US) + EquivArea_file << scientific << (XcoordRot - XcoordRot_init) * 12.0; + else + EquivArea_file << scientific << (XcoordRot - XcoordRot_init); + + EquivArea_file << scientific << ", " << EquivArea_PhiAngle[iPhiAngle][iVertex] + << ", " << TargetArea_PhiAngle[iPhiAngle][iVertex] << ", " << (Pressure_PhiAngle[iPhiAngle][iVertex]-Pressure_Inf)/Pressure_Inf << endl; + } + } + + EquivArea_file.close(); + + /*--- Write Weight file for adjoint computation ---*/ + + FuncGrad_file.precision(15); + FuncGrad_file.open("WeightNF.dat", ios::out); + + FuncGrad_file << scientific << "-1.0"; + for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) + FuncGrad_file << scientific << "\t" << PhiAngleList[iPhiAngle]; + FuncGrad_file << endl; + + for (iVertex = 0; iVertex < NearFieldWeight_PhiAngle[0].size(); iVertex++) { + su2double XcoordRot = Xcoord_PhiAngle[0][iVertex]*cos(AoA) - Zcoord_PhiAngle[0][iVertex]*sin(AoA); + FuncGrad_file << scientific << XcoordRot; + for (iPhiAngle = 0; iPhiAngle < PhiAngleList.size(); iPhiAngle++) + FuncGrad_file << scientific << "\t" << NearFieldWeight_PhiAngle[iPhiAngle][iVertex]; + FuncGrad_file << endl; + } + FuncGrad_file.close(); + + /*--- Delete structures ---*/ + + delete [] Xcoord; delete [] Ycoord; delete [] Zcoord; + delete [] AzimuthalAngle; delete [] IdPoint; delete [] IdDomain; + delete [] Pressure; delete [] FaceArea; + delete [] EquivArea; delete [] TargetArea; + delete [] NearFieldWeight; delete [] Weight; + + } + +#ifndef HAVE_MPI + + /*--- Store the value of the NearField coefficient ---*/ + + solver_container->SetTotal_CEquivArea(InverseDesign); + +#else + + /*--- Send the value of the NearField coefficient to all the processors ---*/ + + SU2_MPI::Bcast(&InverseDesign, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + + /*--- Store the value of the NearField coefficient ---*/ + + solver_container->SetTotal_CEquivArea(InverseDesign); + +#endif + +} + diff --git a/SU2_CFD/src/output_su2.cpp b/SU2_CFD/src/output_su2.cpp index dff6f6b86f4..34ca34fe5d9 100644 --- a/SU2_CFD/src/output_su2.cpp +++ b/SU2_CFD/src/output_su2.cpp @@ -1,224 +1,224 @@ -/*! - * \file output_su2.cpp - * \brief Main subroutines for output solver information. - * \author F. Palacios, T. Economon, M. Colonno - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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_structure.hpp" - -void COutput::SetSU2_MeshASCII(CConfig *config, CGeometry *geometry) { - - char cstr[MAX_STRING_SIZE], out_file[MAX_STRING_SIZE]; - unsigned long iElem, iPoint, iElem_Bound, nElem_Bound_, vnodes_edge[2], vnodes_triangle[3], vnodes_quad[4], iNode, nElem; - unsigned short iMarker, iDim, nDim = geometry->GetnDim(), iChar, iPeriodic, nPeriodic = 0, VTK_Type, nMarker_; - su2double *center, *angles, *transl; - ofstream output_file; - ifstream input_file; - string Grid_Marker, text_line, Marker_Tag, str; - string::size_type position; - - /*--- Read the name of the output and input file ---*/ - - str = config->GetMesh_Out_FileName(); - strcpy (out_file, str.c_str()); - strcpy (cstr, out_file); - output_file.precision(15); - output_file.open(cstr, ios::out); - - /*--- Write dimensions data. ---*/ - - output_file << "NDIME= " << nDim << endl; - - /*--- Write connectivity data. ---*/ - - nElem = nGlobal_Tria+nGlobal_Quad+nGlobal_Tetr+nGlobal_Hexa+nGlobal_Pris+nGlobal_Pyra; - - output_file << "NELEM= " << nElem<< endl; - - nElem = 0; - - for (iElem = 0; iElem < nGlobal_Tria; iElem++) { - iNode = iElem*N_POINTS_TRIANGLE; - output_file << "5\t"; - output_file << Conn_Tria[iNode+0]-1 << "\t"; output_file << Conn_Tria[iNode+1]-1 << "\t"; - output_file << Conn_Tria[iNode+2]-1 << "\t"; - output_file << nElem << "\n"; nElem++; - } - - for (iElem = 0; iElem < nGlobal_Quad; iElem++) { - iNode = iElem*N_POINTS_QUADRILATERAL; - output_file << "9\t"; - output_file << Conn_Quad[iNode+0]-1 << "\t"; output_file << Conn_Quad[iNode+1]-1 << "\t"; - output_file << Conn_Quad[iNode+2]-1 << "\t"; output_file << Conn_Quad[iNode+3]-1 << "\t"; - output_file << nElem << "\n"; nElem++; - } - - for (iElem = 0; iElem < nGlobal_Tetr; iElem++) { - iNode = iElem*N_POINTS_TETRAHEDRON; - output_file << "10\t"; - output_file << Conn_Tetr[iNode+0]-1 << "\t" << Conn_Tetr[iNode+1]-1 << "\t"; - output_file << Conn_Tetr[iNode+2]-1 << "\t" << Conn_Tetr[iNode+3]-1 << "\t"; - output_file << nElem << "\n"; nElem++; - } - - for (iElem = 0; iElem < nGlobal_Hexa; iElem++) { - iNode = iElem*N_POINTS_HEXAHEDRON; - output_file << "12\t"; - output_file << Conn_Hexa[iNode+0]-1 << "\t" << Conn_Hexa[iNode+1]-1 << "\t"; - output_file << Conn_Hexa[iNode+2]-1 << "\t" << Conn_Hexa[iNode+3]-1 << "\t"; - output_file << Conn_Hexa[iNode+4]-1 << "\t" << Conn_Hexa[iNode+5]-1 << "\t"; - output_file << Conn_Hexa[iNode+6]-1 << "\t" << Conn_Hexa[iNode+7]-1 << "\t"; - output_file << nElem << "\n"; nElem++; - } - - for (iElem = 0; iElem < nGlobal_Pris; iElem++) { - iNode = iElem*N_POINTS_PRISM; - output_file << "13\t"; - output_file << Conn_Pris[iNode+0]-1 << "\t" << Conn_Pris[iNode+1]-1 << "\t"; - output_file << Conn_Pris[iNode+2]-1 << "\t" << Conn_Pris[iNode+3]-1 << "\t"; - output_file << Conn_Pris[iNode+4]-1 << "\t" << Conn_Pris[iNode+5]-1 << "\t"; - output_file << nElem << "\n"; nElem++; - } - - for (iElem = 0; iElem < nGlobal_Pyra; iElem++) { - iNode = iElem*N_POINTS_PYRAMID; - output_file << "14\t"; - output_file << Conn_Pyra[iNode+0]-1 << "\t" << Conn_Pyra[iNode+1]-1 << "\t"; - output_file << Conn_Pyra[iNode+2]-1 << "\t" << Conn_Pyra[iNode+3]-1 << "\t"; - output_file << Conn_Pyra[iNode+4]-1 << "\t"; - output_file << nElem << "\n"; nElem++; - } - - /*--- Write the node coordinates ---*/ - - output_file << "NPOIN= " << nGlobal_Poin<< endl; - - for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { - for (iDim = 0; iDim < nDim; iDim++) - output_file << scientific << Coords[iDim][iPoint] << "\t"; - output_file << iPoint << endl; - } - - /*--- Read the boundary information ---*/ - - input_file.open("boundary.su2", ios::out); - - /*--- Read grid file with format SU2 ---*/ - - while (getline (input_file, text_line)) { - - /*--- Write the physical boundaries ---*/ - - position = text_line.find ("NMARK=",0); - if (position != string::npos) { - - text_line.erase (0,6); nMarker_ = atoi(text_line.c_str()); - output_file << "NMARK= " << nMarker_ << endl; - - for (iMarker = 0 ; iMarker < nMarker_; iMarker++) { - - getline (input_file, text_line); - text_line.erase (0,11); - string::size_type position; - for (iChar = 0; iChar < 20; iChar++) { - position = text_line.find( " ", 0 ); - if (position != string::npos) text_line.erase (position,1); - position = text_line.find( "\r", 0 ); - if (position != string::npos) text_line.erase (position,1); - position = text_line.find( "\n", 0 ); - if (position != string::npos) text_line.erase (position,1); - } - Marker_Tag = text_line.c_str(); - - /*--- Standart physical boundary ---*/ - - getline (input_file, text_line); - - text_line.erase (0,13); nElem_Bound_ = atoi(text_line.c_str()); - output_file << "MARKER_TAG= " << Marker_Tag << endl; - output_file << "MARKER_ELEMS= " << nElem_Bound_<< endl; - - for (iElem_Bound = 0; iElem_Bound < nElem_Bound_; iElem_Bound++) { - - getline(input_file, text_line); - istringstream bound_line(text_line); - - bound_line >> VTK_Type; - output_file << VTK_Type; - - switch(VTK_Type) { - case LINE: - bound_line >> vnodes_edge[0]; bound_line >> vnodes_edge[1]; - output_file << "\t" << vnodes_edge[0] << "\t" << vnodes_edge[1] << endl; - break; - case TRIANGLE: - bound_line >> vnodes_triangle[0]; bound_line >> vnodes_triangle[1]; bound_line >> vnodes_triangle[2]; - output_file << "\t" << vnodes_triangle[0] << "\t" << vnodes_triangle[1] << "\t" << vnodes_triangle[2] << endl; - break; - case QUADRILATERAL: - bound_line >> vnodes_quad[0]; bound_line >> vnodes_quad[1]; bound_line >> vnodes_quad[2]; bound_line >> vnodes_quad[3]; - output_file << "\t" << vnodes_quad[0] << "\t" << vnodes_quad[1] << "\t" << vnodes_quad[2] << "\t" << vnodes_quad[3] << endl; - break; - } - } - } - } - - } - - input_file.close(); - - remove("boundary.su2"); - - /*--- Get the total number of periodic transformations ---*/ - - nPeriodic = config->GetnPeriodicIndex(); - output_file << "NPERIODIC= " << nPeriodic << endl; - - /*--- From iPeriodic obtain the iMarker ---*/ - - for (iPeriodic = 0; iPeriodic < nPeriodic; iPeriodic++) { - - /*--- Retrieve the supplied periodic information. ---*/ - - center = config->GetPeriodicCenter(iPeriodic); - angles = config->GetPeriodicRotation(iPeriodic); - transl = config->GetPeriodicTranslate(iPeriodic); - - output_file << "PERIODIC_INDEX= " << iPeriodic << endl; - output_file << center[0] << "\t" << center[1] << "\t" << center[2] << endl; - output_file << angles[0] << "\t" << angles[1] << "\t" << angles[2] << endl; - output_file << transl[0] << "\t" << transl[1] << "\t" << transl[2] << endl; - - } - - output_file.close(); - -} - -void COutput::SetSU2_MeshBinary(CConfig *config, CGeometry *geometry) { } +/*! + * \file output_su2.cpp + * \brief Main subroutines for output solver information. + * \author F. Palacios, T. Economon, M. Colonno + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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_structure.hpp" + +void COutput::SetSU2_MeshASCII(CConfig *config, CGeometry *geometry) { + + char cstr[MAX_STRING_SIZE], out_file[MAX_STRING_SIZE]; + unsigned long iElem, iPoint, iElem_Bound, nElem_Bound_, vnodes_edge[2], vnodes_triangle[3], vnodes_quad[4], iNode, nElem; + unsigned short iMarker, iDim, nDim = geometry->GetnDim(), iChar, iPeriodic, nPeriodic = 0, VTK_Type, nMarker_; + su2double *center, *angles, *transl; + ofstream output_file; + ifstream input_file; + string Grid_Marker, text_line, Marker_Tag, str; + string::size_type position; + + /*--- Read the name of the output and input file ---*/ + + str = config->GetMesh_Out_FileName(); + strcpy (out_file, str.c_str()); + strcpy (cstr, out_file); + output_file.precision(15); + output_file.open(cstr, ios::out); + + /*--- Write dimensions data. ---*/ + + output_file << "NDIME= " << nDim << endl; + + /*--- Write connectivity data. ---*/ + + nElem = nGlobal_Tria+nGlobal_Quad+nGlobal_Tetr+nGlobal_Hexa+nGlobal_Pris+nGlobal_Pyra; + + output_file << "NELEM= " << nElem<< endl; + + nElem = 0; + + for (iElem = 0; iElem < nGlobal_Tria; iElem++) { + iNode = iElem*N_POINTS_TRIANGLE; + output_file << "5\t"; + output_file << Conn_Tria[iNode+0]-1 << "\t"; output_file << Conn_Tria[iNode+1]-1 << "\t"; + output_file << Conn_Tria[iNode+2]-1 << "\t"; + output_file << nElem << "\n"; nElem++; + } + + for (iElem = 0; iElem < nGlobal_Quad; iElem++) { + iNode = iElem*N_POINTS_QUADRILATERAL; + output_file << "9\t"; + output_file << Conn_Quad[iNode+0]-1 << "\t"; output_file << Conn_Quad[iNode+1]-1 << "\t"; + output_file << Conn_Quad[iNode+2]-1 << "\t"; output_file << Conn_Quad[iNode+3]-1 << "\t"; + output_file << nElem << "\n"; nElem++; + } + + for (iElem = 0; iElem < nGlobal_Tetr; iElem++) { + iNode = iElem*N_POINTS_TETRAHEDRON; + output_file << "10\t"; + output_file << Conn_Tetr[iNode+0]-1 << "\t" << Conn_Tetr[iNode+1]-1 << "\t"; + output_file << Conn_Tetr[iNode+2]-1 << "\t" << Conn_Tetr[iNode+3]-1 << "\t"; + output_file << nElem << "\n"; nElem++; + } + + for (iElem = 0; iElem < nGlobal_Hexa; iElem++) { + iNode = iElem*N_POINTS_HEXAHEDRON; + output_file << "12\t"; + output_file << Conn_Hexa[iNode+0]-1 << "\t" << Conn_Hexa[iNode+1]-1 << "\t"; + output_file << Conn_Hexa[iNode+2]-1 << "\t" << Conn_Hexa[iNode+3]-1 << "\t"; + output_file << Conn_Hexa[iNode+4]-1 << "\t" << Conn_Hexa[iNode+5]-1 << "\t"; + output_file << Conn_Hexa[iNode+6]-1 << "\t" << Conn_Hexa[iNode+7]-1 << "\t"; + output_file << nElem << "\n"; nElem++; + } + + for (iElem = 0; iElem < nGlobal_Pris; iElem++) { + iNode = iElem*N_POINTS_PRISM; + output_file << "13\t"; + output_file << Conn_Pris[iNode+0]-1 << "\t" << Conn_Pris[iNode+1]-1 << "\t"; + output_file << Conn_Pris[iNode+2]-1 << "\t" << Conn_Pris[iNode+3]-1 << "\t"; + output_file << Conn_Pris[iNode+4]-1 << "\t" << Conn_Pris[iNode+5]-1 << "\t"; + output_file << nElem << "\n"; nElem++; + } + + for (iElem = 0; iElem < nGlobal_Pyra; iElem++) { + iNode = iElem*N_POINTS_PYRAMID; + output_file << "14\t"; + output_file << Conn_Pyra[iNode+0]-1 << "\t" << Conn_Pyra[iNode+1]-1 << "\t"; + output_file << Conn_Pyra[iNode+2]-1 << "\t" << Conn_Pyra[iNode+3]-1 << "\t"; + output_file << Conn_Pyra[iNode+4]-1 << "\t"; + output_file << nElem << "\n"; nElem++; + } + + /*--- Write the node coordinates ---*/ + + output_file << "NPOIN= " << nGlobal_Poin<< endl; + + for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { + for (iDim = 0; iDim < nDim; iDim++) + output_file << scientific << Coords[iDim][iPoint] << "\t"; + output_file << iPoint << endl; + } + + /*--- Read the boundary information ---*/ + + input_file.open("boundary.su2", ios::out); + + /*--- Read grid file with format SU2 ---*/ + + while (getline (input_file, text_line)) { + + /*--- Write the physical boundaries ---*/ + + position = text_line.find ("NMARK=",0); + if (position != string::npos) { + + text_line.erase (0,6); nMarker_ = atoi(text_line.c_str()); + output_file << "NMARK= " << nMarker_ << endl; + + for (iMarker = 0 ; iMarker < nMarker_; iMarker++) { + + getline (input_file, text_line); + text_line.erase (0,11); + string::size_type position; + for (iChar = 0; iChar < 20; iChar++) { + position = text_line.find( " ", 0 ); + if (position != string::npos) text_line.erase (position,1); + position = text_line.find( "\r", 0 ); + if (position != string::npos) text_line.erase (position,1); + position = text_line.find( "\n", 0 ); + if (position != string::npos) text_line.erase (position,1); + } + Marker_Tag = text_line.c_str(); + + /*--- Standart physical boundary ---*/ + + getline (input_file, text_line); + + text_line.erase (0,13); nElem_Bound_ = atoi(text_line.c_str()); + output_file << "MARKER_TAG= " << Marker_Tag << endl; + output_file << "MARKER_ELEMS= " << nElem_Bound_<< endl; + + for (iElem_Bound = 0; iElem_Bound < nElem_Bound_; iElem_Bound++) { + + getline(input_file, text_line); + istringstream bound_line(text_line); + + bound_line >> VTK_Type; + output_file << VTK_Type; + + switch(VTK_Type) { + case LINE: + bound_line >> vnodes_edge[0]; bound_line >> vnodes_edge[1]; + output_file << "\t" << vnodes_edge[0] << "\t" << vnodes_edge[1] << endl; + break; + case TRIANGLE: + bound_line >> vnodes_triangle[0]; bound_line >> vnodes_triangle[1]; bound_line >> vnodes_triangle[2]; + output_file << "\t" << vnodes_triangle[0] << "\t" << vnodes_triangle[1] << "\t" << vnodes_triangle[2] << endl; + break; + case QUADRILATERAL: + bound_line >> vnodes_quad[0]; bound_line >> vnodes_quad[1]; bound_line >> vnodes_quad[2]; bound_line >> vnodes_quad[3]; + output_file << "\t" << vnodes_quad[0] << "\t" << vnodes_quad[1] << "\t" << vnodes_quad[2] << "\t" << vnodes_quad[3] << endl; + break; + } + } + } + } + + } + + input_file.close(); + + remove("boundary.su2"); + + /*--- Get the total number of periodic transformations ---*/ + + nPeriodic = config->GetnPeriodicIndex(); + output_file << "NPERIODIC= " << nPeriodic << endl; + + /*--- From iPeriodic obtain the iMarker ---*/ + + for (iPeriodic = 0; iPeriodic < nPeriodic; iPeriodic++) { + + /*--- Retrieve the supplied periodic information. ---*/ + + center = config->GetPeriodicCenter(iPeriodic); + angles = config->GetPeriodicRotation(iPeriodic); + transl = config->GetPeriodicTranslate(iPeriodic); + + output_file << "PERIODIC_INDEX= " << iPeriodic << endl; + output_file << center[0] << "\t" << center[1] << "\t" << center[2] << endl; + output_file << angles[0] << "\t" << angles[1] << "\t" << angles[2] << endl; + output_file << transl[0] << "\t" << transl[1] << "\t" << transl[2] << endl; + + } + + output_file.close(); + +} + +void COutput::SetSU2_MeshBinary(CConfig *config, CGeometry *geometry) { } diff --git a/SU2_CFD/src/output_tecplot.cpp b/SU2_CFD/src/output_tecplot.cpp index 717ebb6c0cb..1c76d880184 100644 --- a/SU2_CFD/src/output_tecplot.cpp +++ b/SU2_CFD/src/output_tecplot.cpp @@ -1,2657 +1,2657 @@ -/*! - * \file output_tecplot.cpp - * \brief Main subroutines for output solver information. - * \author F. Palacios, T. Economon, M. Colonno - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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_structure.hpp" - -void COutput::SetTecplotASCII(CConfig *config, CGeometry *geometry, CSolver **solver, unsigned short val_iZone, unsigned short val_nZone, bool surf_sol) { - - unsigned short iDim, iVar, nDim = geometry->GetnDim(); - unsigned short Kind_Solver = config->GetKind_Solver(); - - unsigned long iPoint, iElem, iNode; - unsigned long iExtIter = config->GetExtIter(); - unsigned long *LocalIndex = NULL; - bool *SurfacePoint = NULL; - - bool grid_movement = config->GetGrid_Movement(); - bool adjoint = config->GetAdjoint() || config->GetDiscrete_Adjoint(); - - char cstr[200], buffer[50]; - string filename; - - /*--- Write file name with extension ---*/ - - if (surf_sol) { - if (adjoint) filename = config->GetSurfAdjCoeff_FileName(); - else filename = config->GetSurfFlowCoeff_FileName(); - } - else { - if (adjoint) - filename = config->GetAdj_FileName(); - else filename = config->GetFlow_FileName(); - } - - if (Kind_Solver == LINEAR_ELASTICITY) { - if (surf_sol) filename = config->GetSurfStructure_FileName().c_str(); - else filename = config->GetStructure_FileName().c_str(); - } - - if (Kind_Solver == WAVE_EQUATION) { - if (surf_sol) filename = config->GetSurfWave_FileName().c_str(); - else filename = config->GetWave_FileName().c_str(); - } - - if (Kind_Solver == HEAT_EQUATION) { - if (surf_sol) filename = config->GetSurfHeat_FileName().c_str(); - else filename = config->GetHeat_FileName().c_str(); - } - - if (Kind_Solver == POISSON_EQUATION) { - if (surf_sol) filename = config->GetSurfStructure_FileName().c_str(); - else filename = config->GetStructure_FileName().c_str(); - } - - strcpy (cstr, filename.c_str()); - - /*--- Special cases where a number needs to be appended to the file name. ---*/ - - if ((Kind_Solver == EULER || Kind_Solver == NAVIER_STOKES || Kind_Solver == RANS || - Kind_Solver == ADJ_EULER || Kind_Solver == ADJ_NAVIER_STOKES || Kind_Solver == ADJ_RANS || - Kind_Solver == DISC_ADJ_EULER || Kind_Solver == DISC_ADJ_NAVIER_STOKES || Kind_Solver == DISC_ADJ_RANS) && - (val_nZone > 1) && (config->GetUnsteady_Simulation() != TIME_SPECTRAL)) { - SPRINTF (buffer, "_%d", SU2_TYPE::Int(val_iZone)); - strcat(cstr, buffer); - } - - if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { - - if (config->GetKind_SU2() == SU2_SOL) { val_iZone = iExtIter; } - - if (SU2_TYPE::Int(val_iZone) < 10) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 10) && (SU2_TYPE::Int(val_iZone) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 100) && (SU2_TYPE::Int(val_iZone) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(val_iZone)); - if ((SU2_TYPE::Int(val_iZone) >= 1000) && (SU2_TYPE::Int(val_iZone) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(val_iZone)); - if (SU2_TYPE::Int(val_iZone) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(val_iZone)); - - } - else if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { - if (SU2_TYPE::Int(iExtIter) < 10) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(iExtIter)); - if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(iExtIter)); - } - else { SPRINTF (buffer, ".dat"); } - - strcat(cstr, buffer); - - /*--- Open Tecplot ASCII file and write the header. ---*/ - ofstream Tecplot_File; - Tecplot_File.open(cstr, ios::out); - Tecplot_File.precision(6); - if (surf_sol) Tecplot_File << "TITLE = \"Visualization of the surface solution\"" << endl; - else Tecplot_File << "TITLE = \"Visualization of the volumetric solution\"" << endl; - - /*--- Prepare the variable lists. ---*/ - - /*--- Write the list of the fields in the restart file. - Without including the PointID---*/ - if (config->GetKind_SU2() == SU2_SOL) { - - /*--- If SU2_SOL called this routine, we already have a set of output - variables with the appropriate string tags stored in the config class. ---*/ - Tecplot_File << "VARIABLES = "; - nVar_Total = config->fields.size() - 1; - for (unsigned short iField = 1; iField < config->fields.size(); iField++) { - Tecplot_File << config->fields[iField]; - } - Tecplot_File << endl; - - } else { - - if (nDim == 2) { - Tecplot_File << "VARIABLES = \"x\",\"y\""; - } else { - Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\""; - } - - /*--- Add names for conservative and residual variables ---*/ - for (iVar = 0; iVar < nVar_Consv; iVar++) { - Tecplot_File << ",\"Conservative_" << iVar+1 << "\""; - } - - if (!config->GetLow_MemoryOutput()) { - - if (config->GetWrt_Limiters()) { - for (iVar = 0; iVar < nVar_Consv; iVar++) { - Tecplot_File << ",\"Limiter_" << iVar+1 << "\""; - } - } - if (config->GetWrt_Residuals()) { - for (iVar = 0; iVar < nVar_Consv; iVar++) { - Tecplot_File << ",\"Residual_" << iVar+1 << "\""; - } - } - - /*--- Add names for any extra variables (this will need to be adjusted). ---*/ - if (grid_movement) { - if (nDim == 2) { - Tecplot_File << ",\"Grid_Velx\",\"Grid_Vely\""; - } else { - Tecplot_File << ",\"Grid_Velx\",\"Grid_Vely\",\"Grid_Velz\""; - } - } - - if (config->GetKind_Regime() == FREESURFACE) { - Tecplot_File << ",\"Density\""; - } - - if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - Tecplot_File << ",\"Pressure\",\"Temperature\",\"Pressure_Coefficient\",\"Mach\""; - } - - if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - Tecplot_File << ",\"Laminar_Viscosity\", \"Skin_Friction_Coefficient\", \"Heat_Flux\", \"Y_Plus\""; - } - - if (Kind_Solver == RANS) { - Tecplot_File << ", \"Eddy_Viscosity\""; - } - - if (config->GetWrt_SharpEdges()) { - if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - Tecplot_File << ", \"Sharp_Edge_Dist\""; - } - } - - if (Kind_Solver == POISSON_EQUATION) { - unsigned short iDim; - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) - Tecplot_File << ",\"poissonField_" << iDim+1 << "\""; - } - - if (( Kind_Solver == ADJ_EULER ) || - ( Kind_Solver == ADJ_NAVIER_STOKES ) || - ( Kind_Solver == ADJ_RANS ) ) { - Tecplot_File << ", \"Surface_Sensitivity\", \"Solution_Sensor\""; - } - - if (( Kind_Solver == DISC_ADJ_EULER ) || - ( Kind_Solver == DISC_ADJ_NAVIER_STOKES ) || - ( Kind_Solver == DISC_ADJ_RANS )) { - Tecplot_File << ", \"Surface_Sensitivity\", \"Sensitivity_x\", \"Sensitivity_y\""; - if (geometry->GetnDim() == 3){ - Tecplot_File << ",\"Sensitivity_z\""; - } - } - - if (Kind_Solver == LINEAR_ELASTICITY) { - Tecplot_File << ", \"Von_Mises_Stress\", \"Flow_Pressure\""; - } - - if (config->GetExtraOutput()) { - string *headings = NULL; - //if (Kind_Solver == RANS) { - headings = solver[TURB_SOL]->OutputHeadingNames; - //} - for (iVar = 0; iVar < nVar_Extra; iVar++) { - //Tecplot_File << ", \"ExtraOutput_" << iVar+1<<"\""; - if (headings == NULL) { - Tecplot_File << ", \"ExtraOutput_" << iVar+1<<"\""; - } else{ - Tecplot_File << ", \""<< headings[iVar] <<"\""; - } - } - } - } - - Tecplot_File << endl; - - } - - /*--- If it's a surface output, print only the points - that are in the element list, change the numbering ---*/ - - if (surf_sol) { - - LocalIndex = new unsigned long [nGlobal_Poin+1]; - SurfacePoint = new bool [nGlobal_Poin+1]; - - for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) SurfacePoint[iPoint] = false; - - for (iElem = 0; iElem < nGlobal_Line; iElem++) { - iNode = iElem*N_POINTS_LINE; - SurfacePoint[Conn_Line[iNode+0]] = true; - SurfacePoint[Conn_Line[iNode+1]] = true; - } - for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { - iNode = iElem*N_POINTS_TRIANGLE; - SurfacePoint[Conn_BoundTria[iNode+0]] = true; - SurfacePoint[Conn_BoundTria[iNode+1]] = true; - SurfacePoint[Conn_BoundTria[iNode+2]] = true; - } - for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { - iNode = iElem*N_POINTS_QUADRILATERAL; - SurfacePoint[Conn_BoundQuad[iNode+0]] = true; - SurfacePoint[Conn_BoundQuad[iNode+1]] = true; - SurfacePoint[Conn_BoundQuad[iNode+2]] = true; - SurfacePoint[Conn_BoundQuad[iNode+3]] = true; - } - - nSurf_Poin = 0; - for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) { - LocalIndex[iPoint] = 0; - if (SurfacePoint[iPoint]) { nSurf_Poin++; LocalIndex[iPoint] = nSurf_Poin; } - } - - } - - /*--- Write the header ---*/ - Tecplot_File << "ZONE "; - if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { - Tecplot_File << "STRANDID="<GetUnsteady_Simulation() == TIME_SPECTRAL) { - /*--- Compute period of oscillation & compute time interval using nTimeInstances ---*/ - su2double period = config->GetTimeSpectral_Period(); - su2double deltaT = period/(su2double)(config->GetnTimeInstances()); - Tecplot_File << "STRANDID="<GetKind_SU2() != SU2_SOL) { - for (iDim = 0; iDim < nDim; iDim++) - Tecplot_File << scientific << Coords[iDim][iPoint] << "\t"; - } - - /*--- Loop over the vars/residuals and write the values to file ---*/ - for (iVar = 0; iVar < nVar_Total; iVar++) - Tecplot_File << scientific << Data[iVar][iPoint] << "\t"; - - Tecplot_File << endl; - - } - - } else { - - /*--- Write the node coordinates ---*/ - if (config->GetKind_SU2() != SU2_SOL) { - for (iDim = 0; iDim < nDim; iDim++) - Tecplot_File << scientific << Coords[iDim][iPoint] << "\t"; - } - - /*--- Loop over the vars/residuals and write the values to file ---*/ - for (iVar = 0; iVar < nVar_Total; iVar++) - Tecplot_File << scientific << Data[iVar][iPoint] << "\t"; - - Tecplot_File << endl; - - } - - } - - - /*--- Write connectivity data. ---*/ - if (surf_sol) { - - for (iElem = 0; iElem < nGlobal_Line; iElem++) { - iNode = iElem*N_POINTS_LINE; - Tecplot_File << LocalIndex[Conn_Line[iNode+0]] << "\t"; - Tecplot_File << LocalIndex[Conn_Line[iNode+1]] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { - iNode = iElem*N_POINTS_TRIANGLE; - Tecplot_File << LocalIndex[Conn_BoundTria[iNode+0]] << "\t"; - Tecplot_File << LocalIndex[Conn_BoundTria[iNode+1]] << "\t"; - Tecplot_File << LocalIndex[Conn_BoundTria[iNode+2]] << "\t"; - Tecplot_File << LocalIndex[Conn_BoundTria[iNode+2]] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { - iNode = iElem*N_POINTS_QUADRILATERAL; - Tecplot_File << LocalIndex[Conn_BoundQuad[iNode+0]] << "\t"; - Tecplot_File << LocalIndex[Conn_BoundQuad[iNode+1]] << "\t"; - Tecplot_File << LocalIndex[Conn_BoundQuad[iNode+2]] << "\t"; - Tecplot_File << LocalIndex[Conn_BoundQuad[iNode+3]] << "\n"; - } - - } else { - - for (iElem = 0; iElem < nGlobal_Tria; iElem++) { - iNode = iElem*N_POINTS_TRIANGLE; - Tecplot_File << Conn_Tria[iNode+0] << "\t"; - Tecplot_File << Conn_Tria[iNode+1] << "\t"; - Tecplot_File << Conn_Tria[iNode+2] << "\t"; - Tecplot_File << Conn_Tria[iNode+2] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Quad; iElem++) { - iNode = iElem*N_POINTS_QUADRILATERAL; - Tecplot_File << Conn_Quad[iNode+0] << "\t"; - Tecplot_File << Conn_Quad[iNode+1] << "\t"; - Tecplot_File << Conn_Quad[iNode+2] << "\t"; - Tecplot_File << Conn_Quad[iNode+3] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Tetr; iElem++) { - iNode = iElem*N_POINTS_TETRAHEDRON; - Tecplot_File << Conn_Tetr[iNode+0] << "\t" << Conn_Tetr[iNode+1] << "\t"; - Tecplot_File << Conn_Tetr[iNode+2] << "\t" << Conn_Tetr[iNode+2] << "\t"; - Tecplot_File << Conn_Tetr[iNode+3] << "\t" << Conn_Tetr[iNode+3] << "\t"; - Tecplot_File << Conn_Tetr[iNode+3] << "\t" << Conn_Tetr[iNode+3] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Hexa; iElem++) { - iNode = iElem*N_POINTS_HEXAHEDRON; - Tecplot_File << Conn_Hexa[iNode+0] << "\t" << Conn_Hexa[iNode+1] << "\t"; - Tecplot_File << Conn_Hexa[iNode+2] << "\t" << Conn_Hexa[iNode+3] << "\t"; - Tecplot_File << Conn_Hexa[iNode+4] << "\t" << Conn_Hexa[iNode+5] << "\t"; - Tecplot_File << Conn_Hexa[iNode+6] << "\t" << Conn_Hexa[iNode+7] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Pris; iElem++) { - iNode = iElem*N_POINTS_PRISM; - Tecplot_File << Conn_Pris[iNode+0] << "\t" << Conn_Pris[iNode+1] << "\t"; - Tecplot_File << Conn_Pris[iNode+1] << "\t" << Conn_Pris[iNode+2] << "\t"; - Tecplot_File << Conn_Pris[iNode+3] << "\t" << Conn_Pris[iNode+4] << "\t"; - Tecplot_File << Conn_Pris[iNode+4] << "\t" << Conn_Pris[iNode+5] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Pyra; iElem++) { - iNode = iElem*N_POINTS_PYRAMID; - Tecplot_File << Conn_Pyra[iNode+0] << "\t" << Conn_Pyra[iNode+1] << "\t"; - Tecplot_File << Conn_Pyra[iNode+2] << "\t" << Conn_Pyra[iNode+3] << "\t"; - Tecplot_File << Conn_Pyra[iNode+4] << "\t" << Conn_Pyra[iNode+4] << "\t"; - Tecplot_File << Conn_Pyra[iNode+4] << "\t" << Conn_Pyra[iNode+4] << "\n"; - } - } - - Tecplot_File.close(); - - if (surf_sol) delete [] LocalIndex; - -} - -void COutput::SetTecplotASCII_LowMemory(CConfig *config, CGeometry *geometry, CSolver **solver, char mesh_filename[MAX_STRING_SIZE], bool surf_sol) { - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - int size = SINGLE_NODE; - MPI_Comm_size(MPI_COMM_WORLD, &size); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - unsigned long iElem, iPoint; - unsigned short iVar; - bool grid_movement = config->GetGrid_Movement(); - unsigned short Kind_Solver = config->GetKind_Solver(); - ofstream Tecplot_File; - unsigned long Total_nElem_Bound, *PointSurface = NULL, nPointSurface = 0; - unsigned short iMarker; - - /*--- Open Tecplot ASCII file and write the header. ---*/ - - Tecplot_File.open(mesh_filename, ios::out); - Tecplot_File.precision(6); - if (surf_sol) Tecplot_File << "TITLE = \"Visualization of the surface solution\"" << endl; - else Tecplot_File << "TITLE = \"Visualization of the volumetric solution\"" << endl; - - /*--- Write the list of the fields in the restart file. - Without including the PointID---*/ - if (config->GetKind_SU2() == SU2_SOL) { - - /*--- If SU2_SOL called this routine, we already have a set of output - variables with the appropriate string tags stored in the config class. ---*/ - Tecplot_File << "VARIABLES = "; - nVar_Total = config->fields.size() - 1; - for (unsigned short iField = 1; iField < config->fields.size(); iField++) { - Tecplot_File << config->fields[iField]; - } - - Tecplot_File << endl; - - } else { - - if (geometry->GetnDim() == 2) { Tecplot_File << "VARIABLES = \"x\",\"y\""; } - else { Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\""; } - - /*--- Add names for conservative, limiters, and residual variables ---*/ - - for (iVar = 0; iVar < nVar_Consv; iVar++) { - Tecplot_File << ",\"Conservative_" << iVar+1 << "\""; - } - - if (!config->GetLow_MemoryOutput()) { - - if (config->GetWrt_Limiters()) { - for (iVar = 0; iVar < nVar_Consv; iVar++) { - Tecplot_File << ",\"Limiter_" << iVar+1 << "\""; - } - } - if (config->GetWrt_Residuals()) { - for (iVar = 0; iVar < nVar_Consv; iVar++) { - Tecplot_File << ",\"Residual_" << iVar+1 << "\""; - } - } - - /*--- Add names for any extra variables (this will need to be adjusted). ---*/ - - if (grid_movement) { - if (geometry->GetnDim() == 2) { - Tecplot_File << ",\"Grid_Velx\",\"Grid_Vely\""; - } else { - Tecplot_File << ",\"Grid_Velx\",\"Grid_Vely\",\"Grid_Velz\""; - } - } - - if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - Tecplot_File << ",\"Pressure\",\"Temperature\",\"Pressure_Coefficient\",\"Mach\""; - if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - Tecplot_File << ",\"Laminar_Viscosity\", \"Skin_Friction_Coefficient\", \"Heat_Flux\", \"Y_Plus\""; - if (Kind_Solver == RANS) { Tecplot_File << ", \"Eddy_Viscosity\""; } - } - if (config->GetWrt_SharpEdges()) { Tecplot_File << ", \"Sharp_Edge_Dist\""; } - } - - if ((Kind_Solver == ADJ_EULER) || (Kind_Solver == ADJ_NAVIER_STOKES) || (Kind_Solver == ADJ_RANS) ) { - Tecplot_File << ", \"Surface_Sensitivity\", \"Solution_Sensor\""; - } - - if (( Kind_Solver == DISC_ADJ_EULER ) || - ( Kind_Solver == DISC_ADJ_NAVIER_STOKES ) || - ( Kind_Solver == DISC_ADJ_RANS )) { - Tecplot_File << ", \"Surface_Sensitivity\", \"Sensitivity_x\", \"Sensitivity_y\""; - if (geometry->GetnDim() == 3){ - Tecplot_File << ",\"Sensitivity_z\""; - } - } - - } - - Tecplot_File << endl; - - } - - - if (surf_sol) { - - /*--- It is important to do a renumbering to don't add points - that do not belong to the surfaces ---*/ - - PointSurface = new unsigned long[geometry->GetnPoint()]; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - if (geometry->node[iPoint]->GetBoundary()) { - PointSurface[iPoint] = nPointSurface; - nPointSurface++; - } - - /*--- Compute the total number of elements ---*/ - - Total_nElem_Bound = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_Plotting(iMarker) == YES) { - Total_nElem_Bound += geometry->GetnElem_Bound(iMarker); - } - } - - if (Total_nElem_Bound != 0) { - - /*--- Write the header of the file ---*/ - - Tecplot_File << "ZONE T= \"MPI rank: " << rank << "\", "; - Tecplot_File << "NODES= "<< nPointSurface <<", ELEMENTS= "<< Total_nElem_Bound <<", DATAPACKING= POINT"; - if (geometry->GetnDim() == 2) Tecplot_File << ", ZONETYPE= FELINESEG"<< endl; - if (geometry->GetnDim() == 3) Tecplot_File << ", ZONETYPE= FEQUADRILATERAL"<< endl; - - /*--- Only write the coordiantes of the points that are on the surfaces ---*/ - - if (geometry->GetnDim() == 3) { - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - if (geometry->node[iPoint]->GetBoundary()) { - for (iVar = 0; iVar < solver[FLOW_SOL]->GetnVar(); iVar++) - Tecplot_File << scientific << solver[FLOW_SOL]->node[iPoint]->GetSolution(iVar) << "\t"; - Tecplot_File << "\n"; - } - } - else { - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - if (geometry->node[iPoint]->GetBoundary()) { - for (iVar = 0; iVar < solver[FLOW_SOL]->GetnVar(); iVar++) - Tecplot_File << scientific << solver[FLOW_SOL]->node[iPoint]->GetSolution(iVar) << "\t"; - Tecplot_File << "\n"; - } - } - - /*--- Write the cells using the new numbering ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if (config->GetMarker_All_Plotting(iMarker) == YES) - for (iElem = 0; iElem < geometry->GetnElem_Bound(iMarker); iElem++) { - if (geometry->GetnDim() == 2) { - Tecplot_File << PointSurface[geometry->bound[iMarker][iElem]->GetNode(0)]+1 << " " - << PointSurface[geometry->bound[iMarker][iElem]->GetNode(1)]+1 << endl; - } - if (geometry->GetnDim() == 3) { - if (geometry->bound[iMarker][iElem]->GetnNodes() == 3) { - Tecplot_File << PointSurface[geometry->bound[iMarker][iElem]->GetNode(0)]+1 << " " - << PointSurface[geometry->bound[iMarker][iElem]->GetNode(1)]+1 << " " - << PointSurface[geometry->bound[iMarker][iElem]->GetNode(2)]+1 << " " - << PointSurface[geometry->bound[iMarker][iElem]->GetNode(2)]+1 << endl; - } - if (geometry->bound[iMarker][iElem]->GetnNodes() == 4) { - Tecplot_File << PointSurface[geometry->bound[iMarker][iElem]->GetNode(0)]+1 << " " - << PointSurface[geometry->bound[iMarker][iElem]->GetNode(1)]+1 << " " - << PointSurface[geometry->bound[iMarker][iElem]->GetNode(2)]+1 << " " - << PointSurface[geometry->bound[iMarker][iElem]->GetNode(3)]+1 << endl; - } - } - } - } - else { - - /*--- No elements in the surface ---*/ - - if (geometry->GetnDim() == 2) { - Tecplot_File << "ZONE "; - Tecplot_File << "T= \"MPI rank: " << rank << "\", "; - Tecplot_File << "NODES= 1, ELEMENTS= 1, DATAPACKING=POINT, ZONETYPE=FELINESEG"<< endl; - for (iVar = 0; iVar < solver[FLOW_SOL]->GetnVar(); iVar++) - Tecplot_File << scientific << "0.0\t"; - Tecplot_File << "\n"; - Tecplot_File << "1 1"<< endl; - } - if (geometry->GetnDim() == 3) { - Tecplot_File << "ZONE "; - Tecplot_File << "T= \"MPI rank: " << rank << "\", "; - Tecplot_File << "NODES= 1, ELEMENTS= 1, DATAPACKING=POINT, ZONETYPE=FEQUADRILATERAL"<< endl; - for (iVar = 0; iVar < solver[FLOW_SOL]->GetnVar(); iVar++) - Tecplot_File << scientific << "0.0\t"; - Tecplot_File << "\n"; - Tecplot_File << "1 1 1 1"<< endl; - } - } - - /*--- Dealocate memory and close the file ---*/ - - delete[] PointSurface; - Tecplot_File.close(); - - } - - else { - - Tecplot_File << "ZONE "; - Tecplot_File << "T= \"MPI rank: " << rank << "\", "; - Tecplot_File << "NODES= "<< geometry->GetnPoint() <<", ELEMENTS= "<< geometry->GetnElem() <<", DATAPACKING= POINT"; - if (geometry->GetnDim() == 2) Tecplot_File << ", ZONETYPE= FEQUADRILATERAL"<< endl; - if (geometry->GetnDim() == 3) Tecplot_File << ", ZONETYPE= FEBRICK"<< endl; - - /*--- Adding coordinates ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - for (iVar = 0; iVar < solver[FLOW_SOL]->GetnVar(); iVar++) - Tecplot_File << scientific << solver[FLOW_SOL]->node[iPoint]->GetSolution(iVar) << "\t"; - Tecplot_File << "\n"; - } - - /*--- Adding conectivity ---*/ - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { - Tecplot_File << - geometry->elem[iElem]->GetNode(0)+1 <<" "<< geometry->elem[iElem]->GetNode(1)+1 <<" "<< - geometry->elem[iElem]->GetNode(2)+1 <<" "<< geometry->elem[iElem]->GetNode(2)+1 << endl; - } - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { - Tecplot_File << - geometry->elem[iElem]->GetNode(0)+1 <<" "<< geometry->elem[iElem]->GetNode(1)+1 <<" "<< - geometry->elem[iElem]->GetNode(2)+1 <<" "<< geometry->elem[iElem]->GetNode(3)+1 << endl; - } - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { - Tecplot_File << - geometry->elem[iElem]->GetNode(0)+1 <<" "<< geometry->elem[iElem]->GetNode(1)+1 <<" "<< - geometry->elem[iElem]->GetNode(2)+1 <<" "<< geometry->elem[iElem]->GetNode(2)+1 <<" "<< - geometry->elem[iElem]->GetNode(3)+1 <<" "<< geometry->elem[iElem]->GetNode(3)+1 <<" "<< - geometry->elem[iElem]->GetNode(3)+1 <<" "<< geometry->elem[iElem]->GetNode(3)+1 << endl; - } - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { - Tecplot_File << - geometry->elem[iElem]->GetNode(0)+1 <<" "<< geometry->elem[iElem]->GetNode(1)+1 <<" "<< - geometry->elem[iElem]->GetNode(2)+1 <<" "<< geometry->elem[iElem]->GetNode(3)+1 <<" "<< - geometry->elem[iElem]->GetNode(4)+1 <<" "<< geometry->elem[iElem]->GetNode(5)+1 <<" "<< - geometry->elem[iElem]->GetNode(6)+1 <<" "<< geometry->elem[iElem]->GetNode(7)+1 << endl; - } - if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) { - Tecplot_File << - geometry->elem[iElem]->GetNode(0)+1 <<" "<< geometry->elem[iElem]->GetNode(1)+1 <<" "<< - geometry->elem[iElem]->GetNode(2)+1 <<" "<< geometry->elem[iElem]->GetNode(3)+1 <<" "<< - geometry->elem[iElem]->GetNode(4)+1 <<" "<< geometry->elem[iElem]->GetNode(4)+1 <<" "<< - geometry->elem[iElem]->GetNode(4)+1 <<" "<< geometry->elem[iElem]->GetNode(4)+1 << endl; - } - if (geometry->elem[iElem]->GetVTK_Type() == PRISM) { - Tecplot_File << - geometry->elem[iElem]->GetNode(0)+1 <<" "<< geometry->elem[iElem]->GetNode(1)+1 <<" "<< - geometry->elem[iElem]->GetNode(1)+1 <<" "<< geometry->elem[iElem]->GetNode(2)+1 <<" "<< - geometry->elem[iElem]->GetNode(3)+1 <<" "<< geometry->elem[iElem]->GetNode(4)+1 <<" "<< - geometry->elem[iElem]->GetNode(4)+1 <<" "<< geometry->elem[iElem]->GetNode(5)+1 << endl; - } - } - - Tecplot_File.close(); - - } - - -#ifdef HAVE_MPI - - /*--- Add solution files to a single file ---*/ - - if (rank == MASTER_NODE) { - - ofstream Tecplot_File; - string filename, text_line; - char buffer_char[50], out_file[MAX_STRING_SIZE]; - - if (!config->GetAdjoint()) { - if (surf_sol) filename = config->GetSurfFlowCoeff_FileName(); - else filename = config->GetFlow_FileName(); - } - else { - if (surf_sol) filename = config->GetSurfAdjCoeff_FileName(); - else filename = config->GetAdj_FileName(); - } - - strcpy(mesh_filename, filename.c_str()); - SPRINTF (buffer_char, ".dat"); - strcat(mesh_filename, buffer_char); - - Tecplot_File.open(mesh_filename, ios::out); - - for (int iRank = 0; iRank < size; iRank++) { - - if (!config->GetAdjoint()) { - if (surf_sol) filename = config->GetSurfFlowCoeff_FileName(); - else filename = config->GetFlow_FileName(); - } - else { - if (surf_sol) filename = config->GetSurfAdjCoeff_FileName(); - else filename = config->GetAdj_FileName(); - } - - strcpy(out_file, filename.c_str()); - SPRINTF (buffer_char, "_%i.dat", iRank+1); - strcat(out_file, buffer_char); - ifstream Tecplot_File_; - Tecplot_File_.open(out_file, ios::in); - while (getline (Tecplot_File_, text_line)) { - Tecplot_File << text_line << endl; - } - Tecplot_File_.close(); - remove (out_file); - } - - Tecplot_File.close(); - - } - -#endif - -} - -void COutput::SetTecplotASCII_Mesh(CConfig *config, CGeometry *geometry, bool surf_sol, bool new_file) { - - unsigned short iDim, nDim = geometry->GetnDim(); - unsigned long iPoint, iElem, iNode; - unsigned long *LocalIndex = NULL; - bool *SurfacePoint = NULL; - char cstr[200]; - ofstream Tecplot_File; - - if (surf_sol) strcpy(cstr, "surface_grid.dat"); - else strcpy(cstr, "volumetric_grid.dat"); - - /*--- Open Tecplot ASCII file and write the header. ---*/ - - if (new_file) { - Tecplot_File.open(cstr, ios::out); - Tecplot_File.precision(6); - if (surf_sol) Tecplot_File << "TITLE = \"Visualization of the surface solution\"" << endl; - else Tecplot_File << "TITLE = \"Visualization of the volumetric solution\"" << endl; - - if (nDim == 2) Tecplot_File << "VARIABLES = \"x\",\"y\""; - else Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\""; - } - else Tecplot_File.open(cstr, ios::out | ios::app); - Tecplot_File << endl; - - /*--- If it's a surface output, print only the points - that are in the element list, change the numbering ---*/ - - if (surf_sol) { - - LocalIndex = new unsigned long [nGlobal_Poin+1]; - SurfacePoint = new bool [nGlobal_Poin+1]; - - for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) SurfacePoint[iPoint] = false; - - for (iElem = 0; iElem < nGlobal_Line; iElem++) { - iNode = iElem*N_POINTS_LINE; - SurfacePoint[Conn_Line[iNode+0]] = true; - SurfacePoint[Conn_Line[iNode+1]] = true; - } - for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { - iNode = iElem*N_POINTS_TRIANGLE; - SurfacePoint[Conn_BoundTria[iNode+0]] = true; - SurfacePoint[Conn_BoundTria[iNode+1]] = true; - SurfacePoint[Conn_BoundTria[iNode+2]] = true; - } - for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { - iNode = iElem*N_POINTS_QUADRILATERAL; - SurfacePoint[Conn_BoundQuad[iNode+0]] = true; - SurfacePoint[Conn_BoundQuad[iNode+1]] = true; - SurfacePoint[Conn_BoundQuad[iNode+2]] = true; - SurfacePoint[Conn_BoundQuad[iNode+3]] = true; - } - - nSurf_Poin = 0; - for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) { - LocalIndex[iPoint] = 0; - if (SurfacePoint[iPoint]) { nSurf_Poin++; LocalIndex[iPoint] = nSurf_Poin; } - } - - } - - /*--- Write the header ---*/ - - Tecplot_File << "ZONE T= "; - if (new_file) Tecplot_File << "\"Original grid\", C=BLACK, "; - else Tecplot_File << "\"Deformed grid\", C=RED, "; - - if (nDim == 2) { - if (surf_sol) Tecplot_File << "NODES= "<< nSurf_Poin <<", ELEMENTS= "<< nSurf_Elem <<", DATAPACKING=POINT, ZONETYPE=FELINESEG"<< endl; - else Tecplot_File << "NODES= "<< nGlobal_Poin <<", ELEMENTS= "<< nGlobal_Elem <<", DATAPACKING=POINT, ZONETYPE=FEQUADRILATERAL"<< endl; - } else { - if (surf_sol) Tecplot_File << "NODES= "<< nSurf_Poin<<", ELEMENTS= "<< nSurf_Elem <<", DATAPACKING=POINT, ZONETYPE=FEQUADRILATERAL"<< endl; - else Tecplot_File << "NODES= "<< nGlobal_Poin <<", ELEMENTS= "<< nGlobal_Elem <<", DATAPACKING=POINT, ZONETYPE=FEBRICK"<< endl; - } - - /*--- Write surface and volumetric solution data. ---*/ - - for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { - - if (surf_sol) { - - if (LocalIndex[iPoint+1] != 0) { - - /*--- Write the node coordinates ---*/ - for (iDim = 0; iDim < nDim; iDim++) - Tecplot_File << scientific << Coords[iDim][iPoint] << "\t"; - - Tecplot_File << endl; - - } - - } else { - - /*--- Write the node coordinates ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - Tecplot_File << scientific << Coords[iDim][iPoint] << "\t"; - - - Tecplot_File << endl; - - } - - } - - - /*--- Write connectivity data. ---*/ - - if (surf_sol) { - - for (iElem = 0; iElem < nGlobal_Line; iElem++) { - iNode = iElem*N_POINTS_LINE; - Tecplot_File << LocalIndex[Conn_Line[iNode+0]] << "\t"; - Tecplot_File << LocalIndex[Conn_Line[iNode+1]] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { - iNode = iElem*N_POINTS_TRIANGLE; - Tecplot_File << LocalIndex[Conn_BoundTria[iNode+0]] << "\t"; - Tecplot_File << LocalIndex[Conn_BoundTria[iNode+1]] << "\t"; - Tecplot_File << LocalIndex[Conn_BoundTria[iNode+2]] << "\t"; - Tecplot_File << LocalIndex[Conn_BoundTria[iNode+2]] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { - iNode = iElem*N_POINTS_QUADRILATERAL; - Tecplot_File << LocalIndex[Conn_BoundQuad[iNode+0]] << "\t"; - Tecplot_File << LocalIndex[Conn_BoundQuad[iNode+1]] << "\t"; - Tecplot_File << LocalIndex[Conn_BoundQuad[iNode+2]] << "\t"; - Tecplot_File << LocalIndex[Conn_BoundQuad[iNode+3]] << "\n"; - } - - } else { - - for (iElem = 0; iElem < nGlobal_Tria; iElem++) { - iNode = iElem*N_POINTS_TRIANGLE; - Tecplot_File << Conn_Tria[iNode+0] << "\t"; - Tecplot_File << Conn_Tria[iNode+1] << "\t"; - Tecplot_File << Conn_Tria[iNode+2] << "\t"; - Tecplot_File << Conn_Tria[iNode+2] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Quad; iElem++) { - iNode = iElem*N_POINTS_QUADRILATERAL; - Tecplot_File << Conn_Quad[iNode+0] << "\t"; - Tecplot_File << Conn_Quad[iNode+1] << "\t"; - Tecplot_File << Conn_Quad[iNode+2] << "\t"; - Tecplot_File << Conn_Quad[iNode+3] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Tetr; iElem++) { - iNode = iElem*N_POINTS_TETRAHEDRON; - Tecplot_File << Conn_Tetr[iNode+0] << "\t" << Conn_Tetr[iNode+1] << "\t"; - Tecplot_File << Conn_Tetr[iNode+2] << "\t" << Conn_Tetr[iNode+2] << "\t"; - Tecplot_File << Conn_Tetr[iNode+3] << "\t" << Conn_Tetr[iNode+3] << "\t"; - Tecplot_File << Conn_Tetr[iNode+3] << "\t" << Conn_Tetr[iNode+3] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Hexa; iElem++) { - iNode = iElem*N_POINTS_HEXAHEDRON; - Tecplot_File << Conn_Hexa[iNode+0] << "\t" << Conn_Hexa[iNode+1] << "\t"; - Tecplot_File << Conn_Hexa[iNode+2] << "\t" << Conn_Hexa[iNode+3] << "\t"; - Tecplot_File << Conn_Hexa[iNode+4] << "\t" << Conn_Hexa[iNode+5] << "\t"; - Tecplot_File << Conn_Hexa[iNode+6] << "\t" << Conn_Hexa[iNode+7] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Pris; iElem++) { - iNode = iElem*N_POINTS_PRISM; - Tecplot_File << Conn_Pris[iNode+0] << "\t" << Conn_Pris[iNode+1] << "\t"; - Tecplot_File << Conn_Pris[iNode+1] << "\t" << Conn_Pris[iNode+2] << "\t"; - Tecplot_File << Conn_Pris[iNode+3] << "\t" << Conn_Pris[iNode+4] << "\t"; - Tecplot_File << Conn_Pris[iNode+4] << "\t" << Conn_Pris[iNode+5] << "\n"; - } - - for (iElem = 0; iElem < nGlobal_Pyra; iElem++) { - iNode = iElem*N_POINTS_PYRAMID; - Tecplot_File << Conn_Pyra[iNode+0] << "\t" << Conn_Pyra[iNode+1] << "\t"; - Tecplot_File << Conn_Pyra[iNode+2] << "\t" << Conn_Pyra[iNode+3] << "\t"; - Tecplot_File << Conn_Pyra[iNode+4] << "\t" << Conn_Pyra[iNode+4] << "\t"; - Tecplot_File << Conn_Pyra[iNode+4] << "\t" << Conn_Pyra[iNode+4] << "\n"; - } - } - - Tecplot_File.close(); - - if (surf_sol) delete [] LocalIndex; - -} - -void COutput::SetTecplotBinary_DomainMesh(CConfig *config, CGeometry *geometry, unsigned short val_iZone) { - -#ifdef HAVE_TECIO - - passivedouble t; - INTEGER4 i, err, Debug, NPts, NElm, IsDouble, KMax; - INTEGER4 ICellMax, JCellMax, KCellMax, ZoneType, StrandID, ParentZn, FileType; - INTEGER4 *ShareFromZone = NULL, IsBlock, NumFaceConnections, FaceNeighborMode, ShareConnectivityFromZone; - string buffer, variables; - stringstream file; - bool first_zone = true; - unsigned short dims = geometry->GetnDim(); - enum FileType { FULL = 0, GRID = 1, SOLUTION = 2 }; - enum ZoneType { ORDERED=0, FELINESEG=1, FETRIANGLE=2, FEQUADRILATERAL=3, FETETRAHEDRON=4, FEBRICK=5, FEPOLYGON=6, FEPOLYHEDRON=7 }; - - /*--- Consistent data for Tecplot zones ---*/ - - Debug = 0; - IsDouble = 1; - NPts = (INTEGER4)nGlobal_Poin; - t = 0.0;//iExtIter*config->GetDelta_UnstTimeND(); - KMax = 0; - ICellMax = 0; - JCellMax = 0; - KCellMax = 0; - StrandID = 0;//(INTEGER4)iExtIter; - ParentZn = 0; - IsBlock = 1; - NumFaceConnections = 0; - FaceNeighborMode = 0; - ShareConnectivityFromZone = 0; - - /*--- Write Tecplot solution file ---*/ - - if (!wrote_base_file) { - - file.str(string()); - buffer = config->GetFlow_FileName(); - - file << buffer << ".mesh.plt"; - FileType = GRID; - - if (dims == 2) variables = "x y"; - else if (dims == 3) variables = "x y z"; - else cout << "Error: wrong number of dimensions: " << dims << endl; - - /*--- Open Tecplot file ---*/ - - err = TECINI112((char *)config->GetFlow_FileName().c_str(), - (char *)variables.c_str(), - (char *)file.str().c_str(), - (char *)".", - &FileType, - &Debug, - &IsDouble); - if (err) cout << "Error in opening Tecplot file" << endl; - - first_zone = true; -// ShareFromZone = new INTEGER4[dims]; -// for (i = 0; i < dims; i++) ShareFromZone[i] = 0; - - if (nGlobal_Tria > 0) { - - /*--- Write the zone header information ---*/ - ZoneType = FETRIANGLE; NElm = (INTEGER4)nGlobal_Tria; - - err = TECZNE112((char*)"Triangle Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - ShareFromZone, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - - if (first_zone) { - - ShareFromZone = new INTEGER4[dims]; - for (i = 0; i < dims; i++) ShareFromZone[i] = 0; - - if (config->GetKind_SU2() == SU2_SOL) { - err = TECDAT112(&NPts, Data[0], &IsDouble); ShareFromZone[0] = 1; - err = TECDAT112(&NPts, Data[1], &IsDouble); ShareFromZone[1] = 1; - if (geometry->GetnDim() == 3) { - err = TECDAT112(&NPts, Data[2], &IsDouble); - ShareFromZone[2] = 1; - } - } else { - err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[0] = 1; - err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[1] = 1; - if (geometry->GetnDim() == 3) { - err = TECDAT112(&NPts, Coords[2], &IsDouble); - ShareFromZone[2] = 1; - } - } - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - first_zone = false; - } - - err = TECNOD112(Conn_Tria); - if (err) cout << "Error writing connectivity to Tecplot file" << endl; - - } - if (nGlobal_Quad > 0) { - - /*--- Write the zone header information ---*/ - - ZoneType = FEQUADRILATERAL; NElm = (INTEGER4)nGlobal_Quad; - - err = TECZNE112((char*)"Quadrilateral Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - ShareFromZone, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - - if (first_zone) { - - ShareFromZone = new INTEGER4[dims]; - for (i = 0; i < dims; i++) ShareFromZone[i] = 0; - - if (config->GetKind_SU2() == SU2_SOL) { - err = TECDAT112(&NPts, Data[0], &IsDouble); ShareFromZone[0] = 1; - err = TECDAT112(&NPts, Data[1], &IsDouble); ShareFromZone[1] = 1; - if (geometry->GetnDim() == 3) { - err = TECDAT112(&NPts, Data[2], &IsDouble); - ShareFromZone[2] = 1; - } - } else { - err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[0] = 1; - err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[1] = 1; - if (geometry->GetnDim() == 3) { - err = TECDAT112(&NPts, Coords[2], &IsDouble); - ShareFromZone[2] = 1; - } - } - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - first_zone = false; - } - - err = TECNOD112(Conn_Quad); - if (err) cout << "Error writing connectivity to Tecplot file" << endl; - - } - if (nGlobal_Tetr > 0) { - - /*--- Write the zone header information ---*/ - - ZoneType = FETETRAHEDRON; NElm = (INTEGER4)nGlobal_Tetr; - - err = TECZNE112((char*)"Tetrahedral Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - ShareFromZone, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - - if (first_zone) { - - ShareFromZone = new INTEGER4[dims]; - for (i = 0; i < dims; i++) ShareFromZone[i] = 0; - - if (config->GetKind_SU2() == SU2_SOL) { - err = TECDAT112(&NPts, Data[0], &IsDouble); ShareFromZone[0] = 1; - err = TECDAT112(&NPts, Data[1], &IsDouble); ShareFromZone[1] = 1; - if (geometry->GetnDim() == 3) { - err = TECDAT112(&NPts, Data[2], &IsDouble); - ShareFromZone[2] = 1; - } - } else { - err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[0] = 1; - err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[1] = 1; - if (geometry->GetnDim() == 3) { - err = TECDAT112(&NPts, Coords[2], &IsDouble); - ShareFromZone[2] = 1; - } - } - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - first_zone = false; - } - - err = TECNOD112(Conn_Tetr); - if (err) cout << "Error writing connectivity to Tecplot file" << endl; - - } - if (nGlobal_Hexa > 0) { - - /*--- Write the zone header information ---*/ - - ZoneType = FEBRICK; NElm = (INTEGER4)nGlobal_Hexa; - - err = TECZNE112((char*)"Hexahedral Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - ShareFromZone, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - - if (first_zone) { - - ShareFromZone = new INTEGER4[dims]; - for (i = 0; i < dims; i++) ShareFromZone[i] = 0; - - if (config->GetKind_SU2() == SU2_SOL) { - err = TECDAT112(&NPts, Data[0], &IsDouble); ShareFromZone[0] = 1; - err = TECDAT112(&NPts, Data[1], &IsDouble); ShareFromZone[1] = 1; - if (geometry->GetnDim() == 3) { - err = TECDAT112(&NPts, Data[2], &IsDouble); - ShareFromZone[2] = 1; - } - } else { - err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[0] = 1; - err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[1] = 1; - if (geometry->GetnDim() == 3) { - err = TECDAT112(&NPts, Coords[2], &IsDouble); - ShareFromZone[2] = 1; - } - } - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - first_zone = false; - } - - err = TECNOD112(Conn_Hexa); - if (err) cout << "Error writing connectivity to Tecplot file" << endl; - - } - - if (nGlobal_Pyra > 0) { - - /*--- Here, we reuse the hex implementation to write pyramid elements. - Write the zone header information. ---*/ - ZoneType = FEBRICK; NElm = (INTEGER4)nGlobal_Pyra; - - err = TECZNE112((char*)"Pyramid Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - ShareFromZone, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - - if (first_zone) { - - ShareFromZone = new INTEGER4[dims]; - for (i = 0; i < dims; i++) ShareFromZone[i] = 0; - - if (config->GetKind_SU2() == SU2_SOL) { - err = TECDAT112(&NPts, Data[0], &IsDouble); ShareFromZone[0] = 1; - err = TECDAT112(&NPts, Data[1], &IsDouble); ShareFromZone[1] = 1; - if (geometry->GetnDim() == 3) { - err = TECDAT112(&NPts, Data[2], &IsDouble); - ShareFromZone[2] = 1; - } - } else { - err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[0] = 1; - err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[1] = 1; - if (geometry->GetnDim() == 3) { - err = TECDAT112(&NPts, Coords[2], &IsDouble); - ShareFromZone[2] = 1; - } - } - if (err) cout << "Error writing grid coordinates to Tecplot file" << endl; - first_zone = false; - } - - /*--- Convert the pyramid connectivity from 5 nodes to 8 nodes for FEBRICK ---*/ - int *Conn_Pyra_Mod = new int[nGlobal_Pyra*N_POINTS_HEXAHEDRON]; - unsigned long iNode_Pyra, iNode_Hexa; - for (unsigned long iElem = 0; iElem < nGlobal_Pyra; iElem++) { - iNode_Pyra = iElem*N_POINTS_PYRAMID; - iNode_Hexa = iElem*N_POINTS_HEXAHEDRON; - Conn_Pyra_Mod[iNode_Hexa+0] = Conn_Pyra[iNode_Pyra+4]; - Conn_Pyra_Mod[iNode_Hexa+1] = Conn_Pyra[iNode_Pyra+4]; - Conn_Pyra_Mod[iNode_Hexa+2] = Conn_Pyra[iNode_Pyra+4]; - Conn_Pyra_Mod[iNode_Hexa+3] = Conn_Pyra[iNode_Pyra+4]; - Conn_Pyra_Mod[iNode_Hexa+4] = Conn_Pyra[iNode_Pyra+0]; - Conn_Pyra_Mod[iNode_Hexa+5] = Conn_Pyra[iNode_Pyra+1]; - Conn_Pyra_Mod[iNode_Hexa+6] = Conn_Pyra[iNode_Pyra+2]; - Conn_Pyra_Mod[iNode_Hexa+7] = Conn_Pyra[iNode_Pyra+3]; - } - err = TECNOD112(Conn_Pyra_Mod); - if (err) cout << "Error writing pyramid connectivity to Tecplot file" << endl; - delete [] Conn_Pyra_Mod; - - } - - if (nGlobal_Pris > 0) { - - /*--- Here, we reuse the hex implementation to write prism elements. - Write the zone header information ---*/ - ZoneType = FEBRICK; NElm = (INTEGER4)nGlobal_Pris; - - err = TECZNE112((char*)"Prism Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - ShareFromZone, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - - if (first_zone) { - - ShareFromZone = new INTEGER4[dims]; - for (i = 0; i < dims; i++) ShareFromZone[i] = 0; - - if (config->GetKind_SU2() == SU2_SOL) { - err = TECDAT112(&NPts, Data[0], &IsDouble); ShareFromZone[0] = 1; - err = TECDAT112(&NPts, Data[1], &IsDouble); ShareFromZone[1] = 1; - if (geometry->GetnDim() == 3) { - err = TECDAT112(&NPts, Data[2], &IsDouble); - ShareFromZone[2] = 1; - } - } else { - err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[0] = 1; - err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[1] = 1; - if (geometry->GetnDim() == 3) { - err = TECDAT112(&NPts, Coords[2], &IsDouble); - ShareFromZone[2] = 1; - } - } - if (err) cout << "Error writing grid coordinates to Tecplot file" << endl; - first_zone = false; - } - - /*--- Convert the prism connectivity from 6 nodes to 8 nodes for FEBRICK ---*/ - int *Conn_Pris_Mod = new int[nGlobal_Pris*N_POINTS_HEXAHEDRON]; - unsigned long iNode_Pris, iNode_Hexa; - for (unsigned long iElem = 0; iElem < nGlobal_Pris; iElem++) { - iNode_Pris = iElem*N_POINTS_PRISM; - iNode_Hexa = iElem*N_POINTS_HEXAHEDRON; - Conn_Pris_Mod[iNode_Hexa+0] = Conn_Pris[iNode_Pris+0]; - Conn_Pris_Mod[iNode_Hexa+1] = Conn_Pris[iNode_Pris+0]; - Conn_Pris_Mod[iNode_Hexa+2] = Conn_Pris[iNode_Pris+1]; - Conn_Pris_Mod[iNode_Hexa+3] = Conn_Pris[iNode_Pris+2]; - Conn_Pris_Mod[iNode_Hexa+4] = Conn_Pris[iNode_Pris+3]; - Conn_Pris_Mod[iNode_Hexa+5] = Conn_Pris[iNode_Pris+3]; - Conn_Pris_Mod[iNode_Hexa+6] = Conn_Pris[iNode_Pris+4]; - Conn_Pris_Mod[iNode_Hexa+7] = Conn_Pris[iNode_Pris+5]; - } - err = TECNOD112(Conn_Pris_Mod); - if (err) cout << "Error writing prism connectivity to Tecplot file" << endl; - delete [] Conn_Pris_Mod; - - } - - delete [] ShareFromZone; - wrote_base_file = true; - - err = TECEND112(); - if (err) cout << "Error in closing Tecplot file" << endl; - - } - -#endif - -} - -void COutput::SetTecplotBinary_DomainSolution(CConfig *config, CGeometry *geometry, unsigned short val_iZone) { - -#ifdef HAVE_TECIO - - passivedouble t; - INTEGER4 i, iVar, err, Debug, NPts, NElm, IsDouble, KMax; - INTEGER4 ICellMax, JCellMax, KCellMax, ZoneType, StrandID, ParentZn, FileType; - INTEGER4 *ShareFromZone = NULL, IsBlock, NumFaceConnections, FaceNeighborMode, ShareConnectivityFromZone; - string buffer, variables; - stringstream file; - bool first_zone = true, unsteady = config->GetUnsteady_Simulation(), GridMovement = config->GetGrid_Movement(); - bool Wrt_Unsteady = config->GetWrt_Unsteady(); - unsigned long iExtIter = config->GetExtIter(); - unsigned short NVar, dims = geometry->GetnDim(); - enum FileType { FULL = 0, GRID = 1, SOLUTION = 2 }; - enum ZoneType { ORDERED=0, FELINESEG=1, FETRIANGLE=2, FEQUADRILATERAL=3, FETETRAHEDRON=4, FEBRICK=5, FEPOLYGON=6, FEPOLYHEDRON=7 }; - - /*--- Consistent data for Tecplot zones ---*/ - Debug = 0; - IsDouble = 1; - NPts = (INTEGER4)nGlobal_Poin; - t = SU2_TYPE::GetValue(iExtIter*config->GetDelta_UnstTime()); - KMax = 0; - ICellMax = 0; - JCellMax = 0; - KCellMax = 0; - StrandID = (INTEGER4)iExtIter+1; - ParentZn = 0; - IsBlock = 1; - NumFaceConnections = 0; - FaceNeighborMode = 0; - ShareConnectivityFromZone = 0; - - file.str(string()); - buffer = config->GetFlow_FileName(); - - file << buffer; - - if (unsteady) { - if (((int)iExtIter >= 0) && ((int)iExtIter < 10)) file << "_0000" << iExtIter; - if (((int)iExtIter >= 10) && ((int)iExtIter < 100)) file << "_000" << iExtIter; - if (((int)iExtIter >= 100) && ((int)iExtIter < 1000)) file << "_00" << iExtIter; - if (((int)iExtIter >= 1000) && ((int)iExtIter < 10000)) file << "_0" << iExtIter; - if ((int)iExtIter >= 10000) file << iExtIter; - } - file << ".sol.plt"; - FileType = SOLUTION; - variables = AssembleVariableNames(geometry, config, nVar_Consv, &NVar); - if (config->GetKind_SU2() == SU2_SOL) { - if (Wrt_Unsteady && GridMovement) nVar_Total = NVar; - else nVar_Total = NVar+dims; - } - - /*--- Open Tecplot file ---*/ - err = TECINI112((char *)config->GetFlow_FileName().c_str(), - (char *)variables.c_str(), - (char *)file.str().c_str(), - (char *)".", - &FileType, - &Debug, - &IsDouble); - if (err) cout << "Error in opening Tecplot file" << endl; - -// first_zone = true; -// ShareFromZone = new INTEGER4[NVar]; -// for (i = 0; i < NVar; i++) ShareFromZone[i] = 0; - - if (nGlobal_Tria > 0) { - - /*--- Write the zone header information ---*/ - ZoneType = FETRIANGLE; NElm = (INTEGER4)nGlobal_Tria; - - err = TECZNE112((char*)"Triangle Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - ShareFromZone, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - if (first_zone) { - - ShareFromZone = new INTEGER4[NVar]; - for (i = 0; i < NVar; i++) ShareFromZone[i] = 0; - - i = 0; - if (config->GetKind_SU2() == SU2_SOL) { - if (Wrt_Unsteady && GridMovement) { - for (iVar = 0; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } else { - for (iVar = dims; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - } else { - - if (Wrt_Unsteady && GridMovement) { - - err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - if (dims == 3) { - err = TECDAT112(&NPts, Coords[2], &IsDouble); - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - ShareFromZone[i++] = 1; - } - } - - for (iVar = 0; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - first_zone = false; - } - - } - if (nGlobal_Quad > 0) { - - /*--- Write the zone header information ---*/ - ZoneType = FEQUADRILATERAL; NElm = (INTEGER4)nGlobal_Quad; - - err = TECZNE112((char*)"Quadrilateral Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - ShareFromZone, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - if (first_zone) { - - ShareFromZone = new INTEGER4[NVar]; - for (i = 0; i < NVar; i++) ShareFromZone[i] = 0; - - i = 0; - if (config->GetKind_SU2() == SU2_SOL) { - if (Wrt_Unsteady && GridMovement) { - for (iVar = 0; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } else { - for (iVar = dims; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - } else { - if (Wrt_Unsteady && GridMovement) { - err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - if (dims == 3) { - err = TECDAT112(&NPts, Coords[2], &IsDouble); - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - ShareFromZone[i++] = 1; - } - } - for (iVar = 0; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - - first_zone = false; - } - - } - if (nGlobal_Tetr > 0) { - - /*--- Write the zone header information ---*/ - ZoneType = FETETRAHEDRON; NElm = (INTEGER4)nGlobal_Tetr; - - err = TECZNE112((char*)"Tetrahedral Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - ShareFromZone, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - if (first_zone) { - - ShareFromZone = new INTEGER4[NVar]; - for (i = 0; i < NVar; i++) ShareFromZone[i] = 0; - - i = 0; - if (config->GetKind_SU2() == SU2_SOL) { - if (Wrt_Unsteady && GridMovement) { - for (iVar = 0; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } else { - for (iVar = dims; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - } else { - if (Wrt_Unsteady && GridMovement) { - err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - if (dims == 3) { - err = TECDAT112(&NPts, Coords[2], &IsDouble); - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - ShareFromZone[i++] = 1; - } - } - for (iVar = 0; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - - first_zone = false; - } - - } - if (nGlobal_Hexa > 0) { - - /*--- Write the zone header information ---*/ - ZoneType = FEBRICK; NElm = (INTEGER4)nGlobal_Hexa; - - err = TECZNE112((char*)"Hexahedral Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - ShareFromZone, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - if (first_zone) { - - ShareFromZone = new INTEGER4[NVar]; - for (i = 0; i < NVar; i++) ShareFromZone[i] = 0; - - i = 0; - if (config->GetKind_SU2() == SU2_SOL) { - if (Wrt_Unsteady && GridMovement) { - for (iVar = 0; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } else { - for (iVar = dims; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - } else { - if (Wrt_Unsteady && GridMovement) { - err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - if (dims == 3) { - err = TECDAT112(&NPts, Coords[2], &IsDouble); - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - ShareFromZone[i++] = 1; - } - } - for (iVar = 0; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - - first_zone = false; - } - - } - if (nGlobal_Pyra > 0) { - - /*--- Write the zone header information ---*/ - ZoneType = FEBRICK; NElm = (INTEGER4)nGlobal_Pyra; - - err = TECZNE112((char*)"Pyramid Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - ShareFromZone, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - if (first_zone) { - - ShareFromZone = new INTEGER4[NVar]; - for (i = 0; i < NVar; i++) ShareFromZone[i] = 0; - - i = 0; - if (config->GetKind_SU2() == SU2_SOL) { - if (Wrt_Unsteady && GridMovement) { - for (iVar = 0; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } else { - for (iVar = dims; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - } else { - if (Wrt_Unsteady && GridMovement) { - err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - if (dims == 3) { - err = TECDAT112(&NPts, Coords[2], &IsDouble); - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - ShareFromZone[i++] = 1; - } - } - for (iVar = 0; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - - first_zone = false; - } - - } - if (nGlobal_Pris > 0) { - - /*--- Write the zone header information ---*/ - ZoneType = FEBRICK; NElm = (INTEGER4)nGlobal_Pris; - - err = TECZNE112((char*)"Prism Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - ShareFromZone, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - if (first_zone) { - - ShareFromZone = new INTEGER4[NVar]; - for (i = 0; i < NVar; i++) ShareFromZone[i] = 0; - - i = 0; - if (config->GetKind_SU2() == SU2_SOL) { - if (Wrt_Unsteady && GridMovement) { - for (iVar = 0; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } else { - for (iVar = dims; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - } else { - if (Wrt_Unsteady && GridMovement) { - err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - if (dims == 3) { - err = TECDAT112(&NPts, Coords[2], &IsDouble); - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - ShareFromZone[i++] = 1; - } - } - for (iVar = 0; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - - first_zone = false; - } - } - - delete [] ShareFromZone; - - err = TECEND112(); - if (err) cout << "Error in closing Tecplot file" << endl; - -#endif - -} - -void COutput::SetTecplotBinary_SurfaceMesh(CConfig *config, CGeometry *geometry, unsigned short val_iZone) { - -#ifdef HAVE_TECIO - - passivedouble t; - INTEGER4 i, err, Debug, NPts, NElm, IsDouble, KMax; - INTEGER4 ICellMax, JCellMax, KCellMax, ZoneType, StrandID, ParentZn, FileType; - INTEGER4 *ShareFromZone, IsBlock, NumFaceConnections, FaceNeighborMode, ShareConnectivityFromZone; - string buffer, variables; - stringstream file; - bool first_zone = true; - unsigned short iDim, dims = geometry->GetnDim(); - unsigned long iPoint, iElem, iNode; - enum FileType { FULL = 0, GRID = 1, SOLUTION = 2 }; - enum ZoneType { ORDERED=0, FELINESEG=1, FETRIANGLE=2, FEQUADRILATERAL=3, FETETRAHEDRON=4, FEBRICK=5, FEPOLYGON=6, FEPOLYHEDRON=7 }; - - /*--- Write Tecplot solution file ---*/ - if (!wrote_surf_file) { - - file.str(string()); - buffer = config->GetSurfFlowCoeff_FileName(); - - file << buffer << ".mesh.plt"; - FileType = GRID; - - if (dims == 2) variables = "x y"; - else if (dims == 3) variables = "x y z"; - else cout << "Error: wrong number of dimensions: " << dims << endl; - - first_zone = true; - ShareFromZone = new INTEGER4[dims]; - for (i = 0; i < dims; i++) ShareFromZone[i] = 0; - - /*--- Perform a renumbering for the surface points/elements ---*/ - unsigned long *LocalIndex = new unsigned long [nGlobal_Poin+1]; - bool *SurfacePoint = new bool [nGlobal_Poin+1]; - - for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) SurfacePoint[iPoint] = false; - - for (iElem = 0; iElem < nGlobal_Line; iElem++) { - iNode = iElem*N_POINTS_LINE; - SurfacePoint[Conn_Line[iNode+0]] = true; - SurfacePoint[Conn_Line[iNode+1]] = true; - } - for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { - iNode = iElem*N_POINTS_TRIANGLE; - SurfacePoint[Conn_BoundTria[iNode+0]] = true; - SurfacePoint[Conn_BoundTria[iNode+1]] = true; - SurfacePoint[Conn_BoundTria[iNode+2]] = true; - } - for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { - iNode = iElem*N_POINTS_QUADRILATERAL; - SurfacePoint[Conn_BoundQuad[iNode+0]] = true; - SurfacePoint[Conn_BoundQuad[iNode+1]] = true; - SurfacePoint[Conn_BoundQuad[iNode+2]] = true; - SurfacePoint[Conn_BoundQuad[iNode+3]] = true; - } - - unsigned long nSurf_Poin = 0; - for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) { - LocalIndex[iPoint] = 0; - if (SurfacePoint[iPoint]) { nSurf_Poin++; LocalIndex[iPoint] = nSurf_Poin; } - } - - /*--- Collect surface coordinates into one array as well ---*/ - /*--- Note the -1 in the Coords/Data array in order to undo the 1-based indexing ---*/ - su2double **Surf_Coords = new su2double*[dims]; - for (iDim = 0; iDim < dims; iDim++) - Surf_Coords[iDim] = new su2double[nSurf_Poin]; - - unsigned long iSurf_Poin = 0; - for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) { - if (SurfacePoint[iPoint]) { - for (iDim = 0; iDim < dims; iDim++) { - if (config->GetKind_SU2() == SU2_SOL) - Surf_Coords[iDim][iSurf_Poin] = Data[iDim][iPoint-1]; - else - Surf_Coords[iDim][iSurf_Poin] = Coords[iDim][iPoint-1]; - } - iSurf_Poin++; - } - } - - /*--- Consistent data for Tecplot zones ---*/ - Debug = 0; - IsDouble = 1; - NPts = (INTEGER4)nSurf_Poin; - t = 0.0;//iExtIter*config->GetDelta_UnstTimeND(); - KMax = 0; - ICellMax = 0; - JCellMax = 0; - KCellMax = 0; - StrandID = 0;//(INTEGER4)iExtIter; - ParentZn = 0; - IsBlock = 1; - NumFaceConnections = 0; - FaceNeighborMode = 0; - ShareConnectivityFromZone = 0; - - /*--- Open Tecplot file ---*/ - err = TECINI112((char *)config->GetSurfFlowCoeff_FileName().c_str(), - (char *)variables.c_str(), - (char *)file.str().c_str(), - (char *)".", - &FileType, - &Debug, - &IsDouble); - if (err) cout << "Error in opening Tecplot file" << endl; - - - if (nGlobal_Line > 0) { - - /*--- Put the connectivity into a single array for writing ---*/ - int *Conn_Line_New = new int[nGlobal_Line*N_POINTS_LINE]; - iNode = 0; - for (iElem = 0; iElem < nGlobal_Line; iElem++) { - iNode = iElem*N_POINTS_LINE; - Conn_Line_New[iNode+0] = LocalIndex[Conn_Line[iNode+0]]; - Conn_Line_New[iNode+1] = LocalIndex[Conn_Line[iNode+1]]; - } - - /*--- Write the zone header information ---*/ - ZoneType = FELINESEG; NElm = (INTEGER4)nGlobal_Line; - - err = TECZNE112((char*)"Line Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - NULL, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - if (first_zone) { - - err = TECDAT112(&NPts, Surf_Coords[0], &IsDouble); ShareFromZone[0] = 1; - err = TECDAT112(&NPts, Surf_Coords[1], &IsDouble); ShareFromZone[1] = 1; - if (geometry->GetnDim() == 3) { - err = TECDAT112(&NPts, Surf_Coords[2], &IsDouble); - ShareFromZone[2] = 1; - } - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - first_zone = false; - } - - err = TECNOD112(Conn_Line_New); - if (err) cout << "Error writing connectivity to Tecplot file" << endl; - - delete [] Conn_Line_New; - } - - if (nGlobal_BoundTria > 0) { - - /*--- Put the connectivity into a single array for writing ---*/ - int *Conn_BoundTria_New = new int[nGlobal_BoundTria*N_POINTS_TRIANGLE]; - - iNode = 0; - for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { - iNode = iElem*N_POINTS_TRIANGLE; - Conn_BoundTria_New[iNode+0] = LocalIndex[Conn_BoundTria[iNode+0]]; - Conn_BoundTria_New[iNode+1] = LocalIndex[Conn_BoundTria[iNode+1]]; - Conn_BoundTria_New[iNode+2] = LocalIndex[Conn_BoundTria[iNode+2]]; - } - - /*--- Write the zone header information ---*/ - ZoneType = FETRIANGLE; NElm = (INTEGER4)nGlobal_BoundTria; - - err = TECZNE112((char*)"Triangle Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - ShareFromZone, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - if (first_zone) { - - err = TECDAT112(&NPts, Surf_Coords[0], &IsDouble); ShareFromZone[0] = 1; - err = TECDAT112(&NPts, Surf_Coords[1], &IsDouble); ShareFromZone[1] = 1; - if (geometry->GetnDim() == 3) { - err = TECDAT112(&NPts, Surf_Coords[2], &IsDouble); - ShareFromZone[2] = 1; - } - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - first_zone = false; - } - - err = TECNOD112(Conn_BoundTria_New); - if (err) cout << "Error writing connectivity to Tecplot file" << endl; - - delete [] Conn_BoundTria_New; - } - - if (nGlobal_BoundQuad > 0) { - - - /*--- Put the connectivity into a single array for writing ---*/ - int *Conn_BoundQuad_New = new int[nGlobal_BoundQuad*N_POINTS_QUADRILATERAL]; - iNode = 0; - for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { - iNode = iElem*N_POINTS_QUADRILATERAL; - Conn_BoundQuad_New[iNode+0] = LocalIndex[Conn_BoundQuad[iNode+0]]; - Conn_BoundQuad_New[iNode+1] = LocalIndex[Conn_BoundQuad[iNode+1]]; - Conn_BoundQuad_New[iNode+2] = LocalIndex[Conn_BoundQuad[iNode+2]]; - Conn_BoundQuad_New[iNode+3] = LocalIndex[Conn_BoundQuad[iNode+3]]; - } - - /*--- Write the zone header information ---*/ - ZoneType = FEQUADRILATERAL; NElm = (INTEGER4)nGlobal_BoundQuad; - - err = TECZNE112((char*)"Quadrilateral Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - ShareFromZone, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - if (first_zone) { - - err = TECDAT112(&NPts, Surf_Coords[0], &IsDouble); ShareFromZone[0] = 1; - err = TECDAT112(&NPts, Surf_Coords[1], &IsDouble); ShareFromZone[1] = 1; - if (geometry->GetnDim() == 3) { - err = TECDAT112(&NPts, Surf_Coords[2], &IsDouble); - ShareFromZone[2] = 1; - } - if (err) cout << "Error writing coordinates to Tecplot file" << endl; - first_zone = false; - } - - err = TECNOD112(Conn_BoundQuad_New); - if (err) cout << "Error writing connectivity to Tecplot file" << endl; - - delete [] Conn_BoundQuad_New; - } - - for (iDim = 0; iDim < dims; iDim++) - delete [] Surf_Coords[iDim]; - delete [] Surf_Coords; - delete [] ShareFromZone; - delete [] LocalIndex; - delete [] SurfacePoint; - wrote_surf_file = true; - - err = TECEND112(); - if (err) cout << "Error in closing Tecplot file" << endl; - - } - -#endif - -} - -void COutput::SetTecplotBinary_SurfaceSolution(CConfig *config, CGeometry *geometry, unsigned short val_iZone) { - -#ifdef HAVE_TECIO - - passivedouble t; - INTEGER4 i, iVar, err, Debug, NPts, NElm, IsDouble, KMax; - INTEGER4 ICellMax, JCellMax, KCellMax, ZoneType, StrandID, ParentZn, FileType; - INTEGER4 *ShareFromZone, IsBlock, NumFaceConnections, FaceNeighborMode, ShareConnectivityFromZone; - string buffer, variables; - stringstream file; - bool first_zone = true, unsteady = config->GetUnsteady_Simulation(), GridMovement = config->GetGrid_Movement(); - bool Wrt_Unsteady = config->GetWrt_Unsteady(); - unsigned long iPoint, iElem, iNode, iSurf_Poin, iExtIter = config->GetExtIter(); - unsigned short iDim, NVar, dims = geometry->GetnDim(); - enum FileType { FULL = 0, GRID = 1, SOLUTION = 2 }; - enum ZoneType { ORDERED=0, FELINESEG=1, FETRIANGLE=2, FEQUADRILATERAL=3, FETETRAHEDRON=4, FEBRICK=5, FEPOLYGON=6, FEPOLYHEDRON=7 }; - - - file.str(string()); - buffer = config->GetSurfFlowCoeff_FileName(); - - file << buffer; - - if (unsteady) { - if (((int)iExtIter >= 0) && ((int)iExtIter < 10)) file << "_0000" << iExtIter; - if (((int)iExtIter >= 10) && ((int)iExtIter < 100)) file << "_000" << iExtIter; - if (((int)iExtIter >= 100) && ((int)iExtIter < 1000)) file << "_00" << iExtIter; - if (((int)iExtIter >= 1000) && ((int)iExtIter < 10000)) file << "_0" << iExtIter; - if ((int)iExtIter >= 10000) file << iExtIter; - } - file << ".sol.plt"; - FileType = SOLUTION; - variables = AssembleVariableNames(geometry, config, nVar_Consv, &NVar); - if (config->GetKind_SU2() == SU2_SOL) { - if (Wrt_Unsteady && GridMovement) nVar_Total = NVar; - else nVar_Total = NVar+dims; - } - - first_zone = true; - ShareFromZone = new INTEGER4[NVar]; - for (i = 0; i < NVar; i++) ShareFromZone[i] = 0; - - - /*--- Perform a renumbering for the surface points/elements ---*/ - unsigned long *LocalIndex = new unsigned long [nGlobal_Poin+1]; - bool *SurfacePoint = new bool [nGlobal_Poin+1]; - - for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) SurfacePoint[iPoint] = false; - - for (iElem = 0; iElem < nGlobal_Line; iElem++) { - iNode = iElem*N_POINTS_LINE; - SurfacePoint[Conn_Line[iNode+0]] = true; - SurfacePoint[Conn_Line[iNode+1]] = true; - } - for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { - iNode = iElem*N_POINTS_TRIANGLE; - SurfacePoint[Conn_BoundTria[iNode+0]] = true; - SurfacePoint[Conn_BoundTria[iNode+1]] = true; - SurfacePoint[Conn_BoundTria[iNode+2]] = true; - } - for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { - iNode = iElem*N_POINTS_QUADRILATERAL; - SurfacePoint[Conn_BoundQuad[iNode+0]] = true; - SurfacePoint[Conn_BoundQuad[iNode+1]] = true; - SurfacePoint[Conn_BoundQuad[iNode+2]] = true; - SurfacePoint[Conn_BoundQuad[iNode+3]] = true; - } - - unsigned long nSurf_Poin = 0; - for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) { - LocalIndex[iPoint] = 0; - if (SurfacePoint[iPoint]) { nSurf_Poin++; LocalIndex[iPoint] = nSurf_Poin; } - } - - /*--- Collect surface coordinates into one array as well ---*/ - /*--- Note the -1 in the Coords/Data array in order to undo the 1-based indexing ---*/ - su2double **Surf_Coords = NULL; - if (Wrt_Unsteady && GridMovement) { - Surf_Coords = new su2double*[dims]; - for (iDim = 0; iDim < dims; iDim++) - Surf_Coords[iDim] = new su2double[nSurf_Poin]; - - iSurf_Poin = 0; - for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) { - if (SurfacePoint[iPoint]) { - for (iDim = 0; iDim < dims; iDim++) { - if (config->GetKind_SU2() == SU2_SOL) - Surf_Coords[iDim][iSurf_Poin] = Data[iDim][iPoint-1]; - else - Surf_Coords[iDim][iSurf_Poin] = Coords[iDim][iPoint-1]; - } - iSurf_Poin++; - } - } - } - - /*--- Collect surface data into one array for the surface as well ---*/ - /*--- Note the -1 in the Coords/Data array in order to undo the 1-based indexing ---*/ - su2double **Surf_Data = new su2double*[nVar_Total]; - for (iVar = 0; iVar < nVar_Total; iVar++) - Surf_Data[iVar] = new su2double[nSurf_Poin]; - - iSurf_Poin = 0; - for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) { - if (SurfacePoint[iPoint]) { - for (iVar = 0; iVar < nVar_Total; iVar++) { - if (config->GetKind_SU2() == SU2_SOL) { - if (Wrt_Unsteady && GridMovement) - Surf_Data[iVar][iSurf_Poin] = Data[iVar][iPoint-1]; - else - Surf_Data[iVar][iSurf_Poin] = Data[iVar][iPoint-1]; - } else - Surf_Data[iVar][iSurf_Poin] = Data[iVar][iPoint-1]; - } - iSurf_Poin++; - } - } - - /*--- Consistent data for Tecplot zones ---*/ - Debug = 0; - IsDouble = 1; - NPts = (INTEGER4)nSurf_Poin; - t = SU2_TYPE::GetValue(iExtIter*config->GetDelta_UnstTime()); - KMax = 0; - ICellMax = 0; - JCellMax = 0; - KCellMax = 0; - StrandID = (INTEGER4)iExtIter+1; - ParentZn = 0; - IsBlock = 1; - NumFaceConnections = 0; - FaceNeighborMode = 0; - ShareConnectivityFromZone = 0; - - - /*--- Open Tecplot file ---*/ - err = TECINI112((char *)config->GetFlow_FileName().c_str(), - (char *)variables.c_str(), - (char *)file.str().c_str(), - (char *)".", - &FileType, - &Debug, - &IsDouble); - if (err) cout << "Error in opening Tecplot file" << endl; - - - if (nGlobal_Line > 0) { - - /*--- Write the zone header information ---*/ - ZoneType = FELINESEG; NElm = (INTEGER4)nGlobal_Line; - - err = TECZNE112((char*)"Line Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - ShareFromZone, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - if (first_zone) { - - i = 0; - if (config->GetKind_SU2() == SU2_SOL) { - if (Wrt_Unsteady && GridMovement) { - for (iDim = 0; iDim < dims; iDim++) { - err = TECDAT112(&NPts, Surf_Data[iDim], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - for (iVar = dims; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Surf_Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } else { - if (Wrt_Unsteady && GridMovement) { - for (iDim = 0; iDim < dims; iDim++) { - err = TECDAT112(&NPts, Surf_Coords[iDim], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - for (iVar = 0; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Surf_Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - first_zone = false; - } - - } - - if (nGlobal_BoundTria > 0) { - - /*--- Write the zone header information ---*/ - ZoneType = FETRIANGLE; NElm = (INTEGER4)nGlobal_BoundTria; - - err = TECZNE112((char*)"Triangle Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - ShareFromZone, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - if (first_zone) { - - i = 0; - if (config->GetKind_SU2() == SU2_SOL) { - if (Wrt_Unsteady && GridMovement) { - for (iDim = 0; iDim < dims; iDim++) { - err = TECDAT112(&NPts, Surf_Data[iDim], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - for (iVar = dims; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Surf_Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } else { - if (Wrt_Unsteady && GridMovement) { - for (iDim = 0; iDim < dims; iDim++) { - err = TECDAT112(&NPts, Surf_Coords[iDim], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - for (iVar = 0; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Surf_Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - first_zone = false; - } - - } - - if (nGlobal_BoundQuad > 0) { - - /*--- Write the zone header information ---*/ - ZoneType = FEQUADRILATERAL; NElm = (INTEGER4)nGlobal_BoundQuad; - - err = TECZNE112((char*)"Quadrilateral Elements", - &ZoneType, - &NPts, - &NElm, - &KMax, - &ICellMax, - &JCellMax, - &KCellMax, - &t, - &StrandID, - &ParentZn, - &IsBlock, - &NumFaceConnections, - &FaceNeighborMode, - 0, /* TotalNumFaceNodes */ - 0, /* NumConnectedBoundaryFaces */ - 0, /* TotalNumBoundaryConnections */ - NULL, /* PassiveVarList */ - NULL, /* ValueLocation */ - ShareFromZone, /* ShareVarFromZone */ - &ShareConnectivityFromZone); - if (err) cout << "Error writing Tecplot zone data" << endl; - - /*--- write node coordinates and data if not done already---*/ - if (first_zone) { - - i = 0; - if (config->GetKind_SU2() == SU2_SOL) { - if (Wrt_Unsteady && GridMovement) { - for (iDim = 0; iDim < dims; iDim++) { - err = TECDAT112(&NPts, Surf_Data[iDim], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - for (iVar = dims; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Surf_Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } else { - if (Wrt_Unsteady && GridMovement) { - for (iDim = 0; iDim < dims; iDim++) { - err = TECDAT112(&NPts, Surf_Coords[iDim], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - for (iVar = 0; iVar < nVar_Total; iVar++) { - err = TECDAT112(&NPts, Surf_Data[iVar], &IsDouble); ShareFromZone[i++] = 1; - if (err) cout << "Error writing data to Tecplot file" << endl; - } - } - first_zone = false; - } - - } - - for (iVar = 0; iVar < nVar_Total; iVar++) - delete [] Surf_Data[iVar]; - delete [] Surf_Data; - - if (Surf_Coords != NULL) { - for (iDim = 0; iDim < dims; iDim++) delete [] Surf_Coords[iDim]; - delete [] Surf_Coords; - } - delete [] LocalIndex; - delete [] SurfacePoint; - delete [] ShareFromZone; - - err = TECEND112(); - if (err) cout << "Error in closing Tecplot file" << endl; - -#endif - -} - -string COutput::AssembleVariableNames(CGeometry *geometry, CConfig *config, unsigned short nVar_Consv, unsigned short *NVar) { - - /*--- Local variables ---*/ - stringstream variables; variables.str(string()); - unsigned short iVar; - *NVar = 0; - unsigned short iDim, nDim = geometry->GetnDim(); - unsigned short Kind_Solver = config->GetKind_Solver(); - bool grid_movement = config->GetGrid_Movement(); - bool Wrt_Unsteady = config->GetWrt_Unsteady(); - - - /*--- Write the basic variable header based on the particular solution ----*/ - - /*--- Write the list of the fields in the restart file. - Without including the PointID---*/ - if (config->GetKind_SU2() == SU2_SOL) { - - /*--- If SU2_SOL called this routine, we already have a set of output - variables with the appropriate string tags stored in the config class. - We simply read in and remove the quotation marks from the var names. ---*/ - - /*--- Set the number of variables to be written. Subtract off an index for - the PointID as well as each coordinate (x, y, z). ---*/ - string varname; - - if (Wrt_Unsteady && grid_movement) { - - *NVar = config->fields.size()-1; - for (unsigned short iField = 1; iField < config->fields.size(); iField++) { - varname = config->fields[iField]; - varname.erase (varname.begin(), varname.begin()+1); - varname.erase (varname.end()-1, varname.end()); - variables << varname << " "; - } - } else { - - *NVar = config->fields.size()-1-nDim; - for (unsigned short iField = 1+nDim; iField < config->fields.size(); iField++) { - varname = config->fields[iField]; - varname.erase (varname.begin(), varname.begin()+1); - varname.erase (varname.end()-1, varname.end()); - variables << varname << " "; - } - } - - } else { - - if (Wrt_Unsteady && grid_movement) { - if (nDim == 2) { - variables << "x y "; *NVar += 2; - } else { - variables << "x y z "; *NVar += 3; - } - } - - for (iVar = 0; iVar < nVar_Consv; iVar++) { - variables << "Conservative_" << iVar+1<<" "; *NVar += 1; - } - if (config->GetWrt_Limiters()) { - for (iVar = 0; iVar < nVar_Consv; iVar++) { - variables << "Limiter_" << iVar+1<<" "; *NVar += 1; - } - } - if (config->GetWrt_Residuals()) { - for (iVar = 0; iVar < nVar_Consv; iVar++) { - variables << "Residual_" << iVar+1<<" "; *NVar += 1; - } - } - - /*--- Add names for any extra variables (this will need to be adjusted). ---*/ - if (grid_movement) { - if (nDim == 2) { - variables << "Grid_Velx Grid_Vely "; *NVar += 2; - } else { - variables << "Grid_Velx Grid_Vely Grid_Velz "; *NVar += 3; - } - } - - if (config->GetKind_Regime() == FREESURFACE) { - variables << "Density "; - *NVar += 1; - } - - if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - variables << "Pressure Temperature Pressure_Coefficient Mach "; - *NVar += 4; - } - - if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - variables << "Laminar_Viscosity Skin_Friction_Coefficient Heat_Flux Y_Plus "; - *NVar += 4; - } - - if (Kind_Solver == RANS) { - variables << "Eddy_Viscosity "; - *NVar += 1; - } - - if (config->GetWrt_SharpEdges()) { - if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { - variables << "Sharp_Edge_Dist "; - *NVar += 1; - } - } - - if (Kind_Solver == POISSON_EQUATION) { - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) { - variables << "poissonField_" << iDim+1 << " "; - *NVar += 1; - } - } - - if (( Kind_Solver == ADJ_EULER ) || - ( Kind_Solver == ADJ_NAVIER_STOKES ) || - ( Kind_Solver == ADJ_RANS ) ) { - variables << "Surface_Sensitivity Solution_Sensor "; - *NVar += 2; - } - } - - return variables.str(); - -} +/*! + * \file output_tecplot.cpp + * \brief Main subroutines for output solver information. + * \author F. Palacios, T. Economon, M. Colonno + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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_structure.hpp" + +void COutput::SetTecplotASCII(CConfig *config, CGeometry *geometry, CSolver **solver, unsigned short val_iZone, unsigned short val_nZone, bool surf_sol) { + + unsigned short iDim, iVar, nDim = geometry->GetnDim(); + unsigned short Kind_Solver = config->GetKind_Solver(); + + unsigned long iPoint, iElem, iNode; + unsigned long iExtIter = config->GetExtIter(); + unsigned long *LocalIndex = NULL; + bool *SurfacePoint = NULL; + + bool grid_movement = config->GetGrid_Movement(); + bool adjoint = config->GetAdjoint() || config->GetDiscrete_Adjoint(); + + char cstr[200], buffer[50]; + string filename; + + /*--- Write file name with extension ---*/ + + if (surf_sol) { + if (adjoint) filename = config->GetSurfAdjCoeff_FileName(); + else filename = config->GetSurfFlowCoeff_FileName(); + } + else { + if (adjoint) + filename = config->GetAdj_FileName(); + else filename = config->GetFlow_FileName(); + } + + if (Kind_Solver == LINEAR_ELASTICITY) { + if (surf_sol) filename = config->GetSurfStructure_FileName().c_str(); + else filename = config->GetStructure_FileName().c_str(); + } + + if (Kind_Solver == WAVE_EQUATION) { + if (surf_sol) filename = config->GetSurfWave_FileName().c_str(); + else filename = config->GetWave_FileName().c_str(); + } + + if (Kind_Solver == HEAT_EQUATION) { + if (surf_sol) filename = config->GetSurfHeat_FileName().c_str(); + else filename = config->GetHeat_FileName().c_str(); + } + + if (Kind_Solver == POISSON_EQUATION) { + if (surf_sol) filename = config->GetSurfStructure_FileName().c_str(); + else filename = config->GetStructure_FileName().c_str(); + } + + strcpy (cstr, filename.c_str()); + + /*--- Special cases where a number needs to be appended to the file name. ---*/ + + if ((Kind_Solver == EULER || Kind_Solver == NAVIER_STOKES || Kind_Solver == RANS || + Kind_Solver == ADJ_EULER || Kind_Solver == ADJ_NAVIER_STOKES || Kind_Solver == ADJ_RANS || + Kind_Solver == DISC_ADJ_EULER || Kind_Solver == DISC_ADJ_NAVIER_STOKES || Kind_Solver == DISC_ADJ_RANS) && + (val_nZone > 1) && (config->GetUnsteady_Simulation() != TIME_SPECTRAL)) { + SPRINTF (buffer, "_%d", SU2_TYPE::Int(val_iZone)); + strcat(cstr, buffer); + } + + if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { + + if (config->GetKind_SU2() == SU2_SOL) { val_iZone = iExtIter; } + + if (SU2_TYPE::Int(val_iZone) < 10) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 10) && (SU2_TYPE::Int(val_iZone) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 100) && (SU2_TYPE::Int(val_iZone) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(val_iZone)); + if ((SU2_TYPE::Int(val_iZone) >= 1000) && (SU2_TYPE::Int(val_iZone) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(val_iZone)); + if (SU2_TYPE::Int(val_iZone) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(val_iZone)); + + } + else if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { + if (SU2_TYPE::Int(iExtIter) < 10) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(iExtIter)); + if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(iExtIter)); + } + else { SPRINTF (buffer, ".dat"); } + + strcat(cstr, buffer); + + /*--- Open Tecplot ASCII file and write the header. ---*/ + ofstream Tecplot_File; + Tecplot_File.open(cstr, ios::out); + Tecplot_File.precision(6); + if (surf_sol) Tecplot_File << "TITLE = \"Visualization of the surface solution\"" << endl; + else Tecplot_File << "TITLE = \"Visualization of the volumetric solution\"" << endl; + + /*--- Prepare the variable lists. ---*/ + + /*--- Write the list of the fields in the restart file. + Without including the PointID---*/ + if (config->GetKind_SU2() == SU2_SOL) { + + /*--- If SU2_SOL called this routine, we already have a set of output + variables with the appropriate string tags stored in the config class. ---*/ + Tecplot_File << "VARIABLES = "; + nVar_Total = config->fields.size() - 1; + for (unsigned short iField = 1; iField < config->fields.size(); iField++) { + Tecplot_File << config->fields[iField]; + } + Tecplot_File << endl; + + } else { + + if (nDim == 2) { + Tecplot_File << "VARIABLES = \"x\",\"y\""; + } else { + Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\""; + } + + /*--- Add names for conservative and residual variables ---*/ + for (iVar = 0; iVar < nVar_Consv; iVar++) { + Tecplot_File << ",\"Conservative_" << iVar+1 << "\""; + } + + if (!config->GetLow_MemoryOutput()) { + + if (config->GetWrt_Limiters()) { + for (iVar = 0; iVar < nVar_Consv; iVar++) { + Tecplot_File << ",\"Limiter_" << iVar+1 << "\""; + } + } + if (config->GetWrt_Residuals()) { + for (iVar = 0; iVar < nVar_Consv; iVar++) { + Tecplot_File << ",\"Residual_" << iVar+1 << "\""; + } + } + + /*--- Add names for any extra variables (this will need to be adjusted). ---*/ + if (grid_movement) { + if (nDim == 2) { + Tecplot_File << ",\"Grid_Velx\",\"Grid_Vely\""; + } else { + Tecplot_File << ",\"Grid_Velx\",\"Grid_Vely\",\"Grid_Velz\""; + } + } + + if (config->GetKind_Regime() == FREESURFACE) { + Tecplot_File << ",\"Density\""; + } + + if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + Tecplot_File << ",\"Pressure\",\"Temperature\",\"Pressure_Coefficient\",\"Mach\""; + } + + if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + Tecplot_File << ",\"Laminar_Viscosity\", \"Skin_Friction_Coefficient\", \"Heat_Flux\", \"Y_Plus\""; + } + + if (Kind_Solver == RANS) { + Tecplot_File << ", \"Eddy_Viscosity\""; + } + + if (config->GetWrt_SharpEdges()) { + if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + Tecplot_File << ", \"Sharp_Edge_Dist\""; + } + } + + if (Kind_Solver == POISSON_EQUATION) { + unsigned short iDim; + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) + Tecplot_File << ",\"poissonField_" << iDim+1 << "\""; + } + + if (( Kind_Solver == ADJ_EULER ) || + ( Kind_Solver == ADJ_NAVIER_STOKES ) || + ( Kind_Solver == ADJ_RANS ) ) { + Tecplot_File << ", \"Surface_Sensitivity\", \"Solution_Sensor\""; + } + + if (( Kind_Solver == DISC_ADJ_EULER ) || + ( Kind_Solver == DISC_ADJ_NAVIER_STOKES ) || + ( Kind_Solver == DISC_ADJ_RANS )) { + Tecplot_File << ", \"Surface_Sensitivity\", \"Sensitivity_x\", \"Sensitivity_y\""; + if (geometry->GetnDim() == 3){ + Tecplot_File << ",\"Sensitivity_z\""; + } + } + + if (Kind_Solver == LINEAR_ELASTICITY) { + Tecplot_File << ", \"Von_Mises_Stress\", \"Flow_Pressure\""; + } + + if (config->GetExtraOutput()) { + string *headings = NULL; + //if (Kind_Solver == RANS) { + headings = solver[TURB_SOL]->OutputHeadingNames; + //} + for (iVar = 0; iVar < nVar_Extra; iVar++) { + //Tecplot_File << ", \"ExtraOutput_" << iVar+1<<"\""; + if (headings == NULL) { + Tecplot_File << ", \"ExtraOutput_" << iVar+1<<"\""; + } else{ + Tecplot_File << ", \""<< headings[iVar] <<"\""; + } + } + } + } + + Tecplot_File << endl; + + } + + /*--- If it's a surface output, print only the points + that are in the element list, change the numbering ---*/ + + if (surf_sol) { + + LocalIndex = new unsigned long [nGlobal_Poin+1]; + SurfacePoint = new bool [nGlobal_Poin+1]; + + for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) SurfacePoint[iPoint] = false; + + for (iElem = 0; iElem < nGlobal_Line; iElem++) { + iNode = iElem*N_POINTS_LINE; + SurfacePoint[Conn_Line[iNode+0]] = true; + SurfacePoint[Conn_Line[iNode+1]] = true; + } + for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { + iNode = iElem*N_POINTS_TRIANGLE; + SurfacePoint[Conn_BoundTria[iNode+0]] = true; + SurfacePoint[Conn_BoundTria[iNode+1]] = true; + SurfacePoint[Conn_BoundTria[iNode+2]] = true; + } + for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { + iNode = iElem*N_POINTS_QUADRILATERAL; + SurfacePoint[Conn_BoundQuad[iNode+0]] = true; + SurfacePoint[Conn_BoundQuad[iNode+1]] = true; + SurfacePoint[Conn_BoundQuad[iNode+2]] = true; + SurfacePoint[Conn_BoundQuad[iNode+3]] = true; + } + + nSurf_Poin = 0; + for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) { + LocalIndex[iPoint] = 0; + if (SurfacePoint[iPoint]) { nSurf_Poin++; LocalIndex[iPoint] = nSurf_Poin; } + } + + } + + /*--- Write the header ---*/ + Tecplot_File << "ZONE "; + if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { + Tecplot_File << "STRANDID="<GetUnsteady_Simulation() == TIME_SPECTRAL) { + /*--- Compute period of oscillation & compute time interval using nTimeInstances ---*/ + su2double period = config->GetTimeSpectral_Period(); + su2double deltaT = period/(su2double)(config->GetnTimeInstances()); + Tecplot_File << "STRANDID="<GetKind_SU2() != SU2_SOL) { + for (iDim = 0; iDim < nDim; iDim++) + Tecplot_File << scientific << Coords[iDim][iPoint] << "\t"; + } + + /*--- Loop over the vars/residuals and write the values to file ---*/ + for (iVar = 0; iVar < nVar_Total; iVar++) + Tecplot_File << scientific << Data[iVar][iPoint] << "\t"; + + Tecplot_File << endl; + + } + + } else { + + /*--- Write the node coordinates ---*/ + if (config->GetKind_SU2() != SU2_SOL) { + for (iDim = 0; iDim < nDim; iDim++) + Tecplot_File << scientific << Coords[iDim][iPoint] << "\t"; + } + + /*--- Loop over the vars/residuals and write the values to file ---*/ + for (iVar = 0; iVar < nVar_Total; iVar++) + Tecplot_File << scientific << Data[iVar][iPoint] << "\t"; + + Tecplot_File << endl; + + } + + } + + + /*--- Write connectivity data. ---*/ + if (surf_sol) { + + for (iElem = 0; iElem < nGlobal_Line; iElem++) { + iNode = iElem*N_POINTS_LINE; + Tecplot_File << LocalIndex[Conn_Line[iNode+0]] << "\t"; + Tecplot_File << LocalIndex[Conn_Line[iNode+1]] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { + iNode = iElem*N_POINTS_TRIANGLE; + Tecplot_File << LocalIndex[Conn_BoundTria[iNode+0]] << "\t"; + Tecplot_File << LocalIndex[Conn_BoundTria[iNode+1]] << "\t"; + Tecplot_File << LocalIndex[Conn_BoundTria[iNode+2]] << "\t"; + Tecplot_File << LocalIndex[Conn_BoundTria[iNode+2]] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { + iNode = iElem*N_POINTS_QUADRILATERAL; + Tecplot_File << LocalIndex[Conn_BoundQuad[iNode+0]] << "\t"; + Tecplot_File << LocalIndex[Conn_BoundQuad[iNode+1]] << "\t"; + Tecplot_File << LocalIndex[Conn_BoundQuad[iNode+2]] << "\t"; + Tecplot_File << LocalIndex[Conn_BoundQuad[iNode+3]] << "\n"; + } + + } else { + + for (iElem = 0; iElem < nGlobal_Tria; iElem++) { + iNode = iElem*N_POINTS_TRIANGLE; + Tecplot_File << Conn_Tria[iNode+0] << "\t"; + Tecplot_File << Conn_Tria[iNode+1] << "\t"; + Tecplot_File << Conn_Tria[iNode+2] << "\t"; + Tecplot_File << Conn_Tria[iNode+2] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Quad; iElem++) { + iNode = iElem*N_POINTS_QUADRILATERAL; + Tecplot_File << Conn_Quad[iNode+0] << "\t"; + Tecplot_File << Conn_Quad[iNode+1] << "\t"; + Tecplot_File << Conn_Quad[iNode+2] << "\t"; + Tecplot_File << Conn_Quad[iNode+3] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Tetr; iElem++) { + iNode = iElem*N_POINTS_TETRAHEDRON; + Tecplot_File << Conn_Tetr[iNode+0] << "\t" << Conn_Tetr[iNode+1] << "\t"; + Tecplot_File << Conn_Tetr[iNode+2] << "\t" << Conn_Tetr[iNode+2] << "\t"; + Tecplot_File << Conn_Tetr[iNode+3] << "\t" << Conn_Tetr[iNode+3] << "\t"; + Tecplot_File << Conn_Tetr[iNode+3] << "\t" << Conn_Tetr[iNode+3] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Hexa; iElem++) { + iNode = iElem*N_POINTS_HEXAHEDRON; + Tecplot_File << Conn_Hexa[iNode+0] << "\t" << Conn_Hexa[iNode+1] << "\t"; + Tecplot_File << Conn_Hexa[iNode+2] << "\t" << Conn_Hexa[iNode+3] << "\t"; + Tecplot_File << Conn_Hexa[iNode+4] << "\t" << Conn_Hexa[iNode+5] << "\t"; + Tecplot_File << Conn_Hexa[iNode+6] << "\t" << Conn_Hexa[iNode+7] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Pris; iElem++) { + iNode = iElem*N_POINTS_PRISM; + Tecplot_File << Conn_Pris[iNode+0] << "\t" << Conn_Pris[iNode+1] << "\t"; + Tecplot_File << Conn_Pris[iNode+1] << "\t" << Conn_Pris[iNode+2] << "\t"; + Tecplot_File << Conn_Pris[iNode+3] << "\t" << Conn_Pris[iNode+4] << "\t"; + Tecplot_File << Conn_Pris[iNode+4] << "\t" << Conn_Pris[iNode+5] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Pyra; iElem++) { + iNode = iElem*N_POINTS_PYRAMID; + Tecplot_File << Conn_Pyra[iNode+0] << "\t" << Conn_Pyra[iNode+1] << "\t"; + Tecplot_File << Conn_Pyra[iNode+2] << "\t" << Conn_Pyra[iNode+3] << "\t"; + Tecplot_File << Conn_Pyra[iNode+4] << "\t" << Conn_Pyra[iNode+4] << "\t"; + Tecplot_File << Conn_Pyra[iNode+4] << "\t" << Conn_Pyra[iNode+4] << "\n"; + } + } + + Tecplot_File.close(); + + if (surf_sol) delete [] LocalIndex; + +} + +void COutput::SetTecplotASCII_LowMemory(CConfig *config, CGeometry *geometry, CSolver **solver, char mesh_filename[MAX_STRING_SIZE], bool surf_sol) { + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + int size = SINGLE_NODE; + MPI_Comm_size(MPI_COMM_WORLD, &size); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + unsigned long iElem, iPoint; + unsigned short iVar; + bool grid_movement = config->GetGrid_Movement(); + unsigned short Kind_Solver = config->GetKind_Solver(); + ofstream Tecplot_File; + unsigned long Total_nElem_Bound, *PointSurface = NULL, nPointSurface = 0; + unsigned short iMarker; + + /*--- Open Tecplot ASCII file and write the header. ---*/ + + Tecplot_File.open(mesh_filename, ios::out); + Tecplot_File.precision(6); + if (surf_sol) Tecplot_File << "TITLE = \"Visualization of the surface solution\"" << endl; + else Tecplot_File << "TITLE = \"Visualization of the volumetric solution\"" << endl; + + /*--- Write the list of the fields in the restart file. + Without including the PointID---*/ + if (config->GetKind_SU2() == SU2_SOL) { + + /*--- If SU2_SOL called this routine, we already have a set of output + variables with the appropriate string tags stored in the config class. ---*/ + Tecplot_File << "VARIABLES = "; + nVar_Total = config->fields.size() - 1; + for (unsigned short iField = 1; iField < config->fields.size(); iField++) { + Tecplot_File << config->fields[iField]; + } + + Tecplot_File << endl; + + } else { + + if (geometry->GetnDim() == 2) { Tecplot_File << "VARIABLES = \"x\",\"y\""; } + else { Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\""; } + + /*--- Add names for conservative, limiters, and residual variables ---*/ + + for (iVar = 0; iVar < nVar_Consv; iVar++) { + Tecplot_File << ",\"Conservative_" << iVar+1 << "\""; + } + + if (!config->GetLow_MemoryOutput()) { + + if (config->GetWrt_Limiters()) { + for (iVar = 0; iVar < nVar_Consv; iVar++) { + Tecplot_File << ",\"Limiter_" << iVar+1 << "\""; + } + } + if (config->GetWrt_Residuals()) { + for (iVar = 0; iVar < nVar_Consv; iVar++) { + Tecplot_File << ",\"Residual_" << iVar+1 << "\""; + } + } + + /*--- Add names for any extra variables (this will need to be adjusted). ---*/ + + if (grid_movement) { + if (geometry->GetnDim() == 2) { + Tecplot_File << ",\"Grid_Velx\",\"Grid_Vely\""; + } else { + Tecplot_File << ",\"Grid_Velx\",\"Grid_Vely\",\"Grid_Velz\""; + } + } + + if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + Tecplot_File << ",\"Pressure\",\"Temperature\",\"Pressure_Coefficient\",\"Mach\""; + if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + Tecplot_File << ",\"Laminar_Viscosity\", \"Skin_Friction_Coefficient\", \"Heat_Flux\", \"Y_Plus\""; + if (Kind_Solver == RANS) { Tecplot_File << ", \"Eddy_Viscosity\""; } + } + if (config->GetWrt_SharpEdges()) { Tecplot_File << ", \"Sharp_Edge_Dist\""; } + } + + if ((Kind_Solver == ADJ_EULER) || (Kind_Solver == ADJ_NAVIER_STOKES) || (Kind_Solver == ADJ_RANS) ) { + Tecplot_File << ", \"Surface_Sensitivity\", \"Solution_Sensor\""; + } + + if (( Kind_Solver == DISC_ADJ_EULER ) || + ( Kind_Solver == DISC_ADJ_NAVIER_STOKES ) || + ( Kind_Solver == DISC_ADJ_RANS )) { + Tecplot_File << ", \"Surface_Sensitivity\", \"Sensitivity_x\", \"Sensitivity_y\""; + if (geometry->GetnDim() == 3){ + Tecplot_File << ",\"Sensitivity_z\""; + } + } + + } + + Tecplot_File << endl; + + } + + + if (surf_sol) { + + /*--- It is important to do a renumbering to don't add points + that do not belong to the surfaces ---*/ + + PointSurface = new unsigned long[geometry->GetnPoint()]; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + if (geometry->node[iPoint]->GetBoundary()) { + PointSurface[iPoint] = nPointSurface; + nPointSurface++; + } + + /*--- Compute the total number of elements ---*/ + + Total_nElem_Bound = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_Plotting(iMarker) == YES) { + Total_nElem_Bound += geometry->GetnElem_Bound(iMarker); + } + } + + if (Total_nElem_Bound != 0) { + + /*--- Write the header of the file ---*/ + + Tecplot_File << "ZONE T= \"MPI rank: " << rank << "\", "; + Tecplot_File << "NODES= "<< nPointSurface <<", ELEMENTS= "<< Total_nElem_Bound <<", DATAPACKING= POINT"; + if (geometry->GetnDim() == 2) Tecplot_File << ", ZONETYPE= FELINESEG"<< endl; + if (geometry->GetnDim() == 3) Tecplot_File << ", ZONETYPE= FEQUADRILATERAL"<< endl; + + /*--- Only write the coordiantes of the points that are on the surfaces ---*/ + + if (geometry->GetnDim() == 3) { + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + if (geometry->node[iPoint]->GetBoundary()) { + for (iVar = 0; iVar < solver[FLOW_SOL]->GetnVar(); iVar++) + Tecplot_File << scientific << solver[FLOW_SOL]->node[iPoint]->GetSolution(iVar) << "\t"; + Tecplot_File << "\n"; + } + } + else { + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + if (geometry->node[iPoint]->GetBoundary()) { + for (iVar = 0; iVar < solver[FLOW_SOL]->GetnVar(); iVar++) + Tecplot_File << scientific << solver[FLOW_SOL]->node[iPoint]->GetSolution(iVar) << "\t"; + Tecplot_File << "\n"; + } + } + + /*--- Write the cells using the new numbering ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if (config->GetMarker_All_Plotting(iMarker) == YES) + for (iElem = 0; iElem < geometry->GetnElem_Bound(iMarker); iElem++) { + if (geometry->GetnDim() == 2) { + Tecplot_File << PointSurface[geometry->bound[iMarker][iElem]->GetNode(0)]+1 << " " + << PointSurface[geometry->bound[iMarker][iElem]->GetNode(1)]+1 << endl; + } + if (geometry->GetnDim() == 3) { + if (geometry->bound[iMarker][iElem]->GetnNodes() == 3) { + Tecplot_File << PointSurface[geometry->bound[iMarker][iElem]->GetNode(0)]+1 << " " + << PointSurface[geometry->bound[iMarker][iElem]->GetNode(1)]+1 << " " + << PointSurface[geometry->bound[iMarker][iElem]->GetNode(2)]+1 << " " + << PointSurface[geometry->bound[iMarker][iElem]->GetNode(2)]+1 << endl; + } + if (geometry->bound[iMarker][iElem]->GetnNodes() == 4) { + Tecplot_File << PointSurface[geometry->bound[iMarker][iElem]->GetNode(0)]+1 << " " + << PointSurface[geometry->bound[iMarker][iElem]->GetNode(1)]+1 << " " + << PointSurface[geometry->bound[iMarker][iElem]->GetNode(2)]+1 << " " + << PointSurface[geometry->bound[iMarker][iElem]->GetNode(3)]+1 << endl; + } + } + } + } + else { + + /*--- No elements in the surface ---*/ + + if (geometry->GetnDim() == 2) { + Tecplot_File << "ZONE "; + Tecplot_File << "T= \"MPI rank: " << rank << "\", "; + Tecplot_File << "NODES= 1, ELEMENTS= 1, DATAPACKING=POINT, ZONETYPE=FELINESEG"<< endl; + for (iVar = 0; iVar < solver[FLOW_SOL]->GetnVar(); iVar++) + Tecplot_File << scientific << "0.0\t"; + Tecplot_File << "\n"; + Tecplot_File << "1 1"<< endl; + } + if (geometry->GetnDim() == 3) { + Tecplot_File << "ZONE "; + Tecplot_File << "T= \"MPI rank: " << rank << "\", "; + Tecplot_File << "NODES= 1, ELEMENTS= 1, DATAPACKING=POINT, ZONETYPE=FEQUADRILATERAL"<< endl; + for (iVar = 0; iVar < solver[FLOW_SOL]->GetnVar(); iVar++) + Tecplot_File << scientific << "0.0\t"; + Tecplot_File << "\n"; + Tecplot_File << "1 1 1 1"<< endl; + } + } + + /*--- Dealocate memory and close the file ---*/ + + delete[] PointSurface; + Tecplot_File.close(); + + } + + else { + + Tecplot_File << "ZONE "; + Tecplot_File << "T= \"MPI rank: " << rank << "\", "; + Tecplot_File << "NODES= "<< geometry->GetnPoint() <<", ELEMENTS= "<< geometry->GetnElem() <<", DATAPACKING= POINT"; + if (geometry->GetnDim() == 2) Tecplot_File << ", ZONETYPE= FEQUADRILATERAL"<< endl; + if (geometry->GetnDim() == 3) Tecplot_File << ", ZONETYPE= FEBRICK"<< endl; + + /*--- Adding coordinates ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + for (iVar = 0; iVar < solver[FLOW_SOL]->GetnVar(); iVar++) + Tecplot_File << scientific << solver[FLOW_SOL]->node[iPoint]->GetSolution(iVar) << "\t"; + Tecplot_File << "\n"; + } + + /*--- Adding conectivity ---*/ + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) { + Tecplot_File << + geometry->elem[iElem]->GetNode(0)+1 <<" "<< geometry->elem[iElem]->GetNode(1)+1 <<" "<< + geometry->elem[iElem]->GetNode(2)+1 <<" "<< geometry->elem[iElem]->GetNode(2)+1 << endl; + } + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { + Tecplot_File << + geometry->elem[iElem]->GetNode(0)+1 <<" "<< geometry->elem[iElem]->GetNode(1)+1 <<" "<< + geometry->elem[iElem]->GetNode(2)+1 <<" "<< geometry->elem[iElem]->GetNode(3)+1 << endl; + } + if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) { + Tecplot_File << + geometry->elem[iElem]->GetNode(0)+1 <<" "<< geometry->elem[iElem]->GetNode(1)+1 <<" "<< + geometry->elem[iElem]->GetNode(2)+1 <<" "<< geometry->elem[iElem]->GetNode(2)+1 <<" "<< + geometry->elem[iElem]->GetNode(3)+1 <<" "<< geometry->elem[iElem]->GetNode(3)+1 <<" "<< + geometry->elem[iElem]->GetNode(3)+1 <<" "<< geometry->elem[iElem]->GetNode(3)+1 << endl; + } + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) { + Tecplot_File << + geometry->elem[iElem]->GetNode(0)+1 <<" "<< geometry->elem[iElem]->GetNode(1)+1 <<" "<< + geometry->elem[iElem]->GetNode(2)+1 <<" "<< geometry->elem[iElem]->GetNode(3)+1 <<" "<< + geometry->elem[iElem]->GetNode(4)+1 <<" "<< geometry->elem[iElem]->GetNode(5)+1 <<" "<< + geometry->elem[iElem]->GetNode(6)+1 <<" "<< geometry->elem[iElem]->GetNode(7)+1 << endl; + } + if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) { + Tecplot_File << + geometry->elem[iElem]->GetNode(0)+1 <<" "<< geometry->elem[iElem]->GetNode(1)+1 <<" "<< + geometry->elem[iElem]->GetNode(2)+1 <<" "<< geometry->elem[iElem]->GetNode(3)+1 <<" "<< + geometry->elem[iElem]->GetNode(4)+1 <<" "<< geometry->elem[iElem]->GetNode(4)+1 <<" "<< + geometry->elem[iElem]->GetNode(4)+1 <<" "<< geometry->elem[iElem]->GetNode(4)+1 << endl; + } + if (geometry->elem[iElem]->GetVTK_Type() == PRISM) { + Tecplot_File << + geometry->elem[iElem]->GetNode(0)+1 <<" "<< geometry->elem[iElem]->GetNode(1)+1 <<" "<< + geometry->elem[iElem]->GetNode(1)+1 <<" "<< geometry->elem[iElem]->GetNode(2)+1 <<" "<< + geometry->elem[iElem]->GetNode(3)+1 <<" "<< geometry->elem[iElem]->GetNode(4)+1 <<" "<< + geometry->elem[iElem]->GetNode(4)+1 <<" "<< geometry->elem[iElem]->GetNode(5)+1 << endl; + } + } + + Tecplot_File.close(); + + } + + +#ifdef HAVE_MPI + + /*--- Add solution files to a single file ---*/ + + if (rank == MASTER_NODE) { + + ofstream Tecplot_File; + string filename, text_line; + char buffer_char[50], out_file[MAX_STRING_SIZE]; + + if (!config->GetAdjoint()) { + if (surf_sol) filename = config->GetSurfFlowCoeff_FileName(); + else filename = config->GetFlow_FileName(); + } + else { + if (surf_sol) filename = config->GetSurfAdjCoeff_FileName(); + else filename = config->GetAdj_FileName(); + } + + strcpy(mesh_filename, filename.c_str()); + SPRINTF (buffer_char, ".dat"); + strcat(mesh_filename, buffer_char); + + Tecplot_File.open(mesh_filename, ios::out); + + for (int iRank = 0; iRank < size; iRank++) { + + if (!config->GetAdjoint()) { + if (surf_sol) filename = config->GetSurfFlowCoeff_FileName(); + else filename = config->GetFlow_FileName(); + } + else { + if (surf_sol) filename = config->GetSurfAdjCoeff_FileName(); + else filename = config->GetAdj_FileName(); + } + + strcpy(out_file, filename.c_str()); + SPRINTF (buffer_char, "_%i.dat", iRank+1); + strcat(out_file, buffer_char); + ifstream Tecplot_File_; + Tecplot_File_.open(out_file, ios::in); + while (getline (Tecplot_File_, text_line)) { + Tecplot_File << text_line << endl; + } + Tecplot_File_.close(); + remove (out_file); + } + + Tecplot_File.close(); + + } + +#endif + +} + +void COutput::SetTecplotASCII_Mesh(CConfig *config, CGeometry *geometry, bool surf_sol, bool new_file) { + + unsigned short iDim, nDim = geometry->GetnDim(); + unsigned long iPoint, iElem, iNode; + unsigned long *LocalIndex = NULL; + bool *SurfacePoint = NULL; + char cstr[200]; + ofstream Tecplot_File; + + if (surf_sol) strcpy(cstr, "surface_grid.dat"); + else strcpy(cstr, "volumetric_grid.dat"); + + /*--- Open Tecplot ASCII file and write the header. ---*/ + + if (new_file) { + Tecplot_File.open(cstr, ios::out); + Tecplot_File.precision(6); + if (surf_sol) Tecplot_File << "TITLE = \"Visualization of the surface solution\"" << endl; + else Tecplot_File << "TITLE = \"Visualization of the volumetric solution\"" << endl; + + if (nDim == 2) Tecplot_File << "VARIABLES = \"x\",\"y\""; + else Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\""; + } + else Tecplot_File.open(cstr, ios::out | ios::app); + Tecplot_File << endl; + + /*--- If it's a surface output, print only the points + that are in the element list, change the numbering ---*/ + + if (surf_sol) { + + LocalIndex = new unsigned long [nGlobal_Poin+1]; + SurfacePoint = new bool [nGlobal_Poin+1]; + + for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) SurfacePoint[iPoint] = false; + + for (iElem = 0; iElem < nGlobal_Line; iElem++) { + iNode = iElem*N_POINTS_LINE; + SurfacePoint[Conn_Line[iNode+0]] = true; + SurfacePoint[Conn_Line[iNode+1]] = true; + } + for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { + iNode = iElem*N_POINTS_TRIANGLE; + SurfacePoint[Conn_BoundTria[iNode+0]] = true; + SurfacePoint[Conn_BoundTria[iNode+1]] = true; + SurfacePoint[Conn_BoundTria[iNode+2]] = true; + } + for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { + iNode = iElem*N_POINTS_QUADRILATERAL; + SurfacePoint[Conn_BoundQuad[iNode+0]] = true; + SurfacePoint[Conn_BoundQuad[iNode+1]] = true; + SurfacePoint[Conn_BoundQuad[iNode+2]] = true; + SurfacePoint[Conn_BoundQuad[iNode+3]] = true; + } + + nSurf_Poin = 0; + for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) { + LocalIndex[iPoint] = 0; + if (SurfacePoint[iPoint]) { nSurf_Poin++; LocalIndex[iPoint] = nSurf_Poin; } + } + + } + + /*--- Write the header ---*/ + + Tecplot_File << "ZONE T= "; + if (new_file) Tecplot_File << "\"Original grid\", C=BLACK, "; + else Tecplot_File << "\"Deformed grid\", C=RED, "; + + if (nDim == 2) { + if (surf_sol) Tecplot_File << "NODES= "<< nSurf_Poin <<", ELEMENTS= "<< nSurf_Elem <<", DATAPACKING=POINT, ZONETYPE=FELINESEG"<< endl; + else Tecplot_File << "NODES= "<< nGlobal_Poin <<", ELEMENTS= "<< nGlobal_Elem <<", DATAPACKING=POINT, ZONETYPE=FEQUADRILATERAL"<< endl; + } else { + if (surf_sol) Tecplot_File << "NODES= "<< nSurf_Poin<<", ELEMENTS= "<< nSurf_Elem <<", DATAPACKING=POINT, ZONETYPE=FEQUADRILATERAL"<< endl; + else Tecplot_File << "NODES= "<< nGlobal_Poin <<", ELEMENTS= "<< nGlobal_Elem <<", DATAPACKING=POINT, ZONETYPE=FEBRICK"<< endl; + } + + /*--- Write surface and volumetric solution data. ---*/ + + for (iPoint = 0; iPoint < nGlobal_Poin; iPoint++) { + + if (surf_sol) { + + if (LocalIndex[iPoint+1] != 0) { + + /*--- Write the node coordinates ---*/ + for (iDim = 0; iDim < nDim; iDim++) + Tecplot_File << scientific << Coords[iDim][iPoint] << "\t"; + + Tecplot_File << endl; + + } + + } else { + + /*--- Write the node coordinates ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + Tecplot_File << scientific << Coords[iDim][iPoint] << "\t"; + + + Tecplot_File << endl; + + } + + } + + + /*--- Write connectivity data. ---*/ + + if (surf_sol) { + + for (iElem = 0; iElem < nGlobal_Line; iElem++) { + iNode = iElem*N_POINTS_LINE; + Tecplot_File << LocalIndex[Conn_Line[iNode+0]] << "\t"; + Tecplot_File << LocalIndex[Conn_Line[iNode+1]] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { + iNode = iElem*N_POINTS_TRIANGLE; + Tecplot_File << LocalIndex[Conn_BoundTria[iNode+0]] << "\t"; + Tecplot_File << LocalIndex[Conn_BoundTria[iNode+1]] << "\t"; + Tecplot_File << LocalIndex[Conn_BoundTria[iNode+2]] << "\t"; + Tecplot_File << LocalIndex[Conn_BoundTria[iNode+2]] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { + iNode = iElem*N_POINTS_QUADRILATERAL; + Tecplot_File << LocalIndex[Conn_BoundQuad[iNode+0]] << "\t"; + Tecplot_File << LocalIndex[Conn_BoundQuad[iNode+1]] << "\t"; + Tecplot_File << LocalIndex[Conn_BoundQuad[iNode+2]] << "\t"; + Tecplot_File << LocalIndex[Conn_BoundQuad[iNode+3]] << "\n"; + } + + } else { + + for (iElem = 0; iElem < nGlobal_Tria; iElem++) { + iNode = iElem*N_POINTS_TRIANGLE; + Tecplot_File << Conn_Tria[iNode+0] << "\t"; + Tecplot_File << Conn_Tria[iNode+1] << "\t"; + Tecplot_File << Conn_Tria[iNode+2] << "\t"; + Tecplot_File << Conn_Tria[iNode+2] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Quad; iElem++) { + iNode = iElem*N_POINTS_QUADRILATERAL; + Tecplot_File << Conn_Quad[iNode+0] << "\t"; + Tecplot_File << Conn_Quad[iNode+1] << "\t"; + Tecplot_File << Conn_Quad[iNode+2] << "\t"; + Tecplot_File << Conn_Quad[iNode+3] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Tetr; iElem++) { + iNode = iElem*N_POINTS_TETRAHEDRON; + Tecplot_File << Conn_Tetr[iNode+0] << "\t" << Conn_Tetr[iNode+1] << "\t"; + Tecplot_File << Conn_Tetr[iNode+2] << "\t" << Conn_Tetr[iNode+2] << "\t"; + Tecplot_File << Conn_Tetr[iNode+3] << "\t" << Conn_Tetr[iNode+3] << "\t"; + Tecplot_File << Conn_Tetr[iNode+3] << "\t" << Conn_Tetr[iNode+3] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Hexa; iElem++) { + iNode = iElem*N_POINTS_HEXAHEDRON; + Tecplot_File << Conn_Hexa[iNode+0] << "\t" << Conn_Hexa[iNode+1] << "\t"; + Tecplot_File << Conn_Hexa[iNode+2] << "\t" << Conn_Hexa[iNode+3] << "\t"; + Tecplot_File << Conn_Hexa[iNode+4] << "\t" << Conn_Hexa[iNode+5] << "\t"; + Tecplot_File << Conn_Hexa[iNode+6] << "\t" << Conn_Hexa[iNode+7] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Pris; iElem++) { + iNode = iElem*N_POINTS_PRISM; + Tecplot_File << Conn_Pris[iNode+0] << "\t" << Conn_Pris[iNode+1] << "\t"; + Tecplot_File << Conn_Pris[iNode+1] << "\t" << Conn_Pris[iNode+2] << "\t"; + Tecplot_File << Conn_Pris[iNode+3] << "\t" << Conn_Pris[iNode+4] << "\t"; + Tecplot_File << Conn_Pris[iNode+4] << "\t" << Conn_Pris[iNode+5] << "\n"; + } + + for (iElem = 0; iElem < nGlobal_Pyra; iElem++) { + iNode = iElem*N_POINTS_PYRAMID; + Tecplot_File << Conn_Pyra[iNode+0] << "\t" << Conn_Pyra[iNode+1] << "\t"; + Tecplot_File << Conn_Pyra[iNode+2] << "\t" << Conn_Pyra[iNode+3] << "\t"; + Tecplot_File << Conn_Pyra[iNode+4] << "\t" << Conn_Pyra[iNode+4] << "\t"; + Tecplot_File << Conn_Pyra[iNode+4] << "\t" << Conn_Pyra[iNode+4] << "\n"; + } + } + + Tecplot_File.close(); + + if (surf_sol) delete [] LocalIndex; + +} + +void COutput::SetTecplotBinary_DomainMesh(CConfig *config, CGeometry *geometry, unsigned short val_iZone) { + +#ifdef HAVE_TECIO + + passivedouble t; + INTEGER4 i, err, Debug, NPts, NElm, IsDouble, KMax; + INTEGER4 ICellMax, JCellMax, KCellMax, ZoneType, StrandID, ParentZn, FileType; + INTEGER4 *ShareFromZone = NULL, IsBlock, NumFaceConnections, FaceNeighborMode, ShareConnectivityFromZone; + string buffer, variables; + stringstream file; + bool first_zone = true; + unsigned short dims = geometry->GetnDim(); + enum FileType { FULL = 0, GRID = 1, SOLUTION = 2 }; + enum ZoneType { ORDERED=0, FELINESEG=1, FETRIANGLE=2, FEQUADRILATERAL=3, FETETRAHEDRON=4, FEBRICK=5, FEPOLYGON=6, FEPOLYHEDRON=7 }; + + /*--- Consistent data for Tecplot zones ---*/ + + Debug = 0; + IsDouble = 1; + NPts = (INTEGER4)nGlobal_Poin; + t = 0.0;//iExtIter*config->GetDelta_UnstTimeND(); + KMax = 0; + ICellMax = 0; + JCellMax = 0; + KCellMax = 0; + StrandID = 0;//(INTEGER4)iExtIter; + ParentZn = 0; + IsBlock = 1; + NumFaceConnections = 0; + FaceNeighborMode = 0; + ShareConnectivityFromZone = 0; + + /*--- Write Tecplot solution file ---*/ + + if (!wrote_base_file) { + + file.str(string()); + buffer = config->GetFlow_FileName(); + + file << buffer << ".mesh.plt"; + FileType = GRID; + + if (dims == 2) variables = "x y"; + else if (dims == 3) variables = "x y z"; + else cout << "Error: wrong number of dimensions: " << dims << endl; + + /*--- Open Tecplot file ---*/ + + err = TECINI112((char *)config->GetFlow_FileName().c_str(), + (char *)variables.c_str(), + (char *)file.str().c_str(), + (char *)".", + &FileType, + &Debug, + &IsDouble); + if (err) cout << "Error in opening Tecplot file" << endl; + + first_zone = true; +// ShareFromZone = new INTEGER4[dims]; +// for (i = 0; i < dims; i++) ShareFromZone[i] = 0; + + if (nGlobal_Tria > 0) { + + /*--- Write the zone header information ---*/ + ZoneType = FETRIANGLE; NElm = (INTEGER4)nGlobal_Tria; + + err = TECZNE112((char*)"Triangle Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + ShareFromZone, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + + if (first_zone) { + + ShareFromZone = new INTEGER4[dims]; + for (i = 0; i < dims; i++) ShareFromZone[i] = 0; + + if (config->GetKind_SU2() == SU2_SOL) { + err = TECDAT112(&NPts, Data[0], &IsDouble); ShareFromZone[0] = 1; + err = TECDAT112(&NPts, Data[1], &IsDouble); ShareFromZone[1] = 1; + if (geometry->GetnDim() == 3) { + err = TECDAT112(&NPts, Data[2], &IsDouble); + ShareFromZone[2] = 1; + } + } else { + err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[0] = 1; + err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[1] = 1; + if (geometry->GetnDim() == 3) { + err = TECDAT112(&NPts, Coords[2], &IsDouble); + ShareFromZone[2] = 1; + } + } + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + first_zone = false; + } + + err = TECNOD112(Conn_Tria); + if (err) cout << "Error writing connectivity to Tecplot file" << endl; + + } + if (nGlobal_Quad > 0) { + + /*--- Write the zone header information ---*/ + + ZoneType = FEQUADRILATERAL; NElm = (INTEGER4)nGlobal_Quad; + + err = TECZNE112((char*)"Quadrilateral Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + ShareFromZone, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + + if (first_zone) { + + ShareFromZone = new INTEGER4[dims]; + for (i = 0; i < dims; i++) ShareFromZone[i] = 0; + + if (config->GetKind_SU2() == SU2_SOL) { + err = TECDAT112(&NPts, Data[0], &IsDouble); ShareFromZone[0] = 1; + err = TECDAT112(&NPts, Data[1], &IsDouble); ShareFromZone[1] = 1; + if (geometry->GetnDim() == 3) { + err = TECDAT112(&NPts, Data[2], &IsDouble); + ShareFromZone[2] = 1; + } + } else { + err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[0] = 1; + err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[1] = 1; + if (geometry->GetnDim() == 3) { + err = TECDAT112(&NPts, Coords[2], &IsDouble); + ShareFromZone[2] = 1; + } + } + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + first_zone = false; + } + + err = TECNOD112(Conn_Quad); + if (err) cout << "Error writing connectivity to Tecplot file" << endl; + + } + if (nGlobal_Tetr > 0) { + + /*--- Write the zone header information ---*/ + + ZoneType = FETETRAHEDRON; NElm = (INTEGER4)nGlobal_Tetr; + + err = TECZNE112((char*)"Tetrahedral Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + ShareFromZone, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + + if (first_zone) { + + ShareFromZone = new INTEGER4[dims]; + for (i = 0; i < dims; i++) ShareFromZone[i] = 0; + + if (config->GetKind_SU2() == SU2_SOL) { + err = TECDAT112(&NPts, Data[0], &IsDouble); ShareFromZone[0] = 1; + err = TECDAT112(&NPts, Data[1], &IsDouble); ShareFromZone[1] = 1; + if (geometry->GetnDim() == 3) { + err = TECDAT112(&NPts, Data[2], &IsDouble); + ShareFromZone[2] = 1; + } + } else { + err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[0] = 1; + err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[1] = 1; + if (geometry->GetnDim() == 3) { + err = TECDAT112(&NPts, Coords[2], &IsDouble); + ShareFromZone[2] = 1; + } + } + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + first_zone = false; + } + + err = TECNOD112(Conn_Tetr); + if (err) cout << "Error writing connectivity to Tecplot file" << endl; + + } + if (nGlobal_Hexa > 0) { + + /*--- Write the zone header information ---*/ + + ZoneType = FEBRICK; NElm = (INTEGER4)nGlobal_Hexa; + + err = TECZNE112((char*)"Hexahedral Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + ShareFromZone, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + + if (first_zone) { + + ShareFromZone = new INTEGER4[dims]; + for (i = 0; i < dims; i++) ShareFromZone[i] = 0; + + if (config->GetKind_SU2() == SU2_SOL) { + err = TECDAT112(&NPts, Data[0], &IsDouble); ShareFromZone[0] = 1; + err = TECDAT112(&NPts, Data[1], &IsDouble); ShareFromZone[1] = 1; + if (geometry->GetnDim() == 3) { + err = TECDAT112(&NPts, Data[2], &IsDouble); + ShareFromZone[2] = 1; + } + } else { + err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[0] = 1; + err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[1] = 1; + if (geometry->GetnDim() == 3) { + err = TECDAT112(&NPts, Coords[2], &IsDouble); + ShareFromZone[2] = 1; + } + } + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + first_zone = false; + } + + err = TECNOD112(Conn_Hexa); + if (err) cout << "Error writing connectivity to Tecplot file" << endl; + + } + + if (nGlobal_Pyra > 0) { + + /*--- Here, we reuse the hex implementation to write pyramid elements. + Write the zone header information. ---*/ + ZoneType = FEBRICK; NElm = (INTEGER4)nGlobal_Pyra; + + err = TECZNE112((char*)"Pyramid Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + ShareFromZone, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + + if (first_zone) { + + ShareFromZone = new INTEGER4[dims]; + for (i = 0; i < dims; i++) ShareFromZone[i] = 0; + + if (config->GetKind_SU2() == SU2_SOL) { + err = TECDAT112(&NPts, Data[0], &IsDouble); ShareFromZone[0] = 1; + err = TECDAT112(&NPts, Data[1], &IsDouble); ShareFromZone[1] = 1; + if (geometry->GetnDim() == 3) { + err = TECDAT112(&NPts, Data[2], &IsDouble); + ShareFromZone[2] = 1; + } + } else { + err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[0] = 1; + err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[1] = 1; + if (geometry->GetnDim() == 3) { + err = TECDAT112(&NPts, Coords[2], &IsDouble); + ShareFromZone[2] = 1; + } + } + if (err) cout << "Error writing grid coordinates to Tecplot file" << endl; + first_zone = false; + } + + /*--- Convert the pyramid connectivity from 5 nodes to 8 nodes for FEBRICK ---*/ + int *Conn_Pyra_Mod = new int[nGlobal_Pyra*N_POINTS_HEXAHEDRON]; + unsigned long iNode_Pyra, iNode_Hexa; + for (unsigned long iElem = 0; iElem < nGlobal_Pyra; iElem++) { + iNode_Pyra = iElem*N_POINTS_PYRAMID; + iNode_Hexa = iElem*N_POINTS_HEXAHEDRON; + Conn_Pyra_Mod[iNode_Hexa+0] = Conn_Pyra[iNode_Pyra+4]; + Conn_Pyra_Mod[iNode_Hexa+1] = Conn_Pyra[iNode_Pyra+4]; + Conn_Pyra_Mod[iNode_Hexa+2] = Conn_Pyra[iNode_Pyra+4]; + Conn_Pyra_Mod[iNode_Hexa+3] = Conn_Pyra[iNode_Pyra+4]; + Conn_Pyra_Mod[iNode_Hexa+4] = Conn_Pyra[iNode_Pyra+0]; + Conn_Pyra_Mod[iNode_Hexa+5] = Conn_Pyra[iNode_Pyra+1]; + Conn_Pyra_Mod[iNode_Hexa+6] = Conn_Pyra[iNode_Pyra+2]; + Conn_Pyra_Mod[iNode_Hexa+7] = Conn_Pyra[iNode_Pyra+3]; + } + err = TECNOD112(Conn_Pyra_Mod); + if (err) cout << "Error writing pyramid connectivity to Tecplot file" << endl; + delete [] Conn_Pyra_Mod; + + } + + if (nGlobal_Pris > 0) { + + /*--- Here, we reuse the hex implementation to write prism elements. + Write the zone header information ---*/ + ZoneType = FEBRICK; NElm = (INTEGER4)nGlobal_Pris; + + err = TECZNE112((char*)"Prism Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + ShareFromZone, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + + if (first_zone) { + + ShareFromZone = new INTEGER4[dims]; + for (i = 0; i < dims; i++) ShareFromZone[i] = 0; + + if (config->GetKind_SU2() == SU2_SOL) { + err = TECDAT112(&NPts, Data[0], &IsDouble); ShareFromZone[0] = 1; + err = TECDAT112(&NPts, Data[1], &IsDouble); ShareFromZone[1] = 1; + if (geometry->GetnDim() == 3) { + err = TECDAT112(&NPts, Data[2], &IsDouble); + ShareFromZone[2] = 1; + } + } else { + err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[0] = 1; + err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[1] = 1; + if (geometry->GetnDim() == 3) { + err = TECDAT112(&NPts, Coords[2], &IsDouble); + ShareFromZone[2] = 1; + } + } + if (err) cout << "Error writing grid coordinates to Tecplot file" << endl; + first_zone = false; + } + + /*--- Convert the prism connectivity from 6 nodes to 8 nodes for FEBRICK ---*/ + int *Conn_Pris_Mod = new int[nGlobal_Pris*N_POINTS_HEXAHEDRON]; + unsigned long iNode_Pris, iNode_Hexa; + for (unsigned long iElem = 0; iElem < nGlobal_Pris; iElem++) { + iNode_Pris = iElem*N_POINTS_PRISM; + iNode_Hexa = iElem*N_POINTS_HEXAHEDRON; + Conn_Pris_Mod[iNode_Hexa+0] = Conn_Pris[iNode_Pris+0]; + Conn_Pris_Mod[iNode_Hexa+1] = Conn_Pris[iNode_Pris+0]; + Conn_Pris_Mod[iNode_Hexa+2] = Conn_Pris[iNode_Pris+1]; + Conn_Pris_Mod[iNode_Hexa+3] = Conn_Pris[iNode_Pris+2]; + Conn_Pris_Mod[iNode_Hexa+4] = Conn_Pris[iNode_Pris+3]; + Conn_Pris_Mod[iNode_Hexa+5] = Conn_Pris[iNode_Pris+3]; + Conn_Pris_Mod[iNode_Hexa+6] = Conn_Pris[iNode_Pris+4]; + Conn_Pris_Mod[iNode_Hexa+7] = Conn_Pris[iNode_Pris+5]; + } + err = TECNOD112(Conn_Pris_Mod); + if (err) cout << "Error writing prism connectivity to Tecplot file" << endl; + delete [] Conn_Pris_Mod; + + } + + delete [] ShareFromZone; + wrote_base_file = true; + + err = TECEND112(); + if (err) cout << "Error in closing Tecplot file" << endl; + + } + +#endif + +} + +void COutput::SetTecplotBinary_DomainSolution(CConfig *config, CGeometry *geometry, unsigned short val_iZone) { + +#ifdef HAVE_TECIO + + passivedouble t; + INTEGER4 i, iVar, err, Debug, NPts, NElm, IsDouble, KMax; + INTEGER4 ICellMax, JCellMax, KCellMax, ZoneType, StrandID, ParentZn, FileType; + INTEGER4 *ShareFromZone = NULL, IsBlock, NumFaceConnections, FaceNeighborMode, ShareConnectivityFromZone; + string buffer, variables; + stringstream file; + bool first_zone = true, unsteady = config->GetUnsteady_Simulation(), GridMovement = config->GetGrid_Movement(); + bool Wrt_Unsteady = config->GetWrt_Unsteady(); + unsigned long iExtIter = config->GetExtIter(); + unsigned short NVar, dims = geometry->GetnDim(); + enum FileType { FULL = 0, GRID = 1, SOLUTION = 2 }; + enum ZoneType { ORDERED=0, FELINESEG=1, FETRIANGLE=2, FEQUADRILATERAL=3, FETETRAHEDRON=4, FEBRICK=5, FEPOLYGON=6, FEPOLYHEDRON=7 }; + + /*--- Consistent data for Tecplot zones ---*/ + Debug = 0; + IsDouble = 1; + NPts = (INTEGER4)nGlobal_Poin; + t = SU2_TYPE::GetValue(iExtIter*config->GetDelta_UnstTime()); + KMax = 0; + ICellMax = 0; + JCellMax = 0; + KCellMax = 0; + StrandID = (INTEGER4)iExtIter+1; + ParentZn = 0; + IsBlock = 1; + NumFaceConnections = 0; + FaceNeighborMode = 0; + ShareConnectivityFromZone = 0; + + file.str(string()); + buffer = config->GetFlow_FileName(); + + file << buffer; + + if (unsteady) { + if (((int)iExtIter >= 0) && ((int)iExtIter < 10)) file << "_0000" << iExtIter; + if (((int)iExtIter >= 10) && ((int)iExtIter < 100)) file << "_000" << iExtIter; + if (((int)iExtIter >= 100) && ((int)iExtIter < 1000)) file << "_00" << iExtIter; + if (((int)iExtIter >= 1000) && ((int)iExtIter < 10000)) file << "_0" << iExtIter; + if ((int)iExtIter >= 10000) file << iExtIter; + } + file << ".sol.plt"; + FileType = SOLUTION; + variables = AssembleVariableNames(geometry, config, nVar_Consv, &NVar); + if (config->GetKind_SU2() == SU2_SOL) { + if (Wrt_Unsteady && GridMovement) nVar_Total = NVar; + else nVar_Total = NVar+dims; + } + + /*--- Open Tecplot file ---*/ + err = TECINI112((char *)config->GetFlow_FileName().c_str(), + (char *)variables.c_str(), + (char *)file.str().c_str(), + (char *)".", + &FileType, + &Debug, + &IsDouble); + if (err) cout << "Error in opening Tecplot file" << endl; + +// first_zone = true; +// ShareFromZone = new INTEGER4[NVar]; +// for (i = 0; i < NVar; i++) ShareFromZone[i] = 0; + + if (nGlobal_Tria > 0) { + + /*--- Write the zone header information ---*/ + ZoneType = FETRIANGLE; NElm = (INTEGER4)nGlobal_Tria; + + err = TECZNE112((char*)"Triangle Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + ShareFromZone, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + if (first_zone) { + + ShareFromZone = new INTEGER4[NVar]; + for (i = 0; i < NVar; i++) ShareFromZone[i] = 0; + + i = 0; + if (config->GetKind_SU2() == SU2_SOL) { + if (Wrt_Unsteady && GridMovement) { + for (iVar = 0; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } else { + for (iVar = dims; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + } else { + + if (Wrt_Unsteady && GridMovement) { + + err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + if (dims == 3) { + err = TECDAT112(&NPts, Coords[2], &IsDouble); + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + ShareFromZone[i++] = 1; + } + } + + for (iVar = 0; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + first_zone = false; + } + + } + if (nGlobal_Quad > 0) { + + /*--- Write the zone header information ---*/ + ZoneType = FEQUADRILATERAL; NElm = (INTEGER4)nGlobal_Quad; + + err = TECZNE112((char*)"Quadrilateral Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + ShareFromZone, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + if (first_zone) { + + ShareFromZone = new INTEGER4[NVar]; + for (i = 0; i < NVar; i++) ShareFromZone[i] = 0; + + i = 0; + if (config->GetKind_SU2() == SU2_SOL) { + if (Wrt_Unsteady && GridMovement) { + for (iVar = 0; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } else { + for (iVar = dims; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + } else { + if (Wrt_Unsteady && GridMovement) { + err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + if (dims == 3) { + err = TECDAT112(&NPts, Coords[2], &IsDouble); + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + ShareFromZone[i++] = 1; + } + } + for (iVar = 0; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + + first_zone = false; + } + + } + if (nGlobal_Tetr > 0) { + + /*--- Write the zone header information ---*/ + ZoneType = FETETRAHEDRON; NElm = (INTEGER4)nGlobal_Tetr; + + err = TECZNE112((char*)"Tetrahedral Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + ShareFromZone, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + if (first_zone) { + + ShareFromZone = new INTEGER4[NVar]; + for (i = 0; i < NVar; i++) ShareFromZone[i] = 0; + + i = 0; + if (config->GetKind_SU2() == SU2_SOL) { + if (Wrt_Unsteady && GridMovement) { + for (iVar = 0; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } else { + for (iVar = dims; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + } else { + if (Wrt_Unsteady && GridMovement) { + err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + if (dims == 3) { + err = TECDAT112(&NPts, Coords[2], &IsDouble); + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + ShareFromZone[i++] = 1; + } + } + for (iVar = 0; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + + first_zone = false; + } + + } + if (nGlobal_Hexa > 0) { + + /*--- Write the zone header information ---*/ + ZoneType = FEBRICK; NElm = (INTEGER4)nGlobal_Hexa; + + err = TECZNE112((char*)"Hexahedral Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + ShareFromZone, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + if (first_zone) { + + ShareFromZone = new INTEGER4[NVar]; + for (i = 0; i < NVar; i++) ShareFromZone[i] = 0; + + i = 0; + if (config->GetKind_SU2() == SU2_SOL) { + if (Wrt_Unsteady && GridMovement) { + for (iVar = 0; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } else { + for (iVar = dims; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + } else { + if (Wrt_Unsteady && GridMovement) { + err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + if (dims == 3) { + err = TECDAT112(&NPts, Coords[2], &IsDouble); + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + ShareFromZone[i++] = 1; + } + } + for (iVar = 0; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + + first_zone = false; + } + + } + if (nGlobal_Pyra > 0) { + + /*--- Write the zone header information ---*/ + ZoneType = FEBRICK; NElm = (INTEGER4)nGlobal_Pyra; + + err = TECZNE112((char*)"Pyramid Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + ShareFromZone, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + if (first_zone) { + + ShareFromZone = new INTEGER4[NVar]; + for (i = 0; i < NVar; i++) ShareFromZone[i] = 0; + + i = 0; + if (config->GetKind_SU2() == SU2_SOL) { + if (Wrt_Unsteady && GridMovement) { + for (iVar = 0; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } else { + for (iVar = dims; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + } else { + if (Wrt_Unsteady && GridMovement) { + err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + if (dims == 3) { + err = TECDAT112(&NPts, Coords[2], &IsDouble); + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + ShareFromZone[i++] = 1; + } + } + for (iVar = 0; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + + first_zone = false; + } + + } + if (nGlobal_Pris > 0) { + + /*--- Write the zone header information ---*/ + ZoneType = FEBRICK; NElm = (INTEGER4)nGlobal_Pris; + + err = TECZNE112((char*)"Prism Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + ShareFromZone, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + if (first_zone) { + + ShareFromZone = new INTEGER4[NVar]; + for (i = 0; i < NVar; i++) ShareFromZone[i] = 0; + + i = 0; + if (config->GetKind_SU2() == SU2_SOL) { + if (Wrt_Unsteady && GridMovement) { + for (iVar = 0; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } else { + for (iVar = dims; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + } else { + if (Wrt_Unsteady && GridMovement) { + err = TECDAT112(&NPts, Coords[0], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + err = TECDAT112(&NPts, Coords[1], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + if (dims == 3) { + err = TECDAT112(&NPts, Coords[2], &IsDouble); + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + ShareFromZone[i++] = 1; + } + } + for (iVar = 0; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + + first_zone = false; + } + } + + delete [] ShareFromZone; + + err = TECEND112(); + if (err) cout << "Error in closing Tecplot file" << endl; + +#endif + +} + +void COutput::SetTecplotBinary_SurfaceMesh(CConfig *config, CGeometry *geometry, unsigned short val_iZone) { + +#ifdef HAVE_TECIO + + passivedouble t; + INTEGER4 i, err, Debug, NPts, NElm, IsDouble, KMax; + INTEGER4 ICellMax, JCellMax, KCellMax, ZoneType, StrandID, ParentZn, FileType; + INTEGER4 *ShareFromZone, IsBlock, NumFaceConnections, FaceNeighborMode, ShareConnectivityFromZone; + string buffer, variables; + stringstream file; + bool first_zone = true; + unsigned short iDim, dims = geometry->GetnDim(); + unsigned long iPoint, iElem, iNode; + enum FileType { FULL = 0, GRID = 1, SOLUTION = 2 }; + enum ZoneType { ORDERED=0, FELINESEG=1, FETRIANGLE=2, FEQUADRILATERAL=3, FETETRAHEDRON=4, FEBRICK=5, FEPOLYGON=6, FEPOLYHEDRON=7 }; + + /*--- Write Tecplot solution file ---*/ + if (!wrote_surf_file) { + + file.str(string()); + buffer = config->GetSurfFlowCoeff_FileName(); + + file << buffer << ".mesh.plt"; + FileType = GRID; + + if (dims == 2) variables = "x y"; + else if (dims == 3) variables = "x y z"; + else cout << "Error: wrong number of dimensions: " << dims << endl; + + first_zone = true; + ShareFromZone = new INTEGER4[dims]; + for (i = 0; i < dims; i++) ShareFromZone[i] = 0; + + /*--- Perform a renumbering for the surface points/elements ---*/ + unsigned long *LocalIndex = new unsigned long [nGlobal_Poin+1]; + bool *SurfacePoint = new bool [nGlobal_Poin+1]; + + for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) SurfacePoint[iPoint] = false; + + for (iElem = 0; iElem < nGlobal_Line; iElem++) { + iNode = iElem*N_POINTS_LINE; + SurfacePoint[Conn_Line[iNode+0]] = true; + SurfacePoint[Conn_Line[iNode+1]] = true; + } + for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { + iNode = iElem*N_POINTS_TRIANGLE; + SurfacePoint[Conn_BoundTria[iNode+0]] = true; + SurfacePoint[Conn_BoundTria[iNode+1]] = true; + SurfacePoint[Conn_BoundTria[iNode+2]] = true; + } + for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { + iNode = iElem*N_POINTS_QUADRILATERAL; + SurfacePoint[Conn_BoundQuad[iNode+0]] = true; + SurfacePoint[Conn_BoundQuad[iNode+1]] = true; + SurfacePoint[Conn_BoundQuad[iNode+2]] = true; + SurfacePoint[Conn_BoundQuad[iNode+3]] = true; + } + + unsigned long nSurf_Poin = 0; + for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) { + LocalIndex[iPoint] = 0; + if (SurfacePoint[iPoint]) { nSurf_Poin++; LocalIndex[iPoint] = nSurf_Poin; } + } + + /*--- Collect surface coordinates into one array as well ---*/ + /*--- Note the -1 in the Coords/Data array in order to undo the 1-based indexing ---*/ + su2double **Surf_Coords = new su2double*[dims]; + for (iDim = 0; iDim < dims; iDim++) + Surf_Coords[iDim] = new su2double[nSurf_Poin]; + + unsigned long iSurf_Poin = 0; + for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) { + if (SurfacePoint[iPoint]) { + for (iDim = 0; iDim < dims; iDim++) { + if (config->GetKind_SU2() == SU2_SOL) + Surf_Coords[iDim][iSurf_Poin] = Data[iDim][iPoint-1]; + else + Surf_Coords[iDim][iSurf_Poin] = Coords[iDim][iPoint-1]; + } + iSurf_Poin++; + } + } + + /*--- Consistent data for Tecplot zones ---*/ + Debug = 0; + IsDouble = 1; + NPts = (INTEGER4)nSurf_Poin; + t = 0.0;//iExtIter*config->GetDelta_UnstTimeND(); + KMax = 0; + ICellMax = 0; + JCellMax = 0; + KCellMax = 0; + StrandID = 0;//(INTEGER4)iExtIter; + ParentZn = 0; + IsBlock = 1; + NumFaceConnections = 0; + FaceNeighborMode = 0; + ShareConnectivityFromZone = 0; + + /*--- Open Tecplot file ---*/ + err = TECINI112((char *)config->GetSurfFlowCoeff_FileName().c_str(), + (char *)variables.c_str(), + (char *)file.str().c_str(), + (char *)".", + &FileType, + &Debug, + &IsDouble); + if (err) cout << "Error in opening Tecplot file" << endl; + + + if (nGlobal_Line > 0) { + + /*--- Put the connectivity into a single array for writing ---*/ + int *Conn_Line_New = new int[nGlobal_Line*N_POINTS_LINE]; + iNode = 0; + for (iElem = 0; iElem < nGlobal_Line; iElem++) { + iNode = iElem*N_POINTS_LINE; + Conn_Line_New[iNode+0] = LocalIndex[Conn_Line[iNode+0]]; + Conn_Line_New[iNode+1] = LocalIndex[Conn_Line[iNode+1]]; + } + + /*--- Write the zone header information ---*/ + ZoneType = FELINESEG; NElm = (INTEGER4)nGlobal_Line; + + err = TECZNE112((char*)"Line Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + NULL, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + if (first_zone) { + + err = TECDAT112(&NPts, Surf_Coords[0], &IsDouble); ShareFromZone[0] = 1; + err = TECDAT112(&NPts, Surf_Coords[1], &IsDouble); ShareFromZone[1] = 1; + if (geometry->GetnDim() == 3) { + err = TECDAT112(&NPts, Surf_Coords[2], &IsDouble); + ShareFromZone[2] = 1; + } + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + first_zone = false; + } + + err = TECNOD112(Conn_Line_New); + if (err) cout << "Error writing connectivity to Tecplot file" << endl; + + delete [] Conn_Line_New; + } + + if (nGlobal_BoundTria > 0) { + + /*--- Put the connectivity into a single array for writing ---*/ + int *Conn_BoundTria_New = new int[nGlobal_BoundTria*N_POINTS_TRIANGLE]; + + iNode = 0; + for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { + iNode = iElem*N_POINTS_TRIANGLE; + Conn_BoundTria_New[iNode+0] = LocalIndex[Conn_BoundTria[iNode+0]]; + Conn_BoundTria_New[iNode+1] = LocalIndex[Conn_BoundTria[iNode+1]]; + Conn_BoundTria_New[iNode+2] = LocalIndex[Conn_BoundTria[iNode+2]]; + } + + /*--- Write the zone header information ---*/ + ZoneType = FETRIANGLE; NElm = (INTEGER4)nGlobal_BoundTria; + + err = TECZNE112((char*)"Triangle Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + ShareFromZone, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + if (first_zone) { + + err = TECDAT112(&NPts, Surf_Coords[0], &IsDouble); ShareFromZone[0] = 1; + err = TECDAT112(&NPts, Surf_Coords[1], &IsDouble); ShareFromZone[1] = 1; + if (geometry->GetnDim() == 3) { + err = TECDAT112(&NPts, Surf_Coords[2], &IsDouble); + ShareFromZone[2] = 1; + } + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + first_zone = false; + } + + err = TECNOD112(Conn_BoundTria_New); + if (err) cout << "Error writing connectivity to Tecplot file" << endl; + + delete [] Conn_BoundTria_New; + } + + if (nGlobal_BoundQuad > 0) { + + + /*--- Put the connectivity into a single array for writing ---*/ + int *Conn_BoundQuad_New = new int[nGlobal_BoundQuad*N_POINTS_QUADRILATERAL]; + iNode = 0; + for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { + iNode = iElem*N_POINTS_QUADRILATERAL; + Conn_BoundQuad_New[iNode+0] = LocalIndex[Conn_BoundQuad[iNode+0]]; + Conn_BoundQuad_New[iNode+1] = LocalIndex[Conn_BoundQuad[iNode+1]]; + Conn_BoundQuad_New[iNode+2] = LocalIndex[Conn_BoundQuad[iNode+2]]; + Conn_BoundQuad_New[iNode+3] = LocalIndex[Conn_BoundQuad[iNode+3]]; + } + + /*--- Write the zone header information ---*/ + ZoneType = FEQUADRILATERAL; NElm = (INTEGER4)nGlobal_BoundQuad; + + err = TECZNE112((char*)"Quadrilateral Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + ShareFromZone, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + if (first_zone) { + + err = TECDAT112(&NPts, Surf_Coords[0], &IsDouble); ShareFromZone[0] = 1; + err = TECDAT112(&NPts, Surf_Coords[1], &IsDouble); ShareFromZone[1] = 1; + if (geometry->GetnDim() == 3) { + err = TECDAT112(&NPts, Surf_Coords[2], &IsDouble); + ShareFromZone[2] = 1; + } + if (err) cout << "Error writing coordinates to Tecplot file" << endl; + first_zone = false; + } + + err = TECNOD112(Conn_BoundQuad_New); + if (err) cout << "Error writing connectivity to Tecplot file" << endl; + + delete [] Conn_BoundQuad_New; + } + + for (iDim = 0; iDim < dims; iDim++) + delete [] Surf_Coords[iDim]; + delete [] Surf_Coords; + delete [] ShareFromZone; + delete [] LocalIndex; + delete [] SurfacePoint; + wrote_surf_file = true; + + err = TECEND112(); + if (err) cout << "Error in closing Tecplot file" << endl; + + } + +#endif + +} + +void COutput::SetTecplotBinary_SurfaceSolution(CConfig *config, CGeometry *geometry, unsigned short val_iZone) { + +#ifdef HAVE_TECIO + + passivedouble t; + INTEGER4 i, iVar, err, Debug, NPts, NElm, IsDouble, KMax; + INTEGER4 ICellMax, JCellMax, KCellMax, ZoneType, StrandID, ParentZn, FileType; + INTEGER4 *ShareFromZone, IsBlock, NumFaceConnections, FaceNeighborMode, ShareConnectivityFromZone; + string buffer, variables; + stringstream file; + bool first_zone = true, unsteady = config->GetUnsteady_Simulation(), GridMovement = config->GetGrid_Movement(); + bool Wrt_Unsteady = config->GetWrt_Unsteady(); + unsigned long iPoint, iElem, iNode, iSurf_Poin, iExtIter = config->GetExtIter(); + unsigned short iDim, NVar, dims = geometry->GetnDim(); + enum FileType { FULL = 0, GRID = 1, SOLUTION = 2 }; + enum ZoneType { ORDERED=0, FELINESEG=1, FETRIANGLE=2, FEQUADRILATERAL=3, FETETRAHEDRON=4, FEBRICK=5, FEPOLYGON=6, FEPOLYHEDRON=7 }; + + + file.str(string()); + buffer = config->GetSurfFlowCoeff_FileName(); + + file << buffer; + + if (unsteady) { + if (((int)iExtIter >= 0) && ((int)iExtIter < 10)) file << "_0000" << iExtIter; + if (((int)iExtIter >= 10) && ((int)iExtIter < 100)) file << "_000" << iExtIter; + if (((int)iExtIter >= 100) && ((int)iExtIter < 1000)) file << "_00" << iExtIter; + if (((int)iExtIter >= 1000) && ((int)iExtIter < 10000)) file << "_0" << iExtIter; + if ((int)iExtIter >= 10000) file << iExtIter; + } + file << ".sol.plt"; + FileType = SOLUTION; + variables = AssembleVariableNames(geometry, config, nVar_Consv, &NVar); + if (config->GetKind_SU2() == SU2_SOL) { + if (Wrt_Unsteady && GridMovement) nVar_Total = NVar; + else nVar_Total = NVar+dims; + } + + first_zone = true; + ShareFromZone = new INTEGER4[NVar]; + for (i = 0; i < NVar; i++) ShareFromZone[i] = 0; + + + /*--- Perform a renumbering for the surface points/elements ---*/ + unsigned long *LocalIndex = new unsigned long [nGlobal_Poin+1]; + bool *SurfacePoint = new bool [nGlobal_Poin+1]; + + for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) SurfacePoint[iPoint] = false; + + for (iElem = 0; iElem < nGlobal_Line; iElem++) { + iNode = iElem*N_POINTS_LINE; + SurfacePoint[Conn_Line[iNode+0]] = true; + SurfacePoint[Conn_Line[iNode+1]] = true; + } + for (iElem = 0; iElem < nGlobal_BoundTria; iElem++) { + iNode = iElem*N_POINTS_TRIANGLE; + SurfacePoint[Conn_BoundTria[iNode+0]] = true; + SurfacePoint[Conn_BoundTria[iNode+1]] = true; + SurfacePoint[Conn_BoundTria[iNode+2]] = true; + } + for (iElem = 0; iElem < nGlobal_BoundQuad; iElem++) { + iNode = iElem*N_POINTS_QUADRILATERAL; + SurfacePoint[Conn_BoundQuad[iNode+0]] = true; + SurfacePoint[Conn_BoundQuad[iNode+1]] = true; + SurfacePoint[Conn_BoundQuad[iNode+2]] = true; + SurfacePoint[Conn_BoundQuad[iNode+3]] = true; + } + + unsigned long nSurf_Poin = 0; + for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) { + LocalIndex[iPoint] = 0; + if (SurfacePoint[iPoint]) { nSurf_Poin++; LocalIndex[iPoint] = nSurf_Poin; } + } + + /*--- Collect surface coordinates into one array as well ---*/ + /*--- Note the -1 in the Coords/Data array in order to undo the 1-based indexing ---*/ + su2double **Surf_Coords = NULL; + if (Wrt_Unsteady && GridMovement) { + Surf_Coords = new su2double*[dims]; + for (iDim = 0; iDim < dims; iDim++) + Surf_Coords[iDim] = new su2double[nSurf_Poin]; + + iSurf_Poin = 0; + for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) { + if (SurfacePoint[iPoint]) { + for (iDim = 0; iDim < dims; iDim++) { + if (config->GetKind_SU2() == SU2_SOL) + Surf_Coords[iDim][iSurf_Poin] = Data[iDim][iPoint-1]; + else + Surf_Coords[iDim][iSurf_Poin] = Coords[iDim][iPoint-1]; + } + iSurf_Poin++; + } + } + } + + /*--- Collect surface data into one array for the surface as well ---*/ + /*--- Note the -1 in the Coords/Data array in order to undo the 1-based indexing ---*/ + su2double **Surf_Data = new su2double*[nVar_Total]; + for (iVar = 0; iVar < nVar_Total; iVar++) + Surf_Data[iVar] = new su2double[nSurf_Poin]; + + iSurf_Poin = 0; + for (iPoint = 0; iPoint < nGlobal_Poin+1; iPoint++) { + if (SurfacePoint[iPoint]) { + for (iVar = 0; iVar < nVar_Total; iVar++) { + if (config->GetKind_SU2() == SU2_SOL) { + if (Wrt_Unsteady && GridMovement) + Surf_Data[iVar][iSurf_Poin] = Data[iVar][iPoint-1]; + else + Surf_Data[iVar][iSurf_Poin] = Data[iVar][iPoint-1]; + } else + Surf_Data[iVar][iSurf_Poin] = Data[iVar][iPoint-1]; + } + iSurf_Poin++; + } + } + + /*--- Consistent data for Tecplot zones ---*/ + Debug = 0; + IsDouble = 1; + NPts = (INTEGER4)nSurf_Poin; + t = SU2_TYPE::GetValue(iExtIter*config->GetDelta_UnstTime()); + KMax = 0; + ICellMax = 0; + JCellMax = 0; + KCellMax = 0; + StrandID = (INTEGER4)iExtIter+1; + ParentZn = 0; + IsBlock = 1; + NumFaceConnections = 0; + FaceNeighborMode = 0; + ShareConnectivityFromZone = 0; + + + /*--- Open Tecplot file ---*/ + err = TECINI112((char *)config->GetFlow_FileName().c_str(), + (char *)variables.c_str(), + (char *)file.str().c_str(), + (char *)".", + &FileType, + &Debug, + &IsDouble); + if (err) cout << "Error in opening Tecplot file" << endl; + + + if (nGlobal_Line > 0) { + + /*--- Write the zone header information ---*/ + ZoneType = FELINESEG; NElm = (INTEGER4)nGlobal_Line; + + err = TECZNE112((char*)"Line Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + ShareFromZone, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + if (first_zone) { + + i = 0; + if (config->GetKind_SU2() == SU2_SOL) { + if (Wrt_Unsteady && GridMovement) { + for (iDim = 0; iDim < dims; iDim++) { + err = TECDAT112(&NPts, Surf_Data[iDim], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + for (iVar = dims; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Surf_Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } else { + if (Wrt_Unsteady && GridMovement) { + for (iDim = 0; iDim < dims; iDim++) { + err = TECDAT112(&NPts, Surf_Coords[iDim], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + for (iVar = 0; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Surf_Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + first_zone = false; + } + + } + + if (nGlobal_BoundTria > 0) { + + /*--- Write the zone header information ---*/ + ZoneType = FETRIANGLE; NElm = (INTEGER4)nGlobal_BoundTria; + + err = TECZNE112((char*)"Triangle Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + ShareFromZone, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + if (first_zone) { + + i = 0; + if (config->GetKind_SU2() == SU2_SOL) { + if (Wrt_Unsteady && GridMovement) { + for (iDim = 0; iDim < dims; iDim++) { + err = TECDAT112(&NPts, Surf_Data[iDim], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + for (iVar = dims; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Surf_Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } else { + if (Wrt_Unsteady && GridMovement) { + for (iDim = 0; iDim < dims; iDim++) { + err = TECDAT112(&NPts, Surf_Coords[iDim], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + for (iVar = 0; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Surf_Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + first_zone = false; + } + + } + + if (nGlobal_BoundQuad > 0) { + + /*--- Write the zone header information ---*/ + ZoneType = FEQUADRILATERAL; NElm = (INTEGER4)nGlobal_BoundQuad; + + err = TECZNE112((char*)"Quadrilateral Elements", + &ZoneType, + &NPts, + &NElm, + &KMax, + &ICellMax, + &JCellMax, + &KCellMax, + &t, + &StrandID, + &ParentZn, + &IsBlock, + &NumFaceConnections, + &FaceNeighborMode, + 0, /* TotalNumFaceNodes */ + 0, /* NumConnectedBoundaryFaces */ + 0, /* TotalNumBoundaryConnections */ + NULL, /* PassiveVarList */ + NULL, /* ValueLocation */ + ShareFromZone, /* ShareVarFromZone */ + &ShareConnectivityFromZone); + if (err) cout << "Error writing Tecplot zone data" << endl; + + /*--- write node coordinates and data if not done already---*/ + if (first_zone) { + + i = 0; + if (config->GetKind_SU2() == SU2_SOL) { + if (Wrt_Unsteady && GridMovement) { + for (iDim = 0; iDim < dims; iDim++) { + err = TECDAT112(&NPts, Surf_Data[iDim], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + for (iVar = dims; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Surf_Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } else { + if (Wrt_Unsteady && GridMovement) { + for (iDim = 0; iDim < dims; iDim++) { + err = TECDAT112(&NPts, Surf_Coords[iDim], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + for (iVar = 0; iVar < nVar_Total; iVar++) { + err = TECDAT112(&NPts, Surf_Data[iVar], &IsDouble); ShareFromZone[i++] = 1; + if (err) cout << "Error writing data to Tecplot file" << endl; + } + } + first_zone = false; + } + + } + + for (iVar = 0; iVar < nVar_Total; iVar++) + delete [] Surf_Data[iVar]; + delete [] Surf_Data; + + if (Surf_Coords != NULL) { + for (iDim = 0; iDim < dims; iDim++) delete [] Surf_Coords[iDim]; + delete [] Surf_Coords; + } + delete [] LocalIndex; + delete [] SurfacePoint; + delete [] ShareFromZone; + + err = TECEND112(); + if (err) cout << "Error in closing Tecplot file" << endl; + +#endif + +} + +string COutput::AssembleVariableNames(CGeometry *geometry, CConfig *config, unsigned short nVar_Consv, unsigned short *NVar) { + + /*--- Local variables ---*/ + stringstream variables; variables.str(string()); + unsigned short iVar; + *NVar = 0; + unsigned short iDim, nDim = geometry->GetnDim(); + unsigned short Kind_Solver = config->GetKind_Solver(); + bool grid_movement = config->GetGrid_Movement(); + bool Wrt_Unsteady = config->GetWrt_Unsteady(); + + + /*--- Write the basic variable header based on the particular solution ----*/ + + /*--- Write the list of the fields in the restart file. + Without including the PointID---*/ + if (config->GetKind_SU2() == SU2_SOL) { + + /*--- If SU2_SOL called this routine, we already have a set of output + variables with the appropriate string tags stored in the config class. + We simply read in and remove the quotation marks from the var names. ---*/ + + /*--- Set the number of variables to be written. Subtract off an index for + the PointID as well as each coordinate (x, y, z). ---*/ + string varname; + + if (Wrt_Unsteady && grid_movement) { + + *NVar = config->fields.size()-1; + for (unsigned short iField = 1; iField < config->fields.size(); iField++) { + varname = config->fields[iField]; + varname.erase (varname.begin(), varname.begin()+1); + varname.erase (varname.end()-1, varname.end()); + variables << varname << " "; + } + } else { + + *NVar = config->fields.size()-1-nDim; + for (unsigned short iField = 1+nDim; iField < config->fields.size(); iField++) { + varname = config->fields[iField]; + varname.erase (varname.begin(), varname.begin()+1); + varname.erase (varname.end()-1, varname.end()); + variables << varname << " "; + } + } + + } else { + + if (Wrt_Unsteady && grid_movement) { + if (nDim == 2) { + variables << "x y "; *NVar += 2; + } else { + variables << "x y z "; *NVar += 3; + } + } + + for (iVar = 0; iVar < nVar_Consv; iVar++) { + variables << "Conservative_" << iVar+1<<" "; *NVar += 1; + } + if (config->GetWrt_Limiters()) { + for (iVar = 0; iVar < nVar_Consv; iVar++) { + variables << "Limiter_" << iVar+1<<" "; *NVar += 1; + } + } + if (config->GetWrt_Residuals()) { + for (iVar = 0; iVar < nVar_Consv; iVar++) { + variables << "Residual_" << iVar+1<<" "; *NVar += 1; + } + } + + /*--- Add names for any extra variables (this will need to be adjusted). ---*/ + if (grid_movement) { + if (nDim == 2) { + variables << "Grid_Velx Grid_Vely "; *NVar += 2; + } else { + variables << "Grid_Velx Grid_Vely Grid_Velz "; *NVar += 3; + } + } + + if (config->GetKind_Regime() == FREESURFACE) { + variables << "Density "; + *NVar += 1; + } + + if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + variables << "Pressure Temperature Pressure_Coefficient Mach "; + *NVar += 4; + } + + if ((Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + variables << "Laminar_Viscosity Skin_Friction_Coefficient Heat_Flux Y_Plus "; + *NVar += 4; + } + + if (Kind_Solver == RANS) { + variables << "Eddy_Viscosity "; + *NVar += 1; + } + + if (config->GetWrt_SharpEdges()) { + if ((Kind_Solver == EULER) || (Kind_Solver == NAVIER_STOKES) || (Kind_Solver == RANS)) { + variables << "Sharp_Edge_Dist "; + *NVar += 1; + } + } + + if (Kind_Solver == POISSON_EQUATION) { + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) { + variables << "poissonField_" << iDim+1 << " "; + *NVar += 1; + } + } + + if (( Kind_Solver == ADJ_EULER ) || + ( Kind_Solver == ADJ_NAVIER_STOKES ) || + ( Kind_Solver == ADJ_RANS ) ) { + variables << "Surface_Sensitivity Solution_Sensor "; + *NVar += 2; + } + } + + return variables.str(); + +} diff --git a/SU2_CFD/src/solver_adjoint_levelset.cpp b/SU2_CFD/src/solver_adjoint_levelset.cpp index 177fcc94ae1..bb2ed7aacd6 100644 --- a/SU2_CFD/src/solver_adjoint_levelset.cpp +++ b/SU2_CFD/src/solver_adjoint_levelset.cpp @@ -1,1105 +1,1105 @@ -/*! - * \file solution_adjoint_levelset.cpp - * \brief Main subrotuines for solving the level set problem. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/solver_structure.hpp" - -CAdjLevelSetSolver::CAdjLevelSetSolver(CGeometry *geometry, CConfig *config, unsigned short iMesh) : CSolver() { - unsigned short iVar, iDim, nLineLets; - unsigned long iPoint, index; - su2double dull_val; - ifstream restart_file; - string text_line, mesh_filename, filename, AdjExt; - - bool restart = config->GetRestart(); - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Define geometry constans in the solver structure ---*/ - nDim = geometry->GetnDim(); - node = new CVariable*[geometry->GetnPoint()]; - - /*--- Dimension of the problem ---*/ - nVar = 1; - - /*--- Single grid simulation ---*/ - if (iMesh == MESH_0) { - - /*--- Define some auxiliar vector related with the residual ---*/ - Residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; - Residual_RMS = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_RMS[iVar] = 0.0; - Residual_Max = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_Max[iVar] = 0.0; - Point_Max = new unsigned long[nVar]; for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; - Point_Max_Coord = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Point_Max_Coord[iVar] = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; - } - Residual_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_i[iVar] = 0.0; - Residual_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_j[iVar] = 0.0; - - /*--- Define some auxiliar vector related with the solution ---*/ - Solution = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; - Solution_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_i[iVar] = 0.0; - Solution_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_j[iVar] = 0.0; - - /*--- Define some auxiliar vector related with the geometry ---*/ - Vector = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = 0.0; - Vector_i = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_i[iDim] = 0.0; - Vector_j = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_j[iDim] = 0.0; - - /*--- Define some auxiliar vector related with the flow solution ---*/ - FlowSolution_i = new su2double[nDim+1]; for (iVar = 0; iVar < nDim+1; iVar++) FlowSolution_i[iVar] = 0.0; - FlowSolution_j = new su2double[nDim+1]; for (iVar = 0; iVar < nDim+1; iVar++) FlowSolution_j[iVar] = 0.0; - - /*--- Solution and residual vectors ---*/ - LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); - - /*--- Jacobians and vector structures for implicit computations ---*/ - if (config->GetKind_TimeIntScheme_AdjLevelSet() == EULER_IMPLICIT) { - - /*--- Point to point Jacobians ---*/ - Jacobian_i = new su2double* [nVar]; - Jacobian_j = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Jacobian_i[iVar] = new su2double [nVar]; - Jacobian_j[iVar] = new su2double [nVar]; - } - - Jacobian_ii = new su2double* [nVar]; - Jacobian_ij = new su2double* [nVar]; - Jacobian_ji = new su2double* [nVar]; - Jacobian_jj = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Jacobian_ii[iVar] = new su2double [nVar]; - Jacobian_ij[iVar] = new su2double [nVar]; - Jacobian_ji[iVar] = new su2double [nVar]; - Jacobian_jj[iVar] = new su2double [nVar]; - } - - /*--- Initialization of the structure of the whole Jacobian ---*/ - if (rank == MASTER_NODE) cout << "Initialize Jacobian structure (Adj. Level Set). MG level: 0." << endl; - Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); - - if ((config->GetKind_Linear_Solver_Prec() == LINELET) || - (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { - nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); - if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; - } - - } - - /*--- Computation of gradients by least squares ---*/ - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { - /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ - Smatrix = new su2double* [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Smatrix[iDim] = new su2double [nDim]; - /*--- c vector := transpose(WA)*(Wb) ---*/ - cvector = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - cvector[iVar] = new su2double [nDim]; - } - - } - - /*--- Restart the solution from file information ---*/ - if (!restart || (iMesh != MESH_0)) { - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - node[iPoint] = new CAdjLevelSetVariable(0.0, nDim, nVar, config); - } - - } - else { - - /*--- Restart the solution from file information ---*/ - mesh_filename = config->GetSolution_AdjFileName(); - filename = config->GetObjFunc_Extension(mesh_filename); - - restart_file.open(filename.data(), ios::in); - - if (restart_file.fail()) { - cout << "There is no level set restart file!!" << endl; - exit(EXIT_FAILURE); - } - - /*--- In case this is a parallel simulation, we need to perform the - Global2Local index transformation first. ---*/ - long *Global2Local; - Global2Local = new long[geometry->GetGlobal_nPointDomain()]; - /*--- First, set all indices to a negative value by default ---*/ - for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) { - Global2Local[iPoint] = -1; - } - /*--- Now fill array with the transform values only for local points ---*/ - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { - Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; - } - - /*--- Read all lines in the restart file ---*/ - long iPoint_Local; unsigned long iPoint_Global = 0; - - /*--- The first line is the header ---*/ - getline (restart_file, text_line); - - while (getline (restart_file, text_line)) { - istringstream point_line(text_line); - - /*--- Retrieve local index. If this node from the restart file lives - on a different processor, the value of iPoint_Local will be -1. - Otherwise, the local index for this node on the current processor - will be returned and used to instantiate the vars. ---*/ - iPoint_Local = Global2Local[iPoint_Global]; - if (iPoint_Local >= 0) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; - node[iPoint_Local] = new CAdjLevelSetVariable(Solution[0], nDim, nVar, config); - } - iPoint_Global++; - } - - /*--- Instantiate the variable class with an arbitrary solution - at any halo/periodic nodes. The initial solution can be arbitrary, - because a send/recv is performed immediately in the solver. ---*/ - for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { - node[iPoint] = new CAdjLevelSetVariable(Solution[0], nDim, nVar, config); - } - - /*--- Close the restart file ---*/ - restart_file.close(); - - /*--- Free memory needed for the transformation ---*/ - delete [] Global2Local; - } - - /*--- MPI solution ---*/ - Set_MPI_Solution(geometry, config); - - /*--- Compute the gradient (Mean flow source term) ---*/ - if (iMesh == MESH_0) { - if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); - } - -} - -CAdjLevelSetSolver::~CAdjLevelSetSolver(void) { } - -void CAdjLevelSetSolver::Set_MPI_Solution(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_U = new su2double [nBufferR_Vector]; - Buffer_Send_U = new su2double[nBufferS_Vector]; - - /*--- Copy the solution that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution(iVar); - } - -#ifdef HAVE_MPI - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_U; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = Buffer_Receive_U[iVar*nVertexR+iVertex]; - - /*--- Rotate the momentum components. ---*/ - if (nDim == 2) { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex]; - } - else { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex] + - rotMatrix[0][2]*Buffer_Receive_U[3*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex] + - rotMatrix[1][2]*Buffer_Receive_U[3*nVertexR+iVertex]; - Solution[3] = rotMatrix[2][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[2][1]*Buffer_Receive_U[2*nVertexR+iVertex] + - rotMatrix[2][2]*Buffer_Receive_U[3*nVertexR+iVertex]; - } - - /*--- Copy transformed conserved variables back into buffer. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetSolution(iVar, Solution[iVar]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_U; - - } - - } - -} - -void CAdjLevelSetSolver::Set_MPI_Solution_Limiter(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, - *Buffer_Receive_Limit = NULL, *Buffer_Send_Limit = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_Limit = new su2double [nBufferR_Vector]; - Buffer_Send_Limit = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_Limit[iVar*nVertexS+iVertex] = node[iPoint]->GetLimiter(iVar); - } - -#ifdef HAVE_MPI - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Limit, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_Limit, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_Limit[iVar*nVertexR+iVertex] = Buffer_Send_Limit[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_Limit; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = Buffer_Receive_Limit[iVar*nVertexR+iVertex]; - - /*--- Rotate the momentum components. ---*/ - if (nDim == 2) { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_Limit[2*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_Limit[2*nVertexR+iVertex]; - } - else { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + - rotMatrix[0][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + - rotMatrix[1][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; - Solution[3] = rotMatrix[2][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[2][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + - rotMatrix[2][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; - } - - /*--- Copy transformed conserved variables back into buffer. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetLimiter(iVar, Solution[iVar]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_Limit; - - } - - } -} - -void CAdjLevelSetSolver::Set_MPI_Solution_Gradient(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, - *Buffer_Receive_Gradient = NULL, *Buffer_Send_Gradient = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - su2double **Gradient = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - Gradient[iVar] = new su2double[nDim]; - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar*nDim; nBufferR_Vector = nVertexR*nVar*nDim; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_Gradient = new su2double [nBufferR_Vector]; - Buffer_Send_Gradient = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Gradient[iDim*nVar*nVertexS+iVar*nVertexS+iVertex] = node[iPoint]->GetGradient(iVar, iDim); - } - -#ifdef HAVE_MPI - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Gradient, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_Gradient, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex] = Buffer_Send_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_Gradient; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Gradient[iVar][iDim] = Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; - - /*--- Need to rotate the gradients for all conserved variables. ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - if (nDim == 2) { - Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; - } - else { - Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][2] = rotMatrix[2][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; - } - } - - /*--- Store the received information ---*/ - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - node[iPoint]->SetGradient(iVar, iDim, Gradient[iVar][iDim]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_Gradient; - - } - - } - - for (iVar = 0; iVar < nVar; iVar++) - delete [] Gradient[iVar]; - delete [] Gradient; - -} - -void CAdjLevelSetSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { - unsigned long iPoint; - - bool implicit = (config->GetKind_TimeIntScheme_AdjLevelSet() == EULER_IMPLICIT); - bool second_order = ((config->GetSpatialOrder_AdjLevelSet() == SECOND_ORDER) || (config->GetSpatialOrder_AdjLevelSet() == SECOND_ORDER_LIMITER)); - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) - LinSysRes.SetBlock_Zero(iPoint); - - /*--- Implicit part ---*/ - if (implicit) - Jacobian.SetValZero(); - - if (second_order) { - if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); - } - -} - -void CAdjLevelSetSolver::Upwind_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, unsigned short iMesh) { - su2double *LevelSet_var_i, *LevelSet_var_j, *U_i, *U_j, **Gradient_i, **Gradient_j, Project_Grad_i, Project_Grad_j, DensityInc_i, DensityInc_j; - unsigned long iEdge, iPoint, jPoint; - unsigned short iDim, iVar; - - bool implicit = (config->GetKind_TimeIntScheme_AdjLevelSet() == EULER_IMPLICIT); - bool second_order = ((config->GetSpatialOrder_AdjLevelSet() == SECOND_ORDER) || (config->GetSpatialOrder_AdjLevelSet() == SECOND_ORDER_LIMITER)); - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Points in edge and normal vectors ---*/ - iPoint = geometry->edge[iEdge]->GetNode(0); jPoint = geometry->edge[iEdge]->GetNode(1); - numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); - - /*--- Conservative variables w/o reconstruction ---*/ - U_i = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); - U_j = solver_container[FLOW_SOL]->node[jPoint]->GetSolution(); - numerics->SetConservative(U_i, U_j); - - /*--- Level Set variables w/o reconstruction ---*/ - LevelSet_var_i = node[iPoint]->GetSolution(); - LevelSet_var_j = node[jPoint]->GetSolution(); - numerics->SetLevelSetVar(LevelSet_var_i, LevelSet_var_j); - - /*--- Set the value of the density ---*/ - DensityInc_i = solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); - DensityInc_j = solver_container[FLOW_SOL]->node[jPoint]->GetDensityInc(); - numerics->SetDensityInc(DensityInc_i, DensityInc_j); - - if (second_order) { - - for (iDim = 0; iDim < nDim; iDim++) { - Vector_i[iDim] = 0.5*(geometry->node[jPoint]->GetCoord(iDim) - geometry->node[iPoint]->GetCoord(iDim)); - Vector_j[iDim] = 0.5*(geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim)); - } - - /*--- Level Set variables using gradient reconstruction ---*/ - Gradient_i = node[iPoint]->GetGradient(); Gradient_j = node[jPoint]->GetGradient(); - for (iVar = 0; iVar < nVar; iVar++) { - Project_Grad_i = 0.0; Project_Grad_j = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Project_Grad_i += Vector_i[iDim]*Gradient_i[iVar][iDim]; - Project_Grad_j += Vector_j[iDim]*Gradient_j[iVar][iDim]; - } - Solution_i[iVar] = LevelSet_var_i[iVar] + Project_Grad_i; - Solution_j[iVar] = LevelSet_var_j[iVar] + Project_Grad_j; - } - numerics->SetLevelSetVar(Solution_i, Solution_j); - - } - - numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - /*--- Add and subtract Residual ---*/ - LinSysRes.AddBlock(iPoint, Residual_i); - LinSysRes.AddBlock(jPoint, Residual_j); - - /*--- Implicit part ---*/ - if (implicit) { - Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); - Jacobian.AddBlock(iPoint, jPoint, Jacobian_ij); - Jacobian.AddBlock(jPoint, iPoint, Jacobian_ji); - Jacobian.AddBlock(jPoint, jPoint, Jacobian_jj); - } - - } -} - -void CAdjLevelSetSolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, - CConfig *config, unsigned short iMesh) { -// unsigned short iVar, iDim; -// unsigned long iPoint; -// su2double epsilon, DeltaDirac, lambda, dRho_dPhi, dMud_Phi, Vol, DiffLevelSet, LevelSet, *AdjMeanFlow, **AdjLevelSetGradient, **AdjMeanFlowGradient, -// Density, Velocity[3] = {0.0,0.0,0.0}, ProjAdj, dFc_dRho[3][4], ProjFlux; -// -// su2double Froude2 = config->GetFroude()*config->GetFroude(); -// -// for (iVar = 0; iVar < nVar; iVar++) -// Residual[iVar] = 0; -// -// /*--- loop over points ---*/ -// -// for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { -// -// Vol = geometry->node[iPoint]->GetVolume(); -// -// /*--- Direct problem quantities ---*/ -// -// DiffLevelSet = solver_container[LEVELSET_SOL]->node[iPoint]->GetDiffLevelSet(); -// LevelSet = solver_container[LEVELSET_SOL]->node[iPoint]->GetSolution(0); -// MeanFlow = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); -// Density = solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); -// -// /*--- Adjoint problem quantities ---*/ -// -// AdjMeanFlow = solver_container[ADJFLOW_SOL]->node[iPoint]->GetSolution(); -// AdjLevelSetGradient = solver_container[ADJLEVELSET_SOL]->node[iPoint]->GetGradient(); -// AdjMeanFlowGradient = solver_container[ADJFLOW_SOL]->node[iPoint]->GetGradient(); -// -// /*--- Projected adjoint velocity ---*/ -// -// ProjAdj = 0.0; -// for (iDim = 0; iDim < nDim; iDim++) { -// Velocity[iDim] = solver_container[FLOW_SOL]->node[iPoint]->GetVelocity(iDim); -// ProjAdj += Velocity[iDim]*AdjLevelSetGradient[0][iDim]; -// } -// -// /*--- Compute the flow solution using the level set value. ---*/ -// -// epsilon = config->GetFreeSurface_Thickness(); -// DeltaDirac = 0.0; -// if (fabs(LevelSet) <= epsilon) DeltaDirac = 1.0 - (0.5*(1.0+(LevelSet/epsilon)+(1.0/PI_NUMBER)*sin(PI_NUMBER*LevelSet/epsilon))); -// -// /*--- Set the value of the incompressible density for free surface flows (density ratio g/l) ---*/ -// -// lambda = config->GetRatioDensity(); -// dRho_dPhi = (1.0 - lambda)*DeltaDirac*config->GetDensity_FreeStreamND(); -// -// /*--- Set the value of the incompressible viscosity for free surface flows (viscosity ratio g/l) ---*/ -// -// lambda = config->GetRatioViscosity(); -// dMud_Phi = (1.0 - lambda)*DeltaDirac*config->GetViscosity_FreeStreamND(); -// -// /*--- Flux derivative ---*/ -// -// for (iDim = 0; iDim < nDim; iDim++) { -// dFc_dRho[iDim][0] = 0.0; -// dFc_dRho[iDim][1] = Velocity[iDim]*Velocity[0]; -// dFc_dRho[iDim][2] = Velocity[iDim]*Velocity[1]; -// dFc_dRho[iDim][3] = Velocity[iDim]*Velocity[2]; -// } -// -// /*--- Projected flux derivative ---*/ -// -// ProjFlux = 0.0; -// for (iDim = 0; iDim < nDim; iDim++) { -// for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { -// ProjFlux += AdjMeanFlowGradient[iVar][iDim]*dFc_dRho[iDim][iVar]; -// } -// } -// -// Residual[0] = ( ProjFlux -(LevelSet*ProjAdj/Density) - (AdjMeanFlow[nDim]/Froude2))*dRho_dPhi*Vol; -// -// /*--- The Free surface objective function requires the levelt set difference ---*/ -// -// if (config->GetKind_ObjFunc() == FREE_SURFACE) Residual[0] += DiffLevelSet* Vol; -// -// /*--- Add Residual ---*/ -// LinSysRes.AddBlock(iPoint, Residual); -// } -// -} - -void CAdjLevelSetSolver::Source_Template(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, unsigned short iMesh) { } - -void CAdjLevelSetSolver::BC_Euler_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, unsigned short val_marker) { - unsigned long iPoint, iVertex, Point_Normal; - unsigned short iVar, iDim; - su2double *U_domain, *U_wall, *LevelSet_domain, *LevelSet_wall; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - - U_domain = new su2double[solver_container[FLOW_SOL]->GetnVar()]; - U_wall = new su2double[solver_container[FLOW_SOL]->GetnVar()]; - LevelSet_domain = new su2double[1]; - LevelSet_wall = new su2double[1]; - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- If the node belong to the domain ---*/ - if (geometry->node[iPoint]->GetDomain()) { - - for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { - U_domain[iVar] = solver_container[FLOW_SOL]->node[Point_Normal]->GetSolution(iVar); - U_wall[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); - } - - LevelSet_domain[0] = node[Point_Normal]->GetSolution(0); - LevelSet_wall[0] = node[iPoint]->GetSolution(0); - - /*--- Set the normal vector ---*/ - geometry->vertex[val_marker][iVertex]->GetNormal(Vector); - for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = -Vector[iDim]; - numerics->SetNormal(Vector); - - numerics->SetConservative(U_wall, U_wall); - numerics->SetLevelSetVar(LevelSet_wall, LevelSet_wall); - numerics->SetDensityInc(solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(), solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc()); - numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - LinSysRes.AddBlock(iPoint, Residual_i); - - if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); - - } - } -} - -void CAdjLevelSetSolver::BC_Sym_Plane(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, - CConfig *config, unsigned short val_marker) { - unsigned long iPoint, iVertex, Point_Normal; - unsigned short iVar, iDim; - su2double *U_domain, *U_wall, *LevelSet_domain, *LevelSet_wall; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - - U_domain = new su2double[solver_container[FLOW_SOL]->GetnVar()]; - U_wall = new su2double[solver_container[FLOW_SOL]->GetnVar()]; - LevelSet_domain = new su2double[1]; - LevelSet_wall = new su2double[1]; - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- If the node belong to the domain ---*/ - if (geometry->node[iPoint]->GetDomain()) { - - for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { - U_domain[iVar] = solver_container[FLOW_SOL]->node[Point_Normal]->GetSolution(iVar); - U_wall[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); - } - - LevelSet_domain[0] = node[Point_Normal]->GetSolution(0); - LevelSet_wall[0] = node[iPoint]->GetSolution(0); - - /*--- Set the normal vector ---*/ - geometry->vertex[val_marker][iVertex]->GetNormal(Vector); - for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = -Vector[iDim]; - conv_numerics->SetNormal(Vector); - - conv_numerics->SetConservative(U_wall, U_wall); - conv_numerics->SetLevelSetVar(LevelSet_wall, LevelSet_wall); - conv_numerics->SetDensityInc(solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(), solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc()); - conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - LinSysRes.AddBlock(iPoint, Residual_i); - - if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); - - } - } -} - -void CAdjLevelSetSolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - unsigned long iPoint, iVertex, Point_Normal; - unsigned short iVar, iDim; - su2double *U_domain, *U_wall, *LevelSet_domain, *LevelSet_wall; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - - U_domain = new su2double[solver_container[FLOW_SOL]->GetnVar()]; - U_wall = new su2double[solver_container[FLOW_SOL]->GetnVar()]; - LevelSet_domain = new su2double[1]; - LevelSet_wall = new su2double[1]; - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- If the node belong to the domain ---*/ - if (geometry->node[iPoint]->GetDomain()) { - - for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { - U_domain[iVar] = solver_container[FLOW_SOL]->node[Point_Normal]->GetSolution(iVar); - U_wall[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); - } - - LevelSet_domain[0] = node[Point_Normal]->GetSolution(0); - LevelSet_wall[0] = node[iPoint]->GetSolution(0); - - /*--- Set the normal vector ---*/ - geometry->vertex[val_marker][iVertex]->GetNormal(Vector); - for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = -Vector[iDim]; - conv_numerics->SetNormal(Vector); - - conv_numerics->SetConservative(U_wall, U_wall); - conv_numerics->SetLevelSetVar(LevelSet_wall, LevelSet_wall); - conv_numerics->SetDensityInc(solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(), solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc()); - conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - LinSysRes.AddBlock(iPoint, Residual_i); - - if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); - - } - } -} - -void CAdjLevelSetSolver::BC_Far_Field(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - unsigned long iPoint, iVertex, Point_Normal; - unsigned short iVar, iDim; - su2double *U_domain, *U_wall, *LevelSet_domain, *LevelSet_wall; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - - U_domain = new su2double[solver_container[FLOW_SOL]->GetnVar()]; - U_wall = new su2double[solver_container[FLOW_SOL]->GetnVar()]; - LevelSet_domain = new su2double[1]; - LevelSet_wall = new su2double[1]; - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- If the node belong to the domain ---*/ - if (geometry->node[iPoint]->GetDomain()) { - - for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { - U_domain[iVar] = solver_container[FLOW_SOL]->node[Point_Normal]->GetSolution(iVar); - U_wall[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); - } - - LevelSet_domain[0] = node[Point_Normal]->GetSolution(0); - LevelSet_wall[0] = node[iPoint]->GetSolution(0); - - /*--- Set the normal vector ---*/ - geometry->vertex[val_marker][iVertex]->GetNormal(Vector); - for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = -Vector[iDim]; - conv_numerics->SetNormal(Vector); - - conv_numerics->SetConservative(U_wall, U_wall); - conv_numerics->SetLevelSetVar(LevelSet_wall, LevelSet_wall); - conv_numerics->SetDensityInc(solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(), solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc()); - conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - LinSysRes.AddBlock(iPoint, Residual_i); - - if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); - - } - } -} - -void CAdjLevelSetSolver::BC_Inlet(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - unsigned long iPoint, iVertex, Point_Normal; - unsigned short iVar, iDim; - su2double *U_domain, *U_wall, *LevelSet_domain, *LevelSet_wall; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - - U_domain = new su2double[solver_container[FLOW_SOL]->GetnVar()]; - U_wall = new su2double[solver_container[FLOW_SOL]->GetnVar()]; - LevelSet_domain = new su2double[1]; - LevelSet_wall = new su2double[1]; - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- If the node belong to the domain ---*/ - if (geometry->node[iPoint]->GetDomain()) { - - for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { - U_domain[iVar] = solver_container[FLOW_SOL]->node[Point_Normal]->GetSolution(iVar); - U_wall[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); - } - - LevelSet_domain[0] = node[Point_Normal]->GetSolution(0); - LevelSet_wall[0] = node[iPoint]->GetSolution(0); - - /*--- Set the normal vector ---*/ - geometry->vertex[val_marker][iVertex]->GetNormal(Vector); - for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = -Vector[iDim]; - conv_numerics->SetNormal(Vector); - - conv_numerics->SetConservative(U_wall, U_wall); - conv_numerics->SetLevelSetVar(LevelSet_wall, LevelSet_wall); - conv_numerics->SetDensityInc(solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(), solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc()); - conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - LinSysRes.AddBlock(iPoint, Residual_i); - - if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); - - } - } -} - -void CAdjLevelSetSolver::BC_Outlet(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - unsigned long iPoint, iVertex; - - bool implicit = (config->GetKind_TimeIntScheme_AdjLevelSet() == EULER_IMPLICIT); - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Set the solution to the original value ---*/ - Solution[0] = node[iPoint]->GetSolution(0); - - node[iPoint]->SetSolution_Old(Solution); - LinSysRes.SetBlock_Zero(iPoint); - - /*--- Includes 1 in the diagonal ---*/ - if (implicit) - Jacobian.DeleteValsRowi(iPoint); - } -} - -void CAdjLevelSetSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { - - unsigned long iPoint; - su2double Delta = 0.0, Vol; - - /*--- Set maximum residual to zero ---*/ - - SetRes_RMS(0, 0.0); - SetRes_Max(0, 0.0, 0); - - /*--- Build implicit system ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { - - /*--- Read the volume ---*/ - - Vol = geometry->node[iPoint]->GetVolume(); - - /*--- Modify matrix diagonal to assure diagonal dominance ---*/ - - Delta = Vol / solver_container[FLOW_SOL]->node[iPoint]->GetDelta_Time(); - - Jacobian.AddVal2Diag(iPoint, Delta); - - /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ - - LinSysRes[iPoint] = -LinSysRes[iPoint]; - LinSysSol[iPoint] = 0.0; - AddRes_RMS(0, LinSysRes[iPoint]*LinSysRes[iPoint]); - AddRes_Max(0, fabs(LinSysRes[iPoint]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); - } - - /*--- Initialize residual and solution at the ghost points ---*/ - - for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { - LinSysRes[iPoint] = 0.0; - LinSysSol[iPoint] = 0.0; - } - - /*--- Solve or smooth the linear system ---*/ - - CSysSolve system; - system.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); - - /*--- Update solution (system written in terms of increments), be careful with the update of the - scalar equations which includes the density ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) - node[iPoint]->AddSolution(0, LinSysSol[iPoint]); - - /*--- MPI solution ---*/ - - Set_MPI_Solution(geometry, config); - - /*--- Compute the root mean square residual ---*/ - - SetResidual_RMS(geometry, config); - -} - -void CAdjLevelSetSolver::SetResidual_DualTime(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iRKStep, unsigned short iMesh, unsigned short RunTime_EqSystem) { - unsigned long iPoint; - su2double *U_time_nM1, *U_time_n, *U_time_nP1, Volume_nM1, Volume_n, Volume_nP1, TimeStep; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool Grid_Movement = config->GetGrid_Movement(); - - /*--- loop over points ---*/ - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { - - /*--- Solution at time n-1, n and n+1 ---*/ - U_time_nM1 = node[iPoint]->GetSolution_time_n1(); - U_time_n = node[iPoint]->GetSolution_time_n(); - U_time_nP1 = node[iPoint]->GetSolution(); - - /*--- Volume at time n-1 and n ---*/ - if (Grid_Movement) { - Volume_nM1 = geometry->node[iPoint]->GetVolume_nM1(); - Volume_n = geometry->node[iPoint]->GetVolume_n(); - Volume_nP1 = geometry->node[iPoint]->GetVolume(); - } - else { - Volume_nM1 = geometry->node[iPoint]->GetVolume(); - Volume_n = geometry->node[iPoint]->GetVolume(); - Volume_nP1 = geometry->node[iPoint]->GetVolume(); - } - - /*--- Time Step ---*/ - TimeStep = config->GetDelta_UnstTimeND(); - - /*--- Compute Residual ---*/ - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Residual[0] = ( U_time_nP1[0]*Volume_nP1 - U_time_n[0]*Volume_n ) / TimeStep; - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - Residual[0] = ( 3.0*U_time_nP1[0]*Volume_nP1 - 4.0*U_time_n[0]*Volume_n - + 1.0*U_time_nM1[0]*Volume_nM1 ) / (2.0*TimeStep); - - /*--- Add Residual ---*/ - LinSysRes.AddBlock(iPoint, Residual); - - if (implicit) { - Jacobian_i[0][0] = 0.0; - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Jacobian_i[0][0] = Volume_nP1 / TimeStep; - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - Jacobian_i[0][0] = (Volume_nP1*3.0)/(2.0*TimeStep); - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - } - - } -} +/*! + * \file solution_adjoint_levelset.cpp + * \brief Main subrotuines for solving the level set problem. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/solver_structure.hpp" + +CAdjLevelSetSolver::CAdjLevelSetSolver(CGeometry *geometry, CConfig *config, unsigned short iMesh) : CSolver() { + unsigned short iVar, iDim, nLineLets; + unsigned long iPoint, index; + su2double dull_val; + ifstream restart_file; + string text_line, mesh_filename, filename, AdjExt; + + bool restart = config->GetRestart(); + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Define geometry constans in the solver structure ---*/ + nDim = geometry->GetnDim(); + node = new CVariable*[geometry->GetnPoint()]; + + /*--- Dimension of the problem ---*/ + nVar = 1; + + /*--- Single grid simulation ---*/ + if (iMesh == MESH_0) { + + /*--- Define some auxiliar vector related with the residual ---*/ + Residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; + Residual_RMS = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_RMS[iVar] = 0.0; + Residual_Max = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_Max[iVar] = 0.0; + Point_Max = new unsigned long[nVar]; for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; + Point_Max_Coord = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Point_Max_Coord[iVar] = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; + } + Residual_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_i[iVar] = 0.0; + Residual_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_j[iVar] = 0.0; + + /*--- Define some auxiliar vector related with the solution ---*/ + Solution = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; + Solution_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_i[iVar] = 0.0; + Solution_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_j[iVar] = 0.0; + + /*--- Define some auxiliar vector related with the geometry ---*/ + Vector = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = 0.0; + Vector_i = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_i[iDim] = 0.0; + Vector_j = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_j[iDim] = 0.0; + + /*--- Define some auxiliar vector related with the flow solution ---*/ + FlowSolution_i = new su2double[nDim+1]; for (iVar = 0; iVar < nDim+1; iVar++) FlowSolution_i[iVar] = 0.0; + FlowSolution_j = new su2double[nDim+1]; for (iVar = 0; iVar < nDim+1; iVar++) FlowSolution_j[iVar] = 0.0; + + /*--- Solution and residual vectors ---*/ + LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); + LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); + + /*--- Jacobians and vector structures for implicit computations ---*/ + if (config->GetKind_TimeIntScheme_AdjLevelSet() == EULER_IMPLICIT) { + + /*--- Point to point Jacobians ---*/ + Jacobian_i = new su2double* [nVar]; + Jacobian_j = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Jacobian_i[iVar] = new su2double [nVar]; + Jacobian_j[iVar] = new su2double [nVar]; + } + + Jacobian_ii = new su2double* [nVar]; + Jacobian_ij = new su2double* [nVar]; + Jacobian_ji = new su2double* [nVar]; + Jacobian_jj = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Jacobian_ii[iVar] = new su2double [nVar]; + Jacobian_ij[iVar] = new su2double [nVar]; + Jacobian_ji[iVar] = new su2double [nVar]; + Jacobian_jj[iVar] = new su2double [nVar]; + } + + /*--- Initialization of the structure of the whole Jacobian ---*/ + if (rank == MASTER_NODE) cout << "Initialize Jacobian structure (Adj. Level Set). MG level: 0." << endl; + Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); + + if ((config->GetKind_Linear_Solver_Prec() == LINELET) || + (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { + nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); + if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; + } + + } + + /*--- Computation of gradients by least squares ---*/ + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { + /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ + Smatrix = new su2double* [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Smatrix[iDim] = new su2double [nDim]; + /*--- c vector := transpose(WA)*(Wb) ---*/ + cvector = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + cvector[iVar] = new su2double [nDim]; + } + + } + + /*--- Restart the solution from file information ---*/ + if (!restart || (iMesh != MESH_0)) { + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + node[iPoint] = new CAdjLevelSetVariable(0.0, nDim, nVar, config); + } + + } + else { + + /*--- Restart the solution from file information ---*/ + mesh_filename = config->GetSolution_AdjFileName(); + filename = config->GetObjFunc_Extension(mesh_filename); + + restart_file.open(filename.data(), ios::in); + + if (restart_file.fail()) { + cout << "There is no level set restart file!!" << endl; + exit(EXIT_FAILURE); + } + + /*--- In case this is a parallel simulation, we need to perform the + Global2Local index transformation first. ---*/ + long *Global2Local; + Global2Local = new long[geometry->GetGlobal_nPointDomain()]; + /*--- First, set all indices to a negative value by default ---*/ + for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) { + Global2Local[iPoint] = -1; + } + /*--- Now fill array with the transform values only for local points ---*/ + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { + Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; + } + + /*--- Read all lines in the restart file ---*/ + long iPoint_Local; unsigned long iPoint_Global = 0; + + /*--- The first line is the header ---*/ + getline (restart_file, text_line); + + while (getline (restart_file, text_line)) { + istringstream point_line(text_line); + + /*--- Retrieve local index. If this node from the restart file lives + on a different processor, the value of iPoint_Local will be -1. + Otherwise, the local index for this node on the current processor + will be returned and used to instantiate the vars. ---*/ + iPoint_Local = Global2Local[iPoint_Global]; + if (iPoint_Local >= 0) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; + node[iPoint_Local] = new CAdjLevelSetVariable(Solution[0], nDim, nVar, config); + } + iPoint_Global++; + } + + /*--- Instantiate the variable class with an arbitrary solution + at any halo/periodic nodes. The initial solution can be arbitrary, + because a send/recv is performed immediately in the solver. ---*/ + for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { + node[iPoint] = new CAdjLevelSetVariable(Solution[0], nDim, nVar, config); + } + + /*--- Close the restart file ---*/ + restart_file.close(); + + /*--- Free memory needed for the transformation ---*/ + delete [] Global2Local; + } + + /*--- MPI solution ---*/ + Set_MPI_Solution(geometry, config); + + /*--- Compute the gradient (Mean flow source term) ---*/ + if (iMesh == MESH_0) { + if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); + } + +} + +CAdjLevelSetSolver::~CAdjLevelSetSolver(void) { } + +void CAdjLevelSetSolver::Set_MPI_Solution(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_U = new su2double [nBufferR_Vector]; + Buffer_Send_U = new su2double[nBufferS_Vector]; + + /*--- Copy the solution that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution(iVar); + } + +#ifdef HAVE_MPI + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_U; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = Buffer_Receive_U[iVar*nVertexR+iVertex]; + + /*--- Rotate the momentum components. ---*/ + if (nDim == 2) { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex]; + } + else { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex] + + rotMatrix[0][2]*Buffer_Receive_U[3*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex] + + rotMatrix[1][2]*Buffer_Receive_U[3*nVertexR+iVertex]; + Solution[3] = rotMatrix[2][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[2][1]*Buffer_Receive_U[2*nVertexR+iVertex] + + rotMatrix[2][2]*Buffer_Receive_U[3*nVertexR+iVertex]; + } + + /*--- Copy transformed conserved variables back into buffer. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetSolution(iVar, Solution[iVar]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_U; + + } + + } + +} + +void CAdjLevelSetSolver::Set_MPI_Solution_Limiter(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, + *Buffer_Receive_Limit = NULL, *Buffer_Send_Limit = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_Limit = new su2double [nBufferR_Vector]; + Buffer_Send_Limit = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_Limit[iVar*nVertexS+iVertex] = node[iPoint]->GetLimiter(iVar); + } + +#ifdef HAVE_MPI + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Limit, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_Limit, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_Limit[iVar*nVertexR+iVertex] = Buffer_Send_Limit[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_Limit; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = Buffer_Receive_Limit[iVar*nVertexR+iVertex]; + + /*--- Rotate the momentum components. ---*/ + if (nDim == 2) { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_Limit[2*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_Limit[2*nVertexR+iVertex]; + } + else { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + + rotMatrix[0][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + + rotMatrix[1][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; + Solution[3] = rotMatrix[2][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[2][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + + rotMatrix[2][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; + } + + /*--- Copy transformed conserved variables back into buffer. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetLimiter(iVar, Solution[iVar]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_Limit; + + } + + } +} + +void CAdjLevelSetSolver::Set_MPI_Solution_Gradient(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, + *Buffer_Receive_Gradient = NULL, *Buffer_Send_Gradient = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + su2double **Gradient = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + Gradient[iVar] = new su2double[nDim]; + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar*nDim; nBufferR_Vector = nVertexR*nVar*nDim; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_Gradient = new su2double [nBufferR_Vector]; + Buffer_Send_Gradient = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Gradient[iDim*nVar*nVertexS+iVar*nVertexS+iVertex] = node[iPoint]->GetGradient(iVar, iDim); + } + +#ifdef HAVE_MPI + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Gradient, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_Gradient, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex] = Buffer_Send_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_Gradient; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Gradient[iVar][iDim] = Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; + + /*--- Need to rotate the gradients for all conserved variables. ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + if (nDim == 2) { + Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; + } + else { + Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][2] = rotMatrix[2][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; + } + } + + /*--- Store the received information ---*/ + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + node[iPoint]->SetGradient(iVar, iDim, Gradient[iVar][iDim]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_Gradient; + + } + + } + + for (iVar = 0; iVar < nVar; iVar++) + delete [] Gradient[iVar]; + delete [] Gradient; + +} + +void CAdjLevelSetSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { + unsigned long iPoint; + + bool implicit = (config->GetKind_TimeIntScheme_AdjLevelSet() == EULER_IMPLICIT); + bool second_order = ((config->GetSpatialOrder_AdjLevelSet() == SECOND_ORDER) || (config->GetSpatialOrder_AdjLevelSet() == SECOND_ORDER_LIMITER)); + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) + LinSysRes.SetBlock_Zero(iPoint); + + /*--- Implicit part ---*/ + if (implicit) + Jacobian.SetValZero(); + + if (second_order) { + if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); + } + +} + +void CAdjLevelSetSolver::Upwind_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, unsigned short iMesh) { + su2double *LevelSet_var_i, *LevelSet_var_j, *U_i, *U_j, **Gradient_i, **Gradient_j, Project_Grad_i, Project_Grad_j, DensityInc_i, DensityInc_j; + unsigned long iEdge, iPoint, jPoint; + unsigned short iDim, iVar; + + bool implicit = (config->GetKind_TimeIntScheme_AdjLevelSet() == EULER_IMPLICIT); + bool second_order = ((config->GetSpatialOrder_AdjLevelSet() == SECOND_ORDER) || (config->GetSpatialOrder_AdjLevelSet() == SECOND_ORDER_LIMITER)); + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Points in edge and normal vectors ---*/ + iPoint = geometry->edge[iEdge]->GetNode(0); jPoint = geometry->edge[iEdge]->GetNode(1); + numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); + + /*--- Conservative variables w/o reconstruction ---*/ + U_i = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); + U_j = solver_container[FLOW_SOL]->node[jPoint]->GetSolution(); + numerics->SetConservative(U_i, U_j); + + /*--- Level Set variables w/o reconstruction ---*/ + LevelSet_var_i = node[iPoint]->GetSolution(); + LevelSet_var_j = node[jPoint]->GetSolution(); + numerics->SetLevelSetVar(LevelSet_var_i, LevelSet_var_j); + + /*--- Set the value of the density ---*/ + DensityInc_i = solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); + DensityInc_j = solver_container[FLOW_SOL]->node[jPoint]->GetDensityInc(); + numerics->SetDensityInc(DensityInc_i, DensityInc_j); + + if (second_order) { + + for (iDim = 0; iDim < nDim; iDim++) { + Vector_i[iDim] = 0.5*(geometry->node[jPoint]->GetCoord(iDim) - geometry->node[iPoint]->GetCoord(iDim)); + Vector_j[iDim] = 0.5*(geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim)); + } + + /*--- Level Set variables using gradient reconstruction ---*/ + Gradient_i = node[iPoint]->GetGradient(); Gradient_j = node[jPoint]->GetGradient(); + for (iVar = 0; iVar < nVar; iVar++) { + Project_Grad_i = 0.0; Project_Grad_j = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Project_Grad_i += Vector_i[iDim]*Gradient_i[iVar][iDim]; + Project_Grad_j += Vector_j[iDim]*Gradient_j[iVar][iDim]; + } + Solution_i[iVar] = LevelSet_var_i[iVar] + Project_Grad_i; + Solution_j[iVar] = LevelSet_var_j[iVar] + Project_Grad_j; + } + numerics->SetLevelSetVar(Solution_i, Solution_j); + + } + + numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + /*--- Add and subtract Residual ---*/ + LinSysRes.AddBlock(iPoint, Residual_i); + LinSysRes.AddBlock(jPoint, Residual_j); + + /*--- Implicit part ---*/ + if (implicit) { + Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); + Jacobian.AddBlock(iPoint, jPoint, Jacobian_ij); + Jacobian.AddBlock(jPoint, iPoint, Jacobian_ji); + Jacobian.AddBlock(jPoint, jPoint, Jacobian_jj); + } + + } +} + +void CAdjLevelSetSolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, + CConfig *config, unsigned short iMesh) { +// unsigned short iVar, iDim; +// unsigned long iPoint; +// su2double epsilon, DeltaDirac, lambda, dRho_dPhi, dMud_Phi, Vol, DiffLevelSet, LevelSet, *AdjMeanFlow, **AdjLevelSetGradient, **AdjMeanFlowGradient, +// Density, Velocity[3] = {0.0,0.0,0.0}, ProjAdj, dFc_dRho[3][4], ProjFlux; +// +// su2double Froude2 = config->GetFroude()*config->GetFroude(); +// +// for (iVar = 0; iVar < nVar; iVar++) +// Residual[iVar] = 0; +// +// /*--- loop over points ---*/ +// +// for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { +// +// Vol = geometry->node[iPoint]->GetVolume(); +// +// /*--- Direct problem quantities ---*/ +// +// DiffLevelSet = solver_container[LEVELSET_SOL]->node[iPoint]->GetDiffLevelSet(); +// LevelSet = solver_container[LEVELSET_SOL]->node[iPoint]->GetSolution(0); +// MeanFlow = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); +// Density = solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); +// +// /*--- Adjoint problem quantities ---*/ +// +// AdjMeanFlow = solver_container[ADJFLOW_SOL]->node[iPoint]->GetSolution(); +// AdjLevelSetGradient = solver_container[ADJLEVELSET_SOL]->node[iPoint]->GetGradient(); +// AdjMeanFlowGradient = solver_container[ADJFLOW_SOL]->node[iPoint]->GetGradient(); +// +// /*--- Projected adjoint velocity ---*/ +// +// ProjAdj = 0.0; +// for (iDim = 0; iDim < nDim; iDim++) { +// Velocity[iDim] = solver_container[FLOW_SOL]->node[iPoint]->GetVelocity(iDim); +// ProjAdj += Velocity[iDim]*AdjLevelSetGradient[0][iDim]; +// } +// +// /*--- Compute the flow solution using the level set value. ---*/ +// +// epsilon = config->GetFreeSurface_Thickness(); +// DeltaDirac = 0.0; +// if (fabs(LevelSet) <= epsilon) DeltaDirac = 1.0 - (0.5*(1.0+(LevelSet/epsilon)+(1.0/PI_NUMBER)*sin(PI_NUMBER*LevelSet/epsilon))); +// +// /*--- Set the value of the incompressible density for free surface flows (density ratio g/l) ---*/ +// +// lambda = config->GetRatioDensity(); +// dRho_dPhi = (1.0 - lambda)*DeltaDirac*config->GetDensity_FreeStreamND(); +// +// /*--- Set the value of the incompressible viscosity for free surface flows (viscosity ratio g/l) ---*/ +// +// lambda = config->GetRatioViscosity(); +// dMud_Phi = (1.0 - lambda)*DeltaDirac*config->GetViscosity_FreeStreamND(); +// +// /*--- Flux derivative ---*/ +// +// for (iDim = 0; iDim < nDim; iDim++) { +// dFc_dRho[iDim][0] = 0.0; +// dFc_dRho[iDim][1] = Velocity[iDim]*Velocity[0]; +// dFc_dRho[iDim][2] = Velocity[iDim]*Velocity[1]; +// dFc_dRho[iDim][3] = Velocity[iDim]*Velocity[2]; +// } +// +// /*--- Projected flux derivative ---*/ +// +// ProjFlux = 0.0; +// for (iDim = 0; iDim < nDim; iDim++) { +// for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { +// ProjFlux += AdjMeanFlowGradient[iVar][iDim]*dFc_dRho[iDim][iVar]; +// } +// } +// +// Residual[0] = ( ProjFlux -(LevelSet*ProjAdj/Density) - (AdjMeanFlow[nDim]/Froude2))*dRho_dPhi*Vol; +// +// /*--- The Free surface objective function requires the levelt set difference ---*/ +// +// if (config->GetKind_ObjFunc() == FREE_SURFACE) Residual[0] += DiffLevelSet* Vol; +// +// /*--- Add Residual ---*/ +// LinSysRes.AddBlock(iPoint, Residual); +// } +// +} + +void CAdjLevelSetSolver::Source_Template(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, unsigned short iMesh) { } + +void CAdjLevelSetSolver::BC_Euler_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, unsigned short val_marker) { + unsigned long iPoint, iVertex, Point_Normal; + unsigned short iVar, iDim; + su2double *U_domain, *U_wall, *LevelSet_domain, *LevelSet_wall; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + + U_domain = new su2double[solver_container[FLOW_SOL]->GetnVar()]; + U_wall = new su2double[solver_container[FLOW_SOL]->GetnVar()]; + LevelSet_domain = new su2double[1]; + LevelSet_wall = new su2double[1]; + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- If the node belong to the domain ---*/ + if (geometry->node[iPoint]->GetDomain()) { + + for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { + U_domain[iVar] = solver_container[FLOW_SOL]->node[Point_Normal]->GetSolution(iVar); + U_wall[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); + } + + LevelSet_domain[0] = node[Point_Normal]->GetSolution(0); + LevelSet_wall[0] = node[iPoint]->GetSolution(0); + + /*--- Set the normal vector ---*/ + geometry->vertex[val_marker][iVertex]->GetNormal(Vector); + for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = -Vector[iDim]; + numerics->SetNormal(Vector); + + numerics->SetConservative(U_wall, U_wall); + numerics->SetLevelSetVar(LevelSet_wall, LevelSet_wall); + numerics->SetDensityInc(solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(), solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc()); + numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + LinSysRes.AddBlock(iPoint, Residual_i); + + if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); + + } + } +} + +void CAdjLevelSetSolver::BC_Sym_Plane(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, + CConfig *config, unsigned short val_marker) { + unsigned long iPoint, iVertex, Point_Normal; + unsigned short iVar, iDim; + su2double *U_domain, *U_wall, *LevelSet_domain, *LevelSet_wall; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + + U_domain = new su2double[solver_container[FLOW_SOL]->GetnVar()]; + U_wall = new su2double[solver_container[FLOW_SOL]->GetnVar()]; + LevelSet_domain = new su2double[1]; + LevelSet_wall = new su2double[1]; + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- If the node belong to the domain ---*/ + if (geometry->node[iPoint]->GetDomain()) { + + for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { + U_domain[iVar] = solver_container[FLOW_SOL]->node[Point_Normal]->GetSolution(iVar); + U_wall[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); + } + + LevelSet_domain[0] = node[Point_Normal]->GetSolution(0); + LevelSet_wall[0] = node[iPoint]->GetSolution(0); + + /*--- Set the normal vector ---*/ + geometry->vertex[val_marker][iVertex]->GetNormal(Vector); + for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = -Vector[iDim]; + conv_numerics->SetNormal(Vector); + + conv_numerics->SetConservative(U_wall, U_wall); + conv_numerics->SetLevelSetVar(LevelSet_wall, LevelSet_wall); + conv_numerics->SetDensityInc(solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(), solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc()); + conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + LinSysRes.AddBlock(iPoint, Residual_i); + + if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); + + } + } +} + +void CAdjLevelSetSolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + unsigned long iPoint, iVertex, Point_Normal; + unsigned short iVar, iDim; + su2double *U_domain, *U_wall, *LevelSet_domain, *LevelSet_wall; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + + U_domain = new su2double[solver_container[FLOW_SOL]->GetnVar()]; + U_wall = new su2double[solver_container[FLOW_SOL]->GetnVar()]; + LevelSet_domain = new su2double[1]; + LevelSet_wall = new su2double[1]; + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- If the node belong to the domain ---*/ + if (geometry->node[iPoint]->GetDomain()) { + + for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { + U_domain[iVar] = solver_container[FLOW_SOL]->node[Point_Normal]->GetSolution(iVar); + U_wall[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); + } + + LevelSet_domain[0] = node[Point_Normal]->GetSolution(0); + LevelSet_wall[0] = node[iPoint]->GetSolution(0); + + /*--- Set the normal vector ---*/ + geometry->vertex[val_marker][iVertex]->GetNormal(Vector); + for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = -Vector[iDim]; + conv_numerics->SetNormal(Vector); + + conv_numerics->SetConservative(U_wall, U_wall); + conv_numerics->SetLevelSetVar(LevelSet_wall, LevelSet_wall); + conv_numerics->SetDensityInc(solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(), solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc()); + conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + LinSysRes.AddBlock(iPoint, Residual_i); + + if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); + + } + } +} + +void CAdjLevelSetSolver::BC_Far_Field(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + unsigned long iPoint, iVertex, Point_Normal; + unsigned short iVar, iDim; + su2double *U_domain, *U_wall, *LevelSet_domain, *LevelSet_wall; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + + U_domain = new su2double[solver_container[FLOW_SOL]->GetnVar()]; + U_wall = new su2double[solver_container[FLOW_SOL]->GetnVar()]; + LevelSet_domain = new su2double[1]; + LevelSet_wall = new su2double[1]; + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- If the node belong to the domain ---*/ + if (geometry->node[iPoint]->GetDomain()) { + + for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { + U_domain[iVar] = solver_container[FLOW_SOL]->node[Point_Normal]->GetSolution(iVar); + U_wall[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); + } + + LevelSet_domain[0] = node[Point_Normal]->GetSolution(0); + LevelSet_wall[0] = node[iPoint]->GetSolution(0); + + /*--- Set the normal vector ---*/ + geometry->vertex[val_marker][iVertex]->GetNormal(Vector); + for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = -Vector[iDim]; + conv_numerics->SetNormal(Vector); + + conv_numerics->SetConservative(U_wall, U_wall); + conv_numerics->SetLevelSetVar(LevelSet_wall, LevelSet_wall); + conv_numerics->SetDensityInc(solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(), solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc()); + conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + LinSysRes.AddBlock(iPoint, Residual_i); + + if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); + + } + } +} + +void CAdjLevelSetSolver::BC_Inlet(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + unsigned long iPoint, iVertex, Point_Normal; + unsigned short iVar, iDim; + su2double *U_domain, *U_wall, *LevelSet_domain, *LevelSet_wall; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + + U_domain = new su2double[solver_container[FLOW_SOL]->GetnVar()]; + U_wall = new su2double[solver_container[FLOW_SOL]->GetnVar()]; + LevelSet_domain = new su2double[1]; + LevelSet_wall = new su2double[1]; + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- If the node belong to the domain ---*/ + if (geometry->node[iPoint]->GetDomain()) { + + for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { + U_domain[iVar] = solver_container[FLOW_SOL]->node[Point_Normal]->GetSolution(iVar); + U_wall[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); + } + + LevelSet_domain[0] = node[Point_Normal]->GetSolution(0); + LevelSet_wall[0] = node[iPoint]->GetSolution(0); + + /*--- Set the normal vector ---*/ + geometry->vertex[val_marker][iVertex]->GetNormal(Vector); + for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = -Vector[iDim]; + conv_numerics->SetNormal(Vector); + + conv_numerics->SetConservative(U_wall, U_wall); + conv_numerics->SetLevelSetVar(LevelSet_wall, LevelSet_wall); + conv_numerics->SetDensityInc(solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(), solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc()); + conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + LinSysRes.AddBlock(iPoint, Residual_i); + + if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); + + } + } +} + +void CAdjLevelSetSolver::BC_Outlet(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + unsigned long iPoint, iVertex; + + bool implicit = (config->GetKind_TimeIntScheme_AdjLevelSet() == EULER_IMPLICIT); + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Set the solution to the original value ---*/ + Solution[0] = node[iPoint]->GetSolution(0); + + node[iPoint]->SetSolution_Old(Solution); + LinSysRes.SetBlock_Zero(iPoint); + + /*--- Includes 1 in the diagonal ---*/ + if (implicit) + Jacobian.DeleteValsRowi(iPoint); + } +} + +void CAdjLevelSetSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { + + unsigned long iPoint; + su2double Delta = 0.0, Vol; + + /*--- Set maximum residual to zero ---*/ + + SetRes_RMS(0, 0.0); + SetRes_Max(0, 0.0, 0); + + /*--- Build implicit system ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { + + /*--- Read the volume ---*/ + + Vol = geometry->node[iPoint]->GetVolume(); + + /*--- Modify matrix diagonal to assure diagonal dominance ---*/ + + Delta = Vol / solver_container[FLOW_SOL]->node[iPoint]->GetDelta_Time(); + + Jacobian.AddVal2Diag(iPoint, Delta); + + /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ + + LinSysRes[iPoint] = -LinSysRes[iPoint]; + LinSysSol[iPoint] = 0.0; + AddRes_RMS(0, LinSysRes[iPoint]*LinSysRes[iPoint]); + AddRes_Max(0, fabs(LinSysRes[iPoint]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); + } + + /*--- Initialize residual and solution at the ghost points ---*/ + + for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { + LinSysRes[iPoint] = 0.0; + LinSysSol[iPoint] = 0.0; + } + + /*--- Solve or smooth the linear system ---*/ + + CSysSolve system; + system.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); + + /*--- Update solution (system written in terms of increments), be careful with the update of the + scalar equations which includes the density ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) + node[iPoint]->AddSolution(0, LinSysSol[iPoint]); + + /*--- MPI solution ---*/ + + Set_MPI_Solution(geometry, config); + + /*--- Compute the root mean square residual ---*/ + + SetResidual_RMS(geometry, config); + +} + +void CAdjLevelSetSolver::SetResidual_DualTime(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iRKStep, unsigned short iMesh, unsigned short RunTime_EqSystem) { + unsigned long iPoint; + su2double *U_time_nM1, *U_time_n, *U_time_nP1, Volume_nM1, Volume_n, Volume_nP1, TimeStep; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool Grid_Movement = config->GetGrid_Movement(); + + /*--- loop over points ---*/ + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { + + /*--- Solution at time n-1, n and n+1 ---*/ + U_time_nM1 = node[iPoint]->GetSolution_time_n1(); + U_time_n = node[iPoint]->GetSolution_time_n(); + U_time_nP1 = node[iPoint]->GetSolution(); + + /*--- Volume at time n-1 and n ---*/ + if (Grid_Movement) { + Volume_nM1 = geometry->node[iPoint]->GetVolume_nM1(); + Volume_n = geometry->node[iPoint]->GetVolume_n(); + Volume_nP1 = geometry->node[iPoint]->GetVolume(); + } + else { + Volume_nM1 = geometry->node[iPoint]->GetVolume(); + Volume_n = geometry->node[iPoint]->GetVolume(); + Volume_nP1 = geometry->node[iPoint]->GetVolume(); + } + + /*--- Time Step ---*/ + TimeStep = config->GetDelta_UnstTimeND(); + + /*--- Compute Residual ---*/ + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Residual[0] = ( U_time_nP1[0]*Volume_nP1 - U_time_n[0]*Volume_n ) / TimeStep; + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + Residual[0] = ( 3.0*U_time_nP1[0]*Volume_nP1 - 4.0*U_time_n[0]*Volume_n + + 1.0*U_time_nM1[0]*Volume_nM1 ) / (2.0*TimeStep); + + /*--- Add Residual ---*/ + LinSysRes.AddBlock(iPoint, Residual); + + if (implicit) { + Jacobian_i[0][0] = 0.0; + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Jacobian_i[0][0] = Volume_nP1 / TimeStep; + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + Jacobian_i[0][0] = (Volume_nP1*3.0)/(2.0*TimeStep); + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + } + + } +} diff --git a/SU2_CFD/src/solver_adjoint_mean.cpp b/SU2_CFD/src/solver_adjoint_mean.cpp index b2d9f30b42d..071025a0fe1 100644 --- a/SU2_CFD/src/solver_adjoint_mean.cpp +++ b/SU2_CFD/src/solver_adjoint_mean.cpp @@ -1,7096 +1,7096 @@ -/*! - * \file solution_adjoint_mean.cpp - * \brief Main subrotuines for solving adjoint problems (Euler, Navier-Stokes, etc.). - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/solver_structure.hpp" - -CAdjEulerSolver::CAdjEulerSolver(void) : CSolver() { - - /*--- Array initialization ---*/ - Phi_Inf = NULL; - Sens_Mach = NULL; - Sens_AoA = NULL; - Sens_Geo = NULL; - Sens_Press = NULL; - Sens_Temp = NULL; - Sens_BPress = NULL; - iPoint_UndLapl = NULL; - jPoint_UndLapl = NULL; - Jacobian_Axisymmetric = NULL; - CSensitivity = NULL; - FlowPrimVar_i = NULL; - FlowPrimVar_j = NULL; - -} - -CAdjEulerSolver::CAdjEulerSolver(CGeometry *geometry, CConfig *config, unsigned short iMesh) : CSolver() { - unsigned long iPoint, index, iVertex; - string text_line, mesh_filename; - unsigned short iDim, iVar, iMarker, nLineLets; - ifstream restart_file; - string filename, AdjExt; - su2double dull_val, myArea_Monitored, Area, *Normal; - bool restart = config->GetRestart(); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool axisymmetric = config->GetAxisymmetric(); - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Array initialization ---*/ - Phi_Inf = NULL; - Sens_Mach = NULL; - Sens_AoA = NULL; - Sens_Geo = NULL; - Sens_Press = NULL; - Sens_Temp = NULL; - Sens_BPress = NULL; - iPoint_UndLapl = NULL; - jPoint_UndLapl = NULL; - Jacobian_Axisymmetric = NULL; - CSensitivity = NULL; - FlowPrimVar_i = NULL; - FlowPrimVar_j = NULL; - - /*--- Set the gamma value ---*/ - Gamma = config->GetGamma(); - Gamma_Minus_One = Gamma - 1.0; - - /*--- Define geometry constans in the solver structure ---*/ - nDim = geometry->GetnDim(); - nMarker = config->GetnMarker_All(); - nPoint = geometry->GetnPoint(); - nPointDomain = geometry->GetnPointDomain(); - - if (compressible) { nVar = nDim + 2; } - if (incompressible) { nVar = nDim + 1; } - if (freesurface) { nVar = nDim + 2; } - - node = new CVariable*[nPoint]; - - /*--- Define some auxiliary vectors related to the residual ---*/ - Residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; - Residual_RMS = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_RMS[iVar] = 0.0; - Residual_Max = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_Max[iVar] = 0.0; - Point_Max = new unsigned long[nVar]; for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; - Point_Max_Coord = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Point_Max_Coord[iVar] = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; - } - Residual_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_i[iVar] = 0.0; - Residual_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_j[iVar] = 0.0; - Res_Conv_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Conv_i[iVar] = 0.0; - Res_Visc_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Visc_i[iVar] = 0.0; - Res_Conv_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Conv_j[iVar] = 0.0; - Res_Visc_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Visc_j[iVar] = 0.0; - - /*--- Define some auxiliary vectors related to the solution ---*/ - Solution = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; - Solution_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_i[iVar] = 0.0; - Solution_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_j[iVar] = 0.0; - - /*--- Define some auxiliary arrays related to the flow solution ---*/ - FlowPrimVar_i = new su2double[nDim+7]; for (iVar = 0; iVar < nDim+7; iVar++) FlowPrimVar_i[iVar] = 0.0; - FlowPrimVar_j = new su2double[nDim+7]; for (iVar = 0; iVar < nDim+7; iVar++) FlowPrimVar_j[iVar] = 0.0; - - /*--- Define some auxiliary vectors related to the geometry ---*/ - Vector = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = 0.0; - Vector_i = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_i[iDim] = 0.0; - Vector_j = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_j[iDim] = 0.0; - - /*--- Define some auxiliary vectors related to the undivided lapalacian ---*/ - if (config->GetKind_ConvNumScheme_AdjFlow() == SPACE_CENTERED) { - iPoint_UndLapl = new su2double [nPoint]; - jPoint_UndLapl = new su2double [nPoint]; - } - - /*--- Define some auxiliary vectors related to the geometry ---*/ - Vector_i = new su2double[nDim]; Vector_j = new su2double[nDim]; - - /*--- Point to point Jacobians. These are always defined because - they are also used for sensitivity calculations. ---*/ - Jacobian_i = new su2double* [nVar]; - Jacobian_j = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Jacobian_i[iVar] = new su2double [nVar]; - Jacobian_j[iVar] = new su2double [nVar]; - } - - LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); - - /*--- Jacobians and vector structures for implicit computations ---*/ - if (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT) { - Jacobian_ii = new su2double* [nVar]; - Jacobian_ij = new su2double* [nVar]; - Jacobian_ji = new su2double* [nVar]; - Jacobian_jj = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Jacobian_ii[iVar] = new su2double [nVar]; - Jacobian_ij[iVar] = new su2double [nVar]; - Jacobian_ji[iVar] = new su2double [nVar]; - Jacobian_jj[iVar] = new su2double [nVar]; - } - - if (rank == MASTER_NODE) - cout << "Initialize Jacobian structure (Adjoint Euler). MG level: " << iMesh <<"." << endl; - Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); - - if ((config->GetKind_Linear_Solver_Prec() == LINELET) || - (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { - nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); - if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; - } - - if (axisymmetric) { - Jacobian_Axisymmetric = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - Jacobian_Axisymmetric[iVar] = new su2double [nVar]; - } - } else { - if (rank == MASTER_NODE) - cout << "Explicit scheme. No Jacobian structure (Adjoint Euler). MG level: " << iMesh <<"." << endl; - } - - /*--- Computation of gradients by least squares ---*/ - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { - /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ - Smatrix = new su2double* [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Smatrix[iDim] = new su2double [nDim]; - /*--- c vector := transpose(WA)*(Wb) ---*/ - cvector = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - cvector[iVar] = new su2double [nDim]; - } - - /*--- Sensitivity definition and coefficient in all the markers ---*/ - CSensitivity = new su2double* [nMarker]; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - CSensitivity[iMarker] = new su2double [geometry->nVertex[iMarker]]; - } - Sens_Geo = new su2double[nMarker]; - Sens_Mach = new su2double[nMarker]; - Sens_AoA = new su2double[nMarker]; - Sens_Press = new su2double[nMarker]; - Sens_Temp = new su2double[nMarker]; - Sens_BPress = new su2double[nMarker]; - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - Sens_Geo[iMarker] = 0.0; - Sens_Mach[iMarker] = 0.0; - Sens_AoA[iMarker] = 0.0; - Sens_Press[iMarker] = 0.0; - Sens_Temp[iMarker] = 0.0; - Sens_BPress[iMarker] = 0.0; - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) - CSensitivity[iMarker][iVertex] = 0.0; - } - - /*--- Adjoint flow at the inifinity, initialization stuff ---*/ - PsiRho_Inf = 0.0; PsiE_Inf = 0.0; - Phi_Inf = new su2double [nDim]; - Phi_Inf[0] = 0.0; Phi_Inf[1] = 0.0; - if (nDim == 3) Phi_Inf[2] = 0.0; - - /*--- If outflow objective, nonzero initialization ---*/ - if ((config->GetKind_ObjFunc() == AVG_TOTAL_PRESSURE)){ - su2double SoundSpeed,*vel_inf,R,vel2,vel; - R = config->GetGas_ConstantND(); - vel_inf = config->GetVelocity_FreeStreamND(); - vel2=0; - for (iDim=0; iDimGetTemperature_FreeStreamND()*R, 0.5); - PsiE_Inf = Gamma_Minus_One*vel2/(vel2-pow(SoundSpeed,2.0))*0.5/vel; - PsiRho_Inf += PsiE_Inf*(2*SoundSpeed*SoundSpeed+vel2*Gamma_Minus_One)/(2.0*Gamma_Minus_One); - // Assumes +x flow direction - // Assume v.n = |v|, n = -v/|v| - - for (iDim=0; iDimGetSolution_AdjFileName(); - filename = config->GetObjFunc_Extension(mesh_filename); - - restart_file.open(filename.data(), ios::in); - - /*--- In case there is no file ---*/ - if (restart_file.fail()) { - if (rank == MASTER_NODE) - cout << "There is no adjoint restart file!! " << filename.data() << "."<< endl; - exit(EXIT_FAILURE); - } - - /*--- In case this is a parallel simulation, we need to perform the - Global2Local index transformation first. ---*/ - long *Global2Local; - Global2Local = new long[geometry->GetGlobal_nPointDomain()]; - /*--- First, set all indices to a negative value by default ---*/ - for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) { - Global2Local[iPoint] = -1; - } - /*--- Now fill array with the transform values only for local points ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; - } - - /*--- Read all lines in the restart file ---*/ - long iPoint_Local; unsigned long iPoint_Global = 0; - - /*--- The first line is the header ---*/ - getline (restart_file, text_line); - - while (getline (restart_file, text_line)) { - istringstream point_line(text_line); - - /*--- Retrieve local index. If this node from the restart file lives - on a different processor, the value of iPoint_Local will be -1. - Otherwise, the local index for this node on the current processor - will be returned and used to instantiate the vars. ---*/ - iPoint_Local = Global2Local[iPoint_Global]; - if (iPoint_Local >= 0) { - if (compressible) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3] >> Solution[4]; - } - if (incompressible) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; - } - if (freesurface) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; - } - node[iPoint_Local] = new CAdjEulerVariable(Solution, nDim, nVar, config); - } - iPoint_Global++; - } - - /*--- Instantiate the variable class with an arbitrary solution - at any halo/periodic nodes. The initial solution can be arbitrary, - because a send/recv is performed immediately in the solver. ---*/ - for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { - node[iPoint] = new CAdjEulerVariable(Solution, nDim, nVar, config); - } - - /*--- Close the restart file ---*/ - restart_file.close(); - - /*--- Free memory needed for the transformation ---*/ - delete [] Global2Local; - } - - /*--- Define solver parameters needed for execution of destructor ---*/ - if (config->GetKind_ConvNumScheme_AdjFlow() == SPACE_CENTERED) space_centered = true; - else space_centered = false; - - /*--- Calculate area monitored for area-averaged-outflow-quantity-based objectives ---*/ - myArea_Monitored = 0.0; - if (config->GetKind_ObjFunc()==OUTLET_CHAIN_RULE || config->GetKind_ObjFunc()==AVG_TOTAL_PRESSURE || - config->GetKind_ObjFunc()==AVG_OUTLET_PRESSURE){ - for (iMarker =0; iMarker < config->GetnMarker_All(); iMarker++){ - if (config->GetMarker_All_Monitoring(iMarker) == YES){ - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if (geometry->node[iPoint]->GetDomain()) { - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Area += Normal[iDim]*Normal[iDim]; - myArea_Monitored += sqrt (Area); - } - } - } - } - } -#ifdef HAVE_MPI - Area_Monitored = 0.0; - SU2_MPI::Allreduce(&myArea_Monitored, &Area_Monitored, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); -#else - Area_Monitored = myArea_Monitored; -#endif - - /*--- MPI solution ---*/ - Set_MPI_Solution(geometry, config); - -} - -CAdjEulerSolver::~CAdjEulerSolver(void) { - unsigned short iVar, iMarker; - - if (Phi_Inf != NULL) delete [] Phi_Inf; - if (Sens_Mach != NULL) delete [] Sens_Mach; - if (Sens_AoA != NULL) delete [] Sens_AoA; - if (Sens_Geo != NULL) delete [] Sens_Geo; - if (Sens_Press != NULL) delete [] Sens_Press; - if (Sens_Temp != NULL) delete [] Sens_Temp; - if (Sens_BPress != NULL) delete [] Sens_BPress; - if (iPoint_UndLapl != NULL) delete [] iPoint_UndLapl; - if (jPoint_UndLapl != NULL) delete [] jPoint_UndLapl; - if (FlowPrimVar_i != NULL) delete [] FlowPrimVar_i; - if (FlowPrimVar_j != NULL) delete [] FlowPrimVar_j; - - if (Jacobian_Axisymmetric != NULL) { - for (iVar = 0; iVar < nVar; iVar++) - delete Jacobian_Axisymmetric[iVar]; - delete [] Jacobian_Axisymmetric; - } - - if (CSensitivity != NULL) { - for (iMarker = 0; iMarker < nMarker; iMarker++) - delete CSensitivity[iMarker]; - delete [] CSensitivity; - } - -} - -void CAdjEulerSolver::SetTime_Step(CGeometry *geometry, CSolver **solver_container, CConfig *config, - unsigned short iMesh, unsigned long Iteration) { - - /*--- Use the flow solution to update the time step - * The time step depends on the characteristic velocity, which is the same - * for the adjoint and flow solutions, albeit in the opposite direction. ---*/ - solver_container[FLOW_SOL]->SetTime_Step(geometry, solver_container, config, iMesh, Iteration); -} - - -void CAdjEulerSolver::Set_MPI_Solution(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_U = new su2double [nBufferR_Vector]; - Buffer_Send_U = new su2double[nBufferS_Vector]; - - /*--- Copy the solution that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution(iVar); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); - -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_U; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = Buffer_Receive_U[iVar*nVertexR+iVertex]; - - /*--- Rotate the momentum components. ---*/ - if (nDim == 2) { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex]; - } - else { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex] + - rotMatrix[0][2]*Buffer_Receive_U[3*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex] + - rotMatrix[1][2]*Buffer_Receive_U[3*nVertexR+iVertex]; - Solution[3] = rotMatrix[2][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[2][1]*Buffer_Receive_U[2*nVertexR+iVertex] + - rotMatrix[2][2]*Buffer_Receive_U[3*nVertexR+iVertex]; - } - - /*--- Copy transformed conserved variables back into buffer. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetSolution(iVar, Solution[iVar]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_U; - - } - - } - -} - -void CAdjEulerSolver::Set_MPI_Solution_Old(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, - *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_U = new su2double [nBufferR_Vector]; - Buffer_Send_U = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution_Old(iVar); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); - -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_U; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = Buffer_Receive_U[iVar*nVertexR+iVertex]; - - /*--- Rotate the momentum components. ---*/ - if (nDim == 2) { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex]; - } - else { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex] + - rotMatrix[0][2]*Buffer_Receive_U[3*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex] + - rotMatrix[1][2]*Buffer_Receive_U[3*nVertexR+iVertex]; - Solution[3] = rotMatrix[2][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[2][1]*Buffer_Receive_U[2*nVertexR+iVertex] + - rotMatrix[2][2]*Buffer_Receive_U[3*nVertexR+iVertex]; - } - - /*--- Copy transformed conserved variables back into buffer. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetSolution_Old(iVar, Solution[iVar]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_U; - - } - - } -} - -void CAdjEulerSolver::Set_MPI_Solution_Limiter(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, - *Buffer_Receive_Limit = NULL, *Buffer_Send_Limit = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_Limit = new su2double [nBufferR_Vector]; - Buffer_Send_Limit = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_Limit[iVar*nVertexS+iVertex] = node[iPoint]->GetLimiter(iVar); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Limit, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_Limit, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); - -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_Limit[iVar*nVertexR+iVertex] = Buffer_Send_Limit[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_Limit; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = Buffer_Receive_Limit[iVar*nVertexR+iVertex]; - - /*--- Rotate the momentum components. ---*/ - if (nDim == 2) { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_Limit[2*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_Limit[2*nVertexR+iVertex]; - } - else { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + - rotMatrix[0][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + - rotMatrix[1][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; - Solution[3] = rotMatrix[2][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[2][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + - rotMatrix[2][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; - } - - /*--- Copy transformed conserved variables back into buffer. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetLimiter(iVar, Solution[iVar]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_Limit; - - } - - } -} - -void CAdjEulerSolver::Set_MPI_Solution_Gradient(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, - *Buffer_Receive_Gradient = NULL, *Buffer_Send_Gradient = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - su2double **Gradient = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - Gradient[iVar] = new su2double[nDim]; - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar*nDim; nBufferR_Vector = nVertexR*nVar*nDim; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_Gradient = new su2double [nBufferR_Vector]; - Buffer_Send_Gradient = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Gradient[iDim*nVar*nVertexS+iVar*nVertexS+iVertex] = node[iPoint]->GetGradient(iVar, iDim); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Gradient, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_Gradient, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex] = Buffer_Send_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_Gradient; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Gradient[iVar][iDim] = Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; - - /*--- Need to rotate the gradients for all conserved variables. ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - if (nDim == 2) { - Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; - } - else { - Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][2] = rotMatrix[2][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; - } - } - - /*--- Store the received information ---*/ - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - node[iPoint]->SetGradient(iVar, iDim, Gradient[iVar][iDim]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_Gradient; - - } - - } - - for (iVar = 0; iVar < nVar; iVar++) - delete [] Gradient[iVar]; - delete [] Gradient; - -} - - -void CAdjEulerSolver::Set_MPI_Undivided_Laplacian(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, - *Buffer_Receive_Undivided_Laplacian = NULL, *Buffer_Send_Undivided_Laplacian = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_Undivided_Laplacian = new su2double [nBufferR_Vector]; - Buffer_Send_Undivided_Laplacian = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_Undivided_Laplacian[iVar*nVertexS+iVertex] = node[iPoint]->GetUndivided_Laplacian(iVar); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Undivided_Laplacian, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_Undivided_Laplacian, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_Undivided_Laplacian[iVar*nVertexR+iVertex] = Buffer_Send_Undivided_Laplacian[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_Undivided_Laplacian; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = Buffer_Receive_Undivided_Laplacian[iVar*nVertexR+iVertex]; - - /*--- Rotate the momentum components. ---*/ - if (nDim == 2) { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex]; - } - else { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex] + - rotMatrix[0][2]*Buffer_Receive_Undivided_Laplacian[3*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex] + - rotMatrix[1][2]*Buffer_Receive_Undivided_Laplacian[3*nVertexR+iVertex]; - Solution[3] = rotMatrix[2][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + - rotMatrix[2][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex] + - rotMatrix[2][2]*Buffer_Receive_Undivided_Laplacian[3*nVertexR+iVertex]; - } - - /*--- Copy transformed conserved variables back into buffer. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetUndivided_Laplacian(iVar, Solution[iVar]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_Undivided_Laplacian; - - } - - } - -} - -void CAdjEulerSolver::Set_MPI_Dissipation_Switch(CGeometry *geometry, CConfig *config) { - unsigned short iMarker, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double *Buffer_Receive_Lambda = NULL, *Buffer_Send_Lambda = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS; nBufferR_Vector = nVertexR; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_Lambda = new su2double [nBufferR_Vector]; - Buffer_Send_Lambda = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - Buffer_Send_Lambda[iVertex] = node[iPoint]->GetSensor(); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Lambda, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_Lambda, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - Buffer_Receive_Lambda[iVertex] = Buffer_Send_Lambda[iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_Lambda; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - node[iPoint]->SetSensor(Buffer_Receive_Lambda[iVertex]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_Lambda; - - } - - } -} - -void CAdjEulerSolver::SetForceProj_Vector(CGeometry *geometry, CSolver **solver_container, CConfig *config) { - - su2double *ForceProj_Vector, x = 0.0, y = 0.0, z = 0.0, *Normal, CD, CL, Cp, CpTarget, - CT, CQ, x_origin, y_origin, z_origin, WDrag, Area, invCD, CLCD2, invCQ, CTRCQ2; - unsigned short iMarker; - unsigned long iVertex, iPoint; - - int rank = MASTER_NODE; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - su2double Alpha = (config->GetAoA()*PI_NUMBER)/180.0; - su2double Beta = (config->GetAoS()*PI_NUMBER)/180.0; - su2double RefLengthMoment = config->GetRefLengthMoment(); - su2double *RefOriginMoment = config->GetRefOriginMoment(0); - - ForceProj_Vector = new su2double[nDim]; - - /*--- Compute coefficients needed for objective function evaluation. ---*/ - - CD = solver_container[FLOW_SOL]->GetTotal_CDrag(); - CL = solver_container[FLOW_SOL]->GetTotal_CLift(); - CT = solver_container[FLOW_SOL]->GetTotal_CT(); - CQ = solver_container[FLOW_SOL]->GetTotal_CQ(); - invCD = 1.0/CD; CLCD2 = CL/(CD*CD); - invCQ = 1.0/CQ; CTRCQ2 = CT/(RefLengthMoment*CQ*CQ); - - x_origin = RefOriginMoment[0]; y_origin = RefOriginMoment[1]; z_origin = RefOriginMoment[2]; - - /*--- Evaluate the boundary condition coefficients. ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) - - if ((config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) && - (config->GetMarker_All_Monitoring(iMarker) == YES)) - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - x = geometry->node[iPoint]->GetCoord(0); - y = geometry->node[iPoint]->GetCoord(1); - if (nDim == 3) z = geometry->node[iPoint]->GetCoord(2); - - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - switch (config->GetKind_ObjFunc()) { - case DRAG_COEFFICIENT : - if (nDim == 2) { ForceProj_Vector[0] = cos(Alpha); ForceProj_Vector[1] = sin(Alpha); } - if (nDim == 3) { ForceProj_Vector[0] = cos(Alpha)*cos(Beta); ForceProj_Vector[1] = sin(Beta); ForceProj_Vector[2] = sin(Alpha)*cos(Beta); } - break; - case LIFT_COEFFICIENT : - if (nDim == 2) { ForceProj_Vector[0] = -sin(Alpha); ForceProj_Vector[1] = cos(Alpha); } - if (nDim == 3) { ForceProj_Vector[0] = -sin(Alpha); ForceProj_Vector[1] = 0.0; ForceProj_Vector[2] = cos(Alpha); } - break; - case SIDEFORCE_COEFFICIENT : - if ((nDim == 2) && (rank == MASTER_NODE)) { cout << "This functional is not possible in 2D!!" << endl; - exit(EXIT_FAILURE); - } - if (nDim == 3) { ForceProj_Vector[0] = -sin(Beta) * cos(Alpha); ForceProj_Vector[1] = cos(Beta); ForceProj_Vector[2] = -sin(Beta) * sin(Alpha); } - break; - case INVERSE_DESIGN_PRESSURE : - Cp = solver_container[FLOW_SOL]->GetCPressure(iMarker, iVertex); - CpTarget = solver_container[FLOW_SOL]->GetCPressureTarget(iMarker, iVertex); - Area = sqrt(Normal[0]*Normal[0] + Normal[1]*Normal[1]); - if (nDim == 3) Area = sqrt(Normal[0]*Normal[0] + Normal[1]*Normal[1] + Normal[2]*Normal[2]); - ForceProj_Vector[0] = -2.0*(Cp-CpTarget)*Normal[0]/Area; ForceProj_Vector[1] = -2.0*(Cp-CpTarget)*Normal[1]/Area; - if (nDim == 3) ForceProj_Vector[2] = -2.0*(Cp-CpTarget)*Normal[2]/Area; - break; - case MOMENT_X_COEFFICIENT : - if ((nDim == 2) && (rank == MASTER_NODE)) { cout << "This functional is not possible in 2D!!" << endl; exit(EXIT_FAILURE); } - if (nDim == 3) { ForceProj_Vector[0] = 0.0; ForceProj_Vector[1] = -(z - z_origin)/RefLengthMoment; ForceProj_Vector[2] = (y - y_origin)/RefLengthMoment; } - break; - case MOMENT_Y_COEFFICIENT : - if ((nDim == 2) && (rank == MASTER_NODE)) { cout << "This functional is not possible in 2D!!" << endl; exit(EXIT_FAILURE); } - if (nDim == 3) { ForceProj_Vector[0] = (z - z_origin)/RefLengthMoment; ForceProj_Vector[1] = 0.0; ForceProj_Vector[2] = -(x - x_origin)/RefLengthMoment; } - break; - case MOMENT_Z_COEFFICIENT : - if (nDim == 2) { ForceProj_Vector[0] = -(y - y_origin)/RefLengthMoment; ForceProj_Vector[1] = (x - x_origin)/RefLengthMoment; } - if (nDim == 3) { ForceProj_Vector[0] = -(y - y_origin)/RefLengthMoment; ForceProj_Vector[1] = (x - x_origin)/RefLengthMoment; ForceProj_Vector[2] = 0; } - break; - case EFFICIENCY : - if (nDim == 2) { ForceProj_Vector[0] = -(invCD*sin(Alpha)+CLCD2*cos(Alpha)); ForceProj_Vector[1] = (invCD*cos(Alpha)-CLCD2*sin(Alpha)); } - if (nDim == 3) { ForceProj_Vector[0] = -(invCD*sin(Alpha)+CLCD2*cos(Alpha)*cos(Beta)); ForceProj_Vector[1] = -CLCD2*sin(Beta); ForceProj_Vector[2] = (invCD*cos(Alpha)-CLCD2*sin(Alpha)*cos(Beta)); } - break; - case EQUIVALENT_AREA : - WDrag = config->GetWeightCd(); - if (nDim == 2) { ForceProj_Vector[0] = cos(Alpha)*WDrag; ForceProj_Vector[1] = sin(Alpha)*WDrag; } - if (nDim == 3) { ForceProj_Vector[0] = cos(Alpha)*cos(Beta)*WDrag; ForceProj_Vector[1] = sin(Beta)*WDrag; ForceProj_Vector[2] = sin(Alpha)*cos(Beta)*WDrag; } - break; - case NEARFIELD_PRESSURE : - WDrag = config->GetWeightCd(); - if (nDim == 2) { ForceProj_Vector[0] = cos(Alpha)*WDrag; ForceProj_Vector[1] = sin(Alpha)*WDrag; } - if (nDim == 3) { ForceProj_Vector[0] = cos(Alpha)*cos(Beta)*WDrag; ForceProj_Vector[1] = sin(Beta)*WDrag; ForceProj_Vector[2] = sin(Alpha)*cos(Beta)*WDrag; } - break; - case FORCE_X_COEFFICIENT : - if (nDim == 2) { ForceProj_Vector[0] = 1.0; ForceProj_Vector[1] = 0.0; } - if (nDim == 3) { ForceProj_Vector[0] = 1.0; ForceProj_Vector[1] = 0.0; ForceProj_Vector[2] = 0.0; } - break; - case FORCE_Y_COEFFICIENT : - if (nDim == 2) { ForceProj_Vector[0] = 0.0; ForceProj_Vector[1] = 1.0; } - if (nDim == 3) { ForceProj_Vector[0] = 0.0; ForceProj_Vector[1] = 1.0; ForceProj_Vector[2] = 0.0; } - break; - case FORCE_Z_COEFFICIENT : - if ((nDim == 2) && (rank == MASTER_NODE)) {cout << "This functional is not possible in 2D!!" << endl; - exit(EXIT_FAILURE); - } - if (nDim == 3) { ForceProj_Vector[0] = 0.0; ForceProj_Vector[1] = 0.0; ForceProj_Vector[2] = 1.0; } - break; - case THRUST_COEFFICIENT : - if ((nDim == 2) && (rank == MASTER_NODE)) {cout << "This functional is not possible in 2D!!" << endl; - exit(EXIT_FAILURE); - } - if (nDim == 3) { ForceProj_Vector[0] = 0.0; ForceProj_Vector[1] = 0.0; ForceProj_Vector[2] = 1.0; } - break; - case TORQUE_COEFFICIENT : - if (nDim == 2) { ForceProj_Vector[0] = (y - y_origin)/RefLengthMoment; ForceProj_Vector[1] = -(x - x_origin)/RefLengthMoment; } - if (nDim == 3) { ForceProj_Vector[0] = (y - y_origin)/RefLengthMoment; ForceProj_Vector[1] = -(x - x_origin)/RefLengthMoment; ForceProj_Vector[2] = 0; } - break; - case FIGURE_OF_MERIT : - if ((nDim == 2) && (rank == MASTER_NODE)) {cout << "This functional is not possible in 2D!!" << endl; - exit(EXIT_FAILURE); - } - if (nDim == 3) { - ForceProj_Vector[0] = -invCQ; - ForceProj_Vector[1] = -CTRCQ2*(z - z_origin); - ForceProj_Vector[2] = CTRCQ2*(y - y_origin); - } - break; - default : - if (nDim == 2) { ForceProj_Vector[0] = 0.0; ForceProj_Vector[1] = 0.0; } - if (nDim == 3) { ForceProj_Vector[0] = 0.0; ForceProj_Vector[1] = 0.0; ForceProj_Vector[2] = 0.0; } - break; - } - - /*--- Store the force projection vector at this node ---*/ - - node[iPoint]->SetForceProj_Vector(ForceProj_Vector); - - } - - delete [] ForceProj_Vector; - -} - -void CAdjEulerSolver::SetIntBoundary_Jump(CGeometry *geometry, CSolver **solver_container, CConfig *config) { - unsigned short iMarker, iVar, jVar, kVar, iDim, jDim, iIndex; - unsigned long iVertex, iPoint, iPointNearField, nPointNearField = 0; - su2double factor = 1.0, AngleDouble, data, aux, *IntBound_Vector, *coord, *FlowSolution, WeightSB, MinDist = 1E6, Dist, DerivativeOF = 0.0, *Normal, Area, UnitNormal[3], velocity[3], Energy, Rho, sqvel, proj_vel, phi, a1, a2; - su2double **A, **M, **AM, *b; - short AngleInt = 0, IndexNF_inv[180], iColumn; - ifstream index_file; - string text_line; - vector > NearFieldWeight; - vector CoordNF; - vector IndexNF; - - IntBound_Vector = new su2double [nVar]; - - /*--- Allocate vectors and matrices ---*/ - - b = new su2double [nVar]; - A = new su2double* [nVar]; - M = new su2double* [nVar]; - AM = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - A[iVar] = new su2double [nVar]; - M[iVar] = new su2double [nVar]; - AM[iVar] = new su2double [nVar]; - } - - /*--- If equivalent area objective function, read the value of - the derivative from a file, this is a preprocess of the direct solution ---*/ - - if (config->GetKind_ObjFunc() == EQUIVALENT_AREA) { - - /*--- Read derivative of the objective function at the NearField from file ---*/ - index_file.open("WeightNF.dat", ios::in); - if (index_file.fail()) { - cout << "There is no Weight Nearfield Pressure file (WeightNF.dat)." << endl; - exit(EXIT_FAILURE); - } - - nPointNearField = 0; - - while (index_file) { - string line; - getline(index_file, line); - istringstream is(line); - - /*--- The first row provides the azimuthal angle ---*/ - - if (nPointNearField == 0) { - is >> data; // The first column is related with the coordinate - while (is.good()) { is >> data; IndexNF.push_back(SU2_TYPE::Int(data)); } - } - else { - is >> data; CoordNF.push_back(data); // The first column is the point coordinate - vector row; - while (is.good()) { is >> data; row.push_back(data); } - NearFieldWeight.push_back(row); - } - nPointNearField++; - } - - /*--- Note tha the first row is the azimuthal angle ---*/ - - nPointNearField = nPointNearField - 1; - - for (AngleInt = 0; AngleInt < 180; AngleInt++) - IndexNF_inv[AngleInt] = -1; - - for (iIndex = 0; iIndex < IndexNF.size(); iIndex++) - IndexNF_inv[IndexNF[iIndex]] = iIndex; - - } - - /*--- Compute the jump on the adjoint variables for the upper and the lower side ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) - - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; - Area = sqrt (Area); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = Normal[iDim]/Area; - - if (geometry->node[iPoint]->GetDomain()) { - - coord = geometry->node[iPoint]->GetCoord(); - DerivativeOF = 0.0; - - /*--- Just in case the functional depend also on the surface pressure ---*/ - - WeightSB = 1.0-config->GetWeightCd(); - - su2double AoA, XcoordRot = 0.0, YcoordRot = 0.0, ZcoordRot = 0.0; - - if (nDim == 2) XcoordRot = coord[0]; - if (nDim == 3) { - - /*--- Rotate the nearfield cylinder ---*/ - - AoA = -(config->GetAoA()*PI_NUMBER/180.0); - XcoordRot = coord[0]*cos(AoA) - coord[2]*sin(AoA); - YcoordRot = coord[1]; - ZcoordRot = coord[0]*sin(AoA) + coord[2]*cos(AoA); - } - - switch (config->GetKind_ObjFunc()) { - case EQUIVALENT_AREA : - - if (nDim == 2) AngleInt = 0; - - if (nDim == 3) { - - /*--- Compute the azimuthal angle of the iPoint ---*/ - - AngleDouble = fabs(atan(-YcoordRot/ZcoordRot)*180.0/PI_NUMBER); - - /*--- Fix an azimuthal line due to misalignments of the near-field ---*/ - - su2double FixAzimuthalLine = config->GetFixAzimuthalLine(); - - if ((AngleDouble >= FixAzimuthalLine - 0.1) && (AngleDouble <= FixAzimuthalLine + 0.1)) AngleDouble = FixAzimuthalLine - 0.1; - - AngleInt = SU2_TYPE::Short(floor(AngleDouble + 0.5)); - if (AngleInt < 0) AngleInt = 180 + AngleInt; - - } - - if (AngleInt <= 60) { - iColumn = IndexNF_inv[AngleInt]; - - /*--- An azimuthal angle is not defined... this happens with MG levels ---*/ - - if (iColumn < 0.0) { - if (IndexNF_inv[AngleInt+1] > 0) { iColumn = IndexNF_inv[AngleInt+1]; goto end; } - if (IndexNF_inv[AngleInt-1] > 0) { iColumn = IndexNF_inv[AngleInt-1]; goto end; } - if (IndexNF_inv[AngleInt+2] > 0) { iColumn = IndexNF_inv[AngleInt+2]; goto end; } - if (IndexNF_inv[AngleInt-2] > 0) { iColumn = IndexNF_inv[AngleInt-2]; goto end; } - if (IndexNF_inv[AngleInt+3] > 0) { iColumn = IndexNF_inv[AngleInt+3]; goto end; } - if (IndexNF_inv[AngleInt-3] > 0) { iColumn = IndexNF_inv[AngleInt-3]; goto end; } - if (IndexNF_inv[AngleInt+4] > 0) { iColumn = IndexNF_inv[AngleInt+4]; goto end; } - if (IndexNF_inv[AngleInt-4] > 0) { iColumn = IndexNF_inv[AngleInt-4]; goto end; } - } - - end: - - if (iColumn < 0.0) { cout <<" An azimuthal angle is not defined..." << endl; } - - /*--- Find the value of the weight in the table, using the azimuthal angle ---*/ - - MinDist = 1E6; - for (iPointNearField = 0; iPointNearField < nPointNearField; iPointNearField++) { - Dist = fabs(CoordNF[iPointNearField] - XcoordRot); - if (Dist <= MinDist) { - MinDist = Dist; - DerivativeOF = factor*WeightSB*NearFieldWeight[iPointNearField][iColumn]; - } - } - } - else DerivativeOF = 0.0; - - if ((MinDist > 1E-6) || (coord[nDim-1] > 0.0)) DerivativeOF = 0.0; - - break; - - case NEARFIELD_PRESSURE : - - DerivativeOF = factor*WeightSB*(solver_container[FLOW_SOL]->node[iPoint]->GetPressure() - - solver_container[FLOW_SOL]->GetPressure_Inf()); - - break; - - } - - /*--- Compute the jump of the adjoint variables (2D, and 3D problems) --*/ - - FlowSolution = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); - - Rho = FlowSolution[0]; - Energy = FlowSolution[nVar-1]/FlowSolution[0]; - - sqvel = 0.0; proj_vel = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - velocity[iDim] = FlowSolution[iDim+1]/FlowSolution[0]; - sqvel += velocity[iDim]*velocity[iDim]; - proj_vel += velocity[iDim]*UnitNormal[iDim]; - } - - if (nDim == 2) { - - /*--- Compute the projected Jacobian ---*/ - - A[0][0] = 0.0; A[0][1] = 0.0; A[0][2] = 1.0; A[0][3] = 0.0; - A[1][0] = -velocity[0]*velocity[1]; A[1][1] = velocity[1]; A[1][2] = velocity[0]; A[1][3] = 0.0; - A[2][0] = 0.5*(Gamma-3.0)*velocity[1]*velocity[1]+0.5*Gamma_Minus_One*velocity[0]*velocity[0]; A[2][1] = -Gamma_Minus_One*velocity[0]; - A[2][2] = (3.0-Gamma)*velocity[1]; A[2][3] = Gamma_Minus_One; A[3][0] = -Gamma*velocity[1]*Energy+Gamma_Minus_One*velocity[1]*sqvel; - A[3][1] = -Gamma_Minus_One*velocity[0]*velocity[1]; A[3][2] = Gamma*Energy-0.5*Gamma_Minus_One*(velocity[0]*velocity[0]+3.0*velocity[1]*velocity[1]); A[3][3] = Gamma*velocity[1]; - - /*--- Compute the transformation matrix ---*/ - - M[0][0] = 1.0; M[0][1] = 0.0; M[0][2] = 0.0; M[0][3] = 0.0; - M[1][0] = velocity[0]; M[1][1] = Rho; M[1][2] = 0.0; M[1][3] = 0.0; - M[2][0] = velocity[1]; M[2][1] = 0.0; M[2][2] = Rho; M[2][3] = 0.0; - M[3][0] = 0.5*sqvel; M[3][1] = Rho*velocity[0]; M[3][2] = Rho*velocity[1]; M[3][3] = 1.0/Gamma_Minus_One; - - /*--- Create the soruce term (AM)^T X = b ---*/ - - b[0] = 0.0; b[1] = 0.0; b[2] = 0.0; b[3] = DerivativeOF; - - } - - if (nDim == 3) { - - - /*--- Compute the projected Jacobian ---*/ - - phi = 0.5*Gamma_Minus_One*sqvel; - a1 = Gamma*Energy-phi; a2 = Gamma-1.0; - - A[0][0] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) A[0][iDim+1] = UnitNormal[iDim]; - A[0][nDim+1] = 0.0; - - for (iDim = 0; iDim < nDim; iDim++) { - A[iDim+1][0] = (UnitNormal[iDim]*phi - velocity[iDim]*proj_vel); - for (jDim = 0; jDim < nDim; jDim++) - A[iDim+1][jDim+1] = (UnitNormal[jDim]*velocity[iDim]-a2*UnitNormal[iDim]*velocity[jDim]); - A[iDim+1][iDim+1] += proj_vel; - A[iDim+1][nDim+1] = a2*UnitNormal[iDim]; - } - - A[nDim+1][0] = proj_vel*(phi-a1); - for (iDim = 0; iDim < nDim; iDim++) - A[nDim+1][iDim+1] = (UnitNormal[iDim]*a1-a2*velocity[iDim]*proj_vel); - A[nDim+1][nDim+1] = Gamma*proj_vel; - - /*--- Compute the transformation matrix ---*/ - - M[0][0] = 1.0; M[0][1] = 0.0; M[0][2] = 0.0; M[0][3] = 0.0; M[0][4] = 0.0; - M[1][0] = velocity[0]; M[1][1] = Rho; M[1][2] = 0.0; M[1][3] = 0.0; M[1][4] = 0.0; - M[2][0] = velocity[1]; M[2][1] = 0.0; M[2][2] = Rho; M[2][3] = 0.0; M[2][4] = 0.0; - M[3][0] = velocity[2]; M[3][1] = 0.0; M[3][2] = 0.0; M[3][3] = Rho; M[3][4] = 0.0; - M[4][0] = 0.5*sqvel; M[4][1] = Rho*velocity[0]; M[4][2] = Rho*velocity[1]; - M[4][3] = Rho*velocity[2]; M[4][4] = 1.0/Gamma_Minus_One; - - /*--- Create the soruce term (AM)^T X = b ---*/ - - b[0] = 0.0; b[1] = 0.0; b[2] = 0.0; b[3] = 0.0; b[4] = DerivativeOF; - - } - - /*--- Compute A times M ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) { - aux = 0.0; - for (kVar = 0; kVar < nVar; kVar++) - aux += A[iVar][kVar]*M[kVar][jVar]; - AM[iVar][jVar] = aux; - } - - /*--- Compute the transpose matrix ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - A[iVar][jVar] = AM[jVar][iVar]; - - /*--- Solve the linear system using a LU descomposition --*/ - - Gauss_Elimination(A, b, nVar); - - /*--- Update the internal boundary jump --*/ - - for (iVar = 0; iVar < nVar; iVar++) - IntBound_Vector[iVar] = b[iVar]; - - node[iPoint]->SetIntBoundary_Jump(IntBound_Vector); - - } - } - - delete [] IntBound_Vector; - - /*--- Deallocate the linear system ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - delete [] A[iVar]; - delete [] M[iVar]; - delete [] AM[iVar]; - } - delete [] A; - delete [] M; - delete [] AM; - delete [] b; - -} - -void CAdjEulerSolver::SetInitialCondition(CGeometry **geometry, CSolver ***solver_container, CConfig *config, unsigned long ExtIter) { - unsigned long iPoint, Point_Fine; - unsigned short iMesh, iChildren, iVar; - su2double LevelSet, Area_Children, Area_Parent, LevelSet_Fine, *Solution, *Solution_Fine; - - bool restart = config->GetRestart(); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - - if (freesurface) { - - for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { - - for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { - - /*--- Set initial boundary condition at iter 0 ---*/ - if ((ExtIter == 0) && (!restart)) { - - /*--- Compute the adjoint level set value in all the MG levels ---*/ - if (iMesh == MESH_0) { - solver_container[iMesh][ADJFLOW_SOL]->node[iPoint]->SetSolution(nDim+1, 0.0); - } - else { - Area_Parent = geometry[iMesh]->node[iPoint]->GetVolume(); - LevelSet = 0.0; - for (iChildren = 0; iChildren < geometry[iMesh]->node[iPoint]->GetnChildren_CV(); iChildren++) { - Point_Fine = geometry[iMesh]->node[iPoint]->GetChildren_CV(iChildren); - Area_Children = geometry[iMesh-1]->node[Point_Fine]->GetVolume(); - LevelSet_Fine = solver_container[iMesh-1][ADJFLOW_SOL]->node[Point_Fine]->GetSolution(nDim+1); - LevelSet += LevelSet_Fine*Area_Children/Area_Parent; - } - solver_container[iMesh][ADJFLOW_SOL]->node[iPoint]->SetSolution(nDim+1, LevelSet); - } - - /*--- Compute the flow solution using the level set value. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - solver_container[iMesh][ADJFLOW_SOL]->node[iPoint]->SetSolution(iVar, 0.0); - - } - } - - /*--- Set the MPI communication ---*/ - solver_container[iMesh][ADJFLOW_SOL]->Set_MPI_Solution(geometry[iMesh], config); - - } - - } - - /*--- If restart solution, then interpolate the flow solution to - all the multigrid levels, this is important with the dual time strategy ---*/ - if (restart) { - Solution = new su2double[nVar]; - for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++) { - for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { - Area_Parent = geometry[iMesh]->node[iPoint]->GetVolume(); - for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; - for (iChildren = 0; iChildren < geometry[iMesh]->node[iPoint]->GetnChildren_CV(); iChildren++) { - Point_Fine = geometry[iMesh]->node[iPoint]->GetChildren_CV(iChildren); - Area_Children = geometry[iMesh-1]->node[Point_Fine]->GetVolume(); - Solution_Fine = solver_container[iMesh-1][ADJFLOW_SOL]->node[Point_Fine]->GetSolution(); - for (iVar = 0; iVar < nVar; iVar++) { - Solution[iVar] += Solution_Fine[iVar]*Area_Children/Area_Parent; - } - } - solver_container[iMesh][ADJFLOW_SOL]->node[iPoint]->SetSolution(Solution); - - } - solver_container[iMesh][ADJFLOW_SOL]->Set_MPI_Solution(geometry[iMesh], config); - } - delete [] Solution; - } - - /*--- The value of the solution for the first iteration of the dual time ---*/ - for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { - for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { - if ((ExtIter == 0) && (dual_time)) { - solver_container[iMesh][ADJFLOW_SOL]->node[iPoint]->Set_Solution_time_n(); - solver_container[iMesh][ADJFLOW_SOL]->node[iPoint]->Set_Solution_time_n1(); - } - } - } - -} - -void CAdjEulerSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { - - unsigned long iPoint, ErrorCounter = 0; - su2double SharpEdge_Distance; - bool RightSol = true; - -#ifdef HAVE_MPI - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Retrieve information about the spatial and temporal integration for the - adjoint equations (note that the flow problem may use different methods). ---*/ - - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - bool second_order = ((config->GetSpatialOrder_AdjFlow() == SECOND_ORDER) || (config->GetSpatialOrder_AdjFlow() == SECOND_ORDER_LIMITER)); - bool limiter = (config->GetSpatialOrder_AdjFlow() == SECOND_ORDER_LIMITER); - bool center = (config->GetKind_ConvNumScheme_AdjFlow() == SPACE_CENTERED); - bool center_jst = (config->GetKind_Centered_AdjFlow() == JST); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool engine = ((config->GetnMarker_EngineInflow() != 0) || (config->GetnMarker_EngineBleed() != 0) || (config->GetnMarker_EngineExhaust() != 0)); - - /*--- Compute nacelle inflow and exhaust properties ---*/ - - if (engine) { GetEngine_Properties(geometry, config, iMesh, Output); } - - /*--- Residual initialization ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint ++) { - - /*--- Get the distance form a sharp edge ---*/ - - SharpEdge_Distance = geometry->node[iPoint]->GetSharpEdge_Distance(); - - /*--- Initialize the non-physical points vector ---*/ - - node[iPoint]->SetNon_Physical(false); - - /*--- Set the primitive variables incompressible and compressible - adjoint variables ---*/ - - if (compressible) RightSol = node[iPoint]->SetPrimVar_Compressible(SharpEdge_Distance, false, config); - if (incompressible) RightSol = node[iPoint]->SetPrimVar_Incompressible(SharpEdge_Distance, false, config); - if (freesurface) RightSol = node[iPoint]->SetPrimVar_FreeSurface(SharpEdge_Distance, false, config); - if (!RightSol) { node[iPoint]->SetNon_Physical(true); ErrorCounter++; } - - /*--- Initialize the convective residual vector ---*/ - - LinSysRes.SetBlock_Zero(iPoint); - - } - - - if ((second_order) && (iMesh == MESH_0)) { - - /*--- Compute gradients for upwind second-order reconstruction ---*/ - - if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); - - /*--- Limiter computation ---*/ - - if (limiter) SetSolution_Limiter(geometry, config); - - } - - /*--- Artificial dissipation for centered schemes ---*/ - - if (center) { - if ((center_jst) && (iMesh == MESH_0)) { - SetDissipation_Switch(geometry, config); - SetUndivided_Laplacian(geometry, config); - if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); - } - } - - /*--- Initialize the Jacobian for implicit integration ---*/ - - if (implicit) Jacobian.SetValZero(); - - /*--- Error message ---*/ - - if (config->GetConsole_Output_Verb() == VERB_HIGH) { -#ifdef HAVE_MPI - unsigned long MyErrorCounter = ErrorCounter; ErrorCounter = 0; - SU2_MPI::Allreduce(&MyErrorCounter, &ErrorCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#endif - if (iMesh == MESH_0) config->SetNonphysical_Points(ErrorCounter); - } - -} - -void CAdjEulerSolver::Centered_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config, unsigned short iMesh, unsigned short iRKStep) { - - unsigned long iEdge, iPoint, jPoint; - - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - bool second_order = ((config->GetKind_Centered_AdjFlow() == JST) && (iMesh == MESH_0)); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool grid_movement = config->GetGrid_Movement(); - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Points in edge, normal, and neighbors---*/ - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); - numerics->SetNeighbor(geometry->node[iPoint]->GetnNeighbor(), geometry->node[jPoint]->GetnNeighbor()); - - /*--- Adjoint variables w/o reconstruction ---*/ - - numerics->SetAdjointVar(node[iPoint]->GetSolution(), node[jPoint]->GetSolution()); - - /*--- Conservative variables w/o reconstruction ---*/ - - numerics->SetConservative(solver_container[FLOW_SOL]->node[iPoint]->GetSolution(), - solver_container[FLOW_SOL]->node[jPoint]->GetSolution()); - - if (compressible) { - numerics->SetSoundSpeed(solver_container[FLOW_SOL]->node[iPoint]->GetSoundSpeed(), - solver_container[FLOW_SOL]->node[jPoint]->GetSoundSpeed()); - numerics->SetEnthalpy(solver_container[FLOW_SOL]->node[iPoint]->GetEnthalpy(), - solver_container[FLOW_SOL]->node[jPoint]->GetEnthalpy()); - } - if (incompressible || freesurface) { - numerics->SetDensityInc(solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(), solver_container[FLOW_SOL]->node[jPoint]->GetDensityInc()); - numerics->SetBetaInc2(solver_container[FLOW_SOL]->node[iPoint]->GetBetaInc2(), solver_container[FLOW_SOL]->node[jPoint]->GetBetaInc2()); - numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[jPoint]->GetCoord()); - } - - numerics->SetLambda(solver_container[FLOW_SOL]->node[iPoint]->GetLambda(), - solver_container[FLOW_SOL]->node[jPoint]->GetLambda()); - - if (second_order) { - numerics->SetUndivided_Laplacian(node[iPoint]->GetUndivided_Laplacian(), node[jPoint]->GetUndivided_Laplacian()); - numerics->SetSensor(node[iPoint]->GetSensor(), node[jPoint]->GetSensor()); - } - - /*--- Mesh motion ---*/ - - if (grid_movement) { - numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[jPoint]->GetGridVel()); - } - - /*--- Compute residuals ---*/ - - numerics->ComputeResidual(Res_Conv_i, Res_Visc_i, Res_Conv_j, Res_Visc_j, - Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - /*--- Update convective and artificial dissipation residuals ---*/ - - LinSysRes.SubtractBlock(iPoint, Res_Conv_i); - LinSysRes.SubtractBlock(jPoint, Res_Conv_j); - LinSysRes.SubtractBlock(iPoint, Res_Visc_i); - LinSysRes.SubtractBlock(jPoint, Res_Visc_j); - - /*--- Implicit contribution to the residual ---*/ - - if (implicit) { - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - Jacobian.SubtractBlock(iPoint, jPoint, Jacobian_ij); - Jacobian.SubtractBlock(jPoint, iPoint, Jacobian_ji); - Jacobian.SubtractBlock(jPoint, jPoint, Jacobian_jj); - } - - } -} - - -void CAdjEulerSolver::Upwind_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, unsigned short iMesh) { - - su2double **Gradient_i, **Gradient_j, Project_Grad_i, Project_Grad_j, *Limiter_i = NULL, - *Limiter_j = NULL, *Psi_i = NULL, *Psi_j = NULL, *V_i, *V_j, Non_Physical = 1.0; - unsigned long iEdge, iPoint, jPoint; - unsigned short iDim, iVar; - - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - bool second_order = (((config->GetSpatialOrder_AdjFlow() == SECOND_ORDER) || (config->GetSpatialOrder_AdjFlow() == SECOND_ORDER_LIMITER)) && (iMesh == MESH_0)); - bool limiter = (config->GetSpatialOrder_AdjFlow() == SECOND_ORDER_LIMITER); - bool grid_movement = config->GetGrid_Movement(); - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Points in edge and normal vectors ---*/ - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); - - /*--- Adjoint variables w/o reconstruction ---*/ - - Psi_i = node[iPoint]->GetSolution(); - Psi_j = node[jPoint]->GetSolution(); - numerics->SetAdjointVar(Psi_i, Psi_j); - - /*--- Primitive variables w/o reconstruction ---*/ - - V_i = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - V_j = solver_container[FLOW_SOL]->node[jPoint]->GetPrimitive(); - numerics->SetPrimitive(V_i, V_j); - - /*--- Grid velocities for dynamic meshes ---*/ - - if (grid_movement) { - numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[jPoint]->GetGridVel()); - } - - /*--- High order reconstruction using MUSCL strategy ---*/ - - if (second_order) { - - for (iDim = 0; iDim < nDim; iDim++) { - Vector_i[iDim] = 0.5*(geometry->node[jPoint]->GetCoord(iDim) - geometry->node[iPoint]->GetCoord(iDim)); - Vector_j[iDim] = 0.5*(geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim)); - } - - /*--- Adjoint variables using gradient reconstruction and limiters ---*/ - - Gradient_i = node[iPoint]->GetGradient(); Gradient_j = node[jPoint]->GetGradient(); - if (limiter) { Limiter_i = node[iPoint]->GetLimiter(); Limiter_j = node[jPoint]->GetLimiter(); } - - for (iVar = 0; iVar < nVar; iVar++) { - Project_Grad_i = 0; Project_Grad_j = 0; - Non_Physical = node[iPoint]->GetNon_Physical()*node[jPoint]->GetNon_Physical(); - for (iDim = 0; iDim < nDim; iDim++) { - Project_Grad_i += Vector_i[iDim]*Gradient_i[iVar][iDim]*Non_Physical; - Project_Grad_j += Vector_j[iDim]*Gradient_j[iVar][iDim]*Non_Physical; - } - if (limiter) { - Solution_i[iVar] = Psi_i[iVar] + Project_Grad_i*Limiter_i[iDim]; - Solution_j[iVar] = Psi_j[iVar] + Project_Grad_j*Limiter_j[iDim]; - } - else { - Solution_i[iVar] = Psi_i[iVar] + Project_Grad_i; - Solution_j[iVar] = Psi_j[iVar] + Project_Grad_j; - } - } - - numerics->SetAdjointVar(Solution_i, Solution_j); - - } - - /*--- Compute the residual---*/ - - numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - /*--- Add and Subtract Residual ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual_i); - LinSysRes.SubtractBlock(jPoint, Residual_j); - - /*--- Implicit contribution to the residual ---*/ - - if (implicit) { - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - Jacobian.SubtractBlock(iPoint, jPoint, Jacobian_ij); - Jacobian.SubtractBlock(jPoint, iPoint, Jacobian_ji); - Jacobian.SubtractBlock(jPoint, jPoint, Jacobian_jj); - } - - } - -} - -void CAdjEulerSolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, - CConfig *config, unsigned short iMesh) { - - unsigned short iVar; - unsigned long iPoint; - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - bool rotating_frame = config->GetRotating_Frame(); - bool axisymmetric = config->GetAxisymmetric(); - // bool gravity = (config->GetGravityForce() == YES); - bool time_spectral = (config->GetUnsteady_Simulation() == TIME_SPECTRAL); - // bool freesurface = (config->GetKind_Regime() == FREESURFACE); - - /*--- Initialize the source residual to zero ---*/ - for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; - - if (rotating_frame) { - - /*--- Loop over all points ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Load the adjoint variables ---*/ - numerics->SetAdjointVar(node[iPoint]->GetSolution(), - node[iPoint]->GetSolution()); - - /*--- Load the volume of the dual mesh cell ---*/ - numerics->SetVolume(geometry->node[iPoint]->GetVolume()); - - /*--- Compute the adjoint rotating frame source residual ---*/ - numerics->ComputeResidual(Residual, Jacobian_i, config); - - /*--- Add the source residual to the total ---*/ - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Add the implicit Jacobian contribution ---*/ - if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - } - } - - if (time_spectral) { - - su2double Volume, Source; - - /*--- loop over points ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Get control volume ---*/ - Volume = geometry->node[iPoint]->GetVolume(); - - /*--- Get stored time spectral source term ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - Source = node[iPoint]->GetTimeSpectral_Source(iVar); - Residual[iVar] = Source*Volume; - } - - /*--- Add Residual ---*/ - LinSysRes.AddBlock(iPoint, Residual); - - } - } - - if (axisymmetric) { - - /*--- Zero out Jacobian structure ---*/ - if (implicit) { - for (iVar = 0; iVar < nVar; iVar ++) - for (unsigned short jVar = 0; jVar < nVar; jVar ++) - Jacobian_i[iVar][jVar] = 0.0; - } - - /*--- loop over points ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Set solution ---*/ - numerics->SetConservative(solver_container[FLOW_SOL]->node[iPoint]->GetSolution(), solver_container[FLOW_SOL]->node[iPoint]->GetSolution()); - - /*--- Set adjoint variables ---*/ - numerics->SetAdjointVar(node[iPoint]->GetSolution(), node[iPoint]->GetSolution()); - - /*--- Set control volume ---*/ - numerics->SetVolume(geometry->node[iPoint]->GetVolume()); - - /*--- Set coordinate ---*/ - numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[iPoint]->GetCoord()); - - /*--- Compute Source term Residual ---*/ - numerics->ComputeResidual(Residual, Jacobian_i, config); - - /*--- Add Residual ---*/ - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Implicit part ---*/ - if (implicit) - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - } - } - - // if (gravity) { - // - // } - - // if (freesurface) { - // for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - // - // su2double Volume = geometry->node[iPoint]->GetVolume(); - // su2double **Gradient = solver_container[ADJLEVELSET_SOL]->node[iPoint]->GetGradient(); - // su2double coeff = solver_container[LEVELSET_SOL]->node[iPoint]->GetSolution(0) / solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); - // - // Residual[0] = 0.0; - // for (iDim = 0; iDim < nDim; iDim++) { - // Residual[iDim+1] = coeff*Gradient[0][iDim]*Volume; - // } - // - // LinSysRes.AddBlock(iPoint, Residual); - // - // } - // } - -} - -void CAdjEulerSolver::Source_Template(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config, unsigned short iMesh) { -} - -void CAdjEulerSolver::SetUndivided_Laplacian(CGeometry *geometry, CConfig *config) { - unsigned long iPoint, jPoint, iEdge; - unsigned short iVar; - su2double *Diff; - - Diff = new su2double[nVar]; - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) - node[iPoint]->SetUnd_LaplZero(); - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - - for (iVar = 0; iVar < nVar; iVar++) - Diff[iVar] = node[iPoint]->GetSolution(iVar) - node[jPoint]->GetSolution(iVar); - -#ifdef STRUCTURED_GRID - - if (geometry->node[iPoint]->GetDomain()) node[iPoint]->SubtractUnd_Lapl(Diff); - if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddUnd_Lapl(Diff); - -#else - - bool boundary_i = geometry->node[iPoint]->GetPhysicalBoundary(); - bool boundary_j = geometry->node[jPoint]->GetPhysicalBoundary(); - - /*--- Both points inside the domain, or both in the boundary ---*/ - if ((!boundary_i && !boundary_j) || (boundary_i && boundary_j)) { - if (geometry->node[iPoint]->GetDomain()) node[iPoint]->SubtractUnd_Lapl(Diff); - if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddUnd_Lapl(Diff); - } - - /*--- iPoint inside the domain, jPoint on the boundary ---*/ - if (!boundary_i && boundary_j) - if (geometry->node[iPoint]->GetDomain()) node[iPoint]->SubtractUnd_Lapl(Diff); - - /*--- jPoint inside the domain, iPoint on the boundary ---*/ - if (boundary_i && !boundary_j) - if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddUnd_Lapl(Diff); - -#endif - - } - -#ifdef STRUCTURED_GRID - - unsigned long Point_Normal = 0, iVertex; - unsigned short iMarker; - su2double *Psi_mirror; - - Psi_mirror = new su2double[nVar]; - - /*--- Loop over all boundaries and include an extra contribution - from a halo node. Find the nearest normal, interior point - for a boundary node and make a linear approximation. ---*/ - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE && - config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY && - config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY && - config->GetMarker_All_KindBC(iMarker) != PERIODIC_BOUNDARY) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - Point_Normal = geometry->vertex[iMarker][iVertex]->GetNormal_Neighbor(); - - /*--- Interpolate & compute difference in the conserved variables ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - Psi_mirror[iVar] = 2.0*node[iPoint]->GetSolution(iVar) - node[Point_Normal]->GetSolution(iVar); - Diff[iVar] = node[iPoint]->GetSolution(iVar) - Psi_mirror[iVar]; - } - - /*--- Subtract contribution at the boundary node only ---*/ - node[iPoint]->SubtractUnd_Lapl(Diff); - } - } - } - } - - delete [] Psi_mirror; - -#endif - - delete [] Diff; - - /*--- MPI parallelization ---*/ - Set_MPI_Undivided_Laplacian(geometry, config); - -} - -void CAdjEulerSolver::SetDissipation_Switch(CGeometry *geometry, CConfig *config) { - - unsigned long iPoint; - su2double SharpEdge_Distance, eps, ds, scale, Sensor, Param_Kappa_2, Param_Kappa_4; - - eps = config->GetLimiterCoeff()*config->GetRefElemLength(); - Param_Kappa_2 = config->GetKappa_2nd_AdjFlow(); - Param_Kappa_4 = config->GetKappa_4th_AdjFlow(); - - if (Param_Kappa_2 != 0.0) scale = 2.0 * Param_Kappa_4 / Param_Kappa_2; - else scale = 0.0; - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - - SharpEdge_Distance = (geometry->node[iPoint]->GetSharpEdge_Distance() - config->GetSharpEdgesCoeff()*eps); - - ds = 0.0; - if (SharpEdge_Distance < -eps) ds = 1.0; - if (fabs(SharpEdge_Distance) <= eps) ds = 1.0 - (0.5*(1.0+(SharpEdge_Distance/eps)+(1.0/PI_NUMBER)*sin(PI_NUMBER*SharpEdge_Distance/eps))); - if (SharpEdge_Distance > eps) ds = 0.0; - - Sensor = scale * ds; - - node[iPoint]->SetSensor(Sensor); - - } - - // su2double dx = 0.1; - // su2double LimK = 0.03; - // su2double eps2 = pow((LimK*dx),3); - // - // unsigned long iPoint, jPoint; - // unsigned short iNeigh, nNeigh, iDim; - // su2double **Gradient_i, *Coord_i, *Coord_j, diff_coord, dist_ij, r_u, r_u_ij, - // du_max, du_min, u_ij, *Solution_i, *Solution_j, dp, dm; - // - // - // for (iPoint = 0; iPoint < nPoint; iPoint++) - // - // if (geometry->node[iPoint]->GetDomain()) { - // - // Solution_i = node[iPoint]->GetSolution(); - // Gradient_i = node[iPoint]->GetGradient(); - // Coord_i = geometry->node[iPoint]->GetCoord(); - // nNeigh = geometry->node[iPoint]->GetnPoint(); - // - // /*--- Find max and min value of the variable in the control volume around the mesh point ---*/ - // du_max = 1.0E-8; du_min = -1.0E-8; - // for (iNeigh = 0; iNeigh < nNeigh; iNeigh++) { - // jPoint = geometry->node[iPoint]->GetPoint(iNeigh); - // Solution_j = node[jPoint]->GetSolution(); - // du_max = max(du_max, Solution_j[0] - Solution_i[0]); - // du_min = min(du_min, Solution_j[0] - Solution_i[0]); - // } - // - // r_u = 1.0; - // for (iNeigh = 0; iNeigh < nNeigh; iNeigh++) { - // - // /*--- Unconstrained reconstructed solution ---*/ - // jPoint = geometry->node[iPoint]->GetPoint(iNeigh); - // Solution_j = node[jPoint]->GetSolution(); - // Coord_j = geometry->node[jPoint]->GetCoord(); - // u_ij = Solution_i[0]; dist_ij = 0; - // for (iDim = 0; iDim < nDim; iDim++) { - // diff_coord = Coord_j[iDim]-Coord_i[iDim]; - // u_ij += 0.5*diff_coord*Gradient_i[0][iDim]; - // } - // - // /*--- Venkatakrishnan limiter ---*/ - // if ((u_ij - Solution_i[0]) >= 0.0) dp = du_max; - // else dp = du_min; - // dm = u_ij - Solution_i[0]; - // r_u_ij = (dp*dp+2.0*dm*dp + eps2)/(dp*dp+2*dm*dm+dm*dp + eps2); - // - // /*--- Take the smallest value of the limiter ---*/ - // r_u = min(r_u, r_u_ij); - // - // } - // node[iPoint]->SetSensor(1.0-r_u); - // } - - /*--- MPI parallelization ---*/ - Set_MPI_Dissipation_Switch(geometry, config); - -} - -void CAdjEulerSolver::ExplicitRK_Iteration(CGeometry *geometry, CSolver **solver_container, - CConfig *config, unsigned short iRKStep) { - su2double *Residual, *Res_TruncError, Vol, Delta, Res; - unsigned short iVar; - unsigned long iPoint; - - su2double RK_AlphaCoeff = config->Get_Alpha_RKStep(iRKStep); - - for (iVar = 0; iVar < nVar; iVar++) { - SetRes_RMS(iVar, 0.0); - SetRes_Max(iVar, 0.0, 0); - } - - /*--- Update the solution ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - Vol = geometry->node[iPoint]->GetVolume(); - Delta = solver_container[FLOW_SOL]->node[iPoint]->GetDelta_Time() / Vol; - - Res_TruncError = node[iPoint]->GetResTruncError(); - Residual = LinSysRes.GetBlock(iPoint); - - for (iVar = 0; iVar < nVar; iVar++) { - Res = Residual[iVar] + Res_TruncError[iVar]; - node[iPoint]->AddSolution(iVar, -Res*Delta*RK_AlphaCoeff); - AddRes_RMS(iVar, Res*Res); - AddRes_Max(iVar, fabs(Res), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); - } - - } - - /*--- MPI solution ---*/ - Set_MPI_Solution(geometry, config); - - /*--- Compute the root mean square residual ---*/ - SetResidual_RMS(geometry, config); - -} - -void CAdjEulerSolver::ExplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { - su2double *local_Residual, *local_Res_TruncError, Vol, Delta, Res; - unsigned short iVar; - unsigned long iPoint; - - for (iVar = 0; iVar < nVar; iVar++) { - SetRes_RMS(iVar, 0.0); - SetRes_Max(iVar, 0.0, 0); - } - - /*--- Update the solution ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - Vol = geometry->node[iPoint]->GetVolume(); - Delta = solver_container[FLOW_SOL]->node[iPoint]->GetDelta_Time() / Vol; - - local_Res_TruncError = node[iPoint]->GetResTruncError(); - local_Residual = LinSysRes.GetBlock(iPoint); - - for (iVar = 0; iVar < nVar; iVar++) { - Res = local_Residual[iVar] + local_Res_TruncError[iVar]; - node[iPoint]->AddSolution(iVar, -Res*Delta); - AddRes_RMS(iVar, Res*Res); - AddRes_Max(iVar, fabs(Res), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); - } - - } - - /*--- MPI solution ---*/ - Set_MPI_Solution(geometry, config); - - /*--- Compute the root mean square residual ---*/ - SetResidual_RMS(geometry, config); - -} - -void CAdjEulerSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { - - unsigned short iVar; - unsigned long iPoint, total_index; - su2double Delta, *local_Res_TruncError, Vol; - - /*--- Set maximum residual to zero ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - SetRes_RMS(iVar, 0.0); - SetRes_Max(iVar, 0.0, 0); - } - - /*--- Build implicit system ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Read the residual ---*/ - - local_Res_TruncError = node[iPoint]->GetResTruncError(); - - /*--- Read the volume ---*/ - - Vol = geometry->node[iPoint]->GetVolume(); - - /*--- Modify matrix diagonal to assure diagonal dominance ---*/ - - if (solver_container[FLOW_SOL]->node[iPoint]->GetDelta_Time() != 0.0) { - Delta = Vol / solver_container[FLOW_SOL]->node[iPoint]->GetDelta_Time(); - Jacobian.AddVal2Diag(iPoint, Delta); - } - else { - Jacobian.SetVal2Diag(iPoint, 1.0); - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar + iVar; - LinSysRes[total_index] = 0.0; - local_Res_TruncError[iVar] = 0.0; - } - } - - /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - LinSysRes[total_index] = -(LinSysRes[total_index] + local_Res_TruncError[iVar]); - LinSysSol[total_index] = 0.0; - AddRes_RMS(iVar, LinSysRes[total_index]*LinSysRes[total_index]); - AddRes_Max(iVar, fabs(LinSysRes[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); - } - - } - - /*--- Initialize residual and solution at the ghost points ---*/ - - for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar + iVar; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - } - } - - /*--- Solve or smooth the linear system ---*/ - - CSysSolve system; - system.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); - - /*--- Update solution (system written in terms of increments) ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) - for (iVar = 0; iVar < nVar; iVar++) { - node[iPoint]->AddSolution(iVar, config->GetRelaxation_Factor_AdjFlow()*LinSysSol[iPoint*nVar+iVar]); - } - - /*--- MPI solution ---*/ - - Set_MPI_Solution(geometry, config); - - /*--- Compute the root mean square residual ---*/ - - SetResidual_RMS(geometry, config); - -} - -void CAdjEulerSolver::Inviscid_Sensitivity(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config) { - - unsigned long iVertex, iPoint, Neigh; - unsigned short iPos, jPos; - unsigned short iDim, iMarker, iNeigh; - su2double *d = NULL, *Normal = NULL, *Psi = NULL, *U = NULL, Enthalpy, conspsi = 0.0, Mach_Inf, - Area, **PrimVar_Grad = NULL, **ConsVar_Grad = NULL, *ConsPsi_Grad = NULL, - ConsPsi, d_press, grad_v, Beta2, v_gradconspsi, UnitNormal[3], *GridVel = NULL, - LevelSet, Target_LevelSet, eps, r, ru, rv, rw, rE, p, T, dp_dr, dp_dru, dp_drv, - dp_drw, dp_drE, dH_dr, dH_dru, dH_drv, dH_drw, dH_drE, H, *USens, D[3][3], Dd[3], scale = 1.0; - su2double RefVel2, RefDensity, Mach2Vel, *Velocity_Inf, factor; - su2double Velocity2, Mach, SoundSpeed, *Velocity; - - USens = new su2double[nVar]; - Velocity = new su2double[nDim]; - - su2double Gas_Constant = config->GetGas_ConstantND(); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool grid_movement = config->GetGrid_Movement(); - su2double RefAreaCoeff = config->GetRefAreaCoeff(); - su2double Mach_Motion = config->GetMach_Motion(); - unsigned short ObjFunc = config->GetKind_ObjFunc(); - - if (config->GetSystemMeasurements() == US) scale = 1.0/12.0; - else scale = 1.0; - - /*--- Compute non-dimensional factor. 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. ---*/ - - if (grid_movement) { - Mach2Vel = sqrt(Gamma*Gas_Constant*config->GetTemperature_FreeStreamND()); - RefVel2 = (Mach_Motion*Mach2Vel)*(Mach_Motion*Mach2Vel); - } - else { - Velocity_Inf = config->GetVelocity_FreeStreamND(); - RefVel2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - RefVel2 += Velocity_Inf[iDim]*Velocity_Inf[iDim]; - } - - RefDensity = config->GetDensity_FreeStreamND(); - - factor = 1.0/(0.5*RefDensity*RefAreaCoeff*RefVel2); - - if ((ObjFunc == INVERSE_DESIGN_HEATFLUX) || (ObjFunc == FREE_SURFACE) || - (ObjFunc == TOTAL_HEATFLUX) || (ObjFunc == MAXIMUM_HEATFLUX) || - (ObjFunc == MASS_FLOW_RATE) ) factor = 1.0; - - if ((ObjFunc == AVG_TOTAL_PRESSURE) || (ObjFunc == AVG_OUTLET_PRESSURE) || - (ObjFunc == OUTLET_CHAIN_RULE)) factor = 1.0/Area_Monitored; - - /*--- Initialize sensitivities to zero ---*/ - - Total_Sens_Geo = 0.0; - Total_Sens_Mach = 0.0; - Total_Sens_AoA = 0.0; - Total_Sens_Press = 0.0; - Total_Sens_Temp = 0.0; - Total_Sens_BPress = 0.0; - - /*--- Loop over boundary markers to select those for Euler walls ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) - - if (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) - - /*--- Loop over points on the surface to store the auxiliary variable ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if (geometry->node[iPoint]->GetDomain()) { - Psi = node[iPoint]->GetSolution(); - U = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); - if (compressible) { - Enthalpy = solver_container[FLOW_SOL]->node[iPoint]->GetEnthalpy(); - conspsi = U[0]*Psi[0] + U[0]*Enthalpy*Psi[nDim+1]; - } - if (incompressible || freesurface) { - Beta2 = solver_container[FLOW_SOL]->node[iPoint]->GetBetaInc2(); - conspsi = Beta2*Psi[0]; - } - for (iDim = 0; iDim < nDim; iDim++) conspsi += U[iDim+1]*Psi[iDim+1]; - - node[iPoint]->SetAuxVar(conspsi); - - /*--- Also load the auxiliary variable for first neighbors ---*/ - - for (iNeigh = 0; iNeigh < geometry->node[iPoint]->GetnPoint(); iNeigh++) { - Neigh = geometry->node[iPoint]->GetPoint(iNeigh); - Psi = node[Neigh]->GetSolution(); - U = solver_container[FLOW_SOL]->node[Neigh]->GetSolution(); - if (compressible) { - Enthalpy = solver_container[FLOW_SOL]->node[Neigh]->GetEnthalpy(); - conspsi = U[0]*Psi[0] + U[0]*Enthalpy*Psi[nDim+1]; - } - if (incompressible || freesurface) { - Beta2 = solver_container[FLOW_SOL]->node[Neigh]->GetBetaInc2(); - conspsi = Beta2*Psi[0]; - } - for (iDim = 0; iDim < nDim; iDim++) conspsi += U[iDim+1]*Psi[iDim+1]; - node[Neigh]->SetAuxVar(conspsi); - } - } - } - - /*--- Compute surface gradients of the auxiliary variable ---*/ - - SetAuxVar_Surface_Gradient(geometry, config); - - /*--- Evaluate the shape sensitivity ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - Sens_Geo[iMarker] = 0.0; - - if (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if (geometry->node[iPoint]->GetDomain()) { - - d = node[iPoint]->GetForceProj_Vector(); - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - Area = 0; - for (iDim = 0; iDim < nDim; iDim++) - Area += Normal[iDim]*Normal[iDim]; - Area = sqrt(Area); - - PrimVar_Grad = solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(); - ConsVar_Grad = solver_container[FLOW_SOL]->node[iPoint]->GetGradient(); - ConsPsi_Grad = node[iPoint]->GetAuxVarGradient(); - ConsPsi = node[iPoint]->GetAuxVar(); - - d_press = 0.0; grad_v = 0.0; v_gradconspsi = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - - /*-- Retrieve the value of the pressure gradient ---*/ - - if (compressible) d_press += d[iDim]*PrimVar_Grad[nDim+1][iDim]; - if (incompressible || freesurface) d_press += d[iDim]*ConsVar_Grad[0][iDim]; - - /*-- Retrieve the value of the velocity gradient ---*/ - - grad_v += PrimVar_Grad[iDim+1][iDim]*ConsPsi; - - /*-- Retrieve the value of the theta gradient ---*/ - - v_gradconspsi += solver_container[FLOW_SOL]->node[iPoint]->GetVelocity(iDim) * ConsPsi_Grad[iDim]; - - /*--- Additional sensitivity term for grid movement ---*/ - - if (grid_movement) { - GridVel = geometry->node[iPoint]->GetGridVel(); - v_gradconspsi -= GridVel[iDim] * ConsPsi_Grad[iDim]; - } - - } - - /*--- Compute additional term in the surface sensitivity for free surface problem. ---*/ - - if (freesurface) { - LevelSet = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(nDim+1); - Target_LevelSet = geometry->node[iPoint]->GetCoord(nDim-1); - d_press += 0.5*(Target_LevelSet - LevelSet)*(Target_LevelSet - LevelSet); - } - - /*--- Compute sensitivity for each surface point ---*/ - - CSensitivity[iMarker][iVertex] = (d_press + grad_v + v_gradconspsi) * Area * scale * factor; - - /*--- Change the sign of the sensitivity if the normal has been flipped --*/ - - if (geometry->node[iPoint]->GetFlip_Orientation()) - CSensitivity[iMarker][iVertex] = -CSensitivity[iMarker][iVertex]; - - /*--- If sharp edge, set the sensitivity to 0 on that region ---*/ - - if (config->GetSens_Remove_Sharp()) { - eps = config->GetLimiterCoeff()*config->GetRefElemLength(); - if ( geometry->node[iPoint]->GetSharpEdge_Distance() < config->GetSharpEdgesCoeff()*eps ) - CSensitivity[iMarker][iVertex] = 0.0; - } - - Sens_Geo[iMarker] -= CSensitivity[iMarker][iVertex]; - - } - } - - Total_Sens_Geo += Sens_Geo[iMarker]; - - } - } - - - /*--- Farfield Sensitivity (Mach, AoA, Press, Temp), only for compressible flows ---*/ - - if (compressible) { - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - Sens_BPress[iMarker] = 0.0; - if (config->GetMarker_All_KindBC(iMarker) == OUTLET_FLOW){ - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - Psi = node[iPoint]->GetSolution(); - U = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - - Mach_Inf = config->GetMach(); - if (grid_movement) Mach_Inf = config->GetMach_Motion(); - - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; - Area = sqrt(Area); - for (iDim = 0; iDim < nDim; iDim++) UnitNormal[iDim] = -Normal[iDim]/Area; - Velocity2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity[iDim] = U[iDim+1]/U[0]; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - } - - SoundSpeed = solver_container[FLOW_SOL]->node[iPoint]->GetSoundSpeed(); - Mach = (sqrt(Velocity2))/SoundSpeed; - if (Mach<1.0 && Mach>0.0) - Sens_BPress[iMarker]+=Psi[nDim+1]*SoundSpeed*(Mach-1/Mach)/Gamma_Minus_One; - } - } - Total_Sens_BPress+= Sens_BPress[iMarker] * scale * factor; - } - - if (config->GetMarker_All_KindBC(iMarker) == FAR_FIELD || config->GetMarker_All_KindBC(iMarker) == INLET_FLOW - || config->GetMarker_All_KindBC(iMarker) == SUPERSONIC_INLET || config->GetMarker_All_KindBC(iMarker) == SUPERSONIC_OUTLET - || config->GetMarker_All_KindBC(iMarker) == ENGINE_INFLOW ) { - - Sens_Mach[iMarker] = 0.0; - Sens_AoA[iMarker] = 0.0; - Sens_Press[iMarker] = 0.0; - Sens_Temp[iMarker] = 0.0; - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - Psi = node[iPoint]->GetSolution(); - U = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - - Mach_Inf = config->GetMach(); - if (grid_movement) Mach_Inf = config->GetMach_Motion(); - - r = U[0]; ru = U[1]; rv = U[2]; - if (nDim == 2) { rw = 0.0; rE = U[3]; } - else { rw = U[3]; rE = U[4]; } - p = Gamma_Minus_One*(rE-(ru*ru + rv*rv + rw*rw)/(2*r)); - - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; - Area = sqrt(Area); - for (iDim = 0; iDim < nDim; iDim++) UnitNormal[iDim] = -Normal[iDim]/Area; - - H = (rE + p)/r; - - dp_dr = Gamma_Minus_One*(ru*ru + rv*rv + rw*rw)/(2*r*r); - dp_dru = -Gamma_Minus_One*ru/r; - dp_drv = -Gamma_Minus_One*rv/r; - if (nDim == 2) { dp_drw = 0.0; dp_drE = Gamma_Minus_One; } - else { dp_drw = -Gamma_Minus_One*rw/r; dp_drE = Gamma_Minus_One; } - - dH_dr = (-H + dp_dr)/r; dH_dru = dp_dru/r; dH_drv = dp_drv/r; - if (nDim == 2) { dH_drw = 0.0; dH_drE = (1 + dp_drE)/r; } - else { dH_drw = dp_drw/r; dH_drE = (1 + dp_drE)/r; } - - if (nDim == 2) { - Jacobian_j[0][0] = 0.0; - Jacobian_j[1][0] = Area*UnitNormal[0]; - Jacobian_j[2][0] = Area*UnitNormal[1]; - Jacobian_j[3][0] = 0.0; - - Jacobian_j[0][1] = (-(ru*ru)/(r*r) + dp_dr)*Area*UnitNormal[0] + (-(ru*rv)/(r*r))*Area*UnitNormal[1]; - Jacobian_j[1][1] = (2*ru/r + dp_dru)*Area*UnitNormal[0] + (rv/r)*Area*UnitNormal[1]; - Jacobian_j[2][1] = (dp_drv)*Area*UnitNormal[0] + (ru/r)*Area*UnitNormal[1]; - Jacobian_j[3][1] = (dp_drE)*Area*UnitNormal[0]; - - Jacobian_j[0][2] = (-(ru*rv)/(r*r))*Area*UnitNormal[0] + (-(rv*rv)/(r*r) + dp_dr)*Area*UnitNormal[1]; - Jacobian_j[1][2] = (rv/r)*Area*UnitNormal[0] + (dp_dru)*Area*UnitNormal[1]; - Jacobian_j[2][2] = (ru/r)*Area*UnitNormal[0] + (2*rv/r + dp_drv)*Area*UnitNormal[1]; - Jacobian_j[3][2] = (dp_drE)*Area*UnitNormal[1]; - - Jacobian_j[0][3] = (ru*dH_dr)*Area*UnitNormal[0] + (rv*dH_dr)*Area*UnitNormal[1]; - Jacobian_j[1][3] = (H + ru*dH_dru)*Area*UnitNormal[0] + (rv*dH_dru)*Area*UnitNormal[1]; - Jacobian_j[2][3] = (ru*dH_drv)*Area*UnitNormal[0] + (H + rv*dH_drv)*Area*UnitNormal[1]; - Jacobian_j[3][3] = (ru*dH_drE)*Area*UnitNormal[0] + (rv*dH_drE)*Area*UnitNormal[1]; - } - else { - Jacobian_j[0][0] = 0.0; - Jacobian_j[1][0] = Area*UnitNormal[0]; - Jacobian_j[2][0] = Area*UnitNormal[1]; - Jacobian_j[3][0] = Area*UnitNormal[2]; - Jacobian_j[4][0] = 0.0; - - Jacobian_j[0][1] = (-(ru*ru)/(r*r) + dp_dr)*Area*UnitNormal[0] + (-(ru*rv)/(r*r))*Area*UnitNormal[1] + (-(ru*rw)/(r*r))*Area*UnitNormal[2]; - Jacobian_j[1][1] = (2*ru/r + dp_dru)*Area*UnitNormal[0] + (rv/r)*Area*UnitNormal[1] + (rw/r)*Area*UnitNormal[2]; - Jacobian_j[2][1] = (dp_drv)*Area*UnitNormal[0] + (ru/r)*Area*UnitNormal[1]; - Jacobian_j[3][1] = (dp_drw)*Area*UnitNormal[0] + (ru/r)*Area*UnitNormal[2]; - Jacobian_j[4][1] = (dp_drE)*Area*UnitNormal[0]; - - Jacobian_j[0][2] = (-(ru*rv)/(r*r))*Area*UnitNormal[0] + (-(rv*rv)/(r*r) + dp_dr)*Area*UnitNormal[1] + (-(rv*rw)/(r*r))*Area*UnitNormal[2]; - Jacobian_j[1][2] = (rv/r)*Area*UnitNormal[0] + (dp_dru)*Area*UnitNormal[1]; - Jacobian_j[2][2] = (ru/r)*Area*UnitNormal[0] + (2*rv/r + dp_drv)*Area*UnitNormal[1] + (rw/r)*Area*UnitNormal[2]; - Jacobian_j[3][2] = (dp_drw)*Area*UnitNormal[1] + (rv/r)*Area*UnitNormal[2]; - Jacobian_j[4][2] = (dp_drE)*Area*UnitNormal[1]; - - Jacobian_j[0][3] = (-(ru*rw)/(r*r))*Area*UnitNormal[0] + (-(rv*rw)/(r*r))*Area*UnitNormal[1] + (-(rw*rw)/(r*r) + dp_dr)*Area*UnitNormal[2]; - Jacobian_j[1][3] = (rw/r)*Area*UnitNormal[0] + (dp_dru)*Area*UnitNormal[2]; - Jacobian_j[2][3] = (rw/r)*Area*UnitNormal[1] + (dp_drv)*Area*UnitNormal[2]; - Jacobian_j[3][3] = (ru/r)*Area*UnitNormal[0] + (rv/r)*Area*UnitNormal[1] + (2*rw/r + dp_drw)*Area*UnitNormal[2]; - Jacobian_j[4][3] = (dp_drE)*Area*UnitNormal[2]; - - Jacobian_j[0][4] = (ru*dH_dr)*Area*UnitNormal[0] + (rv*dH_dr)*Area*UnitNormal[1] + (rw*dH_dr)*Area*UnitNormal[2]; - Jacobian_j[1][4] = (H + ru*dH_dru)*Area*UnitNormal[0] + (rv*dH_dru)*Area*UnitNormal[1] + (rw*dH_dru)*Area*UnitNormal[2]; - Jacobian_j[2][4] = (ru*dH_drv)*Area*UnitNormal[0] + (H + rv*dH_drv)*Area*UnitNormal[1] + (rw*dH_drv)*Area*UnitNormal[2]; - Jacobian_j[3][4] = (ru*dH_drw)*Area*UnitNormal[0] + (rv*dH_drw)*Area*UnitNormal[1] + (H + rw*dH_drw)*Area*UnitNormal[2]; - Jacobian_j[4][4] = (ru*dH_drE)*Area*UnitNormal[0] + (rv*dH_drE)*Area*UnitNormal[1] + (rw*dH_drE)*Area*UnitNormal[2]; - } - - /*--- Mach number sensitivity ---*/ - - USens[0] = 0.0; USens[1] = ru/Mach_Inf; USens[2] = rv/Mach_Inf; - if (nDim == 2) { USens[3] = Gamma*Mach_Inf*p; } - else { USens[3] = rw/Mach_Inf; USens[4] = Gamma*Mach_Inf*p; } - for (iPos = 0; iPos < nVar; iPos++) { - for (jPos = 0; jPos < nVar; jPos++) { - Sens_Mach[iMarker] += Psi[iPos]*Jacobian_j[jPos][iPos]*USens[jPos]; - } - } - - /*--- AoA sensitivity ---*/ - - USens[0] = 0.0; - if (nDim == 2) { USens[1] = -rv; USens[2] = ru; USens[3] = 0.0; } - else { USens[1] = -rw; USens[2] = 0.0; USens[3] = ru; USens[4] = 0.0; } - for (iPos = 0; iPos < nVar; iPos++) { - for (jPos = 0; jPos < nVar; jPos++) { - Sens_AoA[iMarker] += Psi[iPos]*Jacobian_j[jPos][iPos]*USens[jPos]; - } - } - - /*--- Pressure sensitivity ---*/ - - USens[0] = r/p; USens[1] = ru/p; USens[2] = rv/p; - if (nDim == 2) { USens[3] = rE/p; } - else { USens[3] = rw/p; USens[4] = rE/p; } - for (iPos = 0; iPos < nVar; iPos++) { - for (jPos = 0; jPos < nVar; jPos++) { - Sens_Press[iMarker] += Psi[iPos]*Jacobian_j[jPos][iPos]*USens[jPos]; - } - } - - /*--- Temperature sensitivity ---*/ - - T = p/(r*Gas_Constant); - USens[0] = -r/T; USens[1] = 0.5*ru/T; USens[2] = 0.5*rv/T; - if (nDim == 2) { USens[3] = (ru*ru + rv*rv + rw*rw)/(r*T); } - else { USens[3] = 0.5*rw/T; USens[4] = (ru*ru + rv*rv + rw*rw)/(r*T); } - for (iPos = 0; iPos < nVar; iPos++) { - for (jPos = 0; jPos < nVar; jPos++) { - Sens_Temp[iMarker] += Psi[iPos]*Jacobian_j[jPos][iPos]*USens[jPos]; - } - } - } - } - - Total_Sens_Mach -= Sens_Mach[iMarker] * scale * factor; - Total_Sens_AoA -= Sens_AoA[iMarker] * scale * factor; - Total_Sens_Press -= Sens_Press[iMarker] * scale * factor; - Total_Sens_Temp -= Sens_Temp[iMarker] * scale * factor; - - } - } - - /*--- Explicit contribution from objective function quantity ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) { - - Sens_Mach[iMarker] = 0.0; - Sens_AoA[iMarker] = 0.0; - Sens_Press[iMarker] = 0.0; - Sens_Temp[iMarker] = 0.0; - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - p = solver_container[FLOW_SOL]->node[iPoint]->GetPressure(); - - Mach_Inf = config->GetMach(); - if (grid_movement) Mach_Inf = config->GetMach_Motion(); - - d = node[iPoint]->GetForceProj_Vector(); - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; - Area = sqrt(Area); - for (iDim = 0; iDim < nDim; iDim++) UnitNormal[iDim] = -Normal[iDim]/Area; - - /*--- Mach number sensitivity ---*/ - - for (iPos = 0; iPos < nDim; iPos++) Dd[iPos] = -(2.0/Mach_Inf)*d[iPos]; - for (iPos = 0; iPos < nDim; iPos++) Sens_Mach[iMarker] += p*Dd[iPos]*Area*UnitNormal[iPos]; - - /*--- AoA sensitivity ---*/ - - if (config->GetKind_ObjFunc() == DRAG_COEFFICIENT || - config->GetKind_ObjFunc() == LIFT_COEFFICIENT || - config->GetKind_ObjFunc() == SIDEFORCE_COEFFICIENT || - config->GetKind_ObjFunc() == EQUIVALENT_AREA || - config->GetKind_ObjFunc() == NEARFIELD_PRESSURE) { - if (nDim == 2) { - D[0][0] = 0.0; D[0][1] = -1.0; - D[1][0] = 1.0; D[1][1] = 0.0; - } - else { - D[0][0] = 0.0; D[0][1] = 0.0; D[0][2] = -1.0; - D[1][0] = 0.0; D[1][1] = 0.0; D[1][2] = 0.0; - D[2][0] = 1.0; D[2][1] = 0.0; D[2][2] = 0.0; - } - for (iPos = 0; iPos < nDim; iPos++) Dd[iPos] = 0.0; - for (iPos = 0; iPos < nDim; iPos++) { - for (jPos = 0; jPos < nDim; jPos++) - Dd[iPos] += D[iPos][jPos]*d[jPos]; - } - } - - /*--- Coefficients with no explicit AoA dependece ---*/ - - else { - for (iPos = 0; iPosGetMarker_All_KindBC(iMarker) == EULER_WALL) { - nVertex = geometry->nVertex[iMarker]; - - /*--- Allocate the linear system ---*/ - - A = new su2double* [nVertex]; - b = new su2double [nVertex]; - ArchLength = new su2double [nVertex]; - for (iVertex = 0; iVertex < nVertex; iVertex++) { - A[iVertex] = new su2double [nVertex]; - } - - /*--- Initialization ---*/ - - for (iVertex = 0; iVertex < nVertex; iVertex++) { - b[iVertex] = 0.0; ArchLength[iVertex] = 0.0; - for (jVertex = 0; jVertex < nVertex; jVertex++) - A[iVertex][jVertex] = 0.0; - } - - /*--- Set the arch length ---*/ - - ArchLength[0] = 0.0; - for (iVertex = 1; iVertex < nVertex; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex-1]->GetNode(); - Coord_begin = geometry->node[iPoint]->GetCoord(); - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Coord_end = geometry->node[iPoint]->GetCoord(); - dist = sqrt (pow( Coord_end[0]-Coord_begin[0], 2.0) + pow( Coord_end[1]-Coord_begin[1], 2.0)); - ArchLength[iVertex] = ArchLength[iVertex-1] + dist; - } - - /*--- Remove the trailing edge effect ---*/ - - su2double MinPosSens = 0.0; su2double MinNegSens = 0.0; - for (iVertex = 0; iVertex < nVertex; iVertex++) { - Sens = CSensitivity[iMarker][iVertex]; - if (ArchLength[iVertex] > ArchLength[nVertex-1]*0.01) { MinNegSens = Sens; break; } - } - - for (iVertex = 0; iVertex < nVertex; iVertex++) { - Sens = CSensitivity[iMarker][iVertex]; - if (ArchLength[iVertex] > ArchLength[nVertex-1]*0.99) { MinPosSens = Sens; break; } - } - - for (iVertex = 0; iVertex < nVertex; iVertex++) { - if (ArchLength[iVertex] < ArchLength[nVertex-1]*0.01) - CSensitivity[iMarker][iVertex] = MinNegSens; - if (ArchLength[iVertex] > ArchLength[nVertex-1]*0.99) - CSensitivity[iMarker][iVertex] = MinPosSens; - } - - /*--- Set the right hand side of the system ---*/ - - for (iVertex = 0; iVertex < nVertex; iVertex++) { - b[iVertex] = CSensitivity[iMarker][iVertex]; - } - - /*--- Set the mass matrix ---*/ - - su2double Coeff = 0.0, BackDiff = 0.0, ForwDiff = 0.0, CentDiff = 0.0; - su2double epsilon = 5E-5; - for (iVertex = 0; iVertex < nVertex; iVertex++) { - - if ((iVertex != nVertex-1) && (iVertex != 0)) { - BackDiff = (ArchLength[iVertex]-ArchLength[iVertex-1]); - ForwDiff = (ArchLength[iVertex+1]-ArchLength[iVertex]); - CentDiff = (ArchLength[iVertex+1]-ArchLength[iVertex-1]); - } - if (iVertex == nVertex-1) { - BackDiff = (ArchLength[nVertex-1]-ArchLength[nVertex-2]); - ForwDiff = (ArchLength[0]-ArchLength[nVertex-1]); - CentDiff = (ArchLength[0]-ArchLength[nVertex-2]); - } - if (iVertex == 0) { - BackDiff = (ArchLength[0]-ArchLength[nVertex-1]); - ForwDiff = (ArchLength[1]-ArchLength[0]); - CentDiff = (ArchLength[1]-ArchLength[nVertex-1]); - } - - Coeff = epsilon*2.0/(BackDiff*ForwDiff*CentDiff); - - A[iVertex][iVertex] = Coeff*CentDiff; - - if (iVertex != 0) A[iVertex][iVertex-1] = -Coeff*ForwDiff; - else A[iVertex][nVertex-1] = -Coeff*ForwDiff; - - if (iVertex != nVertex-1) A[iVertex][iVertex+1] = -Coeff*BackDiff; - else A[iVertex][0] = -Coeff*BackDiff; - - } - - /*--- Add the gradient value in the main diagonal ---*/ - - for (iVertex = 0; iVertex < nVertex; iVertex++) - A[iVertex][iVertex] += 1.0; - - /*--- Dirichlet boundary condition ---*/ - - unsigned long iVertex = SU2_TYPE::Int(nVertex/2); - A[iVertex][iVertex] = 1.0; - A[iVertex][iVertex+1] = 0.0; - A[iVertex][iVertex-1] = 0.0; - - Gauss_Elimination(A, b, (unsigned short)nVertex); - - /*--- Set the new value of the sensitiviy ---*/ - - for (iVertex = 0; iVertex < nVertex; iVertex++) - CSensitivity[iMarker][iVertex] = b[iVertex]; - - /*--- Deallocate the linear system ---*/ - - for (iVertex = 0; iVertex < nVertex; iVertex++) - delete [] A[iVertex]; - delete [] A; - delete [] b; - delete [] ArchLength; - - } - } - - -} - -void CAdjEulerSolver::GetEngine_Properties(CGeometry *geometry, CConfig *config, unsigned short iMesh, bool Output) { - unsigned short iDim, iMarker, iVar; - unsigned long iVertex, iPoint; - su2double Area, Flow_Dir[3], alpha; - - unsigned short nMarker_EngineInflow = config->GetnMarker_EngineInflow(); - unsigned short nMarker_EngineBleed = config->GetnMarker_EngineBleed(); - unsigned short nMarker_EngineExhaust = config->GetnMarker_EngineExhaust(); - - if ((nMarker_EngineInflow != 0) || (nMarker_EngineBleed != 0) || (nMarker_EngineExhaust != 0)) { - - /*--- Check the flow orientation in the nacelle inflow ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == ENGINE_EXHAUST) || (config->GetMarker_All_KindBC(iMarker) == ENGINE_BLEED)) { - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[iMarker][iVertex]->GetNormal(Vector); - - for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = -Vector[iDim]; - - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Area += Vector[iDim]*Vector[iDim]; - Area = sqrt (Area); - - /*--- Compute unitary vector ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - Vector[iDim] /= Area; - - /*--- The flow direction is defined by the local velocity on the surface ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - Flow_Dir[iDim] = node[iPoint]->GetSolution(iDim+1) / node[iPoint]->GetSolution(0); - - /*--- Dot product of normal and flow direction. ---*/ - - alpha = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - alpha += Vector[iDim]*Flow_Dir[iDim]; - - /*--- Flow in the wrong direction. ---*/ - - if (alpha < 0.0) { - - /*--- Copy the old solution ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetSolution(iVar, node[iPoint]->GetSolution_Old(iVar)); - - } - - } - } - - } - - } - -} - -void CAdjEulerSolver::BC_Euler_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, unsigned short val_marker) { - unsigned long iVertex, iPoint; - su2double *d = NULL, *Normal, *U, *Psi_Aux, ProjVel = 0.0, bcn, vn = 0.0, Area, *UnitNormal; - su2double *Velocity, *Psi, Enthalpy = 0.0, sq_vel, phin, phis1, phis2, DensityInc = 0.0, BetaInc2 = 0.0; - unsigned short iDim, iVar, jDim; - - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool grid_movement = config->GetGrid_Movement(); - - UnitNormal = new su2double[nDim]; - Velocity = new su2double[nDim]; - Psi = new su2double[nVar]; - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - Normal = geometry->vertex[val_marker][iVertex]->GetNormal(); - - /*--- Create a copy of the adjoint solution ---*/ - Psi_Aux = node[iPoint]->GetSolution(); - for (iVar = 0; iVar < nVar; iVar++) Psi[iVar] = Psi_Aux[iVar]; - - /*--- Flow solution ---*/ - U = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); - - /*--- Read the value of the objective function ---*/ - d = node[iPoint]->GetForceProj_Vector(); - - /*--- Normal vector computation ---*/ - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; - Area = sqrt(Area); - for (iDim = 0; iDim < nDim; iDim++) UnitNormal[iDim] = -Normal[iDim]/Area; - - - /*--- Compressible solver ---*/ - if (compressible) { - - for (iDim = 0; iDim < nDim; iDim++) - Velocity[iDim] = U[iDim+1] / U[0]; - - Enthalpy = solver_container[FLOW_SOL]->node[iPoint]->GetEnthalpy(); - sq_vel = 0.5*solver_container[FLOW_SOL]->node[iPoint]->GetVelocity2(); - - /*--- Compute projections ---*/ - ProjVel = 0.0; bcn = 0.0; vn = 0.0, phin = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - ProjVel -= Velocity[iDim]*Normal[iDim]; - bcn += d[iDim]*UnitNormal[iDim]; - vn += Velocity[iDim]*UnitNormal[iDim]; - phin += Psi[iDim+1]*UnitNormal[iDim]; - } - - /*--- Extra boundary term for grid movement ---*/ - if (grid_movement) { - su2double ProjGridVel = 0.0; - su2double *GridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - ProjGridVel += GridVel[iDim]*UnitNormal[iDim]; - phin -= Psi[nVar-1]*ProjGridVel; - } - - /*--- Introduce the boundary condition ---*/ - for (iDim = 0; iDim < nDim; iDim++) - Psi[iDim+1] -= ( phin - bcn ) * UnitNormal[iDim]; - - /*--- Inner products after introducing BC (Psi has changed) ---*/ - phis1 = 0.0; phis2 = Psi[0] + Enthalpy * Psi[nVar-1]; - for (iDim = 0; iDim < nDim; iDim++) { - phis1 -= Normal[iDim]*Psi[iDim+1]; - phis2 += Velocity[iDim]*Psi[iDim+1]; - } - - /*--- Flux of the Euler wall ---*/ - Residual[0] = ProjVel * Psi[0] - phis2 * ProjVel + phis1 * Gamma_Minus_One * sq_vel; - for (iDim = 0; iDim < nDim; iDim++) - Residual[iDim+1] = ProjVel * Psi[iDim+1] - phis2 * Normal[iDim] - phis1 * Gamma_Minus_One * Velocity[iDim]; - Residual[nVar-1] = ProjVel * Psi[nVar-1] + phis1 * Gamma_Minus_One; - - /*--- Flux adjustment for grid movement ---*/ - if (grid_movement) { - su2double ProjGridVel = 0.0; - su2double *GridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - ProjGridVel -= GridVel[iDim]*Normal[iDim]; - Residual[0] -= ProjGridVel*Psi[0]; - for (iDim = 0; iDim < nDim; iDim++) - Residual[iDim+1] -= ProjGridVel*Psi[iDim+1]; - Residual[nVar-1] -= ProjGridVel*Psi[nVar-1]; - } - - if (implicit) { - - /*--- Adjoint density ---*/ - Jacobian_ii[0][0] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Jacobian_ii[0][iDim+1] = -ProjVel * (Velocity[iDim] - UnitNormal[iDim] * vn); - Jacobian_ii[0][nVar-1] = -ProjVel * Enthalpy; - - /*--- Adjoint velocities ---*/ - for (iDim = 0; iDim < nDim; iDim++) { - Jacobian_ii[iDim+1][0] = -Normal[iDim]; - for (jDim = 0; jDim < nDim; jDim++) - Jacobian_ii[iDim+1][jDim+1] = -ProjVel*(UnitNormal[jDim]*UnitNormal[iDim] - Normal[iDim] * (Velocity[jDim] - UnitNormal[jDim] * vn)); - Jacobian_ii[iDim+1][iDim+1] += ProjVel; - Jacobian_ii[iDim+1][nVar-1] = -Normal[iDim] * Enthalpy; - } - - /*--- Adjoint energy ---*/ - Jacobian_ii[nVar-1][0] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Jacobian_ii[nVar-1][iDim+1] = 0.0; - Jacobian_ii[nVar-1][nVar-1] = ProjVel; - - /*--- Jacobian contribution due to grid movement ---*/ - if (grid_movement) { - su2double ProjGridVel = 0.0; - su2double *GridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - ProjGridVel -= GridVel[iDim]*Normal[iDim]; - Jacobian_ii[0][0] -= ProjGridVel; - for (iDim = 0; iDim < nDim; iDim++) - Jacobian_ii[iDim+1][iDim+1] -= ProjGridVel; - Jacobian_ii[nVar-1][nVar-1] -= ProjGridVel; - } - - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - } - - /*--- Update residual ---*/ - LinSysRes.SubtractBlock(iPoint, Residual); - - } - /*--- Incompressible solver ---*/ - if (incompressible || freesurface) { - - DensityInc = solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); - BetaInc2 = solver_container[FLOW_SOL]->node[iPoint]->GetBetaInc2(); - - for (iDim = 0; iDim < nDim; iDim++) - Velocity[iDim] = U[iDim+1] / solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); - - /*--- Compute projections ---*/ - bcn = 0.0; phin = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - bcn += d[iDim]*UnitNormal[iDim]; - phin += Psi[iDim+1]*UnitNormal[iDim]; - } - - /*--- Introduce the boundary condition ---*/ - for (iDim = 0; iDim < nDim; iDim++) - Psi[iDim+1] -= ( phin - bcn ) * UnitNormal[iDim]; - - /*--- Inner products after introducing BC (Psi has changed) ---*/ - phis1 = 0.0; phis2 = Psi[0] * (BetaInc2 / DensityInc); - for (iDim = 0; iDim < nDim; iDim++) { - phis1 -= Normal[iDim]*Psi[iDim+1]; - phis2 += Velocity[iDim]*Psi[iDim+1]; - } - - /*--- Flux of the Euler wall ---*/ - Residual[0] = phis1; - for (iDim = 0; iDim < nDim; iDim++) - Residual[iDim+1] = - phis2 * Normal[iDim]; - - /*--- Update residual ---*/ - LinSysRes.SubtractBlock(iPoint, Residual); - - if (implicit) { - - /*--- Adjoint density ---*/ - Jacobian_ii[0][0] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Jacobian_ii[0][iDim+1] = - Normal[iDim]; - - /*--- Adjoint velocities ---*/ - for (iDim = 0; iDim < nDim; iDim++) { - Jacobian_ii[iDim+1][0] = -Normal[iDim] * (BetaInc2 / DensityInc) ; - for (jDim = 0; jDim < nDim; jDim++) - Jacobian_ii[iDim+1][jDim+1] = - Normal[iDim] * Velocity[jDim]; - } - - /*--- Update Jacobian ---*/ - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - } - - } - - } - } - - delete [] Velocity; - delete [] UnitNormal; - delete [] Psi; - -} - -void CAdjEulerSolver::BC_Sym_Plane(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, - CConfig *config, unsigned short val_marker) { - - unsigned long iVertex, iPoint; - su2double *Normal, ProjVel = 0.0, vn = 0.0, Area, *UnitNormal, - *V_domain, *V_sym, *Psi_domain, *Psi_sym, *Velocity, Enthalpy = 0.0, - sq_vel, phin, phis1, phis2, NormalAdjVel; - unsigned short iDim, iVar, jDim; - - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool grid_movement = config->GetGrid_Movement(); - - Normal = new su2double[nDim]; - UnitNormal = new su2double[nDim]; - Velocity = new su2double[nDim]; - Psi_domain = new su2double[nVar]; - Psi_sym = new su2double[nVar]; - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - - Area = 0; - for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; - Area = sqrt(Area); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = -Normal[iDim]/Area; - - if (compressible) { - - /*--- Create a copy of the adjoint solution ---*/ - - for (iVar = 0; iVar < nVar; iVar++) Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); - - /*--- Retrieve flow variables ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - Velocity[iDim] = solver_container[FLOW_SOL]->node[iPoint]->GetVelocity(iDim); - - Enthalpy = solver_container[FLOW_SOL]->node[iPoint]->GetEnthalpy(); - sq_vel = 0.5*solver_container[FLOW_SOL]->node[iPoint]->GetVelocity2(); - - /*--- Compute projections ---*/ - - ProjVel = 0.0; vn = 0.0, phin = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - ProjVel -= Velocity[iDim]*Normal[iDim]; - vn += Velocity[iDim]*UnitNormal[iDim]; - phin += Psi_domain[iDim+1]*UnitNormal[iDim]; - } - - /*--- Grid Movement ---*/ - - if (grid_movement) { - su2double ProjGridVel = 0.0; - su2double *GridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) { - ProjGridVel += GridVel[iDim]*UnitNormal[iDim]; - } - phin -= Psi_domain[nVar-1]*ProjGridVel; - } - - /*--- Introduce the boundary condition ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - Psi_domain[iDim+1] -= phin * UnitNormal[iDim]; - - /*--- Inner products after introducing BC (Psi has changed) ---*/ - - phis1 = 0.0; phis2 = Psi_domain[0] + Enthalpy * Psi_domain[nVar-1]; - for (iDim = 0; iDim < nDim; iDim++) { - phis1 -= Normal[iDim]*Psi_domain[iDim+1]; - phis2 += Velocity[iDim]*Psi_domain[iDim+1]; - } - - /*--- Flux of the Euler wall ---*/ - - Residual_i[0] = ProjVel * Psi_domain[0] - phis2 * ProjVel + phis1 * Gamma_Minus_One * sq_vel; - for (iDim = 0; iDim < nDim; iDim++) - Residual_i[iDim+1] = ProjVel * Psi_domain[iDim+1] - phis2 * Normal[iDim] - phis1 * Gamma_Minus_One * Velocity[iDim]; - Residual_i[nVar-1] = ProjVel * Psi_domain[nVar-1] + phis1 * Gamma_Minus_One; - - /*--- Grid Movement ---*/ - - if (grid_movement) { - su2double ProjGridVel = 0.0; - su2double *GridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - ProjGridVel -= GridVel[iDim]*Normal[iDim]; - Residual_i[0] -= ProjGridVel*Psi_domain[0]; - for (iDim = 0; iDim < nDim; iDim++) - Residual_i[iDim+1] -= ProjGridVel*Psi_domain[iDim+1]; - Residual_i[nVar-1] -= ProjGridVel*Psi_domain[nVar-1]; - } - - } - - if (incompressible || freesurface) { - - /*--- Set the normal vector ---*/ - - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - /*--- Retrieve solution at boundary node ---*/ - - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - V_sym = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - conv_numerics->SetPrimitive(V_domain, V_sym); - - /*--- Adjoint flow solution at the wall ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); - Psi_sym[iVar] = node[iPoint]->GetSolution(iVar); - } - - /*--- Compute normal component of the adjoint velocity ---*/ - - NormalAdjVel = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - NormalAdjVel += Psi_domain[iDim+1]*UnitNormal[iDim]; - - /*--- Remove the normal component ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - Psi_sym[iDim+1] -= NormalAdjVel*UnitNormal[iDim]; - - /*--- Set the value of the adjoint variables ---*/ - - conv_numerics->SetAdjointVar(Psi_domain, Psi_sym); - - /*--- Compute the upwind flux ---*/ - - conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - } - - /*--- Update residual ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual_i); - - /*--- Implicit stuff ---*/ - - if (implicit) { - - if (compressible) { - - /*--- Adjoint density ---*/ - - Jacobian_ii[0][0] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Jacobian_ii[0][iDim+1] = -ProjVel * (Velocity[iDim] - UnitNormal[iDim] * vn); - Jacobian_ii[0][nVar-1] = -ProjVel * Enthalpy; - - /*--- Adjoint velocities ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - Jacobian_ii[iDim+1][0] = -Normal[iDim]; - for (jDim = 0; jDim < nDim; jDim++) - Jacobian_ii[iDim+1][jDim+1] = -ProjVel*(UnitNormal[jDim]*UnitNormal[iDim] - Normal[iDim] * (Velocity[jDim] - UnitNormal[jDim] * vn)); - Jacobian_ii[iDim+1][iDim+1] += ProjVel; - Jacobian_ii[iDim+1][nVar-1] = -Normal[iDim] * Enthalpy; - } - - /*--- Adjoint energy ---*/ - - Jacobian_ii[nVar-1][0] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Jacobian_ii[nVar-1][iDim+1] = 0.0; - Jacobian_ii[nVar-1][nVar-1] = ProjVel; - - /*--- Contribution from grid movement ---*/ - - if (grid_movement) { - su2double ProjGridVel = 0.0; - su2double *GridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - ProjGridVel -= GridVel[iDim]*Normal[iDim]; - Jacobian_ii[0][0] -= ProjGridVel; - for (iDim = 0; iDim < nDim; iDim++) - Jacobian_ii[iDim+1][iDim+1] -= ProjGridVel; - Jacobian_ii[nVar-1][nVar-1] -= ProjGridVel; - } - } - - /*--- Update jacobian ---*/ - - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - } - - } - } - - delete [] Velocity; - delete [] Psi_domain; - delete [] Psi_sym; - delete [] Normal; - delete [] UnitNormal; - -} - -void CAdjEulerSolver::BC_Interface_Boundary(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config) { - - unsigned long iVertex, iPoint, jPoint; - unsigned short iDim, iVar, iMarker; - su2double *V_i, *V_j; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - - su2double *Normal = new su2double[nDim]; - su2double *Psi_i = new su2double[nVar]; - su2double *Psi_j = new su2double[nVar]; - -#ifndef HAVE_MPI - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - jPoint = geometry->vertex[iMarker][iVertex]->GetDonorPoint(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Adjoint variables w/o reconstruction ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - Psi_i[iVar] = node[iPoint]->GetSolution(iVar); - Psi_j[iVar] = node[jPoint]->GetSolution(iVar); - } - numerics->SetAdjointVar(Psi_i, Psi_j); - - /*--- Conservative variables w/o reconstruction ---*/ - - V_i = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - V_j = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - numerics->SetPrimitive(V_i, V_j); - - /*--- Set face vector, and area ---*/ - - geometry->vertex[iMarker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - numerics->SetNormal(Normal); - - /*--- Compute residual ---*/ - - numerics->ComputeResidual(Res_Conv_i, Res_Conv_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - /*--- Add Residuals and Jacobians ---*/ - - LinSysRes.SubtractBlock(iPoint, Res_Conv_i); - if (implicit) Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - } - } - } - } - -#else - - int rank, jProcessor; - MPI_Status send_stat[1], recv_stat[1]; - MPI_Request send_req[1], recv_req[1]; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - bool compute; - su2double *Buffer_Send_Psi = new su2double[nVar]; - su2double *Buffer_Receive_Psi = new su2double[nVar]; - - /*--- Do the send process, by the moment we are sending each - node individually, this must be changed ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Find the associate pair to the original node ---*/ - - jPoint = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; - jProcessor = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; - - if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; - else compute = true; - - /*--- We only send the information that belong to other boundary ---*/ - - if (compute) { - - if (jProcessor != rank) { - - /*--- Copy the adjoint variable ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_Psi[iVar] = node[iPoint]->GetSolution(iVar); - - SU2_MPI::Isend(Buffer_Send_Psi, nVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD, &send_req[0]); - - /*--- Wait for this set of non-blocking comm. to complete ---*/ - - SU2_MPI::Waitall(1, send_req, send_stat); - - } - - } - - } - } - - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Find the associate pair to the original node ---*/ - - jPoint = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; - jProcessor = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; - - if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; - else compute = true; - - if (compute) { - - /*--- We only receive the information that belong to other boundary ---*/ - - if (jProcessor != rank) { - - SU2_MPI::Irecv(Buffer_Receive_Psi, nVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &recv_req[0]); - - /*--- Wait for the this set of non-blocking recv's to complete ---*/ - - SU2_MPI::Waitall(1, recv_req, recv_stat); - - } else { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_Psi[iVar] = node[jPoint]->GetSolution(iVar); - } - - /*--- Store the solution for both points ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - Psi_i[iVar] = node[iPoint]->GetSolution(iVar); - Psi_j[iVar] = Buffer_Receive_Psi[iVar]; - } - - /*--- Set adjoint Variables ---*/ - - numerics->SetAdjointVar(Psi_i, Psi_j); - - /*--- Conservative variables w/o reconstruction (the same at both points) ---*/ - - V_i = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - V_j = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - numerics->SetPrimitive(V_i, V_j); - - /*--- Set Normal ---*/ - - geometry->vertex[iMarker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - numerics->SetNormal(Normal); - - /*--- Compute the convective residual using an upwind scheme ---*/ - numerics->ComputeResidual(Res_Conv_i, Res_Conv_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - /*--- Add Residuals and Jacobians ---*/ - - LinSysRes.SubtractBlock(iPoint, Res_Conv_i); - if (implicit) Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - } - - } - } - } - } - - MPI_Barrier(MPI_COMM_WORLD); - - delete[] Buffer_Send_Psi; - delete[] Buffer_Receive_Psi; - -#endif - - delete[] Normal; - delete[] Psi_i; - delete[] Psi_j; - -} - -void CAdjEulerSolver::BC_NearField_Boundary(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config) { - - unsigned long iVertex, iPoint, jPoint, Pin, Pout; - unsigned short iDim, iVar, iMarker; - su2double *V_i, *V_j, *IntBoundary_Jump; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - - su2double *Normal = new su2double[nDim]; - su2double *Psi_i = new su2double[nVar]; - su2double *Psi_j = new su2double[nVar]; - su2double *Psi_out = new su2double[nVar]; - su2double *Psi_in = new su2double[nVar]; - su2double *MeanPsi = new su2double[nVar]; - su2double *Psi_out_ghost = new su2double[nVar]; - su2double *Psi_in_ghost = new su2double[nVar]; - - -#ifndef HAVE_MPI - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - jPoint = geometry->vertex[iMarker][iVertex]->GetDonorPoint(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Adjoint variables w/o reconstruction ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - Psi_i[iVar] = node[iPoint]->GetSolution(iVar); - Psi_j[iVar] = node[jPoint]->GetSolution(iVar); - } - - /*--- If equivalent area or nearfield pressure condition ---*/ - - if ((config->GetKind_ObjFunc() == EQUIVALENT_AREA) || - (config->GetKind_ObjFunc() == NEARFIELD_PRESSURE)) { - - /*--- Identify the inner and the outer point (based on the normal direction) ---*/ - - if (Normal[nDim-1] < 0.0) { Pin = iPoint; Pout = jPoint; } - else { Pout = iPoint; Pin = jPoint; } - - for (iVar = 0; iVar < nVar; iVar++) { - Psi_out[iVar] = node[Pout]->GetSolution(iVar); - Psi_in[iVar] = node[Pin]->GetSolution(iVar); - MeanPsi[iVar] = 0.5*(Psi_out[iVar] + Psi_in[iVar]); - } - - IntBoundary_Jump = node[iPoint]->GetIntBoundary_Jump(); - - /*--- Inner point ---*/ - - if (iPoint == Pin) { - for (iVar = 0; iVar < nVar; iVar++) - Psi_in_ghost[iVar] = 2.0*MeanPsi[iVar] - Psi_in[iVar] - IntBoundary_Jump[iVar]; - numerics->SetAdjointVar(Psi_in, Psi_in_ghost); - } - - /*--- Outer point ---*/ - - if (iPoint == Pout) { - for (iVar = 0; iVar < nVar; iVar++) - Psi_out_ghost[iVar] = 2.0*MeanPsi[iVar] - Psi_out[iVar] + IntBoundary_Jump[iVar]; - numerics->SetAdjointVar(Psi_out, Psi_out_ghost); - } - - } - else { - - /*--- Just do a periodic BC ---*/ - - numerics->SetAdjointVar(Psi_i, Psi_j); - - } - - /*--- Conservative variables w/o reconstruction ---*/ - - V_i = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - V_j = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - numerics->SetPrimitive(V_i, V_j); - - /*--- Set Normal ---*/ - - geometry->vertex[iMarker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - numerics->SetNormal(Normal); - - - /*--- Compute residual ---*/ - - numerics->ComputeResidual(Res_Conv_i, Res_Conv_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - /*--- Add Residuals and Jacobians ---*/ - - LinSysRes.SubtractBlock(iPoint, Res_Conv_i); - if (implicit) Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - } - } - } - } - -#else - - int rank, jProcessor; - MPI_Status status; - //MPI_Status send_stat[1], recv_stat[1]; - //MPI_Request send_req[1], recv_req[1]; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - bool compute; - su2double *Buffer_Send_Psi = new su2double[nVar]; - su2double *Buffer_Receive_Psi = new su2double[nVar]; - - /*--- Do the send process, by the moment we are sending each - node individually, this must be changed ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Find the associate pair to the original node ---*/ - - jPoint = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; - jProcessor = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; - - if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; - else compute = true; - - /*--- We only send the information that belong to other boundary ---*/ - if (compute) { - - if (jProcessor != rank) { - - /*--- Copy the adjoint variable ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_Psi[iVar] = node[iPoint]->GetSolution(iVar); - - SU2_MPI::Bsend(Buffer_Send_Psi, nVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD); - - // SU2_MPI::Isend(Buffer_Send_Psi, nVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD, &send_req[0]); - - /*--- Wait for this set of non-blocking comm. to complete ---*/ - - // SU2_MPI::Waitall(1, send_req, send_stat); - - } - - } - - } - } - - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Find the associate pair to the original node ---*/ - - jPoint = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; - jProcessor = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; - - if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; - else compute = true; - - if (compute) { - - /*--- We only receive the information that belong to other boundary ---*/ - - if (jProcessor != rank) { - - SU2_MPI::Recv(Buffer_Receive_Psi, nVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &status); - - // SU2_MPI::Irecv(Buffer_Receive_Psi, nVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &recv_req[0]); - - /*--- Wait for the this set of non-blocking recv's to complete ---*/ - - // SU2_MPI::Waitall(1, recv_req, recv_stat); - - } - else { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_Psi[iVar] = node[jPoint]->GetSolution(iVar); - } - - /*--- Store the solution for both points ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - Psi_i[iVar] = node[iPoint]->GetSolution(iVar); - Psi_j[iVar] = Buffer_Receive_Psi[iVar]; - } - - /*--- If equivalent area or nearfield pressure condition ---*/ - - if ((config->GetKind_ObjFunc() == EQUIVALENT_AREA) || - (config->GetKind_ObjFunc() == NEARFIELD_PRESSURE)) { - - /*--- Identify the inner and the outer point (based on the normal direction) ---*/ - - if (Normal[nDim-1] < 0.0) { Pin = iPoint; Pout = jPoint; } - else { Pout = iPoint; Pin = jPoint; } - - IntBoundary_Jump = node[iPoint]->GetIntBoundary_Jump(); - - /*--- Inner point ---*/ - - if (iPoint == Pin) { - for (iVar = 0; iVar < nVar; iVar++) { - Psi_in[iVar] = Psi_i[iVar]; Psi_out[iVar] = Psi_j[iVar]; - MeanPsi[iVar] = 0.5*(Psi_out[iVar] + Psi_in[iVar]); - Psi_in_ghost[iVar] = 2.0*MeanPsi[iVar] - Psi_in[iVar] - IntBoundary_Jump[iVar]; - } - numerics->SetAdjointVar(Psi_in, Psi_in_ghost); - } - - /*--- Outer point ---*/ - - if (iPoint == Pout) { - for (iVar = 0; iVar < nVar; iVar++) { - Psi_in[iVar] = Psi_j[iVar]; Psi_out[iVar] = Psi_i[iVar]; - MeanPsi[iVar] = 0.5*(Psi_out[iVar] + Psi_in[iVar]); - Psi_out_ghost[iVar] = 2.0*MeanPsi[iVar] - Psi_out[iVar] + IntBoundary_Jump[iVar]; - } - numerics->SetAdjointVar(Psi_out, Psi_out_ghost); - } - } - else { - - /*--- Just do a periodic BC ---*/ - - numerics->SetAdjointVar(Psi_i, Psi_j); - - } - - /*--- Conservative variables w/o reconstruction (the same at both points) ---*/ - - V_i = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - V_j = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - numerics->SetPrimitive(V_i, V_j); - - /*--- Set Normal ---*/ - - geometry->vertex[iMarker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - numerics->SetNormal(Normal); - - /*--- Compute residual ---*/ - - numerics->ComputeResidual(Res_Conv_i, Res_Conv_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - /*--- Add Residuals and Jacobians ---*/ - - LinSysRes.SubtractBlock(iPoint, Res_Conv_i); - if (implicit) Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - } - } - } - } - } - - MPI_Barrier(MPI_COMM_WORLD); - - delete[] Buffer_Send_Psi; - delete[] Buffer_Receive_Psi; - -#endif - - delete[] Normal; - delete[] Psi_i; - delete[] Psi_j; - delete[] Psi_out; - delete[] Psi_in; - delete[] MeanPsi; - delete[] Psi_out_ghost; - delete[] Psi_in_ghost; - - -} - -void CAdjEulerSolver::BC_Far_Field(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned long iVertex, iPoint, Point_Normal; - unsigned short iVar, iDim; - su2double *Normal, *V_domain, *V_infty, *Psi_domain, *Psi_infty; - - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - bool grid_movement = config->GetGrid_Movement(); - - Normal = new su2double[nDim]; - Psi_domain = new su2double[nVar]; Psi_infty = new su2double[nVar]; - - /*--- Loop over all the vertices ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- If the node belongs to the domain ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Index of the closest interior node ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Set the normal vector ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - /*--- Allocate the value at the infinity ---*/ - - V_infty = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); - - /*--- Retrieve solution at the farfield boundary node ---*/ - - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - conv_numerics->SetPrimitive(V_domain, V_infty); - - /*--- Adjoint flow solution at the wall ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); - Psi_infty[iVar] = 0.0; - } - conv_numerics->SetAdjointVar(Psi_domain, Psi_infty); - - /*--- Grid Movement ---*/ - - if (grid_movement) - conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[iPoint]->GetGridVel()); - - /*--- Compute the upwind flux ---*/ - - conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - /*--- Add and Subtract Residual ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual_i); - - /*--- Implicit contribution to the residual ---*/ - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - /*--- Viscous residual contribution, it doesn't work ---*/ - - if (config->GetViscous()) { - - /*--- Points in edge, coordinates and normal vector---*/ - - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - visc_numerics->SetNormal(Normal); - - /*--- Conservative variables w/o reconstruction and adjoint variables w/o reconstruction---*/ - - visc_numerics->SetPrimitive(V_domain, V_infty); - visc_numerics->SetAdjointVar(Psi_domain, Psi_infty); - - /*--- Gradient and limiter of Adjoint Variables ---*/ - - visc_numerics->SetAdjointVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); - - /*--- Compute residual ---*/ - - visc_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - /*--- Update adjoint viscous residual ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual_i); - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - } - - } - } - - delete [] Normal; - delete [] Psi_domain; delete [] Psi_infty; -} - -void CAdjEulerSolver::BC_Supersonic_Inlet(CGeometry *geometry, CSolver **solver_container, - CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - unsigned short iVar, iDim; - unsigned long iVertex, iPoint, Point_Normal; - su2double *V_inlet, *V_domain, *Normal, *Psi_domain, *Psi_inlet; - - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - bool grid_movement = config->GetGrid_Movement(); - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - - Normal = new su2double[nDim]; - Psi_domain = new su2double[nVar]; Psi_inlet = new su2double[nVar]; - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check that the node belongs to the domain (i.e., not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - /*--- Allocate the value at the inlet ---*/ - - V_inlet = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); - - /*--- Retrieve solution at the boundary node ---*/ - - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - /*--- Adjoint flow solution at the boundary ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); - - /*--- Construct the flow & adjoint states at the inlet ---*/ - /*--- Supersonic Inlet: All characteristic are exiting: using nearest neighbor to set value ---*/ - for (iVar = 0; iVar < nVar; iVar++) - Psi_inlet[iVar] = Psi_domain[iVar]; - - /*--- Set the flow and adjoint states in the solver ---*/ - - conv_numerics->SetPrimitive(V_domain, V_inlet); - conv_numerics->SetAdjointVar(Psi_domain, Psi_inlet); - - /*--- Grid Movement ---*/ - - if (grid_movement) - conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), - geometry->node[iPoint]->GetGridVel()); - - /*--- Compute the residual using an upwind scheme ---*/ - - conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, - Jacobian_ji, Jacobian_jj, config); - - /*--- Add and Subtract Residual ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual_i); - - /*--- Implicit contribution to the residual ---*/ - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - /*--- Viscous residual contribution, it doesn't work ---*/ - - if (config->GetViscous()) { - - /*--- Index of the closest interior node ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Points in edge, coordinates and normal vector---*/ - - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - visc_numerics->SetNormal(Normal); - - /*--- Conservative variables w/o reconstruction and adjoint variables w/o reconstruction---*/ - - visc_numerics->SetPrimitive(V_domain, V_inlet); - visc_numerics->SetAdjointVar(Psi_domain, Psi_inlet); - - /*--- Gradient and limiter of Adjoint Variables ---*/ - - visc_numerics->SetAdjointVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); - - /*--- Compute residual ---*/ - - visc_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - /*--- Update adjoint viscous residual ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual_i); - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - } - } - } - - /*--- Free locally allocated memory ---*/ - - delete [] Normal; - delete [] Psi_domain; delete [] Psi_inlet; - -} - -void CAdjEulerSolver::BC_Supersonic_Outlet(CGeometry *geometry, CSolver **solver_container, - CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - unsigned short iVar, iDim; - unsigned long iVertex, iPoint, Point_Normal; - su2double *V_outlet, *V_domain, *Normal, *Psi_domain, *Psi_outlet; - - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - bool grid_movement = config->GetGrid_Movement(); - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - - Normal = new su2double[nDim]; - Psi_domain = new su2double[nVar]; Psi_outlet = new su2double[nVar]; - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check that the node belongs to the domain (i.e., not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - /*--- Allocate the value at the inlet ---*/ - - V_outlet = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); - - /*--- Retrieve solution at the boundary node ---*/ - - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - /*--- Adjoint flow solution at the boundary ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); - - /*--- Construct the flow & adjoint states at the inlet ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Psi_outlet[iVar] = 0.0; - - /*--- Set the flow and adjoint states in the solver ---*/ - - conv_numerics->SetPrimitive(V_domain, V_outlet); - conv_numerics->SetAdjointVar(Psi_domain, Psi_outlet); - - /*--- Grid Movement ---*/ - - if (grid_movement) - conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), - geometry->node[iPoint]->GetGridVel()); - - /*--- Compute the residual using an upwind scheme ---*/ - - conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, - Jacobian_ji, Jacobian_jj, config); - - /*--- Add and Subtract Residual ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual_i); - - /*--- Implicit contribution to the residual ---*/ - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - /*--- Viscous residual contribution (check again, Point_Normal was not being initialized before) ---*/ - - if (config->GetViscous()) { - - /*--- Index of the closest interior node ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Points in edge, coordinates and normal vector---*/ - - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - visc_numerics->SetNormal(Normal); - - /*--- Conservative variables w/o reconstruction and adjoint variables w/o reconstruction---*/ - - visc_numerics->SetPrimitive(V_domain, V_outlet); - visc_numerics->SetAdjointVar(Psi_domain, Psi_outlet); - - /*--- Gradient and limiter of Adjoint Variables ---*/ - - visc_numerics->SetAdjointVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); - - /*--- Compute residual ---*/ - - visc_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - /*--- Update adjoint viscous residual ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual_i); - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - } - } - } - - /*--- Free locally allocated memory ---*/ - - delete [] Normal; - delete [] Psi_domain; delete [] Psi_outlet; - -} - -void CAdjEulerSolver::BC_Inlet(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned short iVar, iDim; - unsigned long iVertex, iPoint, Point_Normal; - su2double Velocity[3], bcn, phin, Area, UnitNormal[3], - ProjGridVel, *GridVel; - su2double *V_inlet, *V_domain, *Normal, *Psi_domain, *Psi_inlet; - - unsigned short Kind_Inlet = config->GetKind_Inlet(); - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool grid_movement = config->GetGrid_Movement(); - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - - Normal = new su2double[nDim]; - Psi_domain = new su2double[nVar]; Psi_inlet = new su2double[nVar]; - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check that the node belongs to the domain (i.e., not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Area += Normal[iDim]*Normal[iDim]; - Area = sqrt (Area); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = Normal[iDim]/Area; - - /*--- Allocate the value at the inlet ---*/ - - V_inlet = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); - - /*--- Retrieve solution at the boundary node ---*/ - - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - /*--- Adjoint flow solution at the boundary ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); - - /*--- Construct the flow & adjoint states at the inlet ---*/ - if (compressible) { - - /*--- Subsonic, compressible inflow: first build the flow state - using the same method as the direct problem. Then, based on - those conservative values, compute the characteristic-based - adjoint boundary condition. The boundary update to be applied - depends on whether total conditions or mass flow are specified. ---*/ - - switch (Kind_Inlet) { - - /*--- Total properties have been specified at the inlet. ---*/ - case TOTAL_CONDITIONS: - - /*--- Adjoint solution at the inlet. Set to zero for now - but should be replaced with derived expression for this type of - inlet. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - Psi_inlet[iVar] = 0.0; - - break; - - /*--- Mass flow has been specified at the inlet. ---*/ - case MASS_FLOW: - - /*--- Get primitives from current inlet state. ---*/ - for (iDim = 0; iDim < nDim; iDim++) - Velocity[iDim] = solver_container[FLOW_SOL]->node[iPoint]->GetVelocity(iDim); - - /*--- Retrieve current adjoint solution values at the boundary ---*/ - for (iVar = 0; iVar < nVar; iVar++) - Psi_inlet[iVar] = node[iPoint]->GetSolution(iVar); - - /*--- Some terms needed for the adjoint BC ---*/ - bcn = 0.0; phin = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - bcn -= (Gamma/Gamma_Minus_One)*Velocity[iDim]*UnitNormal[iDim]; - phin += Psi_domain[iDim+1]*UnitNormal[iDim]; - } - - /*--- Extra boundary term for grid movement ---*/ - if (grid_movement) { - ProjGridVel = 0.0; - GridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - ProjGridVel += GridVel[iDim]*UnitNormal[iDim]; - bcn -= (1.0/Gamma_Minus_One)*ProjGridVel; - } - - /*--- Impose value for PsiE based on hand-derived expression. ---*/ - Psi_inlet[nVar-1] = -phin*(1.0/bcn); - - break; - } - - } - - if (incompressible || freesurface) { - - /*--- Adjoint solution at the inlet ---*/ - - Psi_inlet[0] = node[iPoint]->GetSolution(0); - for (iDim = 0; iDim < nDim; iDim++) - Psi_inlet[iDim+1] = 0.0; - - } - - /*--- Set the flow and adjoint states in the solver ---*/ - - conv_numerics->SetPrimitive(V_domain, V_inlet); - conv_numerics->SetAdjointVar(Psi_domain, Psi_inlet); - - /*--- Grid Movement ---*/ - - if (grid_movement) - conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), - geometry->node[iPoint]->GetGridVel()); - - /*--- Compute the residual using an upwind scheme ---*/ - - conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, - Jacobian_ji, Jacobian_jj, config); - - /*--- Add and Subtract Residual ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual_i); - - /*--- Implicit contribution to the residual ---*/ - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - /*--- Viscous residual contribution, it doesn't work ---*/ - - if (config->GetViscous()) { - /*--- Index of the closest interior node ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Points in edge, coordinates and normal vector---*/ - - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - visc_numerics->SetNormal(Normal); - - /*--- Conservative variables w/o reconstruction and adjoint variables w/o reconstruction---*/ - - visc_numerics->SetPrimitive(V_domain, V_inlet); - visc_numerics->SetAdjointVar(Psi_domain, Psi_inlet); - - /*--- Gradient and limiter of Adjoint Variables ---*/ - - visc_numerics->SetAdjointVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); - - /*--- Compute residual ---*/ - - visc_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - /*--- Update adjoint viscous residual ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual_i); - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - } - } - } - - /*--- Free locally allocated memory ---*/ - - delete [] Normal; - delete [] Psi_domain; delete [] Psi_inlet; - -} - -void CAdjEulerSolver::BC_Outlet(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned short iVar, iDim; - unsigned long iVertex, iPoint, Point_Normal; - su2double Pressure=0.0, P_Exit=0.0, Velocity[3], Velocity2 = 0.0; - su2double Density=0.0, Height=0.0; - su2double Vn = 0.0, SoundSpeed = 0.0, LevelSet=0.0, Vn_Exit=0.0, - Riemann=0.0, Entropy=0.0, Density_Outlet = 0.0, Vn_rel=0.0; - su2double Area, UnitNormal[3]; - su2double *V_outlet, *V_domain, *Psi_domain, *Psi_outlet, *Normal; - su2double Mach_Exit_Normal=0.0; - su2double a1=0.0; /*Placeholder terms to simplify expression/ repeated terms*/ - su2double ProjGridVel = 0.0; - su2double densgrad, pressgrad, velgrad; - - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool grid_movement = config->GetGrid_Movement(); - su2double FreeSurface_Zero = config->GetFreeSurface_Zero(); - su2double PressFreeSurface = solver_container[FLOW_SOL]->GetPressure_Inf(); - su2double epsilon = config->GetFreeSurface_Thickness(); - su2double RatioDensity = config->GetRatioDensity(); - su2double Froude = config->GetFroude(); - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - - Psi_domain = new su2double [nVar]; Psi_outlet = new su2double [nVar]; - Normal = new su2double[nDim]; - - /*--- Loop over all the vertices ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- If the node belong to the domain ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Area += Normal[iDim]*Normal[iDim]; - Area = sqrt (Area); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = Normal[iDim]/Area; - - /*--- Set the normal point ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Allocate the value at the outlet ---*/ - - V_outlet = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); - - /*--- Retrieve solution at the boundary node ---*/ - - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - /*--- Adjoint flow solution at the boundary ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); - - /*--- Construct the flow & adjoint states at the outlet ---*/ - - if (compressible) { - - /*--- Retrieve the specified back pressure for this outlet, Non-dim. the inputs if necessary. ---*/ - - P_Exit = config->GetOutlet_Pressure(Marker_Tag); - P_Exit = P_Exit/config->GetPressure_Ref(); - - /*--- Check whether the flow is supersonic at the exit. The type - of boundary update depends on this. ---*/ - - Density = V_domain[nDim+2]; - Velocity2 = 0.0; Vn = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity[iDim] = V_domain[iDim+1]; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - Vn += Velocity[iDim]*UnitNormal[iDim]; - } - /*--- Extra boundary term for grid movement ---*/ - if (grid_movement) { - su2double *GridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - ProjGridVel += GridVel[iDim]*UnitNormal[iDim]; - } - - - Pressure = V_domain[nDim+1]; - SoundSpeed = sqrt(Pressure*Gamma/Density); - Mach_Exit_Normal = Vn/SoundSpeed; - - /*--- Set Adjoint variables to 0 initially ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - Psi_outlet[iVar] = 0.0; - } - - if (Mach_Exit_Normal >= 1.0) { - /*If there is no objective term defined on the outlet, all Psi are 0 (inviscid case) */ - Vn_Exit = Vn; /* Vn_Exit comes from Reiman conditions in subsonic case*/ - Vn_rel = Vn_Exit-ProjGridVel; - /*-- Some common terms --*/ - a1 = SoundSpeed*SoundSpeed/(Vn_rel)/Gamma_Minus_One; - //a4 = Density*Vn_rel*(pow(SoundSpeed,2.0)-pow(Vn_rel,2.0)); - - /*--- Objective-dependent additions to energy term ---*/ - switch (config->GetKind_ObjFunc()){ - case OUTLET_CHAIN_RULE: - velgrad = 0.0; - for (iDim=0; iDimGetCoeff_ObjChainRule(iDim+1)*Area; - densgrad = config->GetCoeff_ObjChainRule(0)*Area; - pressgrad = config->GetCoeff_ObjChainRule(4)*Area; - Psi_outlet[nDim+1]= (Gamma_Minus_One*Mach_Exit_Normal/(pow(Mach_Exit_Normal,2.0)-1)/SoundSpeed)* - (pressgrad-velgrad/Density/Vn_rel+densgrad/pow(Vn_rel,2.0)); - break; - case AVG_TOTAL_PRESSURE: - /*--- Total Pressure term. NOTE: this is AREA averaged - * Additional terms are added later (as they are common between subsonic, - * supersonic equations) ---*/ - Velocity2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity2 += Velocity[iDim]*Velocity[iDim]; - } - Psi_outlet[nDim+1]+=Gamma_Minus_One*Velocity2/(Vn_rel*SoundSpeed*(pow(Vn_rel,2.0)-pow(SoundSpeed,2.0))); - break; - case AVG_OUTLET_PRESSURE: - /*Area averaged static pressure*/ - /*--- Note: further terms are NOT added later for this case, only energy term is modified ---*/ - Psi_outlet[nDim+1]+=Gamma_Minus_One*Vn_rel/(pow(Vn_rel,2.0)-pow(SoundSpeed,2.0)); - break; - default: - break; - } - } else { - /*---Subsonic Case: Psi-rho E term from volume, objective-specific terms which are common - * between subsonic and supersonic cases are added later ---*/ - /*--- Compute Riemann constant ---*/ - Entropy = Pressure*pow(1.0/Density, Gamma); - Riemann = Vn + 2.0*SoundSpeed/Gamma_Minus_One; - - /*--- Compute the new fictious state at the outlet ---*/ - Density = pow(P_Exit/Entropy,1.0/Gamma); - SoundSpeed = sqrt(Gamma*P_Exit/Density); - Vn_Exit = Riemann - 2.0*SoundSpeed/Gamma_Minus_One; - /*--- Update velocity terms ---*/ - Vn_rel = Vn_Exit-ProjGridVel; - Velocity2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity[iDim] = Velocity[iDim] + (Vn_Exit-Vn)*UnitNormal[iDim]; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - } - - /*--- Extra boundary term for grid movement ---*/ - - if (grid_movement) { - su2double ProjGridVel = 0.0; - su2double *GridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - ProjGridVel += GridVel[iDim]*UnitNormal[iDim]; -// Ubn = ProjGridVel; - } - - /*--- Shorthand for repeated term in the boundary conditions ---*/ - - //a1 = Gamma*(P_Exit/(Density*Gamma_Minus_One))/(Vn-Ubn); - a1 = sqrt(Gamma*P_Exit/Density)/(Gamma_Minus_One); - - /*--- Impose values for PsiRho & Phi using PsiE from domain. ---*/ - - Psi_outlet[nVar-1] = Psi_domain[nVar-1]; - - - } - - /*--- When Psi_outlet[nVar-1] is not 0, the other terms of Psi_outlet must be updated ---*/ - /*--- This occurs when subsonic, or for certain objective functions ---*/ - if ( Psi_outlet[nVar-1]!=0.0 ){ - /*--- Shorthand for repeated term in the boundary conditions ---*/ - a1 = SoundSpeed*SoundSpeed/(Vn_rel)/Gamma_Minus_One; - Psi_outlet[0] += Psi_outlet[nVar-1]*(Velocity2*0.5+Vn_Exit*a1); - for (iDim = 0; iDim < nDim; iDim++) { - Psi_outlet[iDim+1] += -Psi_outlet[nVar-1]*(a1*UnitNormal[iDim] + Velocity[iDim]); - } - } - - } - if (incompressible || freesurface) { - - if (freesurface) { - - /*--- Density computation at the exit using the level set function ---*/ - - Height = geometry->node[iPoint]->GetCoord(nDim-1); - LevelSet = Height - FreeSurface_Zero; - - /*--- Pressure computation the density at the exit (imposed) ---*/ - - if (LevelSet < -epsilon) Density_Outlet = config->GetDensity_FreeStreamND(); - if (LevelSet > epsilon) Density_Outlet = RatioDensity*config->GetDensity_FreeStreamND(); - V_outlet[0] = PressFreeSurface + Density_Outlet*((FreeSurface_Zero-Height)/(Froude*Froude)); - - /*--- Neumann condition in the interface for the pressure and density ---*/ - - if (fabs(LevelSet) <= epsilon) { - V_outlet[0] = solver_container[FLOW_SOL]->node[Point_Normal]->GetSolution(0); - Density_Outlet = solver_container[FLOW_SOL]->node[Point_Normal]->GetDensityInc(); - } - - } - - else { - - /*--- Imposed pressure and density ---*/ - - Density_Outlet = solver_container[FLOW_SOL]->GetDensity_Inf(); - V_outlet[0] = solver_container[FLOW_SOL]->GetPressure_Inf(); - - } - - /*--- Neumann condition for the velocity ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - V_outlet[iDim+1] = node[Point_Normal]->GetSolution(iDim+1); - - /*--- Adjoint flow solution at the outlet (hard-coded for size[3] again?) ---*/ - - Psi_outlet[2] = 0.0; - su2double coeff = (2.0*V_domain[1])/ solver_container[FLOW_SOL]->node[Point_Normal]->GetBetaInc2(); - Psi_outlet[1] = node[Point_Normal]->GetSolution(1); - Psi_outlet[0] = -coeff*Psi_outlet[1]; - - } - - /*--- Add terms for objective functions where additions are needed outside the energy term - * Terms which are added to the energy term are taken care of in the supersonic section above ---*/ - switch (config->GetKind_ObjFunc()){ - case MASS_FLOW_RATE: - /*--- For mass_flow objective function add B.C. contribution ---*/ - Psi_outlet[0]+=1; - break; - case OUTLET_CHAIN_RULE: - /* repeated term */ - a1 = 1.0/Density/pow(Vn_rel,2.0); - velgrad = 0.0; - - for (iDim=0; iDimGetCoeff_ObjChainRule(iDim+1)*Area; - densgrad = Density*config->GetCoeff_ObjChainRule(0)*Area; - Psi_outlet[0]+=((Vn_rel+Vn)*densgrad-Vn_rel*velgrad)*a1; - for (iDim=0; iDimGetCoeff_ObjChainRule(iDim+1)*Area); - - break; - case AVG_TOTAL_PRESSURE: - /*--- For total pressure objective function. NOTE: this is AREA averaged term---*/ - a1 = 1.0/2.0/pow(Vn_rel,2.0); - Velocity2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity[iDim] = Velocity[iDim] + (Vn_Exit-Vn)*UnitNormal[iDim]; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - } - Psi_outlet[0]+=0; //2.0*Velocity2/Vn_rel; - for (iDim = 0; iDim < nDim; iDim++) { - Psi_outlet[iDim+1] +=(Velocity[iDim]/Vn_rel-UnitNormal[iDim]*Velocity2*a1); - } - break; - default: - break; - } - - /*--- Set the flow and adjoint states in the solver ---*/ - - conv_numerics->SetPrimitive(V_domain, V_outlet); - conv_numerics->SetAdjointVar(Psi_domain, Psi_outlet); - - /*--- Grid Movement ---*/ - - if (grid_movement) - conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), - geometry->node[iPoint]->GetGridVel()); - - conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, - Jacobian_ji, Jacobian_jj, config); - - /*--- Add and Subtract Residual ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual_i); - - /*--- Implicit contribution to the residual ---*/ - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - /*--- Viscous residual contribution, it doesn't work ---*/ - - if (config->GetViscous()) { - - /*--- Set laminar and eddy viscosity at the infinity ---*/ - if (compressible) { - V_outlet[nDim+5] = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); - V_outlet[nDim+6] = solver_container[FLOW_SOL]->node[iPoint]->GetEddyViscosity(); - } - if (incompressible || freesurface) { - V_outlet[nDim+3] = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosityInc(); - V_outlet[nDim+4] = solver_container[FLOW_SOL]->node[iPoint]->GetEddyViscosityInc(); - } - - /*--- Points in edge, coordinates and normal vector---*/ - visc_numerics->SetNormal(Normal); - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - - - /*--- Conservative variables w/o reconstruction and adjoint variables w/o reconstruction---*/ - - visc_numerics->SetPrimitive(V_domain, V_outlet); - visc_numerics->SetAdjointVar(Psi_domain, Psi_outlet); - - /*--- Turbulent kinetic energy ---*/ - if (config->GetKind_Turb_Model() == SST) - visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); - - - /*--- Gradient and limiter of Adjoint Variables ---*/ - - visc_numerics->SetAdjointVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); - - /*--- Compute residual ---*/ - - visc_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - /*--- Update adjoint viscous residual ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual_i); - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - } - } - } - - /*--- Free locally allocated memory ---*/ - - delete [] Normal; - delete [] Psi_domain; delete [] Psi_outlet; - -} - -void CAdjEulerSolver::BC_Engine_Inflow(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - su2double *Normal, *V_domain, *V_inflow, *Psi_domain, *Psi_inflow, P_Fan; - su2double Velocity[3] = {0.0,0.0,0.0}, Velocity2, Density, Vn; - su2double UnitNormal[3] = {0.0,0.0,0.0}, Area, a1; - unsigned short iVar, iDim; - unsigned long iVertex, iPoint; - - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - - Normal = new su2double[nDim]; - Psi_domain = new su2double[nVar]; Psi_inflow = new su2double[nVar]; - - /*--- Loop over all the vertices ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- If the node belong to the domain ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Area += Normal[iDim]*Normal[iDim]; - Area = sqrt (Area); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = Normal[iDim]/Area; - - /*--- Allocate the value at the inflow ---*/ - - V_inflow = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); - - /*--- Retrieve solution at the boundary node ---*/ - - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - /*--- Adjoint flow solution at the boundary ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); - - /*--- Subsonic flow is assumed. ---*/ - - P_Fan = config->GetInflow_Pressure(Marker_Tag); - Density = V_domain[nDim+2]; - Velocity2 = 0.0; Vn = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity[iDim] = V_domain[iDim+1]; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - Vn += Velocity[iDim]*UnitNormal[iDim]; - } - - /*--- Shorthand for repeated term in the boundary conditions ---*/ - - a1 = Gamma*(P_Fan/(Density*Gamma_Minus_One))/Vn; - - /*--- Impose values for PsiRho & Phi using PsiE from domain. ---*/ - - Psi_inflow[nVar-1] = Psi_domain[nVar-1]; - Psi_inflow[0] = 0.5*Psi_inflow[nVar-1]*Velocity2; - for (iDim = 0; iDim < nDim; iDim++) { - Psi_inflow[0] += Psi_inflow[nVar-1]*a1*Velocity[iDim]*UnitNormal[iDim]; - Psi_inflow[iDim+1] = -Psi_inflow[nVar-1]*(a1*UnitNormal[iDim] + Velocity[iDim]); - } - - /*--- Set the flow and adjoint states in the solver ---*/ - - conv_numerics->SetPrimitive(V_domain, V_inflow); - conv_numerics->SetAdjointVar(Psi_domain, Psi_inflow); - - /*--- Compute the residual ---*/ - - conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, - Jacobian_ji, Jacobian_jj, config); - - /*--- Add and Subtract Residual ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual_i); - - /*--- Implicit contribution to the residual ---*/ - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - } - } - - /*--- Free locally allocated memory ---*/ - - delete [] Normal; - delete [] Psi_domain; delete [] Psi_inflow; - -} - -void CAdjEulerSolver::BC_Engine_Bleed(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - su2double *Normal, *V_domain, *V_inflow, *Psi_domain, *Psi_inflow, P_Fan; - su2double Velocity[3] = {0.0,0.0,0.0}, Velocity2, Density, Vn; - su2double UnitNormal[3] = {0.0,0.0,0.0}, Area, a1; - unsigned short iVar, iDim; - unsigned long iVertex, iPoint; - - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - - Normal = new su2double[nDim]; - Psi_domain = new su2double[nVar]; Psi_inflow = new su2double[nVar]; - - /*--- Loop over all the vertices ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- If the node belong to the domain ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Area += Normal[iDim]*Normal[iDim]; - Area = sqrt (Area); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = Normal[iDim]/Area; - - /*--- Allocate the value at the inflow ---*/ - - V_inflow = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); - - /*--- Retrieve solution at the boundary node ---*/ - - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - /*--- Adjoint flow solution at the boundary ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); - - /*--- Subsonic flow is assumed. ---*/ - - P_Fan = config->GetInflow_Pressure(Marker_Tag); - Density = V_domain[nDim+2]; - Velocity2 = 0.0; Vn = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity[iDim] = V_domain[iDim+1]; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - Vn += Velocity[iDim]*UnitNormal[iDim]; - } - - /*--- Shorthand for repeated term in the boundary conditions ---*/ - - a1 = Gamma*(P_Fan/(Density*Gamma_Minus_One))/Vn; - - /*--- Impose values for PsiRho & Phi using PsiE from domain. ---*/ - - Psi_inflow[nVar-1] = Psi_domain[nVar-1]; - Psi_inflow[0] = 0.5*Psi_inflow[nVar-1]*Velocity2; - for (iDim = 0; iDim < nDim; iDim++) { - Psi_inflow[0] += Psi_inflow[nVar-1]*a1*Velocity[iDim]*UnitNormal[iDim]; - Psi_inflow[iDim+1] = -Psi_inflow[nVar-1]*(a1*UnitNormal[iDim] + Velocity[iDim]); - } - - /*--- Set the flow and adjoint states in the solver ---*/ - - conv_numerics->SetPrimitive(V_domain, V_inflow); - conv_numerics->SetAdjointVar(Psi_domain, Psi_inflow); - - /*--- Compute the residual ---*/ - - conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, - Jacobian_ji, Jacobian_jj, config); - - /*--- Add and Subtract Residual ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual_i); - - /*--- Implicit contribution to the residual ---*/ - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - } - } - - /*--- Free locally allocated memory ---*/ - - delete [] Normal; - delete [] Psi_domain; delete [] Psi_inflow; - -} - -void CAdjEulerSolver::BC_Engine_Exhaust(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned long iVertex, iPoint, Point_Normal; - su2double *Normal, *V_domain, *V_exhaust, *Psi_domain, *Psi_exhaust; - unsigned short iVar, iDim; - - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - - Normal = new su2double[nDim]; - Psi_domain = new su2double[nVar]; Psi_exhaust = new su2double[nVar]; - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check that the node belongs to the domain (i.e., not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - /*--- Index of the closest interior node ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Allocate the value at the exhaust ---*/ - - V_exhaust = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); - - /*--- Retrieve solution at the boundary node ---*/ - - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - /*--- Adjoint flow solution at the boundary ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); - - /*--- Adjoint flow solution at the exhaust (this should be improved using characteristics bc) ---*/ - - Psi_exhaust[0] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Psi_exhaust[iDim+1] = node[Point_Normal]->GetSolution(iDim+1); - Psi_exhaust[nDim+1] = 0.0; - - /*--- Set the flow and adjoint states in the solver ---*/ - - conv_numerics->SetPrimitive(V_domain, V_exhaust); - conv_numerics->SetAdjointVar(Psi_domain, Psi_exhaust); - - /*--- Compute the residual using an upwind scheme ---*/ - - conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - /*--- Add and Subtract Residual ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual_i); - - /*--- Implicit contribution to the residual ---*/ - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - - } - } - - delete [] Normal; - delete [] Psi_domain; delete [] Psi_exhaust; - -} - -void CAdjEulerSolver::SetResidual_DualTime(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iRKStep, - unsigned short iMesh, unsigned short RunTime_EqSystem) { - unsigned short iVar, jVar; - unsigned long iPoint; - su2double *U_time_nM1, *U_time_n, *U_time_nP1, Volume_nM1, Volume_n, Volume_nP1, TimeStep; - - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - bool FlowEq = (RunTime_EqSystem == RUNTIME_FLOW_SYS); - bool AdjEq = (RunTime_EqSystem == RUNTIME_ADJFLOW_SYS); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool Grid_Movement = config->GetGrid_Movement(); - - /*--- loop over points ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Solution at time n-1, n and n+1 ---*/ - U_time_nM1 = node[iPoint]->GetSolution_time_n1(); - U_time_n = node[iPoint]->GetSolution_time_n(); - U_time_nP1 = node[iPoint]->GetSolution(); - - /*--- Volume at time n-1 and n ---*/ - if (Grid_Movement) { - Volume_nM1 = geometry->node[iPoint]->GetVolume_nM1(); - Volume_n = geometry->node[iPoint]->GetVolume_n(); - Volume_nP1 = geometry->node[iPoint]->GetVolume(); - } - else { - Volume_nM1 = geometry->node[iPoint]->GetVolume(); - Volume_n = geometry->node[iPoint]->GetVolume(); - Volume_nP1 = geometry->node[iPoint]->GetVolume(); - } - - /*--- Time Step ---*/ - TimeStep = config->GetDelta_UnstTimeND(); - - /*--- Compute Residual ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Residual[iVar] = ( U_time_nP1[iVar]*Volume_nP1 - U_time_n[iVar]*Volume_n ) / TimeStep; - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - Residual[iVar] = ( 3.0*U_time_nP1[iVar]*Volume_nP1 - 4.0*U_time_n[iVar]*Volume_n - + 1.0*U_time_nM1[iVar]*Volume_nM1 ) / (2.0*TimeStep); - } - - if (((incompressible || freesurface) && FlowEq) || ((incompressible || freesurface) && AdjEq)) Residual[0] = 0.0; - - /*--- Add Residual ---*/ - LinSysRes.AddBlock(iPoint, Residual); - - if (implicit) { - for (iVar = 0; iVar < nVar; iVar++) { - for (jVar = 0; jVar < nVar; jVar++) - Jacobian_i[iVar][jVar] = 0.0; - - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Jacobian_i[iVar][iVar] = Volume_nP1 / TimeStep; - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - Jacobian_i[iVar][iVar] = (Volume_nP1*3.0)/(2.0*TimeStep); - } - if (((incompressible || freesurface) && FlowEq) || - ((incompressible || freesurface) && AdjEq)) Jacobian_i[0][0] = 0.0; - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - } - } - -} - -CAdjNSSolver::CAdjNSSolver(void) : CAdjEulerSolver() { } - -CAdjNSSolver::CAdjNSSolver(CGeometry *geometry, CConfig *config, unsigned short iMesh) : CAdjEulerSolver() { - unsigned long iPoint, index, iVertex; - string text_line, mesh_filename; - unsigned short iDim, iVar, iMarker, nLineLets; - ifstream restart_file; - string filename, AdjExt; - su2double dull_val, Area=0.0, *Normal = NULL, myArea_Monitored; - bool restart = config->GetRestart(); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Norm heat flux objective test ---*/ - - pnorm = 10; - - /*--- Set the gamma value ---*/ - - Gamma = config->GetGamma(); - Gamma_Minus_One = Gamma - 1.0; - - /*--- Define geometry constants in the solver structure ---*/ - - nDim = geometry->GetnDim(); - nMarker = config->GetnMarker_All(); - nPoint = geometry->GetnPoint(); - nPointDomain = geometry->GetnPointDomain(); - - if (compressible) { nVar = nDim + 2; } - if (incompressible) { nVar = nDim + 1; } - if (freesurface) { nVar = nDim + 1; } - - node = new CVariable*[nPoint]; - - /*--- Define some auxiliary arrays related to the residual ---*/ - - Point_Max = new unsigned long[nVar]; for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; - Point_Max_Coord = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Point_Max_Coord[iVar] = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; - } - Residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; - Residual_RMS = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_RMS[iVar] = 0.0; - Residual_Max = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_Max[iVar] = 0.0; - Residual_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_i[iVar] = 0.0; - Residual_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_j[iVar] = 0.0; - Res_Conv_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Conv_i[iVar] = 0.0; - Res_Visc_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Visc_i[iVar] = 0.0; - Res_Conv_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Conv_j[iVar] = 0.0; - Res_Visc_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Visc_j[iVar] = 0.0; - - /*--- Define some auxiliary arrays related to the solution ---*/ - - Solution = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; - Solution_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_i[iVar] = 0.0; - Solution_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_j[iVar] = 0.0; - - /*--- Define some auxiliary arrays related to the flow solution ---*/ - - FlowPrimVar_i = new su2double[nDim+7]; for (iVar = 0; iVar < nDim+7; iVar++) FlowPrimVar_i[iVar] = 0.0; - FlowPrimVar_j = new su2double[nDim+7]; for (iVar = 0; iVar < nDim+7; iVar++) FlowPrimVar_j[iVar] = 0.0; - - /*--- Define some auxiliary vectors related to the geometry ---*/ - - Vector = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = 0.0; - Vector_i = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_i[iDim] = 0.0; - Vector_j = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_j[iDim] = 0.0; - - /*--- Point to point Jacobians. These are always defined because - they are also used for sensitivity calculations. ---*/ - - Jacobian_i = new su2double* [nVar]; - Jacobian_j = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Jacobian_i[iVar] = new su2double [nVar]; - Jacobian_j[iVar] = new su2double [nVar]; - } - - /*--- Solution and residual vectors ---*/ - - LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); - - /*--- Jacobians and vector structures for implicit computations ---*/ - - if (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT) { - Jacobian_ii = new su2double*[nVar]; - Jacobian_ij = new su2double*[nVar]; - Jacobian_ji = new su2double*[nVar]; - Jacobian_jj = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Jacobian_ii[iVar] = new su2double[nVar]; - Jacobian_ij[iVar] = new su2double[nVar]; - Jacobian_ji[iVar] = new su2double[nVar]; - Jacobian_jj[iVar] = new su2double[nVar]; - } - if (rank == MASTER_NODE) - cout << "Initialize Jacobian structure (Adjoint N-S). MG level: " << iMesh <<"." << endl; - Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); - - if ((config->GetKind_Linear_Solver_Prec() == LINELET) || - (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { - nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); - if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; - } - - } else { - if (rank == MASTER_NODE) - cout << "Explicit scheme. No Jacobian structure (Adjoint N-S). MG level: " << iMesh <<"." << endl; - } - - /*--- Array structures for computation of gradients by least squares ---*/ - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { - /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ - Smatrix = new su2double* [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Smatrix[iDim] = new su2double [nDim]; - /*--- c vector := transpose(WA)*(Wb) ---*/ - cvector = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - cvector[iVar] = new su2double [nDim]; - } - - /*--- Sensitivity definition and coefficient on all markers ---*/ - CSensitivity = new su2double* [nMarker]; - for (iMarker=0; iMarkernVertex[iMarker]]; - } - Sens_Geo = new su2double[nMarker]; - Sens_Mach = new su2double[nMarker]; - Sens_AoA = new su2double[nMarker]; - Sens_Press = new su2double[nMarker]; - Sens_Temp = new su2double[nMarker]; - Sens_BPress = new su2double[nMarker]; - - /*--- Initialize sensitivities to zero ---*/ - for (iMarker = 0; iMarker < nMarker; iMarker++) { - Sens_Geo[iMarker] = 0.0; - Sens_Mach[iMarker] = 0.0; - Sens_AoA[iMarker] = 0.0; - Sens_Press[iMarker] = 0.0; - Sens_Temp[iMarker] = 0.0; - Sens_BPress[iMarker] = 0.0; - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) - CSensitivity[iMarker][iVertex] = 0.0; - } - - /*--- Initialize the adjoint variables to zero (infinity state) ---*/ - PsiRho_Inf = 0.0; - if ((config->GetKind_ObjFunc() == TOTAL_HEATFLUX) || - (config->GetKind_ObjFunc() == MAXIMUM_HEATFLUX) || - (config->GetKind_ObjFunc() == INVERSE_DESIGN_HEATFLUX)) - PsiE_Inf = -1.0; - else - PsiE_Inf = 0.0; - Phi_Inf = new su2double [nDim]; - Phi_Inf[0] = 0.0; Phi_Inf[1] = 0.0; - if (nDim == 3) Phi_Inf[2] = 0.0; - - if (!restart || (iMesh != MESH_0)) { - /*--- Restart the solution from infinity ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint++) - node[iPoint] = new CAdjNSVariable(PsiRho_Inf, Phi_Inf, PsiE_Inf, nDim, nVar, config); - } - else { - - /*--- Restart the solution from file information ---*/ - mesh_filename = config->GetSolution_AdjFileName(); - filename = config->GetObjFunc_Extension(mesh_filename); - - restart_file.open(filename.data(), ios::in); - - /*--- In case there is no file ---*/ - if (restart_file.fail()) { - if (rank == MASTER_NODE) - cout << "There is no adjoint restart file!! " << filename.data() << "."<< endl; - exit(EXIT_FAILURE); - } - - /*--- In case this is a parallel simulation, we need to perform the - Global2Local index transformation first. ---*/ - long *Global2Local; - Global2Local = new long[geometry->GetGlobal_nPointDomain()]; - /*--- First, set all indices to a negative value by default ---*/ - for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) { - Global2Local[iPoint] = -1; - } - /*--- Now fill array with the transform values only for local points ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; - } - - /*--- Read all lines in the restart file ---*/ - long iPoint_Local; unsigned long iPoint_Global = 0; - - /*--- The first line is the header ---*/ - getline (restart_file, text_line); - - while (getline (restart_file, text_line)) { - istringstream point_line(text_line); - - /*--- Retrieve local index. If this node from the restart file lives - on a different processor, the value of iPoint_Local will be -1. - Otherwise, the local index for this node on the current processor - will be returned and used to instantiate the vars. ---*/ - iPoint_Local = Global2Local[iPoint_Global]; - if (iPoint_Local >= 0) { - if (compressible) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3] >> Solution[4]; - } - if (incompressible) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; - } - if (freesurface) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; - } - node[iPoint_Local] = new CAdjNSVariable(Solution, nDim, nVar, config); - } - iPoint_Global++; - } - - /*--- Instantiate the variable class with an arbitrary solution - at any halo/periodic nodes. The initial solution can be arbitrary, - because a send/recv is performed immediately in the solver. ---*/ - for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { - node[iPoint] = new CAdjNSVariable(Solution, nDim, nVar, config); - } - - /*--- Close the restart file ---*/ - restart_file.close(); - - /*--- Free memory needed for the transformation ---*/ - delete [] Global2Local; - } - - /*--- Calculate area monitored for area-averaged-outflow-quantity-based objectives ---*/ - myArea_Monitored = 0.0; - if (config->GetKind_ObjFunc()==OUTLET_CHAIN_RULE || config->GetKind_ObjFunc()==AVG_TOTAL_PRESSURE || - config->GetKind_ObjFunc()==AVG_OUTLET_PRESSURE){ - for (iMarker =0; iMarker < config->GetnMarker_All(); iMarker++){ - if (config->GetMarker_All_Monitoring(iMarker) == YES){ - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if (geometry->node[iPoint]->GetDomain()) { - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Area += Normal[iDim]*Normal[iDim]; - myArea_Monitored += sqrt (Area); - } - } - } - } - } -#ifdef HAVE_MPI - Area_Monitored = 0.0; - SU2_MPI::Allreduce(&myArea_Monitored, &Area_Monitored, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); -#else - Area_Monitored = myArea_Monitored; -#endif - - /*--- MPI solution ---*/ - Set_MPI_Solution(geometry, config); - -} - -CAdjNSSolver::~CAdjNSSolver(void) { - -} - - -void CAdjNSSolver::SetTime_Step(CGeometry *geometry, CSolver **solver_container, CConfig *config, - unsigned short iMesh, unsigned long Iteration) { - - /*--- Use the flow solution to update the time step - * The time step depends on the characteristic velocity, which is the same - * for the adjoint and flow solutions, albeit in the opposite direction. ---*/ - solver_container[FLOW_SOL]->SetTime_Step(geometry, solver_container, config, iMesh, Iteration); -} - -void CAdjNSSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { - - unsigned long iPoint, ErrorCounter = 0; - su2double SharpEdge_Distance; - bool RightSol = true; - -#ifdef HAVE_MPI - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Retrieve information about the spatial and temporal integration for the - adjoint equations (note that the flow problem may use different methods). ---*/ - - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - bool limiter = (config->GetSpatialOrder_AdjFlow() == SECOND_ORDER_LIMITER); - bool center_jst = (config->GetKind_Centered_AdjFlow() == JST); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool engine = ((config->GetnMarker_EngineInflow() != 0) || (config->GetnMarker_EngineBleed() != 0) || (config->GetnMarker_EngineExhaust() != 0)); - - /*--- Compute nacelle inflow and exhaust properties ---*/ - - if (engine) { GetEngine_Properties(geometry, config, iMesh, Output); } - - /*--- Residual initialization ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint ++) { - - /*--- Get the distance form a sharp edge ---*/ - - SharpEdge_Distance = geometry->node[iPoint]->GetSharpEdge_Distance(); - - /*--- Initialize the non-physical points vector ---*/ - - node[iPoint]->SetNon_Physical(false); - - /*--- Set the primitive variables incompressible and compressible - adjoint variables ---*/ - - if (compressible) RightSol = node[iPoint]->SetPrimVar_Compressible(SharpEdge_Distance, false, config); - if (incompressible) RightSol = node[iPoint]->SetPrimVar_Incompressible(SharpEdge_Distance, false, config); - if (freesurface) RightSol = node[iPoint]->SetPrimVar_FreeSurface(SharpEdge_Distance, false, config); - if (!RightSol) { node[iPoint]->SetNon_Physical(true); ErrorCounter++; } - - /*--- Initialize the convective residual vector ---*/ - - LinSysRes.SetBlock_Zero(iPoint); - - } - - /*--- Compute gradients adj for solution reconstruction and viscous term ---*/ - - if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); - - /*--- Limiter computation (upwind reconstruction) ---*/ - - if (limiter) SetSolution_Limiter(geometry, config); - - /*--- Compute gradients adj for viscous term coupling ---*/ - - if ((config->GetKind_Solver() == ADJ_RANS) && (!config->GetFrozen_Visc())) { - if (config->GetKind_Gradient_Method() == GREEN_GAUSS) solver_container[ADJTURB_SOL]->SetSolution_Gradient_GG(geometry, config); - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) solver_container[ADJTURB_SOL]->SetSolution_Gradient_LS(geometry, config); - } - - /*--- Artificial dissipation for centered schemes ---*/ - - if (center_jst && (iMesh == MESH_0)) { - SetDissipation_Switch(geometry, config); - SetUndivided_Laplacian(geometry, config); - } - - /*--- Initialize the Jacobian for implicit integration ---*/ - - if (implicit) Jacobian.SetValZero(); - - /*--- Error message ---*/ - - if (config->GetConsole_Output_Verb() == VERB_HIGH) { -#ifdef HAVE_MPI - unsigned long MyErrorCounter = ErrorCounter; ErrorCounter = 0; - SU2_MPI::Allreduce(&MyErrorCounter, &ErrorCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#endif - if (iMesh == MESH_0) config->SetNonphysical_Points(ErrorCounter); - } - -} - -void CAdjNSSolver::Viscous_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config, unsigned short iMesh, unsigned short iRKStep) { - unsigned long iPoint, jPoint, iEdge; - - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Points in edge, coordinates and normal vector---*/ - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - - numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[jPoint]->GetCoord()); - numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); - - /*--- Primitive variables w/o reconstruction and adjoint variables w/o reconstruction---*/ - - numerics->SetPrimitive(solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(), - solver_container[FLOW_SOL]->node[jPoint]->GetPrimitive()); - - numerics->SetAdjointVar(node[iPoint]->GetSolution(), node[jPoint]->GetSolution()); - - /*--- Gradient and limiter of Adjoint Variables ---*/ - - numerics->SetAdjointVarGradient(node[iPoint]->GetGradient(), node[jPoint]->GetGradient()); - - /*--- Compute residual ---*/ - - numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - /*--- Update adjoint viscous residual ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual_i); - LinSysRes.AddBlock(jPoint, Residual_j); - - if (implicit) { - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - Jacobian.SubtractBlock(iPoint, jPoint, Jacobian_ij); - Jacobian.AddBlock(jPoint, iPoint, Jacobian_ji); - Jacobian.AddBlock(jPoint, jPoint, Jacobian_jj); - } - - } - -} - -void CAdjNSSolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, - CConfig *config, unsigned short iMesh) { - - unsigned long iPoint, jPoint, iEdge; - - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - bool rotating_frame = config->GetRotating_Frame(); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - - /*--- Loop over all the points, note that we are supposing that primitive and - adjoint gradients have been computed previously ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Primitive variables w/o reconstruction, and its gradient ---*/ - - numerics->SetPrimitive(solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(), NULL); - - numerics->SetPrimVarGradient(solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(), NULL); - - /*--- Gradient of adjoint variables ---*/ - - numerics->SetAdjointVarGradient(node[iPoint]->GetGradient(), NULL); - numerics->SetAdjointVarLimiter(node[iPoint]->GetLimiter(), NULL); - - /*--- Set volume ---*/ - - numerics->SetVolume(geometry->node[iPoint]->GetVolume()); - - /*--- If turbulence computation we must add some coupling terms to the NS adjoint eq. ---*/ - - if ((config->GetKind_Solver() == ADJ_RANS) && (!config->GetFrozen_Visc())) { - - /*--- Turbulent variables w/o reconstruction and its gradient ---*/ - - numerics->SetTurbVar(solver_container[TURB_SOL]->node[iPoint]->GetSolution(), NULL); - - numerics->SetTurbVarGradient(solver_container[TURB_SOL]->node[iPoint]->GetGradient(), NULL); - - /*--- Turbulent adjoint variables w/o reconstruction and its gradient ---*/ - - numerics->SetTurbAdjointVar(solver_container[ADJTURB_SOL]->node[iPoint]->GetSolution(), NULL); - - numerics->SetTurbAdjointGradient(solver_container[ADJTURB_SOL]->node[iPoint]->GetGradient(), NULL); - - /*--- Set distance to the surface ---*/ - - numerics->SetDistance(geometry->node[iPoint]->GetWall_Distance(), 0.0); - - } - - /*--- Compute residual ---*/ - - numerics->ComputeResidual(Residual, config); - - /*--- Add to the residual ---*/ - - LinSysRes.AddBlock(iPoint, Residual); - - } - - /*--- If turbulence computation we must add some coupling terms to the NS adjoint eq. ---*/ - - if ((config->GetKind_Solver() == ADJ_RANS) && (!config->GetFrozen_Visc())) { - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Points in edge, and normal vector ---*/ - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - second_numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); - - /*--- Conservative variables w/o reconstruction ---*/ - - second_numerics->SetConservative(solver_container[FLOW_SOL]->node[iPoint]->GetSolution(), - solver_container[FLOW_SOL]->node[jPoint]->GetSolution()); - - /*--- Gradient of primitive variables w/o reconstruction ---*/ - - second_numerics->SetPrimVarGradient(solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(), - solver_container[FLOW_SOL]->node[jPoint]->GetGradient_Primitive()); - - /*--- Viscosity ---*/ - - second_numerics->SetLaminarViscosity(solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(), - solver_container[FLOW_SOL]->node[jPoint]->GetLaminarViscosity()); - - /*--- Turbulent variables w/o reconstruction ---*/ - - second_numerics->SetTurbVar(solver_container[TURB_SOL]->node[iPoint]->GetSolution(), - solver_container[TURB_SOL]->node[jPoint]->GetSolution()); - - /*--- Turbulent adjoint variables w/o reconstruction ---*/ - - second_numerics->SetTurbAdjointVar(solver_container[ADJTURB_SOL]->node[iPoint]->GetSolution(), - solver_container[ADJTURB_SOL]->node[jPoint]->GetSolution()); - - /*--- Set distance to the surface ---*/ - - second_numerics->SetDistance(geometry->node[iPoint]->GetWall_Distance(), geometry->node[jPoint]->GetWall_Distance()); - - /*--- Update adjoint viscous residual ---*/ - - second_numerics->ComputeResidual(Residual, config); - - LinSysRes.AddBlock(iPoint, Residual); - LinSysRes.SubtractBlock(jPoint, Residual); - } - - } - - // WARNING: The rotating frame source term has been placed in the second - // source term container since the section below is commented. This needs a - // permanent fix asap! - - if (rotating_frame) { - - /*--- Loop over all points ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Load the adjoint variables ---*/ - second_numerics->SetAdjointVar(node[iPoint]->GetSolution(), - node[iPoint]->GetSolution()); - - /*--- Load the volume of the dual mesh cell ---*/ - second_numerics->SetVolume(geometry->node[iPoint]->GetVolume()); - - /*--- Compute the adjoint rotating frame source residual ---*/ - second_numerics->ComputeResidual(Residual, Jacobian_i, config); - - /*--- Add the source residual to the total ---*/ - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Add the implicit Jacobian contribution ---*/ - if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - } - } - - if (freesurface) { -// for (iPoint = 0; iPoint < nPointDomain; iPoint++) { -// -// su2double Volume = geometry->node[iPoint]->GetVolume(); -// su2double **Gradient = solver_container[ADJLEVELSET_SOL]->node[iPoint]->GetGradient(); -// su2double coeff = solver_container[LEVELSET_SOL]->node[iPoint]->GetSolution(0) / solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); -// -// Residual[0] = 0.0; -// for (iDim = 0; iDim < nDim; iDim++) { -// Residual[iDim+1] = coeff*Gradient[0][iDim]*Volume; -// } -// -// LinSysRes.AddBlock(iPoint, Residual); -// -// } - } - -} - -void CAdjNSSolver::Viscous_Sensitivity(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config) { - - unsigned long iVertex, iPoint; - unsigned short iDim, jDim, iMarker, iPos, jPos; - su2double *d = NULL, **PsiVar_Grad = NULL, **PrimVar_Grad = NULL, div_phi, *Normal = NULL, Area, - normal_grad_psi5, normal_grad_T, sigma_partial, Laminar_Viscosity = 0.0, heat_flux_factor, LevelSet, Target_LevelSet, temp_sens = 0.0, *Psi = NULL, *U = NULL, Enthalpy, **GridVel_Grad, gradPsi5_v, psi5_tau_partial, psi5_tau_grad_vel, source_v_1, Density, Pressure = 0.0, div_vel, val_turb_ke, vartheta, vartheta_partial, psi5_p_div_vel, Omega[3], rho_v[3] = {0.0,0.0,0.0}, CrossProduct[3], delta[3][3] = {{1.0, 0.0, 0.0},{0.0,1.0,0.0},{0.0,0.0,1.0}}, r, ru, rv, rw, rE, p, T, dp_dr, dp_dru, dp_drv, dp_drw, dp_drE, dH_dr, dH_dru, dH_drv, dH_drw, dH_drE, H, D[3][3], Dd[3], Mach_Inf, eps, scale = 1.0; - su2double RefVel2, RefDensity, Mach2Vel, *Velocity_Inf, factor; - - su2double *USens = new su2double[nVar]; - su2double *UnitNormal = new su2double[nDim]; - su2double *normal_grad_vel = new su2double[nDim]; - su2double *tang_deriv_psi5 = new su2double[nDim]; - su2double *tang_deriv_T = new su2double[nDim]; - su2double **Sigma = new su2double* [nDim]; - - for (iDim = 0; iDim < nDim; iDim++) - Sigma[iDim] = new su2double [nDim]; - - su2double *normal_grad_gridvel = new su2double[nDim]; - su2double *normal_grad_v_ux =new su2double[nDim]; - su2double **Sigma_Psi5v = new su2double* [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Sigma_Psi5v[iDim] = new su2double [nDim]; - su2double **tau = new su2double* [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - tau[iDim] = new su2double [nDim]; - su2double *Velocity = new su2double[nDim]; - - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool rotating_frame = config->GetRotating_Frame(); - bool grid_movement = config->GetGrid_Movement(); - su2double RefAreaCoeff = config->GetRefAreaCoeff(); - su2double Mach_Motion = config->GetMach_Motion(); - unsigned short ObjFunc = config->GetKind_ObjFunc(); - su2double Gas_Constant = config->GetGas_ConstantND(); - su2double Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; - su2double Prandtl_Lam = config->GetPrandtl_Lam(); - - if (config->GetSystemMeasurements() == US) scale = 1.0/12.0; - else scale = 1.0; - - /*--- Compute non-dimensional factor. 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. ---*/ - - if (grid_movement) { - Mach2Vel = sqrt(Gamma*Gas_Constant*config->GetTemperature_FreeStreamND()); - RefVel2 = (Mach_Motion*Mach2Vel)*(Mach_Motion*Mach2Vel); - } - else { - Velocity_Inf = config->GetVelocity_FreeStreamND(); - RefVel2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - RefVel2 += Velocity_Inf[iDim]*Velocity_Inf[iDim]; - } - - RefDensity = config->GetDensity_FreeStreamND(); - - factor = 1.0/(0.5*RefDensity*RefAreaCoeff*RefVel2); - - if ((ObjFunc == INVERSE_DESIGN_HEATFLUX) || (ObjFunc == FREE_SURFACE) || - (ObjFunc == TOTAL_HEATFLUX) || (ObjFunc == MAXIMUM_HEATFLUX) || - (ObjFunc == MASS_FLOW_RATE) ) factor = 1.0; - - if ((ObjFunc == AVG_TOTAL_PRESSURE) || (ObjFunc == AVG_OUTLET_PRESSURE) || - (ObjFunc == OUTLET_CHAIN_RULE)) factor = 1.0/Area_Monitored; - - - /*--- Compute gradient of the grid velocity, if applicable ---*/ - - if (grid_movement) - SetGridVel_Gradient(geometry, config); - - Total_Sens_Geo = 0.0; - Total_Sens_Mach = 0.0; - Total_Sens_AoA = 0.0; - Total_Sens_Press = 0.0; - Total_Sens_Temp = 0.0; - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - Sens_Geo[iMarker] = 0.0; - - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL)) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - PsiVar_Grad = node[iPoint]->GetGradient(); - PrimVar_Grad = solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(); - - if (compressible) Laminar_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); - if (incompressible || freesurface) Laminar_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosityInc(); - - heat_flux_factor = Cp * Laminar_Viscosity / Prandtl_Lam; - - /*--- Compute face area and the unit normal to the surface ---*/ - - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) { Area += Normal[iDim]*Normal[iDim]; } Area = sqrt(Area); - for (iDim = 0; iDim < nDim; iDim++) { UnitNormal[iDim] = Normal[iDim] / Area; } - - /*--- Compute the sensitivity related to the temperature ---*/ - - if (compressible) { - - normal_grad_psi5 = 0.0; normal_grad_T = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - normal_grad_psi5 += PsiVar_Grad[nVar-1][iDim]*UnitNormal[iDim]; - normal_grad_T += PrimVar_Grad[0][iDim]*UnitNormal[iDim]; - } - - temp_sens = 0.0; - if (config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) { - - /*--- Heat Flux Term: temp_sens = (\partial_tg \psi_5)\cdot (k \partial_tg T) ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - tang_deriv_psi5[iDim] = PsiVar_Grad[nVar-1][iDim] - normal_grad_psi5*UnitNormal[iDim]; - tang_deriv_T[iDim] = PrimVar_Grad[0][iDim] - normal_grad_T*UnitNormal[iDim]; - } - for (iDim = 0; iDim < nDim; iDim++) - temp_sens += heat_flux_factor * tang_deriv_psi5[iDim] * tang_deriv_T[iDim]; - - } else if (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) { - - /*--- Isothermal Term: temp_sens = - k * \partial_n(\psi_5) * \partial_n(T) ---*/ - - temp_sens = - heat_flux_factor * normal_grad_psi5 * normal_grad_T; - - } - } - if (incompressible || freesurface) { - - /*--- Incompressible case ---*/ - - temp_sens = 0.0; - - } - - /*--- Term: sigma_partial = \Sigma_{ji} n_i \partial_n v_j ---*/ - - if (compressible) { - div_phi = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - div_phi += PsiVar_Grad[iDim+1][iDim]; - for (jDim = 0; jDim < nDim; jDim++) - Sigma[iDim][jDim] = Laminar_Viscosity * (PsiVar_Grad[iDim+1][jDim]+PsiVar_Grad[jDim+1][iDim]); - } - for (iDim = 0; iDim < nDim; iDim++) - Sigma[iDim][iDim] -= TWO3*Laminar_Viscosity * div_phi; - } - if (incompressible || freesurface) { - for (iDim = 0; iDim < nDim; iDim++) { - for (jDim = 0; jDim < nDim; jDim++) - Sigma[iDim][jDim] = Laminar_Viscosity * PsiVar_Grad[jDim+1][iDim]; - } - } - - for (iDim = 0; iDim < nDim; iDim++) { - normal_grad_vel[iDim] = 0.0; - for (jDim = 0; jDim < nDim; jDim++) - normal_grad_vel[iDim] += PrimVar_Grad[iDim+1][jDim]*UnitNormal[jDim]; - } - - sigma_partial = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - for (jDim = 0; jDim < nDim; jDim++) - sigma_partial += UnitNormal[iDim]*Sigma[iDim][jDim]*normal_grad_vel[jDim]; - - /*--- Compute additional terms in the surface sensitivity for - moving walls in a rotating frame or dynamic mesh problem. ---*/ - - if (grid_movement) { - - Psi = node[iPoint]->GetSolution(); - U = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); - Density = U[0]; - if (compressible) Pressure = solver_container[FLOW_SOL]->node[iPoint]->GetPressure(); - if (incompressible || freesurface) Pressure = solver_container[FLOW_SOL]->node[iPoint]->GetPressureInc(); - Enthalpy = solver_container[FLOW_SOL]->node[iPoint]->GetEnthalpy(); - - /*--- Turbulent kinetic energy ---*/ - - if (config->GetKind_Turb_Model() == SST) - val_turb_ke = solver_container[TURB_SOL]->node[iPoint]->GetSolution(0); - else - val_turb_ke = 0.0; - - div_vel = 0.0; - for (iDim = 0 ; iDim < nDim; iDim++) { - Velocity[iDim] = U[iDim+1]/Density; - div_vel += PrimVar_Grad[iDim+1][iDim]; - } - - for (iDim = 0 ; iDim < nDim; iDim++) - for (jDim = 0 ; jDim < nDim; jDim++) - tau[iDim][jDim] = Laminar_Viscosity*(PrimVar_Grad[jDim+1][iDim] + PrimVar_Grad[iDim+1][jDim]) - - TWO3*Laminar_Viscosity*div_vel*delta[iDim][jDim] - - TWO3*Density*val_turb_ke*delta[iDim][jDim]; - - /*--- Form normal_grad_gridvel = \partial_n (u_omega) ---*/ - - GridVel_Grad = geometry->node[iPoint]->GetGridVel_Grad(); - for (iDim = 0; iDim < nDim; iDim++) { - normal_grad_gridvel[iDim] = 0.0; - for (jDim = 0; jDim < nDim; jDim++) - normal_grad_gridvel[iDim] += GridVel_Grad[iDim][jDim]*UnitNormal[jDim]; - } - - /*--- Form normal_grad_v_ux = \partial_n (v - u_omega) ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - normal_grad_v_ux[iDim] = normal_grad_vel[iDim] - normal_grad_gridvel[iDim]; - - /*--- Form Sigma_Psi5v ---*/ - - gradPsi5_v = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - gradPsi5_v += PsiVar_Grad[nDim+1][iDim]*Velocity[iDim]; - for (jDim = 0; jDim < nDim; jDim++) - Sigma_Psi5v[iDim][jDim] = Laminar_Viscosity * (PsiVar_Grad[nDim+1][iDim]*Velocity[jDim]+PsiVar_Grad[nDim+1][jDim]*Velocity[iDim]); - } - for (iDim = 0; iDim < nDim; iDim++) - Sigma_Psi5v[iDim][iDim] -= TWO3*Laminar_Viscosity * gradPsi5_v; - - - /*--- Now compute terms of the surface sensitivity ---*/ - - /*--- Form vartheta_partial = \vartheta * \partial_n (v - u_x) . n ---*/ - vartheta = Density*Psi[0] + Density*Enthalpy*Psi[nDim+1]; - for (iDim = 0; iDim < nDim; iDim++) { - vartheta += U[iDim+1]*Psi[iDim+1]; - } - vartheta_partial = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - vartheta_partial += vartheta * normal_grad_v_ux[iDim] * UnitNormal[iDim]; - - /*--- Form sigma_partial = n_i ( \Sigma_Phi_{ij} + \Sigma_Psi5v_{ij} ) \partial_n (v - u_x)_j ---*/ - - sigma_partial = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - for (jDim = 0; jDim < nDim; jDim++) - sigma_partial += UnitNormal[iDim]*(Sigma[iDim][jDim]+Sigma_Psi5v[iDim][jDim])*normal_grad_v_ux[jDim]; - - /*--- Form psi5_tau_partial = \Psi_5 * \partial_n (v - u_x)_i * tau_{ij} * n_j ---*/ - - psi5_tau_partial = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - for (jDim = 0; jDim < nDim; jDim++) - psi5_tau_partial -= Psi[nDim+1]*normal_grad_v_ux[iDim]*tau[iDim][jDim]*UnitNormal[jDim]; - - /*--- Form psi5_p_div_vel = ---*/ - - psi5_p_div_vel = -Psi[nDim+1]*Pressure*div_vel; - - /*--- Form psi5_tau_grad_vel = \Psi_5 * tau_{ij} : \nabla( v ) ---*/ - - psi5_tau_grad_vel = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - for (jDim = 0; jDim < nDim; jDim++) - psi5_tau_grad_vel += Psi[nDim+1]*tau[iDim][jDim]*PrimVar_Grad[iDim+1][jDim]; - - /*--- Retrieve the angular velocity vector ---*/ - - source_v_1 = 0.0; - if (rotating_frame) { - - Omega[0] = (config->GetRotation_Rate_X(ZONE_0)/config->GetOmega_Ref()); - Omega[1] = (config->GetRotation_Rate_Y(ZONE_0)/config->GetOmega_Ref()); - Omega[2] = (config->GetRotation_Rate_Z(ZONE_0)/config->GetOmega_Ref()); - - /*--- Calculate momentum source terms as: rho * ( Omega X V ) ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - rho_v[iDim] = U[iDim+1]; - if (nDim == 2) rho_v[2] = 0.0; - - CrossProduct[0] = Omega[1]*rho_v[2] - Omega[2]*rho_v[1]; - CrossProduct[1] = Omega[2]*rho_v[0] - Omega[0]*rho_v[2]; - CrossProduct[2] = Omega[0]*rho_v[1] - Omega[1]*rho_v[0]; - - - for (iDim = 0; iDim < nDim; iDim++) { - source_v_1 += Psi[iDim+1]*CrossProduct[iDim]; - } - } - - /*--- For simplicity, store all additional terms within sigma_partial ---*/ - - sigma_partial = sigma_partial + vartheta_partial + psi5_tau_partial + psi5_p_div_vel + psi5_tau_grad_vel + source_v_1; - - } - - /*--- Compute additional term in the surface sensitivity for free surface problem. ---*/ - - if (freesurface) { - LevelSet = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(nDim+1); - Target_LevelSet = geometry->node[iPoint]->GetCoord(nDim-1); - sigma_partial += 0.5*(Target_LevelSet - LevelSet)*(Target_LevelSet - LevelSet); - } - - /*--- Compute sensitivity for each surface point ---*/ - - CSensitivity[iMarker][iVertex] = (sigma_partial - temp_sens) * Area * scale * factor; - - /*--- Change the sign of the sensitivity if the normal has been flipped --*/ - - if (geometry->node[iPoint]->GetFlip_Orientation()) - CSensitivity[iMarker][iVertex] = -CSensitivity[iMarker][iVertex]; - - /*--- If sharp edge, set the sensitivity to 0 on that region ---*/ - - if (config->GetSens_Remove_Sharp()) { - eps = config->GetLimiterCoeff()*config->GetRefElemLength(); - if ( geometry->node[iPoint]->GetSharpEdge_Distance() < config->GetSharpEdgesCoeff()*eps ) - CSensitivity[iMarker][iVertex] = 0.0; - } - - Sens_Geo[iMarker] -= CSensitivity[iMarker][iVertex]; - - } - } - - Total_Sens_Geo += Sens_Geo[iMarker]; - - } - } - - /*--- Farfield Sensitivity (Mach, AoA, Press, Temp), only for compressible flows ---*/ - - if (compressible) { - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) == FAR_FIELD || config->GetMarker_All_KindBC(iMarker) == INLET_FLOW || - config->GetMarker_All_KindBC(iMarker) == SUPERSONIC_INLET || config->GetMarker_All_KindBC(iMarker) == SUPERSONIC_OUTLET || - config->GetMarker_All_KindBC(iMarker) == ENGINE_INFLOW ) { - - Sens_Mach[iMarker] = 0.0; - Sens_AoA[iMarker] = 0.0; - Sens_Press[iMarker] = 0.0; - Sens_Temp[iMarker] = 0.0; - Sens_BPress[iMarker] = 0.0; - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - Psi = node[iPoint]->GetSolution(); - U = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - - Mach_Inf = config->GetMach(); - if (grid_movement) Mach_Inf = config->GetMach_Motion(); - - r = U[0]; ru = U[1]; rv = U[2]; - if (nDim == 2) { rw = 0.0; rE = U[3]; } - else { rw = U[3]; rE = U[4]; } - p = Gamma_Minus_One*(rE-(ru*ru + rv*rv + rw*rw)/(2*r)); - - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; - Area = sqrt(Area); - for (iDim = 0; iDim < nDim; iDim++) UnitNormal[iDim] = -Normal[iDim]/Area; - - H = (rE + p)/r; - - dp_dr = Gamma_Minus_One*(ru*ru + rv*rv + rw*rw)/(2*r*r); - dp_dru = -Gamma_Minus_One*ru/r; - dp_drv = -Gamma_Minus_One*rv/r; - if (nDim == 2) { dp_drw = 0.0; dp_drE = Gamma_Minus_One; } - else { dp_drw = -Gamma_Minus_One*rw/r; dp_drE = Gamma_Minus_One; } - - dH_dr = (-H + dp_dr)/r; dH_dru = dp_dru/r; dH_drv = dp_drv/r; - if (nDim == 2) { dH_drw = 0.0; dH_drE = (1 + dp_drE)/r; } - else { dH_drw = dp_drw/r; dH_drE = (1 + dp_drE)/r; } - - if (nDim == 2) { - Jacobian_j[0][0] = 0.0; - Jacobian_j[1][0] = Area*UnitNormal[0]; - Jacobian_j[2][0] = Area*UnitNormal[1]; - Jacobian_j[3][0] = 0.0; - - Jacobian_j[0][1] = (-(ru*ru)/(r*r) + dp_dr)*Area*UnitNormal[0] + (-(ru*rv)/(r*r))*Area*UnitNormal[1]; - Jacobian_j[1][1] = (2*ru/r + dp_dru)*Area*UnitNormal[0] + (rv/r)*Area*UnitNormal[1]; - Jacobian_j[2][1] = (dp_drv)*Area*UnitNormal[0] + (ru/r)*Area*UnitNormal[1]; - Jacobian_j[3][1] = (dp_drE)*Area*UnitNormal[0]; - - Jacobian_j[0][2] = (-(ru*rv)/(r*r))*Area*UnitNormal[0] + (-(rv*rv)/(r*r) + dp_dr)*Area*UnitNormal[1]; - Jacobian_j[1][2] = (rv/r)*Area*UnitNormal[0] + (dp_dru)*Area*UnitNormal[1]; - Jacobian_j[2][2] = (ru/r)*Area*UnitNormal[0] + (2*rv/r + dp_drv)*Area*UnitNormal[1]; - Jacobian_j[3][2] = (dp_drE)*Area*UnitNormal[1]; - - Jacobian_j[0][3] = (ru*dH_dr)*Area*UnitNormal[0] + (rv*dH_dr)*Area*UnitNormal[1]; - Jacobian_j[1][3] = (H + ru*dH_dru)*Area*UnitNormal[0] + (rv*dH_dru)*Area*UnitNormal[1]; - Jacobian_j[2][3] = (ru*dH_drv)*Area*UnitNormal[0] + (H + rv*dH_drv)*Area*UnitNormal[1]; - Jacobian_j[3][3] = (ru*dH_drE)*Area*UnitNormal[0] + (rv*dH_drE)*Area*UnitNormal[1]; - } - else { - Jacobian_j[0][0] = 0.0; - Jacobian_j[1][0] = Area*UnitNormal[0]; - Jacobian_j[2][0] = Area*UnitNormal[1]; - Jacobian_j[3][0] = Area*UnitNormal[2]; - Jacobian_j[4][0] = 0.0; - - Jacobian_j[0][1] = (-(ru*ru)/(r*r) + dp_dr)*Area*UnitNormal[0] + (-(ru*rv)/(r*r))*Area*UnitNormal[1] + (-(ru*rw)/(r*r))*Area*UnitNormal[2]; - Jacobian_j[1][1] = (2*ru/r + dp_dru)*Area*UnitNormal[0] + (rv/r)*Area*UnitNormal[1] + (rw/r)*Area*UnitNormal[2]; - Jacobian_j[2][1] = (dp_drv)*Area*UnitNormal[0] + (ru/r)*Area*UnitNormal[1]; - Jacobian_j[3][1] = (dp_drw)*Area*UnitNormal[0] + (ru/r)*Area*UnitNormal[2]; - Jacobian_j[4][1] = (dp_drE)*Area*UnitNormal[0]; - - Jacobian_j[0][2] = (-(ru*rv)/(r*r))*Area*UnitNormal[0] + (-(rv*rv)/(r*r) + dp_dr)*Area*UnitNormal[1] + (-(rv*rw)/(r*r))*Area*UnitNormal[2]; - Jacobian_j[1][2] = (rv/r)*Area*UnitNormal[0] + (dp_dru)*Area*UnitNormal[1]; - Jacobian_j[2][2] = (ru/r)*Area*UnitNormal[0] + (2*rv/r + dp_drv)*Area*UnitNormal[1] + (rw/r)*Area*UnitNormal[2]; - Jacobian_j[3][2] = (dp_drw)*Area*UnitNormal[1] + (rv/r)*Area*UnitNormal[2]; - Jacobian_j[4][2] = (dp_drE)*Area*UnitNormal[1]; - - Jacobian_j[0][3] = (-(ru*rw)/(r*r))*Area*UnitNormal[0] + (-(rv*rw)/(r*r))*Area*UnitNormal[1] + (-(rw*rw)/(r*r) + dp_dr)*Area*UnitNormal[2]; - Jacobian_j[1][3] = (rw/r)*Area*UnitNormal[0] + (dp_dru)*Area*UnitNormal[2]; - Jacobian_j[2][3] = (rw/r)*Area*UnitNormal[1] + (dp_drv)*Area*UnitNormal[2]; - Jacobian_j[3][3] = (ru/r)*Area*UnitNormal[0] + (rv/r)*Area*UnitNormal[1] + (2*rw/r + dp_drw)*Area*UnitNormal[2]; - Jacobian_j[4][3] = (dp_drE)*Area*UnitNormal[2]; - - Jacobian_j[0][4] = (ru*dH_dr)*Area*UnitNormal[0] + (rv*dH_dr)*Area*UnitNormal[1] + (rw*dH_dr)*Area*UnitNormal[2]; - Jacobian_j[1][4] = (H + ru*dH_dru)*Area*UnitNormal[0] + (rv*dH_dru)*Area*UnitNormal[1] + (rw*dH_dru)*Area*UnitNormal[2]; - Jacobian_j[2][4] = (ru*dH_drv)*Area*UnitNormal[0] + (H + rv*dH_drv)*Area*UnitNormal[1] + (rw*dH_drv)*Area*UnitNormal[2]; - Jacobian_j[3][4] = (ru*dH_drw)*Area*UnitNormal[0] + (rv*dH_drw)*Area*UnitNormal[1] + (H + rw*dH_drw)*Area*UnitNormal[2]; - Jacobian_j[4][4] = (ru*dH_drE)*Area*UnitNormal[0] + (rv*dH_drE)*Area*UnitNormal[1] + (rw*dH_drE)*Area*UnitNormal[2]; - } - - /*--- Mach number sensitivity ---*/ - - USens[0] = 0.0; USens[1] = ru/Mach_Inf; USens[2] = rv/Mach_Inf; - if (nDim == 2) { USens[3] = Gamma*Mach_Inf*p; } - else { USens[3] = rw/Mach_Inf; USens[4] = Gamma*Mach_Inf*p; } - for (iPos = 0; iPos < nVar; iPos++) { - for (jPos = 0; jPos < nVar; jPos++) { - Sens_Mach[iMarker] += Psi[iPos]*Jacobian_j[jPos][iPos]*USens[jPos]; - } - } - - /*--- AoA sensitivity ---*/ - - USens[0] = 0.0; - if (nDim == 2) { USens[1] = -rv; USens[2] = ru; USens[3] = 0.0; } - else { USens[1] = -rw; USens[2] = 0.0; USens[3] = ru; USens[4] = 0.0; } - for (iPos = 0; iPos < nVar; iPos++) { - for (jPos = 0; jPos < nVar; jPos++) { - Sens_AoA[iMarker] += Psi[iPos]*Jacobian_j[jPos][iPos]*USens[jPos]; - } - } - - /*--- Pressure sensitivity ---*/ - - USens[0] = r/p; USens[1] = ru/p; USens[2] = rv/p; - if (nDim == 2) { USens[3] = rE/p; } - else { USens[3] = rw/p; USens[4] = rE/p; } - for (iPos = 0; iPos < nVar; iPos++) { - for (jPos = 0; jPos < nVar; jPos++) { - Sens_Press[iMarker] += Psi[iPos]*Jacobian_j[jPos][iPos]*USens[jPos]; - } - } - - /*--- Temperature sensitivity ---*/ - - T = p/(r*Gas_Constant); - USens[0] = -r/T; USens[1] = 0.5*ru/T; USens[2] = 0.5*rv/T; - if (nDim == 2) { USens[3] = (ru*ru + rv*rv + rw*rw)/(r*T); } - else { USens[3] = 0.5*rw/T; USens[4] = (ru*ru + rv*rv + rw*rw)/(r*T); } - for (iPos = 0; iPos < nVar; iPos++) { - for (jPos = 0; jPos < nVar; jPos++) { - Sens_Temp[iMarker] += Psi[iPos]*Jacobian_j[jPos][iPos]*USens[jPos]; - } - } - } - } - - Total_Sens_Mach -= Sens_Mach[iMarker] * scale * factor; - Total_Sens_AoA -= Sens_AoA[iMarker] * scale * factor; - Total_Sens_Press -= Sens_Press[iMarker] * scale * factor; - Total_Sens_Temp -= Sens_Temp[iMarker] * scale * factor; - - } - - } - - /*--- Explicit contribution from objective function quantity ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL)) { - - Sens_Mach[iMarker] = 0.0; - Sens_AoA[iMarker] = 0.0; - Sens_Press[iMarker] = 0.0; - Sens_Temp[iMarker] = 0.0; - Sens_BPress[iMarker] = 0.0; - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - p = solver_container[FLOW_SOL]->node[iPoint]->GetPressure(); - - Mach_Inf = config->GetMach(); - if (grid_movement) Mach_Inf = config->GetMach_Motion(); - - d = node[iPoint]->GetForceProj_Vector(); - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; - Area = sqrt(Area); - for (iDim = 0; iDim < nDim; iDim++) UnitNormal[iDim] = -Normal[iDim]/Area; - - /*--- Mach number sensitivity ---*/ - - for (iPos = 0; iPos < nDim; iPos++) Dd[iPos] = -(2.0/Mach_Inf)*d[iPos]; - for (iPos = 0; iPos < nDim; iPos++) Sens_Mach[iMarker] += p*Dd[iPos]*Area*UnitNormal[iPos]; - - /*--- AoA sensitivity ---*/ - - if (config->GetKind_ObjFunc() == DRAG_COEFFICIENT || - config->GetKind_ObjFunc() == LIFT_COEFFICIENT || - config->GetKind_ObjFunc() == SIDEFORCE_COEFFICIENT || - config->GetKind_ObjFunc() == EQUIVALENT_AREA || - config->GetKind_ObjFunc() == NEARFIELD_PRESSURE) { - if (nDim == 2) { - D[0][0] = 0.0; D[0][1] = -1.0; - D[1][0] = 1.0; D[1][1] = 0.0; - } - else { - D[0][0] = 0.0; D[0][1] = 0.0; D[0][2] = -1.0; - D[1][0] = 0.0; D[1][1] = 0.0; D[1][2] = 0.0; - D[2][0] = 1.0; D[2][1] = 0.0; D[2][2] = 0.0; - } - for (iPos = 0; iPos < nDim; iPos++) Dd[iPos] = 0.0; - for (iPos = 0; iPos < nDim; iPos++) { - for (jPos = 0; jPos < nDim; jPos++) - Dd[iPos] += D[iPos][jPos]*d[jPos]; - } - } - - /*--- Coefficients with no explicit AoA dependece ---*/ - - else { - for (iPos = 0; iPosGetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool grid_movement = config->GetGrid_Movement(); - - su2double Prandtl_Lam = config->GetPrandtl_Lam(); - su2double Prandtl_Turb = config->GetPrandtl_Turb(); - - su2double *Psi = new su2double[nVar]; - su2double **Tau = new su2double*[nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Tau[iDim] = new su2double [nDim]; - su2double *Velocity = new su2double[nDim]; - su2double *Normal = new su2double[nDim]; - su2double *Edge_Vector = new su2double[nDim]; - su2double **GradPhi = new su2double*[nDim]; - for (iDim = 0; iDim < nDim; iDim++) - GradPhi[iDim] = new su2double [nDim]; - su2double *GradPsiE = new su2double [nDim]; - - /*--- Loop over all of the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - - /*--- Initialize the convective & viscous residuals to zero ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - Res_Conv_i[iVar] = 0.0; Res_Visc_i[iVar] = 0.0; - if (implicit) { for (jVar = 0; jVar < nVar; jVar ++) Jacobian_ii[iVar][jVar] = 0.0; } - } - - /*--- Retrieve adjoint solution at the wall boundary node ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Psi[iVar] = node[iPoint]->GetSolution(iVar); - - /*--- Get the force projection vector (based on the objective function) ---*/ - - d = node[iPoint]->GetForceProj_Vector(); - - /*--- Set the adjoint velocity BC ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { phi[iDim] = d[iDim]; } - - /*--- Correct the adjoint velocity BC for dynamic meshes ---*/ - - if (grid_movement) { - GridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - phi[iDim] -= Psi[nDim+1]*GridVel[iDim]; - } - - /*--- Impose the value of the adjoint velocity as a strong boundary - condition (Dirichlet). Fix the adjoint velocity and remove any addtional - contribution to the residual at this node. ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - node[iPoint]->SetSolution_Old(iDim+1, phi[iDim]); - - for (iDim = 0; iDim < nDim; iDim++) - LinSysRes.SetBlock_Zero(iPoint, iDim+1); - node[iPoint]->SetVel_ResTruncError_Zero(); - - /*--- Compute additional contributions to the adjoint density and energy - equations which will be added to the residual (weak imposition) ---*/ - - if (compressible) { - - /*--- Energy residual due to the convective term ---*/ - - l1psi = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - l1psi += Normal[iDim]*d[iDim]; - Res_Conv_i[nDim+1] = l1psi*Gamma_Minus_One; - - /*--- Flux contribution and Jacobian contributions for moving - walls. Note that these are only for the adjoint density and - adjoint energy equations (the adjoint vel. uses a strong BC). ---*/ - - if (grid_movement) { - - /*--- Get the grid velocity at this node and impose v = u_wall ---*/ - - GridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) Velocity[iDim] = GridVel[iDim]; - - /*--- Get some additional quantities from the flow solution ---*/ - - Density = solver_container[FLOW_SOL]->node[iPoint]->GetDensity(); - if (compressible) { - Pressure = solver_container[FLOW_SOL]->node[iPoint]->GetPressure(); - Enthalpy = solver_container[FLOW_SOL]->node[iPoint]->GetEnthalpy(); - Laminar_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); - Eddy_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetEddyViscosity(); // Should be zero at the wall - } - if (incompressible || freesurface) { - Pressure = solver_container[FLOW_SOL]->node[iPoint]->GetPressureInc(); - Laminar_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosityInc(); - Eddy_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetEddyViscosityInc(); // Should be zero at the wall - } - - ViscDens = (Laminar_Viscosity + Eddy_Viscosity) / Density; - XiDens = Gamma * (Laminar_Viscosity/Prandtl_Lam + Eddy_Viscosity/Prandtl_Turb) / Density; - - /*--- Compute projections, velocity squared divided by two, and - other inner products. Note that we are imposing v = u_wall from - the direct problem and that phi = d - \psi_5 * v ---*/ - - ProjGridVel = 0.0; sq_vel = 0.0; - vartheta = Psi[0] + Psi[nDim+1]*Enthalpy; - for (iDim = 0; iDim < nDim; iDim++) { - ProjGridVel += GridVel[iDim]*Normal[iDim]; - sq_vel += 0.5*GridVel[iDim]*GridVel[iDim]; - vartheta += GridVel[iDim]*phi[iDim]; - } - - /*--- Convective flux at the wall node (adjoint density) ---*/ - - Res_Conv_i[0] = -vartheta*ProjGridVel + l1psi*Gamma_Minus_One*sq_vel; - - /*--- Implicit contributions from convective part ---*/ - - if (implicit) { - Jacobian_ii[0][0] += -ProjGridVel; - Jacobian_ii[0][nVar-1] += -ProjGridVel * Enthalpy; - } - - /*--- Viscous flux contributions at the wall node. Impose dPhiE_dn = 0 - (adiabatic walls with frozen viscosity). ---*/ - - dPhiE_dn = 0.0; - - /*--- Store the adjoint velocity and energy gradients for clarity ---*/ - - PsiVar_Grad = node[iPoint]->GetGradient(); - for (iDim = 0; iDim < nDim; iDim++) { - GradPsiE[iDim] = PsiVar_Grad[nVar-1][iDim]; - for (jDim = 0; jDim < nDim; jDim++) - GradPhi[iDim][jDim] = PsiVar_Grad[iDim+1][jDim]; - } - - if (nDim == 2) { - - /*--- Compute the adjoint stress tensor ---*/ - - Sigma_xx = ViscDens * (FOUR3 * GradPhi[0][0] - TWO3 * GradPhi[1][1]); - Sigma_yy = ViscDens * (-TWO3 * GradPhi[0][0] + FOUR3 * GradPhi[1][1]); - Sigma_xy = ViscDens * (GradPhi[1][0] + GradPhi[0][1]); - Sigma_xx5 = ViscDens * ( FOUR3 * Velocity[0] * GradPsiE[0] - TWO3 * Velocity[1] * GradPsiE[1]); - Sigma_yy5 = ViscDens * (- TWO3 * Velocity[0] * GradPsiE[0] + FOUR3 * Velocity[1] * GradPsiE[1]); - Sigma_xy5 = ViscDens * (Velocity[0] * GradPsiE[1] + Velocity[1] * GradPsiE[0]); - Sigma_5 = XiDens * dPhiE_dn; - eta_xx = Sigma_xx + Sigma_xx5; - eta_yy = Sigma_yy + Sigma_yy5; - eta_xy = Sigma_xy + Sigma_xy5; - - /*--- Viscous flux at the wall node (adjoint density & energy only) ---*/ - - Res_Visc_i[0] = - (Velocity[0] * Normal[0] * eta_xx + Velocity[1] * Normal[1] * eta_yy - + (Velocity[0] * Normal[1] + Velocity[1] * Normal[0]) * eta_xy - - (sq_vel - Pressure/(Density*Gamma_Minus_One)) * Sigma_5); - Res_Visc_i[nDim+1] = Sigma_5; - - /*--- Computation of the Jacobians at Point i---*/ - - if (implicit) { - - /*--- Compute closest normal neighbor ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Get coordinates of i & nearest normal and compute distance ---*/ - - Coord_i = geometry->node[iPoint]->GetCoord(); - Coord_j = geometry->node[Point_Normal]->GetCoord(); - dist_ij_2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Edge_Vector[iDim] = Coord_j[iDim]-Coord_i[iDim]; - dist_ij_2 += Edge_Vector[iDim]*Edge_Vector[iDim]; - } - - dSigmaxx_phi1 = -FOUR3 * ViscDens * Edge_Vector[0]/dist_ij_2; - dSigmaxx_phi2 = TWO3 * ViscDens * Edge_Vector[1]/dist_ij_2; - dSigmayy_phi1 = TWO3 * ViscDens * Edge_Vector[0]/dist_ij_2; - dSigmayy_phi2 = -FOUR3 * ViscDens * Edge_Vector[1]/dist_ij_2; - dSigmaxy_phi1 = -ViscDens * Edge_Vector[1]/dist_ij_2; - dSigmaxy_phi2 = -ViscDens * Edge_Vector[0]/dist_ij_2; - -// dSigmaxx5_psi5 = -ViscDens * ( FOUR3*Velocity[0]*Edge_Vector[0] - TWO3*Velocity[1]*Edge_Vector[1] )/dist_ij_2; -// dSigmayy5_psi5 = -ViscDens * (- TWO3*Velocity[0]*Edge_Vector[0] + FOUR3*Velocity[1]*Edge_Vector[1] )/dist_ij_2; -// dSigmaxy5_psi5 = -ViscDens * ( Velocity[0]*Edge_Vector[1] + Velocity[1]*Edge_Vector[0] )/dist_ij_2; - dSigma5_psi5 = -XiDens * ( Edge_Vector[0]*Normal[0] + Edge_Vector[1]*Normal[1] )/dist_ij_2; - - Jacobian_ii[0][0] += 0.0; - Jacobian_ii[0][1] += -( Velocity[0]*Normal[0]*dSigmaxx_phi1 + Velocity[1]*Normal[1]*dSigmayy_phi1 - + (Velocity[0]*Normal[1] + Velocity[1]*Normal[0])*dSigmaxy_phi1 ); - Jacobian_ii[0][2] += -( Velocity[0]*Normal[0]*dSigmaxx_phi2 + Velocity[1]*Normal[1]*dSigmayy_phi2 - + (Velocity[0]*Normal[1] + Velocity[1]*Normal[0])*dSigmaxy_phi2 ); - Jacobian_ii[0][3] += (sq_vel - Pressure/(Density*Gamma_Minus_One)) * dSigma5_psi5; - - Jacobian_ii[3][0] += 0.0; - Jacobian_ii[3][1] += 0.0; - Jacobian_ii[3][2] += 0.0; - Jacobian_ii[3][3] += dSigma5_psi5; - - } - - - } else if (nDim == 3) { - - /*--- Compute the adjoint stress tensor ---*/ - Sigma_xx = ViscDens * (FOUR3 * GradPhi[0][0] - TWO3 * GradPhi[1][1] - TWO3 * GradPhi[2][2]); - Sigma_yy = ViscDens * (-TWO3 * GradPhi[0][0] + FOUR3 * GradPhi[1][1] - TWO3 * GradPhi[2][2]); - Sigma_zz = ViscDens * (-TWO3 * GradPhi[0][0] - TWO3 * GradPhi[1][1] + FOUR3 * GradPhi[2][2]); - Sigma_xy = ViscDens * (GradPhi[1][0] + GradPhi[0][1]); - Sigma_xz = ViscDens * (GradPhi[2][0] + GradPhi[0][2]); - Sigma_yz = ViscDens * (GradPhi[2][1] + GradPhi[1][2]); - Sigma_xx5 = ViscDens * ( FOUR3 * Velocity[0] * GradPsiE[0] - TWO3 * Velocity[1] * GradPsiE[1] - TWO3 * Velocity[2] * GradPsiE[2]); - Sigma_yy5 = ViscDens * (- TWO3 * Velocity[0] * GradPsiE[0] + FOUR3 * Velocity[1] * GradPsiE[1] - TWO3 * Velocity[2] * GradPsiE[2]); - Sigma_zz5 = ViscDens * (- TWO3 * Velocity[0] * GradPsiE[0] - TWO3 * Velocity[1] * GradPsiE[1] + FOUR3 * Velocity[2] * GradPsiE[2]); - Sigma_xy5 = ViscDens * (Velocity[0] * GradPsiE[1] + Velocity[1] * GradPsiE[0]); - Sigma_xz5 = ViscDens * (Velocity[0] * GradPsiE[2] + Velocity[2] * GradPsiE[0]); - Sigma_yz5 = ViscDens * (Velocity[1] * GradPsiE[2] + Velocity[2] * GradPsiE[1]); - Sigma_5 = XiDens * dPhiE_dn; - eta_xx = Sigma_xx + Sigma_xx5; eta_yy = Sigma_yy + Sigma_yy5; eta_zz = Sigma_zz + Sigma_zz5; - eta_xy = Sigma_xy + Sigma_xy5; eta_xz = Sigma_xz + Sigma_xz5; eta_yz = Sigma_yz + Sigma_yz5; - - /*--- Viscous flux at the wall node (adjoint density & energy only) ---*/ - - Res_Visc_i[0] = - (Velocity[0] * Normal[0] * eta_xx + Velocity[1] * Normal[1] * eta_yy + Velocity[2] * Normal[2] * eta_zz - + (Velocity[0] * Normal[1] + Velocity[1] * Normal[0]) * eta_xy - + (Velocity[0] * Normal[2] + Velocity[2] * Normal[0]) * eta_xz - + (Velocity[2] * Normal[1] + Velocity[1] * Normal[2]) * eta_yz - - (sq_vel - Pressure/(Density*Gamma_Minus_One)) * Sigma_5); - Res_Visc_i[nDim+1] = Sigma_5; - - /*--- Computation of the Jacobians at Point i---*/ - - if (implicit) { - - /*--- Compute closest normal neighbor ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Get coordinates of i & nearest normal and compute distance ---*/ - - Coord_i = geometry->node[iPoint]->GetCoord(); - Coord_j = geometry->node[Point_Normal]->GetCoord(); - dist_ij_2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Edge_Vector[iDim] = Coord_j[iDim]-Coord_i[iDim]; - dist_ij_2 += Edge_Vector[iDim]*Edge_Vector[iDim]; - } - - dSigmaxx_phi1 = -FOUR3 * ViscDens * Edge_Vector[0]/dist_ij_2; - dSigmaxx_phi2 = TWO3 * ViscDens * Edge_Vector[1]/dist_ij_2; - dSigmaxx_phi3 = TWO3 * ViscDens * Edge_Vector[2]/dist_ij_2; - dSigmayy_phi1 = TWO3 * ViscDens * Edge_Vector[0]/dist_ij_2; - dSigmayy_phi2 = -FOUR3 * ViscDens * Edge_Vector[1]/dist_ij_2; - dSigmayy_phi3 = TWO3 * ViscDens * Edge_Vector[2]/dist_ij_2; - dSigmazz_phi1 = TWO3 * ViscDens * Edge_Vector[0]/dist_ij_2; - dSigmazz_phi2 = TWO3 * ViscDens * Edge_Vector[1]/dist_ij_2; - dSigmazz_phi3 = -FOUR3 * ViscDens * Edge_Vector[2]/dist_ij_2; - dSigmaxy_phi1 = -ViscDens * Edge_Vector[1]/dist_ij_2; - dSigmaxy_phi2 = -ViscDens * Edge_Vector[0]/dist_ij_2; - dSigmaxy_phi3 = 0; - dSigmaxz_phi1 = -ViscDens * Edge_Vector[2]/dist_ij_2; - dSigmaxz_phi2 = 0; - dSigmaxz_phi3 = -ViscDens * Edge_Vector[0]/dist_ij_2; - dSigmayz_phi1 = 0; - dSigmayz_phi2 = -ViscDens * Edge_Vector[2]/dist_ij_2; - dSigmayz_phi3 = -ViscDens * Edge_Vector[1]/dist_ij_2; - -// dSigmaxx5_psi5 = -ViscDens * ( FOUR3*Velocity[0]*Edge_Vector[0] - TWO3*Velocity[1]*Edge_Vector[1] - TWO3*Velocity[2]*Edge_Vector[2])/dist_ij_2; -// dSigmayy5_psi5 = -ViscDens * (- TWO3*Velocity[0]*Edge_Vector[0] + FOUR3*Velocity[1]*Edge_Vector[1] - TWO3*Velocity[2]*Edge_Vector[2])/dist_ij_2; -// dSigmazz5_psi5 = -ViscDens * (- TWO3*Velocity[0]*Edge_Vector[0] - TWO3*Velocity[1]*Edge_Vector[1] + FOUR3*Velocity[2]*Edge_Vector[2])/dist_ij_2; -// dSigmaxy5_psi5 = -ViscDens * ( Velocity[0]*Edge_Vector[1] + Velocity[1]*Edge_Vector[0] )/dist_ij_2; -// dSigmaxz5_psi5 = -ViscDens * ( Velocity[0]*Edge_Vector[2] + Velocity[2]*Edge_Vector[0] )/dist_ij_2; -// dSigmayz5_psi5 = -ViscDens * ( Velocity[1]*Edge_Vector[2] + Velocity[2]*Edge_Vector[1] )/dist_ij_2; - dSigma5_psi5 = -XiDens * ( Edge_Vector[0]*Normal[0] + Edge_Vector[1]*Normal[1] + Edge_Vector[2]*Normal[2] )/dist_ij_2; - - Jacobian_ii[0][0] += 0.0; - Jacobian_ii[0][1] += -( Velocity[0]*Normal[0]*dSigmaxx_phi1 + Velocity[1]*Normal[1]*dSigmayy_phi1 + Velocity[2]*Normal[2]*dSigmazz_phi1 - + (Velocity[0]*Normal[1] + Velocity[1]*Normal[0])*dSigmaxy_phi1 - + (Velocity[0]*Normal[2] + Velocity[2]*Normal[0])*dSigmaxz_phi1 - + (Velocity[2]*Normal[1] + Velocity[1]*Normal[2])*dSigmayz_phi1 ); - Jacobian_ii[0][2] += -( Velocity[0]*Normal[0]*dSigmaxx_phi2 + Velocity[1]*Normal[1]*dSigmayy_phi2 + Velocity[2]*Normal[2]*dSigmazz_phi2 - + (Velocity[0]*Normal[1] + Velocity[1]*Normal[0])*dSigmaxy_phi2 - + (Velocity[0]*Normal[2] + Velocity[2]*Normal[0])*dSigmaxz_phi2 - + (Velocity[2]*Normal[1] + Velocity[1]*Normal[2])*dSigmayz_phi2 ); - Jacobian_ii[0][3] += -( Velocity[0]*Normal[0]*dSigmaxx_phi3 + Velocity[1]*Normal[1]*dSigmayy_phi3 + Velocity[2]*Normal[2]*dSigmazz_phi3 - + (Velocity[0]*Normal[1] + Velocity[1]*Normal[0])*dSigmaxy_phi3 - + (Velocity[0]*Normal[2] + Velocity[2]*Normal[0])*dSigmaxz_phi3 - + (Velocity[2]*Normal[1] + Velocity[1]*Normal[2])*dSigmayz_phi3 ); - Jacobian_ii[0][4] += (sq_vel - Pressure/(Density*Gamma_Minus_One)) * dSigma5_psi5; - - Jacobian_ii[4][0] += 0.0; - Jacobian_ii[4][1] += 0.0; - Jacobian_ii[4][2] += 0.0; - Jacobian_ii[4][3] += 0.0; - Jacobian_ii[4][4] += dSigma5_psi5; - - } - } - } - } - - if (incompressible || freesurface) { - - /*--- Pressure residual due to the convective term ---*/ - - l1psi = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - l1psi += Normal[iDim]*d[iDim]; - Res_Conv_i[0] = l1psi; - } - - /*--- Convective contribution to the residual at the wall ---*/ - - LinSysRes.SubtractBlock(iPoint, Res_Conv_i); - - /*--- Viscous contribution to the residual at the wall ---*/ - - LinSysRes.SubtractBlock(iPoint, Res_Visc_i); - - /*--- Enforce the no-slip boundary condition in a strong way by - modifying the velocity-rows of the Jacobian (1 on the diagonal). ---*/ - - if (implicit) { - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - for (iVar = 1; iVar <= nDim; iVar++) { - total_index = iPoint*nVar+iVar; - Jacobian.DeleteValsRowi(total_index); - } - } - - } - - } - - for (iDim = 0; iDim < nDim; iDim++) - delete [] Tau[iDim]; - delete [] Tau; - delete [] Psi; - delete [] Velocity; - delete [] Normal; - delete [] Edge_Vector; - delete [] GradPsiE; - for (iDim = 0; iDim < nDim; iDim++) - delete [] GradPhi[iDim]; - delete [] GradPhi; - -} - - -void CAdjNSSolver::BC_Isothermal_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned long iVertex, iPoint, total_index; - unsigned short iDim, iVar, jVar, jDim; - su2double *d, q, *U, l1psi, dVisc_T, rho, pressure, div_phi, - force_stress, Sigma_5, **PsiVar_Grad, phi[3] = {0.0,0.0,0.0}; - su2double phis1, phis2, sq_vel, ProjVel, Enthalpy, *GridVel, phi_u, d_n; - su2double Energy, ViscDens, XiDens, Density, SoundSpeed, Pressure, dPhiE_dn, Laminar_Viscosity, Eddy_Viscosity, - Sigma_xx, Sigma_yy, Sigma_zz, Sigma_xy, Sigma_xz, Sigma_yz, - Sigma_xx5, Sigma_yy5, Sigma_zz5, Sigma_xy5, Sigma_xz5, - Sigma_yz5, eta_xx, eta_yy, eta_zz, eta_xy, eta_xz, eta_yz; - su2double kGTdotn; - - su2double *Psi = new su2double[nVar]; - su2double **Tau = new su2double* [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Tau[iDim] = new su2double [nDim]; - su2double *Velocity = new su2double[nDim]; - su2double *Normal = new su2double[nDim]; - - su2double **GradPhi = new su2double* [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - GradPhi[iDim] = new su2double [nDim]; - su2double *GradPsiE = new su2double [nDim]; - su2double *GradT;// = new su2double[nDim]; - su2double *GradP; - su2double *GradDens; - su2double *dPoRho2 = new su2double[nDim]; - - bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool grid_movement = config->GetGrid_Movement(); - bool heat_flux_obj = ((config->GetKind_ObjFunc() == TOTAL_HEATFLUX) || - (config->GetKind_ObjFunc() == MAXIMUM_HEATFLUX) || - (config->GetKind_ObjFunc() == INVERSE_DESIGN_HEATFLUX)); - - su2double Prandtl_Lam = config->GetPrandtl_Lam(); - su2double Prandtl_Turb = config->GetPrandtl_Turb(); - su2double Gas_Constant = config->GetGas_ConstantND(); - su2double Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; - su2double Thermal_Conductivity; - su2double invrho3; - su2double Volume; - su2double mu2; - su2double gpsiAv2; - su2double gpsi5n; - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Initialize the convective & viscous residuals to zero ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - Res_Conv_i[iVar] = 0.0; - Res_Visc_i[iVar] = 0.0; - if (implicit) { - for (jVar = 0; jVar < nVar; jVar ++) - Jacobian_ii[iVar][jVar] = 0.0; - } - } - - /*--- Retrieve adjoint solution at the wall boundary node ---*/ - for (iVar = 0; iVar < nVar; iVar++) - Psi[iVar] = node[iPoint]->GetSolution(iVar); - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - Volume = geometry->node[iPoint]->GetVolume(); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - - /*--- Get the force projection vector (based on the objective function) ---*/ - d = node[iPoint]->GetForceProj_Vector(); - - /*--- Adjustments to strong boundary condition for dynamic meshes ---*/ - if ( grid_movement) { - GridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) { - phi[iDim] = d[iDim] - Psi[nVar-1]*GridVel[iDim]; - } - } else { - for (iDim = 0; iDim < nDim; iDim++) { - phi[iDim] = d[iDim]; - } - } - - /*--- Strong BC imposition for the adjoint velocity equations ---*/ - for (iDim = 0; iDim < nDim; iDim++) - LinSysRes.SetBlock_Zero(iPoint, iDim+1); - node[iPoint]->SetVel_ResTruncError_Zero(); - for (iDim = 0; iDim < nDim; iDim++) - node[iPoint]->SetSolution_Old(iDim+1, phi[iDim]); - if (implicit) { - for (iVar = 1; iVar <= nDim; iVar++) { - total_index = iPoint*nVar+iVar; - Jacobian.DeleteValsRowi(total_index); - } - } - - /*--- Get transport coefficient information ---*/ - Laminar_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); - Eddy_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetEddyViscosity(); - Thermal_Conductivity = Cp * ( Laminar_Viscosity/Prandtl_Lam - +Eddy_Viscosity/Prandtl_Turb); - -// GradV = solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(); - - /*--- Calculate Dirichlet condition for energy equation ---*/ - if (!heat_flux_obj) { - q = 0.0; - } - else { - GradT = solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive()[0]; - kGTdotn = 0; -// Xi = solver_container[FLOW_SOL]->GetTotal_MaxHeatFlux(); -// Xi = 1.0; - for (iDim = 0; iDim < nDim; iDim++) - kGTdotn += Thermal_Conductivity*GradT[iDim]*Normal[iDim]; - //q = - Xi * pnorm * pow(kGTdotn, pnorm-1.0); - q = -1.0; - } - - /*--- Strong BC enforcement of the energy equation ---*/ - LinSysRes.SetBlock_Zero(iPoint, nVar-1); - node[iPoint]->SetEnergy_ResTruncError_Zero(); - node[iPoint]->SetSolution_Old(nDim+1, q); - if (implicit) { - iVar = nDim+1; - total_index = iPoint*nVar+iVar; - Jacobian.DeleteValsRowi(total_index); - } - - /*--- Additional contributions to adjoint density (weak imposition) ---*/ - if (compressible) { - - /*--- Acquire gradient information ---*/ - PsiVar_Grad = node[iPoint]->GetGradient(); - GradP = solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive()[nVar-1]; - GradDens = solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive()[nVar]; - - /*--- Acqure flow information ---*/ - rho = solver_container[FLOW_SOL]->node[iPoint]->GetDensity(); - pressure = solver_container[FLOW_SOL]->node[iPoint]->GetPressure(); - invrho3 = (1.0/rho)*(1.0/rho)*(1.0/rho); - - /*--- Calculate supporting quantities ---*/ - mu2 = Thermal_Conductivity/Cp; - gpsiAv2 = 0.0; - gpsi5n = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - dPoRho2[iDim] = (GradP[iDim]*rho - 2.0*GradDens[iDim]*pressure)*invrho3; - gpsiAv2 += -mu2*Gamma/Gamma_Minus_One * PsiVar_Grad[nVar-1][iDim]*dPoRho2[iDim]; - gpsi5n += PsiVar_Grad[nVar-1][iDim]*Normal[iDim]; - } - - /*--- Apply first order term to boundary ---*/ - Res_Conv_i[0] = gpsiAv2*Volume; - - /*--- Apply second order term to boundary ---*/ - Res_Visc_i[0] = -mu2*Gamma/(rho*Gamma_Minus_One)*(pressure/rho)*gpsi5n; - - /*--- Components of the effective and adjoint stress tensors ---*/ - PsiVar_Grad = node[iPoint]->GetGradient(); - div_phi = 0; - for (iDim = 0; iDim < nDim; iDim++) { - div_phi += PsiVar_Grad[iDim+1][iDim]; - for (jDim = 0; jDim < nDim; jDim++) - Tau[iDim][jDim] = (PsiVar_Grad[iDim+1][jDim]+PsiVar_Grad[jDim+1][iDim]); - } - for (iDim = 0; iDim < nDim; iDim++) - Tau[iDim][iDim] -= TWO3*div_phi; - - /*--- force_stress = n_i \Tau_{ij} d_j ---*/ - force_stress = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - for (jDim = 0; jDim < nDim; jDim++) - force_stress += Normal[iDim]*Tau[iDim][jDim]*d[jDim]; - - /*--- \partial \mu_dyn \partial T ---*/ -// mu_dyn = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); -// Temp = solver_container[FLOW_SOL]->node[iPoint]->GetTemperature(); - dVisc_T = 0.0; // dVisc_T = mu_dyn*(Temp+3.0*mu2)/(2.0*Temp*(Temp+mu2)); - - /*--- \Sigma_5 Check Area computation for Res_Conv[0] ---*/ - Sigma_5 = (Gamma/Cp)*dVisc_T*force_stress; - - /*--- Imposition of residuals ---*/ - rho = solver_container[FLOW_SOL]->node[iPoint]->GetDensity(); - pressure = solver_container[FLOW_SOL]->node[iPoint]->GetPressure(); - Res_Conv_i[0] = pressure*Sigma_5/(Gamma_Minus_One*rho*rho); - - /*--- Flux contribution and Jacobian contributions for moving - walls. Note that these are only for the adjoint density and - adjoint energy equations (the adjoint vel. uses a strong BC). ---*/ - if (grid_movement) { - - /*--- Get the appropriate grid velocity at this node ---*/ - GridVel = geometry->node[iPoint]->GetGridVel(); - - /*--- Get the enthalpy from the direct solution ---*/ - Enthalpy = solver_container[FLOW_SOL]->node[iPoint]->GetEnthalpy(); - - /*--- Compute projections, velocity squared divided by two, and - other inner products. Note that we are imposing v = u_wall from - the direct problem and that phi = d - \psi_5 * v ---*/ - ProjVel = 0.0; sq_vel = 0.0; phi_u = 0.0; d_n = 0.0; - phis1 = 0.0; phis2 = Psi[0] + Enthalpy * Psi[nVar-1]; - for (iDim = 0; iDim < nDim; iDim++) { - ProjVel += GridVel[iDim]*Normal[iDim]; - sq_vel += 0.5*GridVel[iDim]*GridVel[iDim]; - phis1 += Normal[iDim]*phi[iDim]; - phis2 += GridVel[iDim]*phi[iDim]; - phi_u += GridVel[iDim]*phi[iDim]; - d_n += d[iDim]*Normal[iDim]; - } -// phis1 += ProjVel * Psi[nVar-1]; - - /*--- Convective flux at the wall node (adjoint density & energy only) ---*/ - - /*--- Version 1 (full) ---*/ - //Res_Conv_i[0] = ProjVel * Psi[0] - phis2 * ProjVel + phis1 * Gamma_Minus_One * sq_vel - ProjVel*Psi[0]; - //Res_Conv_i[nVar-1] = ProjVel * Psi[nVar-1] + phis1 * Gamma_Minus_One - ProjVel*Psi[nVar-1]; - - /*--- Simplified version ---*/ - Res_Conv_i[0] = -(Psi[0] + phi_u + Psi[nVar-1]*Enthalpy)*ProjVel + d_n*Gamma_Minus_One*sq_vel; - - /*--- TO DO: Implicit contributions for convective part ---*/ - - - /*--- Viscous flux contributions at the wall node ---*/ - U = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); - Laminar_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); - Eddy_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetEddyViscosity(); // Should be zero at the wall - Density = U[0]; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity[iDim] = GridVel[iDim]; - } - Energy = U[nDim+1] / Density; - SoundSpeed = sqrt(Gamma*Gamma_Minus_One*(Energy-sq_vel)); - Pressure = (SoundSpeed * SoundSpeed * Density) / Gamma; - ViscDens = (Laminar_Viscosity + Eddy_Viscosity) / Density; - XiDens = Gamma * (Laminar_Viscosity/Prandtl_Lam + Eddy_Viscosity/Prandtl_Turb) / Density; - - /*--- Average of the derivatives of the adjoint variables ---*/ - PsiVar_Grad = node[iPoint]->GetGradient(); - - for (iDim = 0; iDim < nDim; iDim++) { - GradPsiE[iDim] = PsiVar_Grad[nVar-1][iDim]; - for (jDim = 0; jDim < nDim; jDim++) - GradPhi[iDim][jDim] = PsiVar_Grad[iDim+1][jDim]; - } - - /*--- Impose dPhiE_dn = 0 (adiabatic walls with frozen viscosity). Note - that this is where a different adjoint boundary condition for temperature - could be imposed. ---*/ - dPhiE_dn = 0.0; - - if (nDim ==2) { - - /*--- Compute the adjoint stress tensor ---*/ - Sigma_xx = ViscDens * (FOUR3 * GradPhi[0][0] - TWO3 * GradPhi[1][1]); - Sigma_yy = ViscDens * (-TWO3 * GradPhi[0][0] + FOUR3 * GradPhi[1][1]); - Sigma_xy = ViscDens * (GradPhi[1][0] + GradPhi[0][1]); - Sigma_xx5 = ViscDens * ( FOUR3 * Velocity[0] * GradPsiE[0] - TWO3 * Velocity[1] * GradPsiE[1]); - Sigma_yy5 = ViscDens * (- TWO3 * Velocity[0] * GradPsiE[0] + FOUR3 * Velocity[1] * GradPsiE[1]); - Sigma_xy5 = ViscDens * (Velocity[0] * GradPsiE[1] + Velocity[1] * GradPsiE[0]); - Sigma_5 = XiDens * dPhiE_dn; - eta_xx = Sigma_xx + Sigma_xx5; - eta_yy = Sigma_yy + Sigma_yy5; - eta_xy = Sigma_xy + Sigma_xy5; - - /*--- Viscous flux at the wall node (adjoint density & energy only) ---*/ - Res_Visc_i[0] = - (Velocity[0] * Normal[0] * eta_xx + Velocity[1] * Normal[1] * eta_yy - + (Velocity[0] * Normal[1] + Velocity[1] * Normal[0]) * eta_xy - - (sq_vel - Pressure/(Density*Gamma_Minus_One)) * Sigma_5); - Res_Visc_i[1] = 0.0; - Res_Visc_i[2] = 0.0; - - } else if (nDim == 3) { - - /*--- Compute the adjoint stress tensor ---*/ - Sigma_xx = ViscDens * (FOUR3 * GradPhi[0][0] - TWO3 * GradPhi[1][1] - TWO3 * GradPhi[2][2]); - Sigma_yy = ViscDens * (-TWO3 * GradPhi[0][0] + FOUR3 * GradPhi[1][1] - TWO3 * GradPhi[2][2]); - Sigma_zz = ViscDens * (-TWO3 * GradPhi[0][0] - TWO3 * GradPhi[1][1] + FOUR3 * GradPhi[2][2]); - Sigma_xy = ViscDens * (GradPhi[1][0] + GradPhi[0][1]); - Sigma_xz = ViscDens * (GradPhi[2][0] + GradPhi[0][2]); - Sigma_yz = ViscDens * (GradPhi[2][1] + GradPhi[1][2]); - Sigma_xx5 = ViscDens * ( FOUR3 * Velocity[0] * GradPsiE[0] - TWO3 * Velocity[1] * GradPsiE[1] - TWO3 * Velocity[2] * GradPsiE[2]); - Sigma_yy5 = ViscDens * (- TWO3 * Velocity[0] * GradPsiE[0] + FOUR3 * Velocity[1] * GradPsiE[1] - TWO3 * Velocity[2] * GradPsiE[2]); - Sigma_zz5 = ViscDens * (- TWO3 * Velocity[0] * GradPsiE[0] - TWO3 * Velocity[1] * GradPsiE[1] + FOUR3 * Velocity[2] * GradPsiE[2]); - Sigma_xy5 = ViscDens * (Velocity[0] * GradPsiE[1] + Velocity[1] * GradPsiE[0]); - Sigma_xz5 = ViscDens * (Velocity[0] * GradPsiE[2] + Velocity[2] * GradPsiE[0]); - Sigma_yz5 = ViscDens * (Velocity[1] * GradPsiE[2] + Velocity[2] * GradPsiE[1]); - Sigma_5 = XiDens * dPhiE_dn; - eta_xx = Sigma_xx + Sigma_xx5; eta_yy = Sigma_yy + Sigma_yy5; eta_zz = Sigma_zz + Sigma_zz5; - eta_xy = Sigma_xy + Sigma_xy5; eta_xz = Sigma_xz + Sigma_xz5; eta_yz = Sigma_yz + Sigma_yz5; - - /*--- Viscous flux at the wall node (adjoint density & energy only) ---*/ - Res_Visc_i[0] = - (Velocity[0] * Normal[0] * eta_xx + Velocity[1] * Normal[1] * eta_yy + Velocity[2] * Normal[2] * eta_zz - + (Velocity[0] * Normal[1] + Velocity[1] * Normal[0]) * eta_xy - + (Velocity[0] * Normal[2] + Velocity[2] * Normal[0]) * eta_xz - + (Velocity[2] * Normal[1] + Velocity[1] * Normal[2]) * eta_yz - - (sq_vel - Pressure/(Density*Gamma_Minus_One)) * Sigma_5); - Res_Visc_i[1] = 0.0; - Res_Visc_i[2] = 0.0; - Res_Visc_i[3] = 0.0; - } - } - } - - if (incompressible) { - - /*--- Pressure residual due to the convective term ---*/ - l1psi = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - l1psi += Normal[iDim]*d[iDim]; - Res_Conv_i[0] = l1psi; - - } - - /*--- Update convective and viscous residuals ---*/ - LinSysRes.AddBlock(iPoint, Res_Conv_i); - LinSysRes.SubtractBlock(iPoint, Res_Visc_i); - if (implicit) { - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); - } - - } - - } - - for (iDim = 0; iDim < nDim; iDim++) - delete [] Tau[iDim]; - delete [] Tau; - delete [] Psi; - delete [] Velocity; - delete [] Normal; - delete [] GradPsiE; - for (iDim = 0; iDim < nDim; iDim++) - delete [] GradPhi[iDim]; - delete [] GradPhi; - delete [] dPoRho2; -} - +/*! + * \file solution_adjoint_mean.cpp + * \brief Main subrotuines for solving adjoint problems (Euler, Navier-Stokes, etc.). + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/solver_structure.hpp" + +CAdjEulerSolver::CAdjEulerSolver(void) : CSolver() { + + /*--- Array initialization ---*/ + Phi_Inf = NULL; + Sens_Mach = NULL; + Sens_AoA = NULL; + Sens_Geo = NULL; + Sens_Press = NULL; + Sens_Temp = NULL; + Sens_BPress = NULL; + iPoint_UndLapl = NULL; + jPoint_UndLapl = NULL; + Jacobian_Axisymmetric = NULL; + CSensitivity = NULL; + FlowPrimVar_i = NULL; + FlowPrimVar_j = NULL; + +} + +CAdjEulerSolver::CAdjEulerSolver(CGeometry *geometry, CConfig *config, unsigned short iMesh) : CSolver() { + unsigned long iPoint, index, iVertex; + string text_line, mesh_filename; + unsigned short iDim, iVar, iMarker, nLineLets; + ifstream restart_file; + string filename, AdjExt; + su2double dull_val, myArea_Monitored, Area, *Normal; + bool restart = config->GetRestart(); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool axisymmetric = config->GetAxisymmetric(); + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Array initialization ---*/ + Phi_Inf = NULL; + Sens_Mach = NULL; + Sens_AoA = NULL; + Sens_Geo = NULL; + Sens_Press = NULL; + Sens_Temp = NULL; + Sens_BPress = NULL; + iPoint_UndLapl = NULL; + jPoint_UndLapl = NULL; + Jacobian_Axisymmetric = NULL; + CSensitivity = NULL; + FlowPrimVar_i = NULL; + FlowPrimVar_j = NULL; + + /*--- Set the gamma value ---*/ + Gamma = config->GetGamma(); + Gamma_Minus_One = Gamma - 1.0; + + /*--- Define geometry constans in the solver structure ---*/ + nDim = geometry->GetnDim(); + nMarker = config->GetnMarker_All(); + nPoint = geometry->GetnPoint(); + nPointDomain = geometry->GetnPointDomain(); + + if (compressible) { nVar = nDim + 2; } + if (incompressible) { nVar = nDim + 1; } + if (freesurface) { nVar = nDim + 2; } + + node = new CVariable*[nPoint]; + + /*--- Define some auxiliary vectors related to the residual ---*/ + Residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; + Residual_RMS = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_RMS[iVar] = 0.0; + Residual_Max = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_Max[iVar] = 0.0; + Point_Max = new unsigned long[nVar]; for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; + Point_Max_Coord = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Point_Max_Coord[iVar] = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; + } + Residual_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_i[iVar] = 0.0; + Residual_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_j[iVar] = 0.0; + Res_Conv_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Conv_i[iVar] = 0.0; + Res_Visc_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Visc_i[iVar] = 0.0; + Res_Conv_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Conv_j[iVar] = 0.0; + Res_Visc_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Visc_j[iVar] = 0.0; + + /*--- Define some auxiliary vectors related to the solution ---*/ + Solution = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; + Solution_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_i[iVar] = 0.0; + Solution_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_j[iVar] = 0.0; + + /*--- Define some auxiliary arrays related to the flow solution ---*/ + FlowPrimVar_i = new su2double[nDim+7]; for (iVar = 0; iVar < nDim+7; iVar++) FlowPrimVar_i[iVar] = 0.0; + FlowPrimVar_j = new su2double[nDim+7]; for (iVar = 0; iVar < nDim+7; iVar++) FlowPrimVar_j[iVar] = 0.0; + + /*--- Define some auxiliary vectors related to the geometry ---*/ + Vector = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = 0.0; + Vector_i = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_i[iDim] = 0.0; + Vector_j = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_j[iDim] = 0.0; + + /*--- Define some auxiliary vectors related to the undivided lapalacian ---*/ + if (config->GetKind_ConvNumScheme_AdjFlow() == SPACE_CENTERED) { + iPoint_UndLapl = new su2double [nPoint]; + jPoint_UndLapl = new su2double [nPoint]; + } + + /*--- Define some auxiliary vectors related to the geometry ---*/ + Vector_i = new su2double[nDim]; Vector_j = new su2double[nDim]; + + /*--- Point to point Jacobians. These are always defined because + they are also used for sensitivity calculations. ---*/ + Jacobian_i = new su2double* [nVar]; + Jacobian_j = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Jacobian_i[iVar] = new su2double [nVar]; + Jacobian_j[iVar] = new su2double [nVar]; + } + + LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); + LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); + + /*--- Jacobians and vector structures for implicit computations ---*/ + if (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT) { + Jacobian_ii = new su2double* [nVar]; + Jacobian_ij = new su2double* [nVar]; + Jacobian_ji = new su2double* [nVar]; + Jacobian_jj = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Jacobian_ii[iVar] = new su2double [nVar]; + Jacobian_ij[iVar] = new su2double [nVar]; + Jacobian_ji[iVar] = new su2double [nVar]; + Jacobian_jj[iVar] = new su2double [nVar]; + } + + if (rank == MASTER_NODE) + cout << "Initialize Jacobian structure (Adjoint Euler). MG level: " << iMesh <<"." << endl; + Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); + + if ((config->GetKind_Linear_Solver_Prec() == LINELET) || + (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { + nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); + if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; + } + + if (axisymmetric) { + Jacobian_Axisymmetric = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + Jacobian_Axisymmetric[iVar] = new su2double [nVar]; + } + } else { + if (rank == MASTER_NODE) + cout << "Explicit scheme. No Jacobian structure (Adjoint Euler). MG level: " << iMesh <<"." << endl; + } + + /*--- Computation of gradients by least squares ---*/ + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { + /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ + Smatrix = new su2double* [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Smatrix[iDim] = new su2double [nDim]; + /*--- c vector := transpose(WA)*(Wb) ---*/ + cvector = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + cvector[iVar] = new su2double [nDim]; + } + + /*--- Sensitivity definition and coefficient in all the markers ---*/ + CSensitivity = new su2double* [nMarker]; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + CSensitivity[iMarker] = new su2double [geometry->nVertex[iMarker]]; + } + Sens_Geo = new su2double[nMarker]; + Sens_Mach = new su2double[nMarker]; + Sens_AoA = new su2double[nMarker]; + Sens_Press = new su2double[nMarker]; + Sens_Temp = new su2double[nMarker]; + Sens_BPress = new su2double[nMarker]; + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + Sens_Geo[iMarker] = 0.0; + Sens_Mach[iMarker] = 0.0; + Sens_AoA[iMarker] = 0.0; + Sens_Press[iMarker] = 0.0; + Sens_Temp[iMarker] = 0.0; + Sens_BPress[iMarker] = 0.0; + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) + CSensitivity[iMarker][iVertex] = 0.0; + } + + /*--- Adjoint flow at the inifinity, initialization stuff ---*/ + PsiRho_Inf = 0.0; PsiE_Inf = 0.0; + Phi_Inf = new su2double [nDim]; + Phi_Inf[0] = 0.0; Phi_Inf[1] = 0.0; + if (nDim == 3) Phi_Inf[2] = 0.0; + + /*--- If outflow objective, nonzero initialization ---*/ + if ((config->GetKind_ObjFunc() == AVG_TOTAL_PRESSURE)){ + su2double SoundSpeed,*vel_inf,R,vel2,vel; + R = config->GetGas_ConstantND(); + vel_inf = config->GetVelocity_FreeStreamND(); + vel2=0; + for (iDim=0; iDimGetTemperature_FreeStreamND()*R, 0.5); + PsiE_Inf = Gamma_Minus_One*vel2/(vel2-pow(SoundSpeed,2.0))*0.5/vel; + PsiRho_Inf += PsiE_Inf*(2*SoundSpeed*SoundSpeed+vel2*Gamma_Minus_One)/(2.0*Gamma_Minus_One); + // Assumes +x flow direction + // Assume v.n = |v|, n = -v/|v| + + for (iDim=0; iDimGetSolution_AdjFileName(); + filename = config->GetObjFunc_Extension(mesh_filename); + + restart_file.open(filename.data(), ios::in); + + /*--- In case there is no file ---*/ + if (restart_file.fail()) { + if (rank == MASTER_NODE) + cout << "There is no adjoint restart file!! " << filename.data() << "."<< endl; + exit(EXIT_FAILURE); + } + + /*--- In case this is a parallel simulation, we need to perform the + Global2Local index transformation first. ---*/ + long *Global2Local; + Global2Local = new long[geometry->GetGlobal_nPointDomain()]; + /*--- First, set all indices to a negative value by default ---*/ + for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) { + Global2Local[iPoint] = -1; + } + /*--- Now fill array with the transform values only for local points ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; + } + + /*--- Read all lines in the restart file ---*/ + long iPoint_Local; unsigned long iPoint_Global = 0; + + /*--- The first line is the header ---*/ + getline (restart_file, text_line); + + while (getline (restart_file, text_line)) { + istringstream point_line(text_line); + + /*--- Retrieve local index. If this node from the restart file lives + on a different processor, the value of iPoint_Local will be -1. + Otherwise, the local index for this node on the current processor + will be returned and used to instantiate the vars. ---*/ + iPoint_Local = Global2Local[iPoint_Global]; + if (iPoint_Local >= 0) { + if (compressible) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3] >> Solution[4]; + } + if (incompressible) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; + } + if (freesurface) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; + } + node[iPoint_Local] = new CAdjEulerVariable(Solution, nDim, nVar, config); + } + iPoint_Global++; + } + + /*--- Instantiate the variable class with an arbitrary solution + at any halo/periodic nodes. The initial solution can be arbitrary, + because a send/recv is performed immediately in the solver. ---*/ + for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { + node[iPoint] = new CAdjEulerVariable(Solution, nDim, nVar, config); + } + + /*--- Close the restart file ---*/ + restart_file.close(); + + /*--- Free memory needed for the transformation ---*/ + delete [] Global2Local; + } + + /*--- Define solver parameters needed for execution of destructor ---*/ + if (config->GetKind_ConvNumScheme_AdjFlow() == SPACE_CENTERED) space_centered = true; + else space_centered = false; + + /*--- Calculate area monitored for area-averaged-outflow-quantity-based objectives ---*/ + myArea_Monitored = 0.0; + if (config->GetKind_ObjFunc()==OUTLET_CHAIN_RULE || config->GetKind_ObjFunc()==AVG_TOTAL_PRESSURE || + config->GetKind_ObjFunc()==AVG_OUTLET_PRESSURE){ + for (iMarker =0; iMarker < config->GetnMarker_All(); iMarker++){ + if (config->GetMarker_All_Monitoring(iMarker) == YES){ + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if (geometry->node[iPoint]->GetDomain()) { + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Area += Normal[iDim]*Normal[iDim]; + myArea_Monitored += sqrt (Area); + } + } + } + } + } +#ifdef HAVE_MPI + Area_Monitored = 0.0; + SU2_MPI::Allreduce(&myArea_Monitored, &Area_Monitored, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); +#else + Area_Monitored = myArea_Monitored; +#endif + + /*--- MPI solution ---*/ + Set_MPI_Solution(geometry, config); + +} + +CAdjEulerSolver::~CAdjEulerSolver(void) { + unsigned short iVar, iMarker; + + if (Phi_Inf != NULL) delete [] Phi_Inf; + if (Sens_Mach != NULL) delete [] Sens_Mach; + if (Sens_AoA != NULL) delete [] Sens_AoA; + if (Sens_Geo != NULL) delete [] Sens_Geo; + if (Sens_Press != NULL) delete [] Sens_Press; + if (Sens_Temp != NULL) delete [] Sens_Temp; + if (Sens_BPress != NULL) delete [] Sens_BPress; + if (iPoint_UndLapl != NULL) delete [] iPoint_UndLapl; + if (jPoint_UndLapl != NULL) delete [] jPoint_UndLapl; + if (FlowPrimVar_i != NULL) delete [] FlowPrimVar_i; + if (FlowPrimVar_j != NULL) delete [] FlowPrimVar_j; + + if (Jacobian_Axisymmetric != NULL) { + for (iVar = 0; iVar < nVar; iVar++) + delete Jacobian_Axisymmetric[iVar]; + delete [] Jacobian_Axisymmetric; + } + + if (CSensitivity != NULL) { + for (iMarker = 0; iMarker < nMarker; iMarker++) + delete CSensitivity[iMarker]; + delete [] CSensitivity; + } + +} + +void CAdjEulerSolver::SetTime_Step(CGeometry *geometry, CSolver **solver_container, CConfig *config, + unsigned short iMesh, unsigned long Iteration) { + + /*--- Use the flow solution to update the time step + * The time step depends on the characteristic velocity, which is the same + * for the adjoint and flow solutions, albeit in the opposite direction. ---*/ + solver_container[FLOW_SOL]->SetTime_Step(geometry, solver_container, config, iMesh, Iteration); +} + + +void CAdjEulerSolver::Set_MPI_Solution(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_U = new su2double [nBufferR_Vector]; + Buffer_Send_U = new su2double[nBufferS_Vector]; + + /*--- Copy the solution that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution(iVar); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); + +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_U; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = Buffer_Receive_U[iVar*nVertexR+iVertex]; + + /*--- Rotate the momentum components. ---*/ + if (nDim == 2) { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex]; + } + else { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex] + + rotMatrix[0][2]*Buffer_Receive_U[3*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex] + + rotMatrix[1][2]*Buffer_Receive_U[3*nVertexR+iVertex]; + Solution[3] = rotMatrix[2][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[2][1]*Buffer_Receive_U[2*nVertexR+iVertex] + + rotMatrix[2][2]*Buffer_Receive_U[3*nVertexR+iVertex]; + } + + /*--- Copy transformed conserved variables back into buffer. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetSolution(iVar, Solution[iVar]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_U; + + } + + } + +} + +void CAdjEulerSolver::Set_MPI_Solution_Old(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, + *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_U = new su2double [nBufferR_Vector]; + Buffer_Send_U = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution_Old(iVar); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); + +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_U; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = Buffer_Receive_U[iVar*nVertexR+iVertex]; + + /*--- Rotate the momentum components. ---*/ + if (nDim == 2) { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex]; + } + else { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex] + + rotMatrix[0][2]*Buffer_Receive_U[3*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex] + + rotMatrix[1][2]*Buffer_Receive_U[3*nVertexR+iVertex]; + Solution[3] = rotMatrix[2][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[2][1]*Buffer_Receive_U[2*nVertexR+iVertex] + + rotMatrix[2][2]*Buffer_Receive_U[3*nVertexR+iVertex]; + } + + /*--- Copy transformed conserved variables back into buffer. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetSolution_Old(iVar, Solution[iVar]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_U; + + } + + } +} + +void CAdjEulerSolver::Set_MPI_Solution_Limiter(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, + *Buffer_Receive_Limit = NULL, *Buffer_Send_Limit = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_Limit = new su2double [nBufferR_Vector]; + Buffer_Send_Limit = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_Limit[iVar*nVertexS+iVertex] = node[iPoint]->GetLimiter(iVar); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Limit, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_Limit, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); + +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_Limit[iVar*nVertexR+iVertex] = Buffer_Send_Limit[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_Limit; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = Buffer_Receive_Limit[iVar*nVertexR+iVertex]; + + /*--- Rotate the momentum components. ---*/ + if (nDim == 2) { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_Limit[2*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_Limit[2*nVertexR+iVertex]; + } + else { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + + rotMatrix[0][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + + rotMatrix[1][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; + Solution[3] = rotMatrix[2][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[2][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + + rotMatrix[2][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; + } + + /*--- Copy transformed conserved variables back into buffer. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetLimiter(iVar, Solution[iVar]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_Limit; + + } + + } +} + +void CAdjEulerSolver::Set_MPI_Solution_Gradient(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, + *Buffer_Receive_Gradient = NULL, *Buffer_Send_Gradient = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + su2double **Gradient = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + Gradient[iVar] = new su2double[nDim]; + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar*nDim; nBufferR_Vector = nVertexR*nVar*nDim; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_Gradient = new su2double [nBufferR_Vector]; + Buffer_Send_Gradient = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Gradient[iDim*nVar*nVertexS+iVar*nVertexS+iVertex] = node[iPoint]->GetGradient(iVar, iDim); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Gradient, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_Gradient, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex] = Buffer_Send_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_Gradient; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Gradient[iVar][iDim] = Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; + + /*--- Need to rotate the gradients for all conserved variables. ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + if (nDim == 2) { + Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; + } + else { + Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][2] = rotMatrix[2][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; + } + } + + /*--- Store the received information ---*/ + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + node[iPoint]->SetGradient(iVar, iDim, Gradient[iVar][iDim]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_Gradient; + + } + + } + + for (iVar = 0; iVar < nVar; iVar++) + delete [] Gradient[iVar]; + delete [] Gradient; + +} + + +void CAdjEulerSolver::Set_MPI_Undivided_Laplacian(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, + *Buffer_Receive_Undivided_Laplacian = NULL, *Buffer_Send_Undivided_Laplacian = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_Undivided_Laplacian = new su2double [nBufferR_Vector]; + Buffer_Send_Undivided_Laplacian = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_Undivided_Laplacian[iVar*nVertexS+iVertex] = node[iPoint]->GetUndivided_Laplacian(iVar); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Undivided_Laplacian, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_Undivided_Laplacian, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_Undivided_Laplacian[iVar*nVertexR+iVertex] = Buffer_Send_Undivided_Laplacian[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_Undivided_Laplacian; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = Buffer_Receive_Undivided_Laplacian[iVar*nVertexR+iVertex]; + + /*--- Rotate the momentum components. ---*/ + if (nDim == 2) { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex]; + } + else { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex] + + rotMatrix[0][2]*Buffer_Receive_Undivided_Laplacian[3*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex] + + rotMatrix[1][2]*Buffer_Receive_Undivided_Laplacian[3*nVertexR+iVertex]; + Solution[3] = rotMatrix[2][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + + rotMatrix[2][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex] + + rotMatrix[2][2]*Buffer_Receive_Undivided_Laplacian[3*nVertexR+iVertex]; + } + + /*--- Copy transformed conserved variables back into buffer. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetUndivided_Laplacian(iVar, Solution[iVar]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_Undivided_Laplacian; + + } + + } + +} + +void CAdjEulerSolver::Set_MPI_Dissipation_Switch(CGeometry *geometry, CConfig *config) { + unsigned short iMarker, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double *Buffer_Receive_Lambda = NULL, *Buffer_Send_Lambda = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS; nBufferR_Vector = nVertexR; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_Lambda = new su2double [nBufferR_Vector]; + Buffer_Send_Lambda = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + Buffer_Send_Lambda[iVertex] = node[iPoint]->GetSensor(); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Lambda, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_Lambda, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + Buffer_Receive_Lambda[iVertex] = Buffer_Send_Lambda[iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_Lambda; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + node[iPoint]->SetSensor(Buffer_Receive_Lambda[iVertex]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_Lambda; + + } + + } +} + +void CAdjEulerSolver::SetForceProj_Vector(CGeometry *geometry, CSolver **solver_container, CConfig *config) { + + su2double *ForceProj_Vector, x = 0.0, y = 0.0, z = 0.0, *Normal, CD, CL, Cp, CpTarget, + CT, CQ, x_origin, y_origin, z_origin, WDrag, Area, invCD, CLCD2, invCQ, CTRCQ2; + unsigned short iMarker; + unsigned long iVertex, iPoint; + + int rank = MASTER_NODE; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + su2double Alpha = (config->GetAoA()*PI_NUMBER)/180.0; + su2double Beta = (config->GetAoS()*PI_NUMBER)/180.0; + su2double RefLengthMoment = config->GetRefLengthMoment(); + su2double *RefOriginMoment = config->GetRefOriginMoment(0); + + ForceProj_Vector = new su2double[nDim]; + + /*--- Compute coefficients needed for objective function evaluation. ---*/ + + CD = solver_container[FLOW_SOL]->GetTotal_CDrag(); + CL = solver_container[FLOW_SOL]->GetTotal_CLift(); + CT = solver_container[FLOW_SOL]->GetTotal_CT(); + CQ = solver_container[FLOW_SOL]->GetTotal_CQ(); + invCD = 1.0/CD; CLCD2 = CL/(CD*CD); + invCQ = 1.0/CQ; CTRCQ2 = CT/(RefLengthMoment*CQ*CQ); + + x_origin = RefOriginMoment[0]; y_origin = RefOriginMoment[1]; z_origin = RefOriginMoment[2]; + + /*--- Evaluate the boundary condition coefficients. ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) + + if ((config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) && + (config->GetMarker_All_Monitoring(iMarker) == YES)) + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + x = geometry->node[iPoint]->GetCoord(0); + y = geometry->node[iPoint]->GetCoord(1); + if (nDim == 3) z = geometry->node[iPoint]->GetCoord(2); + + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + switch (config->GetKind_ObjFunc()) { + case DRAG_COEFFICIENT : + if (nDim == 2) { ForceProj_Vector[0] = cos(Alpha); ForceProj_Vector[1] = sin(Alpha); } + if (nDim == 3) { ForceProj_Vector[0] = cos(Alpha)*cos(Beta); ForceProj_Vector[1] = sin(Beta); ForceProj_Vector[2] = sin(Alpha)*cos(Beta); } + break; + case LIFT_COEFFICIENT : + if (nDim == 2) { ForceProj_Vector[0] = -sin(Alpha); ForceProj_Vector[1] = cos(Alpha); } + if (nDim == 3) { ForceProj_Vector[0] = -sin(Alpha); ForceProj_Vector[1] = 0.0; ForceProj_Vector[2] = cos(Alpha); } + break; + case SIDEFORCE_COEFFICIENT : + if ((nDim == 2) && (rank == MASTER_NODE)) { cout << "This functional is not possible in 2D!!" << endl; + exit(EXIT_FAILURE); + } + if (nDim == 3) { ForceProj_Vector[0] = -sin(Beta) * cos(Alpha); ForceProj_Vector[1] = cos(Beta); ForceProj_Vector[2] = -sin(Beta) * sin(Alpha); } + break; + case INVERSE_DESIGN_PRESSURE : + Cp = solver_container[FLOW_SOL]->GetCPressure(iMarker, iVertex); + CpTarget = solver_container[FLOW_SOL]->GetCPressureTarget(iMarker, iVertex); + Area = sqrt(Normal[0]*Normal[0] + Normal[1]*Normal[1]); + if (nDim == 3) Area = sqrt(Normal[0]*Normal[0] + Normal[1]*Normal[1] + Normal[2]*Normal[2]); + ForceProj_Vector[0] = -2.0*(Cp-CpTarget)*Normal[0]/Area; ForceProj_Vector[1] = -2.0*(Cp-CpTarget)*Normal[1]/Area; + if (nDim == 3) ForceProj_Vector[2] = -2.0*(Cp-CpTarget)*Normal[2]/Area; + break; + case MOMENT_X_COEFFICIENT : + if ((nDim == 2) && (rank == MASTER_NODE)) { cout << "This functional is not possible in 2D!!" << endl; exit(EXIT_FAILURE); } + if (nDim == 3) { ForceProj_Vector[0] = 0.0; ForceProj_Vector[1] = -(z - z_origin)/RefLengthMoment; ForceProj_Vector[2] = (y - y_origin)/RefLengthMoment; } + break; + case MOMENT_Y_COEFFICIENT : + if ((nDim == 2) && (rank == MASTER_NODE)) { cout << "This functional is not possible in 2D!!" << endl; exit(EXIT_FAILURE); } + if (nDim == 3) { ForceProj_Vector[0] = (z - z_origin)/RefLengthMoment; ForceProj_Vector[1] = 0.0; ForceProj_Vector[2] = -(x - x_origin)/RefLengthMoment; } + break; + case MOMENT_Z_COEFFICIENT : + if (nDim == 2) { ForceProj_Vector[0] = -(y - y_origin)/RefLengthMoment; ForceProj_Vector[1] = (x - x_origin)/RefLengthMoment; } + if (nDim == 3) { ForceProj_Vector[0] = -(y - y_origin)/RefLengthMoment; ForceProj_Vector[1] = (x - x_origin)/RefLengthMoment; ForceProj_Vector[2] = 0; } + break; + case EFFICIENCY : + if (nDim == 2) { ForceProj_Vector[0] = -(invCD*sin(Alpha)+CLCD2*cos(Alpha)); ForceProj_Vector[1] = (invCD*cos(Alpha)-CLCD2*sin(Alpha)); } + if (nDim == 3) { ForceProj_Vector[0] = -(invCD*sin(Alpha)+CLCD2*cos(Alpha)*cos(Beta)); ForceProj_Vector[1] = -CLCD2*sin(Beta); ForceProj_Vector[2] = (invCD*cos(Alpha)-CLCD2*sin(Alpha)*cos(Beta)); } + break; + case EQUIVALENT_AREA : + WDrag = config->GetWeightCd(); + if (nDim == 2) { ForceProj_Vector[0] = cos(Alpha)*WDrag; ForceProj_Vector[1] = sin(Alpha)*WDrag; } + if (nDim == 3) { ForceProj_Vector[0] = cos(Alpha)*cos(Beta)*WDrag; ForceProj_Vector[1] = sin(Beta)*WDrag; ForceProj_Vector[2] = sin(Alpha)*cos(Beta)*WDrag; } + break; + case NEARFIELD_PRESSURE : + WDrag = config->GetWeightCd(); + if (nDim == 2) { ForceProj_Vector[0] = cos(Alpha)*WDrag; ForceProj_Vector[1] = sin(Alpha)*WDrag; } + if (nDim == 3) { ForceProj_Vector[0] = cos(Alpha)*cos(Beta)*WDrag; ForceProj_Vector[1] = sin(Beta)*WDrag; ForceProj_Vector[2] = sin(Alpha)*cos(Beta)*WDrag; } + break; + case FORCE_X_COEFFICIENT : + if (nDim == 2) { ForceProj_Vector[0] = 1.0; ForceProj_Vector[1] = 0.0; } + if (nDim == 3) { ForceProj_Vector[0] = 1.0; ForceProj_Vector[1] = 0.0; ForceProj_Vector[2] = 0.0; } + break; + case FORCE_Y_COEFFICIENT : + if (nDim == 2) { ForceProj_Vector[0] = 0.0; ForceProj_Vector[1] = 1.0; } + if (nDim == 3) { ForceProj_Vector[0] = 0.0; ForceProj_Vector[1] = 1.0; ForceProj_Vector[2] = 0.0; } + break; + case FORCE_Z_COEFFICIENT : + if ((nDim == 2) && (rank == MASTER_NODE)) {cout << "This functional is not possible in 2D!!" << endl; + exit(EXIT_FAILURE); + } + if (nDim == 3) { ForceProj_Vector[0] = 0.0; ForceProj_Vector[1] = 0.0; ForceProj_Vector[2] = 1.0; } + break; + case THRUST_COEFFICIENT : + if ((nDim == 2) && (rank == MASTER_NODE)) {cout << "This functional is not possible in 2D!!" << endl; + exit(EXIT_FAILURE); + } + if (nDim == 3) { ForceProj_Vector[0] = 0.0; ForceProj_Vector[1] = 0.0; ForceProj_Vector[2] = 1.0; } + break; + case TORQUE_COEFFICIENT : + if (nDim == 2) { ForceProj_Vector[0] = (y - y_origin)/RefLengthMoment; ForceProj_Vector[1] = -(x - x_origin)/RefLengthMoment; } + if (nDim == 3) { ForceProj_Vector[0] = (y - y_origin)/RefLengthMoment; ForceProj_Vector[1] = -(x - x_origin)/RefLengthMoment; ForceProj_Vector[2] = 0; } + break; + case FIGURE_OF_MERIT : + if ((nDim == 2) && (rank == MASTER_NODE)) {cout << "This functional is not possible in 2D!!" << endl; + exit(EXIT_FAILURE); + } + if (nDim == 3) { + ForceProj_Vector[0] = -invCQ; + ForceProj_Vector[1] = -CTRCQ2*(z - z_origin); + ForceProj_Vector[2] = CTRCQ2*(y - y_origin); + } + break; + default : + if (nDim == 2) { ForceProj_Vector[0] = 0.0; ForceProj_Vector[1] = 0.0; } + if (nDim == 3) { ForceProj_Vector[0] = 0.0; ForceProj_Vector[1] = 0.0; ForceProj_Vector[2] = 0.0; } + break; + } + + /*--- Store the force projection vector at this node ---*/ + + node[iPoint]->SetForceProj_Vector(ForceProj_Vector); + + } + + delete [] ForceProj_Vector; + +} + +void CAdjEulerSolver::SetIntBoundary_Jump(CGeometry *geometry, CSolver **solver_container, CConfig *config) { + unsigned short iMarker, iVar, jVar, kVar, iDim, jDim, iIndex; + unsigned long iVertex, iPoint, iPointNearField, nPointNearField = 0; + su2double factor = 1.0, AngleDouble, data, aux, *IntBound_Vector, *coord, *FlowSolution, WeightSB, MinDist = 1E6, Dist, DerivativeOF = 0.0, *Normal, Area, UnitNormal[3], velocity[3], Energy, Rho, sqvel, proj_vel, phi, a1, a2; + su2double **A, **M, **AM, *b; + short AngleInt = 0, IndexNF_inv[180], iColumn; + ifstream index_file; + string text_line; + vector > NearFieldWeight; + vector CoordNF; + vector IndexNF; + + IntBound_Vector = new su2double [nVar]; + + /*--- Allocate vectors and matrices ---*/ + + b = new su2double [nVar]; + A = new su2double* [nVar]; + M = new su2double* [nVar]; + AM = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + A[iVar] = new su2double [nVar]; + M[iVar] = new su2double [nVar]; + AM[iVar] = new su2double [nVar]; + } + + /*--- If equivalent area objective function, read the value of + the derivative from a file, this is a preprocess of the direct solution ---*/ + + if (config->GetKind_ObjFunc() == EQUIVALENT_AREA) { + + /*--- Read derivative of the objective function at the NearField from file ---*/ + index_file.open("WeightNF.dat", ios::in); + if (index_file.fail()) { + cout << "There is no Weight Nearfield Pressure file (WeightNF.dat)." << endl; + exit(EXIT_FAILURE); + } + + nPointNearField = 0; + + while (index_file) { + string line; + getline(index_file, line); + istringstream is(line); + + /*--- The first row provides the azimuthal angle ---*/ + + if (nPointNearField == 0) { + is >> data; // The first column is related with the coordinate + while (is.good()) { is >> data; IndexNF.push_back(SU2_TYPE::Int(data)); } + } + else { + is >> data; CoordNF.push_back(data); // The first column is the point coordinate + vector row; + while (is.good()) { is >> data; row.push_back(data); } + NearFieldWeight.push_back(row); + } + nPointNearField++; + } + + /*--- Note tha the first row is the azimuthal angle ---*/ + + nPointNearField = nPointNearField - 1; + + for (AngleInt = 0; AngleInt < 180; AngleInt++) + IndexNF_inv[AngleInt] = -1; + + for (iIndex = 0; iIndex < IndexNF.size(); iIndex++) + IndexNF_inv[IndexNF[iIndex]] = iIndex; + + } + + /*--- Compute the jump on the adjoint variables for the upper and the lower side ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) + + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; + Area = sqrt (Area); + + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] = Normal[iDim]/Area; + + if (geometry->node[iPoint]->GetDomain()) { + + coord = geometry->node[iPoint]->GetCoord(); + DerivativeOF = 0.0; + + /*--- Just in case the functional depend also on the surface pressure ---*/ + + WeightSB = 1.0-config->GetWeightCd(); + + su2double AoA, XcoordRot = 0.0, YcoordRot = 0.0, ZcoordRot = 0.0; + + if (nDim == 2) XcoordRot = coord[0]; + if (nDim == 3) { + + /*--- Rotate the nearfield cylinder ---*/ + + AoA = -(config->GetAoA()*PI_NUMBER/180.0); + XcoordRot = coord[0]*cos(AoA) - coord[2]*sin(AoA); + YcoordRot = coord[1]; + ZcoordRot = coord[0]*sin(AoA) + coord[2]*cos(AoA); + } + + switch (config->GetKind_ObjFunc()) { + case EQUIVALENT_AREA : + + if (nDim == 2) AngleInt = 0; + + if (nDim == 3) { + + /*--- Compute the azimuthal angle of the iPoint ---*/ + + AngleDouble = fabs(atan(-YcoordRot/ZcoordRot)*180.0/PI_NUMBER); + + /*--- Fix an azimuthal line due to misalignments of the near-field ---*/ + + su2double FixAzimuthalLine = config->GetFixAzimuthalLine(); + + if ((AngleDouble >= FixAzimuthalLine - 0.1) && (AngleDouble <= FixAzimuthalLine + 0.1)) AngleDouble = FixAzimuthalLine - 0.1; + + AngleInt = SU2_TYPE::Short(floor(AngleDouble + 0.5)); + if (AngleInt < 0) AngleInt = 180 + AngleInt; + + } + + if (AngleInt <= 60) { + iColumn = IndexNF_inv[AngleInt]; + + /*--- An azimuthal angle is not defined... this happens with MG levels ---*/ + + if (iColumn < 0.0) { + if (IndexNF_inv[AngleInt+1] > 0) { iColumn = IndexNF_inv[AngleInt+1]; goto end; } + if (IndexNF_inv[AngleInt-1] > 0) { iColumn = IndexNF_inv[AngleInt-1]; goto end; } + if (IndexNF_inv[AngleInt+2] > 0) { iColumn = IndexNF_inv[AngleInt+2]; goto end; } + if (IndexNF_inv[AngleInt-2] > 0) { iColumn = IndexNF_inv[AngleInt-2]; goto end; } + if (IndexNF_inv[AngleInt+3] > 0) { iColumn = IndexNF_inv[AngleInt+3]; goto end; } + if (IndexNF_inv[AngleInt-3] > 0) { iColumn = IndexNF_inv[AngleInt-3]; goto end; } + if (IndexNF_inv[AngleInt+4] > 0) { iColumn = IndexNF_inv[AngleInt+4]; goto end; } + if (IndexNF_inv[AngleInt-4] > 0) { iColumn = IndexNF_inv[AngleInt-4]; goto end; } + } + + end: + + if (iColumn < 0.0) { cout <<" An azimuthal angle is not defined..." << endl; } + + /*--- Find the value of the weight in the table, using the azimuthal angle ---*/ + + MinDist = 1E6; + for (iPointNearField = 0; iPointNearField < nPointNearField; iPointNearField++) { + Dist = fabs(CoordNF[iPointNearField] - XcoordRot); + if (Dist <= MinDist) { + MinDist = Dist; + DerivativeOF = factor*WeightSB*NearFieldWeight[iPointNearField][iColumn]; + } + } + } + else DerivativeOF = 0.0; + + if ((MinDist > 1E-6) || (coord[nDim-1] > 0.0)) DerivativeOF = 0.0; + + break; + + case NEARFIELD_PRESSURE : + + DerivativeOF = factor*WeightSB*(solver_container[FLOW_SOL]->node[iPoint]->GetPressure() + - solver_container[FLOW_SOL]->GetPressure_Inf()); + + break; + + } + + /*--- Compute the jump of the adjoint variables (2D, and 3D problems) --*/ + + FlowSolution = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); + + Rho = FlowSolution[0]; + Energy = FlowSolution[nVar-1]/FlowSolution[0]; + + sqvel = 0.0; proj_vel = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + velocity[iDim] = FlowSolution[iDim+1]/FlowSolution[0]; + sqvel += velocity[iDim]*velocity[iDim]; + proj_vel += velocity[iDim]*UnitNormal[iDim]; + } + + if (nDim == 2) { + + /*--- Compute the projected Jacobian ---*/ + + A[0][0] = 0.0; A[0][1] = 0.0; A[0][2] = 1.0; A[0][3] = 0.0; + A[1][0] = -velocity[0]*velocity[1]; A[1][1] = velocity[1]; A[1][2] = velocity[0]; A[1][3] = 0.0; + A[2][0] = 0.5*(Gamma-3.0)*velocity[1]*velocity[1]+0.5*Gamma_Minus_One*velocity[0]*velocity[0]; A[2][1] = -Gamma_Minus_One*velocity[0]; + A[2][2] = (3.0-Gamma)*velocity[1]; A[2][3] = Gamma_Minus_One; A[3][0] = -Gamma*velocity[1]*Energy+Gamma_Minus_One*velocity[1]*sqvel; + A[3][1] = -Gamma_Minus_One*velocity[0]*velocity[1]; A[3][2] = Gamma*Energy-0.5*Gamma_Minus_One*(velocity[0]*velocity[0]+3.0*velocity[1]*velocity[1]); A[3][3] = Gamma*velocity[1]; + + /*--- Compute the transformation matrix ---*/ + + M[0][0] = 1.0; M[0][1] = 0.0; M[0][2] = 0.0; M[0][3] = 0.0; + M[1][0] = velocity[0]; M[1][1] = Rho; M[1][2] = 0.0; M[1][3] = 0.0; + M[2][0] = velocity[1]; M[2][1] = 0.0; M[2][2] = Rho; M[2][3] = 0.0; + M[3][0] = 0.5*sqvel; M[3][1] = Rho*velocity[0]; M[3][2] = Rho*velocity[1]; M[3][3] = 1.0/Gamma_Minus_One; + + /*--- Create the soruce term (AM)^T X = b ---*/ + + b[0] = 0.0; b[1] = 0.0; b[2] = 0.0; b[3] = DerivativeOF; + + } + + if (nDim == 3) { + + + /*--- Compute the projected Jacobian ---*/ + + phi = 0.5*Gamma_Minus_One*sqvel; + a1 = Gamma*Energy-phi; a2 = Gamma-1.0; + + A[0][0] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) A[0][iDim+1] = UnitNormal[iDim]; + A[0][nDim+1] = 0.0; + + for (iDim = 0; iDim < nDim; iDim++) { + A[iDim+1][0] = (UnitNormal[iDim]*phi - velocity[iDim]*proj_vel); + for (jDim = 0; jDim < nDim; jDim++) + A[iDim+1][jDim+1] = (UnitNormal[jDim]*velocity[iDim]-a2*UnitNormal[iDim]*velocity[jDim]); + A[iDim+1][iDim+1] += proj_vel; + A[iDim+1][nDim+1] = a2*UnitNormal[iDim]; + } + + A[nDim+1][0] = proj_vel*(phi-a1); + for (iDim = 0; iDim < nDim; iDim++) + A[nDim+1][iDim+1] = (UnitNormal[iDim]*a1-a2*velocity[iDim]*proj_vel); + A[nDim+1][nDim+1] = Gamma*proj_vel; + + /*--- Compute the transformation matrix ---*/ + + M[0][0] = 1.0; M[0][1] = 0.0; M[0][2] = 0.0; M[0][3] = 0.0; M[0][4] = 0.0; + M[1][0] = velocity[0]; M[1][1] = Rho; M[1][2] = 0.0; M[1][3] = 0.0; M[1][4] = 0.0; + M[2][0] = velocity[1]; M[2][1] = 0.0; M[2][2] = Rho; M[2][3] = 0.0; M[2][4] = 0.0; + M[3][0] = velocity[2]; M[3][1] = 0.0; M[3][2] = 0.0; M[3][3] = Rho; M[3][4] = 0.0; + M[4][0] = 0.5*sqvel; M[4][1] = Rho*velocity[0]; M[4][2] = Rho*velocity[1]; + M[4][3] = Rho*velocity[2]; M[4][4] = 1.0/Gamma_Minus_One; + + /*--- Create the soruce term (AM)^T X = b ---*/ + + b[0] = 0.0; b[1] = 0.0; b[2] = 0.0; b[3] = 0.0; b[4] = DerivativeOF; + + } + + /*--- Compute A times M ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) { + aux = 0.0; + for (kVar = 0; kVar < nVar; kVar++) + aux += A[iVar][kVar]*M[kVar][jVar]; + AM[iVar][jVar] = aux; + } + + /*--- Compute the transpose matrix ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + A[iVar][jVar] = AM[jVar][iVar]; + + /*--- Solve the linear system using a LU descomposition --*/ + + Gauss_Elimination(A, b, nVar); + + /*--- Update the internal boundary jump --*/ + + for (iVar = 0; iVar < nVar; iVar++) + IntBound_Vector[iVar] = b[iVar]; + + node[iPoint]->SetIntBoundary_Jump(IntBound_Vector); + + } + } + + delete [] IntBound_Vector; + + /*--- Deallocate the linear system ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + delete [] A[iVar]; + delete [] M[iVar]; + delete [] AM[iVar]; + } + delete [] A; + delete [] M; + delete [] AM; + delete [] b; + +} + +void CAdjEulerSolver::SetInitialCondition(CGeometry **geometry, CSolver ***solver_container, CConfig *config, unsigned long ExtIter) { + unsigned long iPoint, Point_Fine; + unsigned short iMesh, iChildren, iVar; + su2double LevelSet, Area_Children, Area_Parent, LevelSet_Fine, *Solution, *Solution_Fine; + + bool restart = config->GetRestart(); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + + if (freesurface) { + + for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { + + for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { + + /*--- Set initial boundary condition at iter 0 ---*/ + if ((ExtIter == 0) && (!restart)) { + + /*--- Compute the adjoint level set value in all the MG levels ---*/ + if (iMesh == MESH_0) { + solver_container[iMesh][ADJFLOW_SOL]->node[iPoint]->SetSolution(nDim+1, 0.0); + } + else { + Area_Parent = geometry[iMesh]->node[iPoint]->GetVolume(); + LevelSet = 0.0; + for (iChildren = 0; iChildren < geometry[iMesh]->node[iPoint]->GetnChildren_CV(); iChildren++) { + Point_Fine = geometry[iMesh]->node[iPoint]->GetChildren_CV(iChildren); + Area_Children = geometry[iMesh-1]->node[Point_Fine]->GetVolume(); + LevelSet_Fine = solver_container[iMesh-1][ADJFLOW_SOL]->node[Point_Fine]->GetSolution(nDim+1); + LevelSet += LevelSet_Fine*Area_Children/Area_Parent; + } + solver_container[iMesh][ADJFLOW_SOL]->node[iPoint]->SetSolution(nDim+1, LevelSet); + } + + /*--- Compute the flow solution using the level set value. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + solver_container[iMesh][ADJFLOW_SOL]->node[iPoint]->SetSolution(iVar, 0.0); + + } + } + + /*--- Set the MPI communication ---*/ + solver_container[iMesh][ADJFLOW_SOL]->Set_MPI_Solution(geometry[iMesh], config); + + } + + } + + /*--- If restart solution, then interpolate the flow solution to + all the multigrid levels, this is important with the dual time strategy ---*/ + if (restart) { + Solution = new su2double[nVar]; + for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++) { + for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { + Area_Parent = geometry[iMesh]->node[iPoint]->GetVolume(); + for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; + for (iChildren = 0; iChildren < geometry[iMesh]->node[iPoint]->GetnChildren_CV(); iChildren++) { + Point_Fine = geometry[iMesh]->node[iPoint]->GetChildren_CV(iChildren); + Area_Children = geometry[iMesh-1]->node[Point_Fine]->GetVolume(); + Solution_Fine = solver_container[iMesh-1][ADJFLOW_SOL]->node[Point_Fine]->GetSolution(); + for (iVar = 0; iVar < nVar; iVar++) { + Solution[iVar] += Solution_Fine[iVar]*Area_Children/Area_Parent; + } + } + solver_container[iMesh][ADJFLOW_SOL]->node[iPoint]->SetSolution(Solution); + + } + solver_container[iMesh][ADJFLOW_SOL]->Set_MPI_Solution(geometry[iMesh], config); + } + delete [] Solution; + } + + /*--- The value of the solution for the first iteration of the dual time ---*/ + for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { + for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { + if ((ExtIter == 0) && (dual_time)) { + solver_container[iMesh][ADJFLOW_SOL]->node[iPoint]->Set_Solution_time_n(); + solver_container[iMesh][ADJFLOW_SOL]->node[iPoint]->Set_Solution_time_n1(); + } + } + } + +} + +void CAdjEulerSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { + + unsigned long iPoint, ErrorCounter = 0; + su2double SharpEdge_Distance; + bool RightSol = true; + +#ifdef HAVE_MPI + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Retrieve information about the spatial and temporal integration for the + adjoint equations (note that the flow problem may use different methods). ---*/ + + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + bool second_order = ((config->GetSpatialOrder_AdjFlow() == SECOND_ORDER) || (config->GetSpatialOrder_AdjFlow() == SECOND_ORDER_LIMITER)); + bool limiter = (config->GetSpatialOrder_AdjFlow() == SECOND_ORDER_LIMITER); + bool center = (config->GetKind_ConvNumScheme_AdjFlow() == SPACE_CENTERED); + bool center_jst = (config->GetKind_Centered_AdjFlow() == JST); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool engine = ((config->GetnMarker_EngineInflow() != 0) || (config->GetnMarker_EngineBleed() != 0) || (config->GetnMarker_EngineExhaust() != 0)); + + /*--- Compute nacelle inflow and exhaust properties ---*/ + + if (engine) { GetEngine_Properties(geometry, config, iMesh, Output); } + + /*--- Residual initialization ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint ++) { + + /*--- Get the distance form a sharp edge ---*/ + + SharpEdge_Distance = geometry->node[iPoint]->GetSharpEdge_Distance(); + + /*--- Initialize the non-physical points vector ---*/ + + node[iPoint]->SetNon_Physical(false); + + /*--- Set the primitive variables incompressible and compressible + adjoint variables ---*/ + + if (compressible) RightSol = node[iPoint]->SetPrimVar_Compressible(SharpEdge_Distance, false, config); + if (incompressible) RightSol = node[iPoint]->SetPrimVar_Incompressible(SharpEdge_Distance, false, config); + if (freesurface) RightSol = node[iPoint]->SetPrimVar_FreeSurface(SharpEdge_Distance, false, config); + if (!RightSol) { node[iPoint]->SetNon_Physical(true); ErrorCounter++; } + + /*--- Initialize the convective residual vector ---*/ + + LinSysRes.SetBlock_Zero(iPoint); + + } + + + if ((second_order) && (iMesh == MESH_0)) { + + /*--- Compute gradients for upwind second-order reconstruction ---*/ + + if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); + + /*--- Limiter computation ---*/ + + if (limiter) SetSolution_Limiter(geometry, config); + + } + + /*--- Artificial dissipation for centered schemes ---*/ + + if (center) { + if ((center_jst) && (iMesh == MESH_0)) { + SetDissipation_Switch(geometry, config); + SetUndivided_Laplacian(geometry, config); + if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); + } + } + + /*--- Initialize the Jacobian for implicit integration ---*/ + + if (implicit) Jacobian.SetValZero(); + + /*--- Error message ---*/ + + if (config->GetConsole_Output_Verb() == VERB_HIGH) { +#ifdef HAVE_MPI + unsigned long MyErrorCounter = ErrorCounter; ErrorCounter = 0; + SU2_MPI::Allreduce(&MyErrorCounter, &ErrorCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); +#endif + if (iMesh == MESH_0) config->SetNonphysical_Points(ErrorCounter); + } + +} + +void CAdjEulerSolver::Centered_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config, unsigned short iMesh, unsigned short iRKStep) { + + unsigned long iEdge, iPoint, jPoint; + + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + bool second_order = ((config->GetKind_Centered_AdjFlow() == JST) && (iMesh == MESH_0)); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool grid_movement = config->GetGrid_Movement(); + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Points in edge, normal, and neighbors---*/ + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); + numerics->SetNeighbor(geometry->node[iPoint]->GetnNeighbor(), geometry->node[jPoint]->GetnNeighbor()); + + /*--- Adjoint variables w/o reconstruction ---*/ + + numerics->SetAdjointVar(node[iPoint]->GetSolution(), node[jPoint]->GetSolution()); + + /*--- Conservative variables w/o reconstruction ---*/ + + numerics->SetConservative(solver_container[FLOW_SOL]->node[iPoint]->GetSolution(), + solver_container[FLOW_SOL]->node[jPoint]->GetSolution()); + + if (compressible) { + numerics->SetSoundSpeed(solver_container[FLOW_SOL]->node[iPoint]->GetSoundSpeed(), + solver_container[FLOW_SOL]->node[jPoint]->GetSoundSpeed()); + numerics->SetEnthalpy(solver_container[FLOW_SOL]->node[iPoint]->GetEnthalpy(), + solver_container[FLOW_SOL]->node[jPoint]->GetEnthalpy()); + } + if (incompressible || freesurface) { + numerics->SetDensityInc(solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(), solver_container[FLOW_SOL]->node[jPoint]->GetDensityInc()); + numerics->SetBetaInc2(solver_container[FLOW_SOL]->node[iPoint]->GetBetaInc2(), solver_container[FLOW_SOL]->node[jPoint]->GetBetaInc2()); + numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[jPoint]->GetCoord()); + } + + numerics->SetLambda(solver_container[FLOW_SOL]->node[iPoint]->GetLambda(), + solver_container[FLOW_SOL]->node[jPoint]->GetLambda()); + + if (second_order) { + numerics->SetUndivided_Laplacian(node[iPoint]->GetUndivided_Laplacian(), node[jPoint]->GetUndivided_Laplacian()); + numerics->SetSensor(node[iPoint]->GetSensor(), node[jPoint]->GetSensor()); + } + + /*--- Mesh motion ---*/ + + if (grid_movement) { + numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[jPoint]->GetGridVel()); + } + + /*--- Compute residuals ---*/ + + numerics->ComputeResidual(Res_Conv_i, Res_Visc_i, Res_Conv_j, Res_Visc_j, + Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + /*--- Update convective and artificial dissipation residuals ---*/ + + LinSysRes.SubtractBlock(iPoint, Res_Conv_i); + LinSysRes.SubtractBlock(jPoint, Res_Conv_j); + LinSysRes.SubtractBlock(iPoint, Res_Visc_i); + LinSysRes.SubtractBlock(jPoint, Res_Visc_j); + + /*--- Implicit contribution to the residual ---*/ + + if (implicit) { + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + Jacobian.SubtractBlock(iPoint, jPoint, Jacobian_ij); + Jacobian.SubtractBlock(jPoint, iPoint, Jacobian_ji); + Jacobian.SubtractBlock(jPoint, jPoint, Jacobian_jj); + } + + } +} + + +void CAdjEulerSolver::Upwind_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, unsigned short iMesh) { + + su2double **Gradient_i, **Gradient_j, Project_Grad_i, Project_Grad_j, *Limiter_i = NULL, + *Limiter_j = NULL, *Psi_i = NULL, *Psi_j = NULL, *V_i, *V_j, Non_Physical = 1.0; + unsigned long iEdge, iPoint, jPoint; + unsigned short iDim, iVar; + + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + bool second_order = (((config->GetSpatialOrder_AdjFlow() == SECOND_ORDER) || (config->GetSpatialOrder_AdjFlow() == SECOND_ORDER_LIMITER)) && (iMesh == MESH_0)); + bool limiter = (config->GetSpatialOrder_AdjFlow() == SECOND_ORDER_LIMITER); + bool grid_movement = config->GetGrid_Movement(); + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Points in edge and normal vectors ---*/ + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); + + /*--- Adjoint variables w/o reconstruction ---*/ + + Psi_i = node[iPoint]->GetSolution(); + Psi_j = node[jPoint]->GetSolution(); + numerics->SetAdjointVar(Psi_i, Psi_j); + + /*--- Primitive variables w/o reconstruction ---*/ + + V_i = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + V_j = solver_container[FLOW_SOL]->node[jPoint]->GetPrimitive(); + numerics->SetPrimitive(V_i, V_j); + + /*--- Grid velocities for dynamic meshes ---*/ + + if (grid_movement) { + numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[jPoint]->GetGridVel()); + } + + /*--- High order reconstruction using MUSCL strategy ---*/ + + if (second_order) { + + for (iDim = 0; iDim < nDim; iDim++) { + Vector_i[iDim] = 0.5*(geometry->node[jPoint]->GetCoord(iDim) - geometry->node[iPoint]->GetCoord(iDim)); + Vector_j[iDim] = 0.5*(geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim)); + } + + /*--- Adjoint variables using gradient reconstruction and limiters ---*/ + + Gradient_i = node[iPoint]->GetGradient(); Gradient_j = node[jPoint]->GetGradient(); + if (limiter) { Limiter_i = node[iPoint]->GetLimiter(); Limiter_j = node[jPoint]->GetLimiter(); } + + for (iVar = 0; iVar < nVar; iVar++) { + Project_Grad_i = 0; Project_Grad_j = 0; + Non_Physical = node[iPoint]->GetNon_Physical()*node[jPoint]->GetNon_Physical(); + for (iDim = 0; iDim < nDim; iDim++) { + Project_Grad_i += Vector_i[iDim]*Gradient_i[iVar][iDim]*Non_Physical; + Project_Grad_j += Vector_j[iDim]*Gradient_j[iVar][iDim]*Non_Physical; + } + if (limiter) { + Solution_i[iVar] = Psi_i[iVar] + Project_Grad_i*Limiter_i[iDim]; + Solution_j[iVar] = Psi_j[iVar] + Project_Grad_j*Limiter_j[iDim]; + } + else { + Solution_i[iVar] = Psi_i[iVar] + Project_Grad_i; + Solution_j[iVar] = Psi_j[iVar] + Project_Grad_j; + } + } + + numerics->SetAdjointVar(Solution_i, Solution_j); + + } + + /*--- Compute the residual---*/ + + numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + /*--- Add and Subtract Residual ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual_i); + LinSysRes.SubtractBlock(jPoint, Residual_j); + + /*--- Implicit contribution to the residual ---*/ + + if (implicit) { + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + Jacobian.SubtractBlock(iPoint, jPoint, Jacobian_ij); + Jacobian.SubtractBlock(jPoint, iPoint, Jacobian_ji); + Jacobian.SubtractBlock(jPoint, jPoint, Jacobian_jj); + } + + } + +} + +void CAdjEulerSolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, + CConfig *config, unsigned short iMesh) { + + unsigned short iVar; + unsigned long iPoint; + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + bool rotating_frame = config->GetRotating_Frame(); + bool axisymmetric = config->GetAxisymmetric(); + // bool gravity = (config->GetGravityForce() == YES); + bool time_spectral = (config->GetUnsteady_Simulation() == TIME_SPECTRAL); + // bool freesurface = (config->GetKind_Regime() == FREESURFACE); + + /*--- Initialize the source residual to zero ---*/ + for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; + + if (rotating_frame) { + + /*--- Loop over all points ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Load the adjoint variables ---*/ + numerics->SetAdjointVar(node[iPoint]->GetSolution(), + node[iPoint]->GetSolution()); + + /*--- Load the volume of the dual mesh cell ---*/ + numerics->SetVolume(geometry->node[iPoint]->GetVolume()); + + /*--- Compute the adjoint rotating frame source residual ---*/ + numerics->ComputeResidual(Residual, Jacobian_i, config); + + /*--- Add the source residual to the total ---*/ + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Add the implicit Jacobian contribution ---*/ + if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + } + } + + if (time_spectral) { + + su2double Volume, Source; + + /*--- loop over points ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Get control volume ---*/ + Volume = geometry->node[iPoint]->GetVolume(); + + /*--- Get stored time spectral source term ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + Source = node[iPoint]->GetTimeSpectral_Source(iVar); + Residual[iVar] = Source*Volume; + } + + /*--- Add Residual ---*/ + LinSysRes.AddBlock(iPoint, Residual); + + } + } + + if (axisymmetric) { + + /*--- Zero out Jacobian structure ---*/ + if (implicit) { + for (iVar = 0; iVar < nVar; iVar ++) + for (unsigned short jVar = 0; jVar < nVar; jVar ++) + Jacobian_i[iVar][jVar] = 0.0; + } + + /*--- loop over points ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Set solution ---*/ + numerics->SetConservative(solver_container[FLOW_SOL]->node[iPoint]->GetSolution(), solver_container[FLOW_SOL]->node[iPoint]->GetSolution()); + + /*--- Set adjoint variables ---*/ + numerics->SetAdjointVar(node[iPoint]->GetSolution(), node[iPoint]->GetSolution()); + + /*--- Set control volume ---*/ + numerics->SetVolume(geometry->node[iPoint]->GetVolume()); + + /*--- Set coordinate ---*/ + numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[iPoint]->GetCoord()); + + /*--- Compute Source term Residual ---*/ + numerics->ComputeResidual(Residual, Jacobian_i, config); + + /*--- Add Residual ---*/ + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Implicit part ---*/ + if (implicit) + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + } + } + + // if (gravity) { + // + // } + + // if (freesurface) { + // for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + // + // su2double Volume = geometry->node[iPoint]->GetVolume(); + // su2double **Gradient = solver_container[ADJLEVELSET_SOL]->node[iPoint]->GetGradient(); + // su2double coeff = solver_container[LEVELSET_SOL]->node[iPoint]->GetSolution(0) / solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); + // + // Residual[0] = 0.0; + // for (iDim = 0; iDim < nDim; iDim++) { + // Residual[iDim+1] = coeff*Gradient[0][iDim]*Volume; + // } + // + // LinSysRes.AddBlock(iPoint, Residual); + // + // } + // } + +} + +void CAdjEulerSolver::Source_Template(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config, unsigned short iMesh) { +} + +void CAdjEulerSolver::SetUndivided_Laplacian(CGeometry *geometry, CConfig *config) { + unsigned long iPoint, jPoint, iEdge; + unsigned short iVar; + su2double *Diff; + + Diff = new su2double[nVar]; + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) + node[iPoint]->SetUnd_LaplZero(); + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + + for (iVar = 0; iVar < nVar; iVar++) + Diff[iVar] = node[iPoint]->GetSolution(iVar) - node[jPoint]->GetSolution(iVar); + +#ifdef STRUCTURED_GRID + + if (geometry->node[iPoint]->GetDomain()) node[iPoint]->SubtractUnd_Lapl(Diff); + if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddUnd_Lapl(Diff); + +#else + + bool boundary_i = geometry->node[iPoint]->GetPhysicalBoundary(); + bool boundary_j = geometry->node[jPoint]->GetPhysicalBoundary(); + + /*--- Both points inside the domain, or both in the boundary ---*/ + if ((!boundary_i && !boundary_j) || (boundary_i && boundary_j)) { + if (geometry->node[iPoint]->GetDomain()) node[iPoint]->SubtractUnd_Lapl(Diff); + if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddUnd_Lapl(Diff); + } + + /*--- iPoint inside the domain, jPoint on the boundary ---*/ + if (!boundary_i && boundary_j) + if (geometry->node[iPoint]->GetDomain()) node[iPoint]->SubtractUnd_Lapl(Diff); + + /*--- jPoint inside the domain, iPoint on the boundary ---*/ + if (boundary_i && !boundary_j) + if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddUnd_Lapl(Diff); + +#endif + + } + +#ifdef STRUCTURED_GRID + + unsigned long Point_Normal = 0, iVertex; + unsigned short iMarker; + su2double *Psi_mirror; + + Psi_mirror = new su2double[nVar]; + + /*--- Loop over all boundaries and include an extra contribution + from a halo node. Find the nearest normal, interior point + for a boundary node and make a linear approximation. ---*/ + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE && + config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY && + config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY && + config->GetMarker_All_KindBC(iMarker) != PERIODIC_BOUNDARY) { + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + Point_Normal = geometry->vertex[iMarker][iVertex]->GetNormal_Neighbor(); + + /*--- Interpolate & compute difference in the conserved variables ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + Psi_mirror[iVar] = 2.0*node[iPoint]->GetSolution(iVar) - node[Point_Normal]->GetSolution(iVar); + Diff[iVar] = node[iPoint]->GetSolution(iVar) - Psi_mirror[iVar]; + } + + /*--- Subtract contribution at the boundary node only ---*/ + node[iPoint]->SubtractUnd_Lapl(Diff); + } + } + } + } + + delete [] Psi_mirror; + +#endif + + delete [] Diff; + + /*--- MPI parallelization ---*/ + Set_MPI_Undivided_Laplacian(geometry, config); + +} + +void CAdjEulerSolver::SetDissipation_Switch(CGeometry *geometry, CConfig *config) { + + unsigned long iPoint; + su2double SharpEdge_Distance, eps, ds, scale, Sensor, Param_Kappa_2, Param_Kappa_4; + + eps = config->GetLimiterCoeff()*config->GetRefElemLength(); + Param_Kappa_2 = config->GetKappa_2nd_AdjFlow(); + Param_Kappa_4 = config->GetKappa_4th_AdjFlow(); + + if (Param_Kappa_2 != 0.0) scale = 2.0 * Param_Kappa_4 / Param_Kappa_2; + else scale = 0.0; + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + + SharpEdge_Distance = (geometry->node[iPoint]->GetSharpEdge_Distance() - config->GetSharpEdgesCoeff()*eps); + + ds = 0.0; + if (SharpEdge_Distance < -eps) ds = 1.0; + if (fabs(SharpEdge_Distance) <= eps) ds = 1.0 - (0.5*(1.0+(SharpEdge_Distance/eps)+(1.0/PI_NUMBER)*sin(PI_NUMBER*SharpEdge_Distance/eps))); + if (SharpEdge_Distance > eps) ds = 0.0; + + Sensor = scale * ds; + + node[iPoint]->SetSensor(Sensor); + + } + + // su2double dx = 0.1; + // su2double LimK = 0.03; + // su2double eps2 = pow((LimK*dx),3); + // + // unsigned long iPoint, jPoint; + // unsigned short iNeigh, nNeigh, iDim; + // su2double **Gradient_i, *Coord_i, *Coord_j, diff_coord, dist_ij, r_u, r_u_ij, + // du_max, du_min, u_ij, *Solution_i, *Solution_j, dp, dm; + // + // + // for (iPoint = 0; iPoint < nPoint; iPoint++) + // + // if (geometry->node[iPoint]->GetDomain()) { + // + // Solution_i = node[iPoint]->GetSolution(); + // Gradient_i = node[iPoint]->GetGradient(); + // Coord_i = geometry->node[iPoint]->GetCoord(); + // nNeigh = geometry->node[iPoint]->GetnPoint(); + // + // /*--- Find max and min value of the variable in the control volume around the mesh point ---*/ + // du_max = 1.0E-8; du_min = -1.0E-8; + // for (iNeigh = 0; iNeigh < nNeigh; iNeigh++) { + // jPoint = geometry->node[iPoint]->GetPoint(iNeigh); + // Solution_j = node[jPoint]->GetSolution(); + // du_max = max(du_max, Solution_j[0] - Solution_i[0]); + // du_min = min(du_min, Solution_j[0] - Solution_i[0]); + // } + // + // r_u = 1.0; + // for (iNeigh = 0; iNeigh < nNeigh; iNeigh++) { + // + // /*--- Unconstrained reconstructed solution ---*/ + // jPoint = geometry->node[iPoint]->GetPoint(iNeigh); + // Solution_j = node[jPoint]->GetSolution(); + // Coord_j = geometry->node[jPoint]->GetCoord(); + // u_ij = Solution_i[0]; dist_ij = 0; + // for (iDim = 0; iDim < nDim; iDim++) { + // diff_coord = Coord_j[iDim]-Coord_i[iDim]; + // u_ij += 0.5*diff_coord*Gradient_i[0][iDim]; + // } + // + // /*--- Venkatakrishnan limiter ---*/ + // if ((u_ij - Solution_i[0]) >= 0.0) dp = du_max; + // else dp = du_min; + // dm = u_ij - Solution_i[0]; + // r_u_ij = (dp*dp+2.0*dm*dp + eps2)/(dp*dp+2*dm*dm+dm*dp + eps2); + // + // /*--- Take the smallest value of the limiter ---*/ + // r_u = min(r_u, r_u_ij); + // + // } + // node[iPoint]->SetSensor(1.0-r_u); + // } + + /*--- MPI parallelization ---*/ + Set_MPI_Dissipation_Switch(geometry, config); + +} + +void CAdjEulerSolver::ExplicitRK_Iteration(CGeometry *geometry, CSolver **solver_container, + CConfig *config, unsigned short iRKStep) { + su2double *Residual, *Res_TruncError, Vol, Delta, Res; + unsigned short iVar; + unsigned long iPoint; + + su2double RK_AlphaCoeff = config->Get_Alpha_RKStep(iRKStep); + + for (iVar = 0; iVar < nVar; iVar++) { + SetRes_RMS(iVar, 0.0); + SetRes_Max(iVar, 0.0, 0); + } + + /*--- Update the solution ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + Vol = geometry->node[iPoint]->GetVolume(); + Delta = solver_container[FLOW_SOL]->node[iPoint]->GetDelta_Time() / Vol; + + Res_TruncError = node[iPoint]->GetResTruncError(); + Residual = LinSysRes.GetBlock(iPoint); + + for (iVar = 0; iVar < nVar; iVar++) { + Res = Residual[iVar] + Res_TruncError[iVar]; + node[iPoint]->AddSolution(iVar, -Res*Delta*RK_AlphaCoeff); + AddRes_RMS(iVar, Res*Res); + AddRes_Max(iVar, fabs(Res), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); + } + + } + + /*--- MPI solution ---*/ + Set_MPI_Solution(geometry, config); + + /*--- Compute the root mean square residual ---*/ + SetResidual_RMS(geometry, config); + +} + +void CAdjEulerSolver::ExplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { + su2double *local_Residual, *local_Res_TruncError, Vol, Delta, Res; + unsigned short iVar; + unsigned long iPoint; + + for (iVar = 0; iVar < nVar; iVar++) { + SetRes_RMS(iVar, 0.0); + SetRes_Max(iVar, 0.0, 0); + } + + /*--- Update the solution ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + Vol = geometry->node[iPoint]->GetVolume(); + Delta = solver_container[FLOW_SOL]->node[iPoint]->GetDelta_Time() / Vol; + + local_Res_TruncError = node[iPoint]->GetResTruncError(); + local_Residual = LinSysRes.GetBlock(iPoint); + + for (iVar = 0; iVar < nVar; iVar++) { + Res = local_Residual[iVar] + local_Res_TruncError[iVar]; + node[iPoint]->AddSolution(iVar, -Res*Delta); + AddRes_RMS(iVar, Res*Res); + AddRes_Max(iVar, fabs(Res), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); + } + + } + + /*--- MPI solution ---*/ + Set_MPI_Solution(geometry, config); + + /*--- Compute the root mean square residual ---*/ + SetResidual_RMS(geometry, config); + +} + +void CAdjEulerSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { + + unsigned short iVar; + unsigned long iPoint, total_index; + su2double Delta, *local_Res_TruncError, Vol; + + /*--- Set maximum residual to zero ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + SetRes_RMS(iVar, 0.0); + SetRes_Max(iVar, 0.0, 0); + } + + /*--- Build implicit system ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Read the residual ---*/ + + local_Res_TruncError = node[iPoint]->GetResTruncError(); + + /*--- Read the volume ---*/ + + Vol = geometry->node[iPoint]->GetVolume(); + + /*--- Modify matrix diagonal to assure diagonal dominance ---*/ + + if (solver_container[FLOW_SOL]->node[iPoint]->GetDelta_Time() != 0.0) { + Delta = Vol / solver_container[FLOW_SOL]->node[iPoint]->GetDelta_Time(); + Jacobian.AddVal2Diag(iPoint, Delta); + } + else { + Jacobian.SetVal2Diag(iPoint, 1.0); + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar + iVar; + LinSysRes[total_index] = 0.0; + local_Res_TruncError[iVar] = 0.0; + } + } + + /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + LinSysRes[total_index] = -(LinSysRes[total_index] + local_Res_TruncError[iVar]); + LinSysSol[total_index] = 0.0; + AddRes_RMS(iVar, LinSysRes[total_index]*LinSysRes[total_index]); + AddRes_Max(iVar, fabs(LinSysRes[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); + } + + } + + /*--- Initialize residual and solution at the ghost points ---*/ + + for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar + iVar; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + } + } + + /*--- Solve or smooth the linear system ---*/ + + CSysSolve system; + system.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); + + /*--- Update solution (system written in terms of increments) ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) + for (iVar = 0; iVar < nVar; iVar++) { + node[iPoint]->AddSolution(iVar, config->GetRelaxation_Factor_AdjFlow()*LinSysSol[iPoint*nVar+iVar]); + } + + /*--- MPI solution ---*/ + + Set_MPI_Solution(geometry, config); + + /*--- Compute the root mean square residual ---*/ + + SetResidual_RMS(geometry, config); + +} + +void CAdjEulerSolver::Inviscid_Sensitivity(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config) { + + unsigned long iVertex, iPoint, Neigh; + unsigned short iPos, jPos; + unsigned short iDim, iMarker, iNeigh; + su2double *d = NULL, *Normal = NULL, *Psi = NULL, *U = NULL, Enthalpy, conspsi = 0.0, Mach_Inf, + Area, **PrimVar_Grad = NULL, **ConsVar_Grad = NULL, *ConsPsi_Grad = NULL, + ConsPsi, d_press, grad_v, Beta2, v_gradconspsi, UnitNormal[3], *GridVel = NULL, + LevelSet, Target_LevelSet, eps, r, ru, rv, rw, rE, p, T, dp_dr, dp_dru, dp_drv, + dp_drw, dp_drE, dH_dr, dH_dru, dH_drv, dH_drw, dH_drE, H, *USens, D[3][3], Dd[3], scale = 1.0; + su2double RefVel2, RefDensity, Mach2Vel, *Velocity_Inf, factor; + su2double Velocity2, Mach, SoundSpeed, *Velocity; + + USens = new su2double[nVar]; + Velocity = new su2double[nDim]; + + su2double Gas_Constant = config->GetGas_ConstantND(); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool grid_movement = config->GetGrid_Movement(); + su2double RefAreaCoeff = config->GetRefAreaCoeff(); + su2double Mach_Motion = config->GetMach_Motion(); + unsigned short ObjFunc = config->GetKind_ObjFunc(); + + if (config->GetSystemMeasurements() == US) scale = 1.0/12.0; + else scale = 1.0; + + /*--- Compute non-dimensional factor. 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. ---*/ + + if (grid_movement) { + Mach2Vel = sqrt(Gamma*Gas_Constant*config->GetTemperature_FreeStreamND()); + RefVel2 = (Mach_Motion*Mach2Vel)*(Mach_Motion*Mach2Vel); + } + else { + Velocity_Inf = config->GetVelocity_FreeStreamND(); + RefVel2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + RefVel2 += Velocity_Inf[iDim]*Velocity_Inf[iDim]; + } + + RefDensity = config->GetDensity_FreeStreamND(); + + factor = 1.0/(0.5*RefDensity*RefAreaCoeff*RefVel2); + + if ((ObjFunc == INVERSE_DESIGN_HEATFLUX) || (ObjFunc == FREE_SURFACE) || + (ObjFunc == TOTAL_HEATFLUX) || (ObjFunc == MAXIMUM_HEATFLUX) || + (ObjFunc == MASS_FLOW_RATE) ) factor = 1.0; + + if ((ObjFunc == AVG_TOTAL_PRESSURE) || (ObjFunc == AVG_OUTLET_PRESSURE) || + (ObjFunc == OUTLET_CHAIN_RULE)) factor = 1.0/Area_Monitored; + + /*--- Initialize sensitivities to zero ---*/ + + Total_Sens_Geo = 0.0; + Total_Sens_Mach = 0.0; + Total_Sens_AoA = 0.0; + Total_Sens_Press = 0.0; + Total_Sens_Temp = 0.0; + Total_Sens_BPress = 0.0; + + /*--- Loop over boundary markers to select those for Euler walls ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) + + if (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) + + /*--- Loop over points on the surface to store the auxiliary variable ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if (geometry->node[iPoint]->GetDomain()) { + Psi = node[iPoint]->GetSolution(); + U = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); + if (compressible) { + Enthalpy = solver_container[FLOW_SOL]->node[iPoint]->GetEnthalpy(); + conspsi = U[0]*Psi[0] + U[0]*Enthalpy*Psi[nDim+1]; + } + if (incompressible || freesurface) { + Beta2 = solver_container[FLOW_SOL]->node[iPoint]->GetBetaInc2(); + conspsi = Beta2*Psi[0]; + } + for (iDim = 0; iDim < nDim; iDim++) conspsi += U[iDim+1]*Psi[iDim+1]; + + node[iPoint]->SetAuxVar(conspsi); + + /*--- Also load the auxiliary variable for first neighbors ---*/ + + for (iNeigh = 0; iNeigh < geometry->node[iPoint]->GetnPoint(); iNeigh++) { + Neigh = geometry->node[iPoint]->GetPoint(iNeigh); + Psi = node[Neigh]->GetSolution(); + U = solver_container[FLOW_SOL]->node[Neigh]->GetSolution(); + if (compressible) { + Enthalpy = solver_container[FLOW_SOL]->node[Neigh]->GetEnthalpy(); + conspsi = U[0]*Psi[0] + U[0]*Enthalpy*Psi[nDim+1]; + } + if (incompressible || freesurface) { + Beta2 = solver_container[FLOW_SOL]->node[Neigh]->GetBetaInc2(); + conspsi = Beta2*Psi[0]; + } + for (iDim = 0; iDim < nDim; iDim++) conspsi += U[iDim+1]*Psi[iDim+1]; + node[Neigh]->SetAuxVar(conspsi); + } + } + } + + /*--- Compute surface gradients of the auxiliary variable ---*/ + + SetAuxVar_Surface_Gradient(geometry, config); + + /*--- Evaluate the shape sensitivity ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + Sens_Geo[iMarker] = 0.0; + + if (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if (geometry->node[iPoint]->GetDomain()) { + + d = node[iPoint]->GetForceProj_Vector(); + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + Area = 0; + for (iDim = 0; iDim < nDim; iDim++) + Area += Normal[iDim]*Normal[iDim]; + Area = sqrt(Area); + + PrimVar_Grad = solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(); + ConsVar_Grad = solver_container[FLOW_SOL]->node[iPoint]->GetGradient(); + ConsPsi_Grad = node[iPoint]->GetAuxVarGradient(); + ConsPsi = node[iPoint]->GetAuxVar(); + + d_press = 0.0; grad_v = 0.0; v_gradconspsi = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + + /*-- Retrieve the value of the pressure gradient ---*/ + + if (compressible) d_press += d[iDim]*PrimVar_Grad[nDim+1][iDim]; + if (incompressible || freesurface) d_press += d[iDim]*ConsVar_Grad[0][iDim]; + + /*-- Retrieve the value of the velocity gradient ---*/ + + grad_v += PrimVar_Grad[iDim+1][iDim]*ConsPsi; + + /*-- Retrieve the value of the theta gradient ---*/ + + v_gradconspsi += solver_container[FLOW_SOL]->node[iPoint]->GetVelocity(iDim) * ConsPsi_Grad[iDim]; + + /*--- Additional sensitivity term for grid movement ---*/ + + if (grid_movement) { + GridVel = geometry->node[iPoint]->GetGridVel(); + v_gradconspsi -= GridVel[iDim] * ConsPsi_Grad[iDim]; + } + + } + + /*--- Compute additional term in the surface sensitivity for free surface problem. ---*/ + + if (freesurface) { + LevelSet = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(nDim+1); + Target_LevelSet = geometry->node[iPoint]->GetCoord(nDim-1); + d_press += 0.5*(Target_LevelSet - LevelSet)*(Target_LevelSet - LevelSet); + } + + /*--- Compute sensitivity for each surface point ---*/ + + CSensitivity[iMarker][iVertex] = (d_press + grad_v + v_gradconspsi) * Area * scale * factor; + + /*--- Change the sign of the sensitivity if the normal has been flipped --*/ + + if (geometry->node[iPoint]->GetFlip_Orientation()) + CSensitivity[iMarker][iVertex] = -CSensitivity[iMarker][iVertex]; + + /*--- If sharp edge, set the sensitivity to 0 on that region ---*/ + + if (config->GetSens_Remove_Sharp()) { + eps = config->GetLimiterCoeff()*config->GetRefElemLength(); + if ( geometry->node[iPoint]->GetSharpEdge_Distance() < config->GetSharpEdgesCoeff()*eps ) + CSensitivity[iMarker][iVertex] = 0.0; + } + + Sens_Geo[iMarker] -= CSensitivity[iMarker][iVertex]; + + } + } + + Total_Sens_Geo += Sens_Geo[iMarker]; + + } + } + + + /*--- Farfield Sensitivity (Mach, AoA, Press, Temp), only for compressible flows ---*/ + + if (compressible) { + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + Sens_BPress[iMarker] = 0.0; + if (config->GetMarker_All_KindBC(iMarker) == OUTLET_FLOW){ + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + Psi = node[iPoint]->GetSolution(); + U = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + + Mach_Inf = config->GetMach(); + if (grid_movement) Mach_Inf = config->GetMach_Motion(); + + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; + Area = sqrt(Area); + for (iDim = 0; iDim < nDim; iDim++) UnitNormal[iDim] = -Normal[iDim]/Area; + Velocity2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity[iDim] = U[iDim+1]/U[0]; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + } + + SoundSpeed = solver_container[FLOW_SOL]->node[iPoint]->GetSoundSpeed(); + Mach = (sqrt(Velocity2))/SoundSpeed; + if (Mach<1.0 && Mach>0.0) + Sens_BPress[iMarker]+=Psi[nDim+1]*SoundSpeed*(Mach-1/Mach)/Gamma_Minus_One; + } + } + Total_Sens_BPress+= Sens_BPress[iMarker] * scale * factor; + } + + if (config->GetMarker_All_KindBC(iMarker) == FAR_FIELD || config->GetMarker_All_KindBC(iMarker) == INLET_FLOW + || config->GetMarker_All_KindBC(iMarker) == SUPERSONIC_INLET || config->GetMarker_All_KindBC(iMarker) == SUPERSONIC_OUTLET + || config->GetMarker_All_KindBC(iMarker) == ENGINE_INFLOW ) { + + Sens_Mach[iMarker] = 0.0; + Sens_AoA[iMarker] = 0.0; + Sens_Press[iMarker] = 0.0; + Sens_Temp[iMarker] = 0.0; + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + Psi = node[iPoint]->GetSolution(); + U = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + + Mach_Inf = config->GetMach(); + if (grid_movement) Mach_Inf = config->GetMach_Motion(); + + r = U[0]; ru = U[1]; rv = U[2]; + if (nDim == 2) { rw = 0.0; rE = U[3]; } + else { rw = U[3]; rE = U[4]; } + p = Gamma_Minus_One*(rE-(ru*ru + rv*rv + rw*rw)/(2*r)); + + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; + Area = sqrt(Area); + for (iDim = 0; iDim < nDim; iDim++) UnitNormal[iDim] = -Normal[iDim]/Area; + + H = (rE + p)/r; + + dp_dr = Gamma_Minus_One*(ru*ru + rv*rv + rw*rw)/(2*r*r); + dp_dru = -Gamma_Minus_One*ru/r; + dp_drv = -Gamma_Minus_One*rv/r; + if (nDim == 2) { dp_drw = 0.0; dp_drE = Gamma_Minus_One; } + else { dp_drw = -Gamma_Minus_One*rw/r; dp_drE = Gamma_Minus_One; } + + dH_dr = (-H + dp_dr)/r; dH_dru = dp_dru/r; dH_drv = dp_drv/r; + if (nDim == 2) { dH_drw = 0.0; dH_drE = (1 + dp_drE)/r; } + else { dH_drw = dp_drw/r; dH_drE = (1 + dp_drE)/r; } + + if (nDim == 2) { + Jacobian_j[0][0] = 0.0; + Jacobian_j[1][0] = Area*UnitNormal[0]; + Jacobian_j[2][0] = Area*UnitNormal[1]; + Jacobian_j[3][0] = 0.0; + + Jacobian_j[0][1] = (-(ru*ru)/(r*r) + dp_dr)*Area*UnitNormal[0] + (-(ru*rv)/(r*r))*Area*UnitNormal[1]; + Jacobian_j[1][1] = (2*ru/r + dp_dru)*Area*UnitNormal[0] + (rv/r)*Area*UnitNormal[1]; + Jacobian_j[2][1] = (dp_drv)*Area*UnitNormal[0] + (ru/r)*Area*UnitNormal[1]; + Jacobian_j[3][1] = (dp_drE)*Area*UnitNormal[0]; + + Jacobian_j[0][2] = (-(ru*rv)/(r*r))*Area*UnitNormal[0] + (-(rv*rv)/(r*r) + dp_dr)*Area*UnitNormal[1]; + Jacobian_j[1][2] = (rv/r)*Area*UnitNormal[0] + (dp_dru)*Area*UnitNormal[1]; + Jacobian_j[2][2] = (ru/r)*Area*UnitNormal[0] + (2*rv/r + dp_drv)*Area*UnitNormal[1]; + Jacobian_j[3][2] = (dp_drE)*Area*UnitNormal[1]; + + Jacobian_j[0][3] = (ru*dH_dr)*Area*UnitNormal[0] + (rv*dH_dr)*Area*UnitNormal[1]; + Jacobian_j[1][3] = (H + ru*dH_dru)*Area*UnitNormal[0] + (rv*dH_dru)*Area*UnitNormal[1]; + Jacobian_j[2][3] = (ru*dH_drv)*Area*UnitNormal[0] + (H + rv*dH_drv)*Area*UnitNormal[1]; + Jacobian_j[3][3] = (ru*dH_drE)*Area*UnitNormal[0] + (rv*dH_drE)*Area*UnitNormal[1]; + } + else { + Jacobian_j[0][0] = 0.0; + Jacobian_j[1][0] = Area*UnitNormal[0]; + Jacobian_j[2][0] = Area*UnitNormal[1]; + Jacobian_j[3][0] = Area*UnitNormal[2]; + Jacobian_j[4][0] = 0.0; + + Jacobian_j[0][1] = (-(ru*ru)/(r*r) + dp_dr)*Area*UnitNormal[0] + (-(ru*rv)/(r*r))*Area*UnitNormal[1] + (-(ru*rw)/(r*r))*Area*UnitNormal[2]; + Jacobian_j[1][1] = (2*ru/r + dp_dru)*Area*UnitNormal[0] + (rv/r)*Area*UnitNormal[1] + (rw/r)*Area*UnitNormal[2]; + Jacobian_j[2][1] = (dp_drv)*Area*UnitNormal[0] + (ru/r)*Area*UnitNormal[1]; + Jacobian_j[3][1] = (dp_drw)*Area*UnitNormal[0] + (ru/r)*Area*UnitNormal[2]; + Jacobian_j[4][1] = (dp_drE)*Area*UnitNormal[0]; + + Jacobian_j[0][2] = (-(ru*rv)/(r*r))*Area*UnitNormal[0] + (-(rv*rv)/(r*r) + dp_dr)*Area*UnitNormal[1] + (-(rv*rw)/(r*r))*Area*UnitNormal[2]; + Jacobian_j[1][2] = (rv/r)*Area*UnitNormal[0] + (dp_dru)*Area*UnitNormal[1]; + Jacobian_j[2][2] = (ru/r)*Area*UnitNormal[0] + (2*rv/r + dp_drv)*Area*UnitNormal[1] + (rw/r)*Area*UnitNormal[2]; + Jacobian_j[3][2] = (dp_drw)*Area*UnitNormal[1] + (rv/r)*Area*UnitNormal[2]; + Jacobian_j[4][2] = (dp_drE)*Area*UnitNormal[1]; + + Jacobian_j[0][3] = (-(ru*rw)/(r*r))*Area*UnitNormal[0] + (-(rv*rw)/(r*r))*Area*UnitNormal[1] + (-(rw*rw)/(r*r) + dp_dr)*Area*UnitNormal[2]; + Jacobian_j[1][3] = (rw/r)*Area*UnitNormal[0] + (dp_dru)*Area*UnitNormal[2]; + Jacobian_j[2][3] = (rw/r)*Area*UnitNormal[1] + (dp_drv)*Area*UnitNormal[2]; + Jacobian_j[3][3] = (ru/r)*Area*UnitNormal[0] + (rv/r)*Area*UnitNormal[1] + (2*rw/r + dp_drw)*Area*UnitNormal[2]; + Jacobian_j[4][3] = (dp_drE)*Area*UnitNormal[2]; + + Jacobian_j[0][4] = (ru*dH_dr)*Area*UnitNormal[0] + (rv*dH_dr)*Area*UnitNormal[1] + (rw*dH_dr)*Area*UnitNormal[2]; + Jacobian_j[1][4] = (H + ru*dH_dru)*Area*UnitNormal[0] + (rv*dH_dru)*Area*UnitNormal[1] + (rw*dH_dru)*Area*UnitNormal[2]; + Jacobian_j[2][4] = (ru*dH_drv)*Area*UnitNormal[0] + (H + rv*dH_drv)*Area*UnitNormal[1] + (rw*dH_drv)*Area*UnitNormal[2]; + Jacobian_j[3][4] = (ru*dH_drw)*Area*UnitNormal[0] + (rv*dH_drw)*Area*UnitNormal[1] + (H + rw*dH_drw)*Area*UnitNormal[2]; + Jacobian_j[4][4] = (ru*dH_drE)*Area*UnitNormal[0] + (rv*dH_drE)*Area*UnitNormal[1] + (rw*dH_drE)*Area*UnitNormal[2]; + } + + /*--- Mach number sensitivity ---*/ + + USens[0] = 0.0; USens[1] = ru/Mach_Inf; USens[2] = rv/Mach_Inf; + if (nDim == 2) { USens[3] = Gamma*Mach_Inf*p; } + else { USens[3] = rw/Mach_Inf; USens[4] = Gamma*Mach_Inf*p; } + for (iPos = 0; iPos < nVar; iPos++) { + for (jPos = 0; jPos < nVar; jPos++) { + Sens_Mach[iMarker] += Psi[iPos]*Jacobian_j[jPos][iPos]*USens[jPos]; + } + } + + /*--- AoA sensitivity ---*/ + + USens[0] = 0.0; + if (nDim == 2) { USens[1] = -rv; USens[2] = ru; USens[3] = 0.0; } + else { USens[1] = -rw; USens[2] = 0.0; USens[3] = ru; USens[4] = 0.0; } + for (iPos = 0; iPos < nVar; iPos++) { + for (jPos = 0; jPos < nVar; jPos++) { + Sens_AoA[iMarker] += Psi[iPos]*Jacobian_j[jPos][iPos]*USens[jPos]; + } + } + + /*--- Pressure sensitivity ---*/ + + USens[0] = r/p; USens[1] = ru/p; USens[2] = rv/p; + if (nDim == 2) { USens[3] = rE/p; } + else { USens[3] = rw/p; USens[4] = rE/p; } + for (iPos = 0; iPos < nVar; iPos++) { + for (jPos = 0; jPos < nVar; jPos++) { + Sens_Press[iMarker] += Psi[iPos]*Jacobian_j[jPos][iPos]*USens[jPos]; + } + } + + /*--- Temperature sensitivity ---*/ + + T = p/(r*Gas_Constant); + USens[0] = -r/T; USens[1] = 0.5*ru/T; USens[2] = 0.5*rv/T; + if (nDim == 2) { USens[3] = (ru*ru + rv*rv + rw*rw)/(r*T); } + else { USens[3] = 0.5*rw/T; USens[4] = (ru*ru + rv*rv + rw*rw)/(r*T); } + for (iPos = 0; iPos < nVar; iPos++) { + for (jPos = 0; jPos < nVar; jPos++) { + Sens_Temp[iMarker] += Psi[iPos]*Jacobian_j[jPos][iPos]*USens[jPos]; + } + } + } + } + + Total_Sens_Mach -= Sens_Mach[iMarker] * scale * factor; + Total_Sens_AoA -= Sens_AoA[iMarker] * scale * factor; + Total_Sens_Press -= Sens_Press[iMarker] * scale * factor; + Total_Sens_Temp -= Sens_Temp[iMarker] * scale * factor; + + } + } + + /*--- Explicit contribution from objective function quantity ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) { + + Sens_Mach[iMarker] = 0.0; + Sens_AoA[iMarker] = 0.0; + Sens_Press[iMarker] = 0.0; + Sens_Temp[iMarker] = 0.0; + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + p = solver_container[FLOW_SOL]->node[iPoint]->GetPressure(); + + Mach_Inf = config->GetMach(); + if (grid_movement) Mach_Inf = config->GetMach_Motion(); + + d = node[iPoint]->GetForceProj_Vector(); + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; + Area = sqrt(Area); + for (iDim = 0; iDim < nDim; iDim++) UnitNormal[iDim] = -Normal[iDim]/Area; + + /*--- Mach number sensitivity ---*/ + + for (iPos = 0; iPos < nDim; iPos++) Dd[iPos] = -(2.0/Mach_Inf)*d[iPos]; + for (iPos = 0; iPos < nDim; iPos++) Sens_Mach[iMarker] += p*Dd[iPos]*Area*UnitNormal[iPos]; + + /*--- AoA sensitivity ---*/ + + if (config->GetKind_ObjFunc() == DRAG_COEFFICIENT || + config->GetKind_ObjFunc() == LIFT_COEFFICIENT || + config->GetKind_ObjFunc() == SIDEFORCE_COEFFICIENT || + config->GetKind_ObjFunc() == EQUIVALENT_AREA || + config->GetKind_ObjFunc() == NEARFIELD_PRESSURE) { + if (nDim == 2) { + D[0][0] = 0.0; D[0][1] = -1.0; + D[1][0] = 1.0; D[1][1] = 0.0; + } + else { + D[0][0] = 0.0; D[0][1] = 0.0; D[0][2] = -1.0; + D[1][0] = 0.0; D[1][1] = 0.0; D[1][2] = 0.0; + D[2][0] = 1.0; D[2][1] = 0.0; D[2][2] = 0.0; + } + for (iPos = 0; iPos < nDim; iPos++) Dd[iPos] = 0.0; + for (iPos = 0; iPos < nDim; iPos++) { + for (jPos = 0; jPos < nDim; jPos++) + Dd[iPos] += D[iPos][jPos]*d[jPos]; + } + } + + /*--- Coefficients with no explicit AoA dependece ---*/ + + else { + for (iPos = 0; iPosGetMarker_All_KindBC(iMarker) == EULER_WALL) { + nVertex = geometry->nVertex[iMarker]; + + /*--- Allocate the linear system ---*/ + + A = new su2double* [nVertex]; + b = new su2double [nVertex]; + ArchLength = new su2double [nVertex]; + for (iVertex = 0; iVertex < nVertex; iVertex++) { + A[iVertex] = new su2double [nVertex]; + } + + /*--- Initialization ---*/ + + for (iVertex = 0; iVertex < nVertex; iVertex++) { + b[iVertex] = 0.0; ArchLength[iVertex] = 0.0; + for (jVertex = 0; jVertex < nVertex; jVertex++) + A[iVertex][jVertex] = 0.0; + } + + /*--- Set the arch length ---*/ + + ArchLength[0] = 0.0; + for (iVertex = 1; iVertex < nVertex; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex-1]->GetNode(); + Coord_begin = geometry->node[iPoint]->GetCoord(); + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Coord_end = geometry->node[iPoint]->GetCoord(); + dist = sqrt (pow( Coord_end[0]-Coord_begin[0], 2.0) + pow( Coord_end[1]-Coord_begin[1], 2.0)); + ArchLength[iVertex] = ArchLength[iVertex-1] + dist; + } + + /*--- Remove the trailing edge effect ---*/ + + su2double MinPosSens = 0.0; su2double MinNegSens = 0.0; + for (iVertex = 0; iVertex < nVertex; iVertex++) { + Sens = CSensitivity[iMarker][iVertex]; + if (ArchLength[iVertex] > ArchLength[nVertex-1]*0.01) { MinNegSens = Sens; break; } + } + + for (iVertex = 0; iVertex < nVertex; iVertex++) { + Sens = CSensitivity[iMarker][iVertex]; + if (ArchLength[iVertex] > ArchLength[nVertex-1]*0.99) { MinPosSens = Sens; break; } + } + + for (iVertex = 0; iVertex < nVertex; iVertex++) { + if (ArchLength[iVertex] < ArchLength[nVertex-1]*0.01) + CSensitivity[iMarker][iVertex] = MinNegSens; + if (ArchLength[iVertex] > ArchLength[nVertex-1]*0.99) + CSensitivity[iMarker][iVertex] = MinPosSens; + } + + /*--- Set the right hand side of the system ---*/ + + for (iVertex = 0; iVertex < nVertex; iVertex++) { + b[iVertex] = CSensitivity[iMarker][iVertex]; + } + + /*--- Set the mass matrix ---*/ + + su2double Coeff = 0.0, BackDiff = 0.0, ForwDiff = 0.0, CentDiff = 0.0; + su2double epsilon = 5E-5; + for (iVertex = 0; iVertex < nVertex; iVertex++) { + + if ((iVertex != nVertex-1) && (iVertex != 0)) { + BackDiff = (ArchLength[iVertex]-ArchLength[iVertex-1]); + ForwDiff = (ArchLength[iVertex+1]-ArchLength[iVertex]); + CentDiff = (ArchLength[iVertex+1]-ArchLength[iVertex-1]); + } + if (iVertex == nVertex-1) { + BackDiff = (ArchLength[nVertex-1]-ArchLength[nVertex-2]); + ForwDiff = (ArchLength[0]-ArchLength[nVertex-1]); + CentDiff = (ArchLength[0]-ArchLength[nVertex-2]); + } + if (iVertex == 0) { + BackDiff = (ArchLength[0]-ArchLength[nVertex-1]); + ForwDiff = (ArchLength[1]-ArchLength[0]); + CentDiff = (ArchLength[1]-ArchLength[nVertex-1]); + } + + Coeff = epsilon*2.0/(BackDiff*ForwDiff*CentDiff); + + A[iVertex][iVertex] = Coeff*CentDiff; + + if (iVertex != 0) A[iVertex][iVertex-1] = -Coeff*ForwDiff; + else A[iVertex][nVertex-1] = -Coeff*ForwDiff; + + if (iVertex != nVertex-1) A[iVertex][iVertex+1] = -Coeff*BackDiff; + else A[iVertex][0] = -Coeff*BackDiff; + + } + + /*--- Add the gradient value in the main diagonal ---*/ + + for (iVertex = 0; iVertex < nVertex; iVertex++) + A[iVertex][iVertex] += 1.0; + + /*--- Dirichlet boundary condition ---*/ + + unsigned long iVertex = SU2_TYPE::Int(nVertex/2); + A[iVertex][iVertex] = 1.0; + A[iVertex][iVertex+1] = 0.0; + A[iVertex][iVertex-1] = 0.0; + + Gauss_Elimination(A, b, (unsigned short)nVertex); + + /*--- Set the new value of the sensitiviy ---*/ + + for (iVertex = 0; iVertex < nVertex; iVertex++) + CSensitivity[iMarker][iVertex] = b[iVertex]; + + /*--- Deallocate the linear system ---*/ + + for (iVertex = 0; iVertex < nVertex; iVertex++) + delete [] A[iVertex]; + delete [] A; + delete [] b; + delete [] ArchLength; + + } + } + + +} + +void CAdjEulerSolver::GetEngine_Properties(CGeometry *geometry, CConfig *config, unsigned short iMesh, bool Output) { + unsigned short iDim, iMarker, iVar; + unsigned long iVertex, iPoint; + su2double Area, Flow_Dir[3], alpha; + + unsigned short nMarker_EngineInflow = config->GetnMarker_EngineInflow(); + unsigned short nMarker_EngineBleed = config->GetnMarker_EngineBleed(); + unsigned short nMarker_EngineExhaust = config->GetnMarker_EngineExhaust(); + + if ((nMarker_EngineInflow != 0) || (nMarker_EngineBleed != 0) || (nMarker_EngineExhaust != 0)) { + + /*--- Check the flow orientation in the nacelle inflow ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == ENGINE_EXHAUST) || (config->GetMarker_All_KindBC(iMarker) == ENGINE_BLEED)) { + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[iMarker][iVertex]->GetNormal(Vector); + + for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = -Vector[iDim]; + + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Area += Vector[iDim]*Vector[iDim]; + Area = sqrt (Area); + + /*--- Compute unitary vector ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + Vector[iDim] /= Area; + + /*--- The flow direction is defined by the local velocity on the surface ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + Flow_Dir[iDim] = node[iPoint]->GetSolution(iDim+1) / node[iPoint]->GetSolution(0); + + /*--- Dot product of normal and flow direction. ---*/ + + alpha = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + alpha += Vector[iDim]*Flow_Dir[iDim]; + + /*--- Flow in the wrong direction. ---*/ + + if (alpha < 0.0) { + + /*--- Copy the old solution ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetSolution(iVar, node[iPoint]->GetSolution_Old(iVar)); + + } + + } + } + + } + + } + +} + +void CAdjEulerSolver::BC_Euler_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, unsigned short val_marker) { + unsigned long iVertex, iPoint; + su2double *d = NULL, *Normal, *U, *Psi_Aux, ProjVel = 0.0, bcn, vn = 0.0, Area, *UnitNormal; + su2double *Velocity, *Psi, Enthalpy = 0.0, sq_vel, phin, phis1, phis2, DensityInc = 0.0, BetaInc2 = 0.0; + unsigned short iDim, iVar, jDim; + + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool grid_movement = config->GetGrid_Movement(); + + UnitNormal = new su2double[nDim]; + Velocity = new su2double[nDim]; + Psi = new su2double[nVar]; + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + Normal = geometry->vertex[val_marker][iVertex]->GetNormal(); + + /*--- Create a copy of the adjoint solution ---*/ + Psi_Aux = node[iPoint]->GetSolution(); + for (iVar = 0; iVar < nVar; iVar++) Psi[iVar] = Psi_Aux[iVar]; + + /*--- Flow solution ---*/ + U = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); + + /*--- Read the value of the objective function ---*/ + d = node[iPoint]->GetForceProj_Vector(); + + /*--- Normal vector computation ---*/ + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; + Area = sqrt(Area); + for (iDim = 0; iDim < nDim; iDim++) UnitNormal[iDim] = -Normal[iDim]/Area; + + + /*--- Compressible solver ---*/ + if (compressible) { + + for (iDim = 0; iDim < nDim; iDim++) + Velocity[iDim] = U[iDim+1] / U[0]; + + Enthalpy = solver_container[FLOW_SOL]->node[iPoint]->GetEnthalpy(); + sq_vel = 0.5*solver_container[FLOW_SOL]->node[iPoint]->GetVelocity2(); + + /*--- Compute projections ---*/ + ProjVel = 0.0; bcn = 0.0; vn = 0.0, phin = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + ProjVel -= Velocity[iDim]*Normal[iDim]; + bcn += d[iDim]*UnitNormal[iDim]; + vn += Velocity[iDim]*UnitNormal[iDim]; + phin += Psi[iDim+1]*UnitNormal[iDim]; + } + + /*--- Extra boundary term for grid movement ---*/ + if (grid_movement) { + su2double ProjGridVel = 0.0; + su2double *GridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + ProjGridVel += GridVel[iDim]*UnitNormal[iDim]; + phin -= Psi[nVar-1]*ProjGridVel; + } + + /*--- Introduce the boundary condition ---*/ + for (iDim = 0; iDim < nDim; iDim++) + Psi[iDim+1] -= ( phin - bcn ) * UnitNormal[iDim]; + + /*--- Inner products after introducing BC (Psi has changed) ---*/ + phis1 = 0.0; phis2 = Psi[0] + Enthalpy * Psi[nVar-1]; + for (iDim = 0; iDim < nDim; iDim++) { + phis1 -= Normal[iDim]*Psi[iDim+1]; + phis2 += Velocity[iDim]*Psi[iDim+1]; + } + + /*--- Flux of the Euler wall ---*/ + Residual[0] = ProjVel * Psi[0] - phis2 * ProjVel + phis1 * Gamma_Minus_One * sq_vel; + for (iDim = 0; iDim < nDim; iDim++) + Residual[iDim+1] = ProjVel * Psi[iDim+1] - phis2 * Normal[iDim] - phis1 * Gamma_Minus_One * Velocity[iDim]; + Residual[nVar-1] = ProjVel * Psi[nVar-1] + phis1 * Gamma_Minus_One; + + /*--- Flux adjustment for grid movement ---*/ + if (grid_movement) { + su2double ProjGridVel = 0.0; + su2double *GridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + ProjGridVel -= GridVel[iDim]*Normal[iDim]; + Residual[0] -= ProjGridVel*Psi[0]; + for (iDim = 0; iDim < nDim; iDim++) + Residual[iDim+1] -= ProjGridVel*Psi[iDim+1]; + Residual[nVar-1] -= ProjGridVel*Psi[nVar-1]; + } + + if (implicit) { + + /*--- Adjoint density ---*/ + Jacobian_ii[0][0] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Jacobian_ii[0][iDim+1] = -ProjVel * (Velocity[iDim] - UnitNormal[iDim] * vn); + Jacobian_ii[0][nVar-1] = -ProjVel * Enthalpy; + + /*--- Adjoint velocities ---*/ + for (iDim = 0; iDim < nDim; iDim++) { + Jacobian_ii[iDim+1][0] = -Normal[iDim]; + for (jDim = 0; jDim < nDim; jDim++) + Jacobian_ii[iDim+1][jDim+1] = -ProjVel*(UnitNormal[jDim]*UnitNormal[iDim] - Normal[iDim] * (Velocity[jDim] - UnitNormal[jDim] * vn)); + Jacobian_ii[iDim+1][iDim+1] += ProjVel; + Jacobian_ii[iDim+1][nVar-1] = -Normal[iDim] * Enthalpy; + } + + /*--- Adjoint energy ---*/ + Jacobian_ii[nVar-1][0] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Jacobian_ii[nVar-1][iDim+1] = 0.0; + Jacobian_ii[nVar-1][nVar-1] = ProjVel; + + /*--- Jacobian contribution due to grid movement ---*/ + if (grid_movement) { + su2double ProjGridVel = 0.0; + su2double *GridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + ProjGridVel -= GridVel[iDim]*Normal[iDim]; + Jacobian_ii[0][0] -= ProjGridVel; + for (iDim = 0; iDim < nDim; iDim++) + Jacobian_ii[iDim+1][iDim+1] -= ProjGridVel; + Jacobian_ii[nVar-1][nVar-1] -= ProjGridVel; + } + + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + } + + /*--- Update residual ---*/ + LinSysRes.SubtractBlock(iPoint, Residual); + + } + /*--- Incompressible solver ---*/ + if (incompressible || freesurface) { + + DensityInc = solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); + BetaInc2 = solver_container[FLOW_SOL]->node[iPoint]->GetBetaInc2(); + + for (iDim = 0; iDim < nDim; iDim++) + Velocity[iDim] = U[iDim+1] / solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); + + /*--- Compute projections ---*/ + bcn = 0.0; phin = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + bcn += d[iDim]*UnitNormal[iDim]; + phin += Psi[iDim+1]*UnitNormal[iDim]; + } + + /*--- Introduce the boundary condition ---*/ + for (iDim = 0; iDim < nDim; iDim++) + Psi[iDim+1] -= ( phin - bcn ) * UnitNormal[iDim]; + + /*--- Inner products after introducing BC (Psi has changed) ---*/ + phis1 = 0.0; phis2 = Psi[0] * (BetaInc2 / DensityInc); + for (iDim = 0; iDim < nDim; iDim++) { + phis1 -= Normal[iDim]*Psi[iDim+1]; + phis2 += Velocity[iDim]*Psi[iDim+1]; + } + + /*--- Flux of the Euler wall ---*/ + Residual[0] = phis1; + for (iDim = 0; iDim < nDim; iDim++) + Residual[iDim+1] = - phis2 * Normal[iDim]; + + /*--- Update residual ---*/ + LinSysRes.SubtractBlock(iPoint, Residual); + + if (implicit) { + + /*--- Adjoint density ---*/ + Jacobian_ii[0][0] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Jacobian_ii[0][iDim+1] = - Normal[iDim]; + + /*--- Adjoint velocities ---*/ + for (iDim = 0; iDim < nDim; iDim++) { + Jacobian_ii[iDim+1][0] = -Normal[iDim] * (BetaInc2 / DensityInc) ; + for (jDim = 0; jDim < nDim; jDim++) + Jacobian_ii[iDim+1][jDim+1] = - Normal[iDim] * Velocity[jDim]; + } + + /*--- Update Jacobian ---*/ + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + } + + } + + } + } + + delete [] Velocity; + delete [] UnitNormal; + delete [] Psi; + +} + +void CAdjEulerSolver::BC_Sym_Plane(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, + CConfig *config, unsigned short val_marker) { + + unsigned long iVertex, iPoint; + su2double *Normal, ProjVel = 0.0, vn = 0.0, Area, *UnitNormal, + *V_domain, *V_sym, *Psi_domain, *Psi_sym, *Velocity, Enthalpy = 0.0, + sq_vel, phin, phis1, phis2, NormalAdjVel; + unsigned short iDim, iVar, jDim; + + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool grid_movement = config->GetGrid_Movement(); + + Normal = new su2double[nDim]; + UnitNormal = new su2double[nDim]; + Velocity = new su2double[nDim]; + Psi_domain = new su2double[nVar]; + Psi_sym = new su2double[nVar]; + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + + Area = 0; + for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; + Area = sqrt(Area); + + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] = -Normal[iDim]/Area; + + if (compressible) { + + /*--- Create a copy of the adjoint solution ---*/ + + for (iVar = 0; iVar < nVar; iVar++) Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); + + /*--- Retrieve flow variables ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + Velocity[iDim] = solver_container[FLOW_SOL]->node[iPoint]->GetVelocity(iDim); + + Enthalpy = solver_container[FLOW_SOL]->node[iPoint]->GetEnthalpy(); + sq_vel = 0.5*solver_container[FLOW_SOL]->node[iPoint]->GetVelocity2(); + + /*--- Compute projections ---*/ + + ProjVel = 0.0; vn = 0.0, phin = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + ProjVel -= Velocity[iDim]*Normal[iDim]; + vn += Velocity[iDim]*UnitNormal[iDim]; + phin += Psi_domain[iDim+1]*UnitNormal[iDim]; + } + + /*--- Grid Movement ---*/ + + if (grid_movement) { + su2double ProjGridVel = 0.0; + su2double *GridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) { + ProjGridVel += GridVel[iDim]*UnitNormal[iDim]; + } + phin -= Psi_domain[nVar-1]*ProjGridVel; + } + + /*--- Introduce the boundary condition ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + Psi_domain[iDim+1] -= phin * UnitNormal[iDim]; + + /*--- Inner products after introducing BC (Psi has changed) ---*/ + + phis1 = 0.0; phis2 = Psi_domain[0] + Enthalpy * Psi_domain[nVar-1]; + for (iDim = 0; iDim < nDim; iDim++) { + phis1 -= Normal[iDim]*Psi_domain[iDim+1]; + phis2 += Velocity[iDim]*Psi_domain[iDim+1]; + } + + /*--- Flux of the Euler wall ---*/ + + Residual_i[0] = ProjVel * Psi_domain[0] - phis2 * ProjVel + phis1 * Gamma_Minus_One * sq_vel; + for (iDim = 0; iDim < nDim; iDim++) + Residual_i[iDim+1] = ProjVel * Psi_domain[iDim+1] - phis2 * Normal[iDim] - phis1 * Gamma_Minus_One * Velocity[iDim]; + Residual_i[nVar-1] = ProjVel * Psi_domain[nVar-1] + phis1 * Gamma_Minus_One; + + /*--- Grid Movement ---*/ + + if (grid_movement) { + su2double ProjGridVel = 0.0; + su2double *GridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + ProjGridVel -= GridVel[iDim]*Normal[iDim]; + Residual_i[0] -= ProjGridVel*Psi_domain[0]; + for (iDim = 0; iDim < nDim; iDim++) + Residual_i[iDim+1] -= ProjGridVel*Psi_domain[iDim+1]; + Residual_i[nVar-1] -= ProjGridVel*Psi_domain[nVar-1]; + } + + } + + if (incompressible || freesurface) { + + /*--- Set the normal vector ---*/ + + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + /*--- Retrieve solution at boundary node ---*/ + + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + V_sym = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + conv_numerics->SetPrimitive(V_domain, V_sym); + + /*--- Adjoint flow solution at the wall ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); + Psi_sym[iVar] = node[iPoint]->GetSolution(iVar); + } + + /*--- Compute normal component of the adjoint velocity ---*/ + + NormalAdjVel = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + NormalAdjVel += Psi_domain[iDim+1]*UnitNormal[iDim]; + + /*--- Remove the normal component ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + Psi_sym[iDim+1] -= NormalAdjVel*UnitNormal[iDim]; + + /*--- Set the value of the adjoint variables ---*/ + + conv_numerics->SetAdjointVar(Psi_domain, Psi_sym); + + /*--- Compute the upwind flux ---*/ + + conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + } + + /*--- Update residual ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual_i); + + /*--- Implicit stuff ---*/ + + if (implicit) { + + if (compressible) { + + /*--- Adjoint density ---*/ + + Jacobian_ii[0][0] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Jacobian_ii[0][iDim+1] = -ProjVel * (Velocity[iDim] - UnitNormal[iDim] * vn); + Jacobian_ii[0][nVar-1] = -ProjVel * Enthalpy; + + /*--- Adjoint velocities ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + Jacobian_ii[iDim+1][0] = -Normal[iDim]; + for (jDim = 0; jDim < nDim; jDim++) + Jacobian_ii[iDim+1][jDim+1] = -ProjVel*(UnitNormal[jDim]*UnitNormal[iDim] - Normal[iDim] * (Velocity[jDim] - UnitNormal[jDim] * vn)); + Jacobian_ii[iDim+1][iDim+1] += ProjVel; + Jacobian_ii[iDim+1][nVar-1] = -Normal[iDim] * Enthalpy; + } + + /*--- Adjoint energy ---*/ + + Jacobian_ii[nVar-1][0] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Jacobian_ii[nVar-1][iDim+1] = 0.0; + Jacobian_ii[nVar-1][nVar-1] = ProjVel; + + /*--- Contribution from grid movement ---*/ + + if (grid_movement) { + su2double ProjGridVel = 0.0; + su2double *GridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + ProjGridVel -= GridVel[iDim]*Normal[iDim]; + Jacobian_ii[0][0] -= ProjGridVel; + for (iDim = 0; iDim < nDim; iDim++) + Jacobian_ii[iDim+1][iDim+1] -= ProjGridVel; + Jacobian_ii[nVar-1][nVar-1] -= ProjGridVel; + } + } + + /*--- Update jacobian ---*/ + + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + } + + } + } + + delete [] Velocity; + delete [] Psi_domain; + delete [] Psi_sym; + delete [] Normal; + delete [] UnitNormal; + +} + +void CAdjEulerSolver::BC_Interface_Boundary(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config) { + + unsigned long iVertex, iPoint, jPoint; + unsigned short iDim, iVar, iMarker; + su2double *V_i, *V_j; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + + su2double *Normal = new su2double[nDim]; + su2double *Psi_i = new su2double[nVar]; + su2double *Psi_j = new su2double[nVar]; + +#ifndef HAVE_MPI + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) { + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + jPoint = geometry->vertex[iMarker][iVertex]->GetDonorPoint(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Adjoint variables w/o reconstruction ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + Psi_i[iVar] = node[iPoint]->GetSolution(iVar); + Psi_j[iVar] = node[jPoint]->GetSolution(iVar); + } + numerics->SetAdjointVar(Psi_i, Psi_j); + + /*--- Conservative variables w/o reconstruction ---*/ + + V_i = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + V_j = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + numerics->SetPrimitive(V_i, V_j); + + /*--- Set face vector, and area ---*/ + + geometry->vertex[iMarker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + numerics->SetNormal(Normal); + + /*--- Compute residual ---*/ + + numerics->ComputeResidual(Res_Conv_i, Res_Conv_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + /*--- Add Residuals and Jacobians ---*/ + + LinSysRes.SubtractBlock(iPoint, Res_Conv_i); + if (implicit) Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + } + } + } + } + +#else + + int rank, jProcessor; + MPI_Status send_stat[1], recv_stat[1]; + MPI_Request send_req[1], recv_req[1]; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + bool compute; + su2double *Buffer_Send_Psi = new su2double[nVar]; + su2double *Buffer_Receive_Psi = new su2double[nVar]; + + /*--- Do the send process, by the moment we are sending each + node individually, this must be changed ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) { + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Find the associate pair to the original node ---*/ + + jPoint = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; + jProcessor = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; + + if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; + else compute = true; + + /*--- We only send the information that belong to other boundary ---*/ + + if (compute) { + + if (jProcessor != rank) { + + /*--- Copy the adjoint variable ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_Psi[iVar] = node[iPoint]->GetSolution(iVar); + + SU2_MPI::Isend(Buffer_Send_Psi, nVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD, &send_req[0]); + + /*--- Wait for this set of non-blocking comm. to complete ---*/ + + SU2_MPI::Waitall(1, send_req, send_stat); + + } + + } + + } + } + + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Find the associate pair to the original node ---*/ + + jPoint = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; + jProcessor = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; + + if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; + else compute = true; + + if (compute) { + + /*--- We only receive the information that belong to other boundary ---*/ + + if (jProcessor != rank) { + + SU2_MPI::Irecv(Buffer_Receive_Psi, nVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &recv_req[0]); + + /*--- Wait for the this set of non-blocking recv's to complete ---*/ + + SU2_MPI::Waitall(1, recv_req, recv_stat); + + } else { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_Psi[iVar] = node[jPoint]->GetSolution(iVar); + } + + /*--- Store the solution for both points ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + Psi_i[iVar] = node[iPoint]->GetSolution(iVar); + Psi_j[iVar] = Buffer_Receive_Psi[iVar]; + } + + /*--- Set adjoint Variables ---*/ + + numerics->SetAdjointVar(Psi_i, Psi_j); + + /*--- Conservative variables w/o reconstruction (the same at both points) ---*/ + + V_i = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + V_j = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + numerics->SetPrimitive(V_i, V_j); + + /*--- Set Normal ---*/ + + geometry->vertex[iMarker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + numerics->SetNormal(Normal); + + /*--- Compute the convective residual using an upwind scheme ---*/ + numerics->ComputeResidual(Res_Conv_i, Res_Conv_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + /*--- Add Residuals and Jacobians ---*/ + + LinSysRes.SubtractBlock(iPoint, Res_Conv_i); + if (implicit) Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + } + + } + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + + delete[] Buffer_Send_Psi; + delete[] Buffer_Receive_Psi; + +#endif + + delete[] Normal; + delete[] Psi_i; + delete[] Psi_j; + +} + +void CAdjEulerSolver::BC_NearField_Boundary(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config) { + + unsigned long iVertex, iPoint, jPoint, Pin, Pout; + unsigned short iDim, iVar, iMarker; + su2double *V_i, *V_j, *IntBoundary_Jump; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + + su2double *Normal = new su2double[nDim]; + su2double *Psi_i = new su2double[nVar]; + su2double *Psi_j = new su2double[nVar]; + su2double *Psi_out = new su2double[nVar]; + su2double *Psi_in = new su2double[nVar]; + su2double *MeanPsi = new su2double[nVar]; + su2double *Psi_out_ghost = new su2double[nVar]; + su2double *Psi_in_ghost = new su2double[nVar]; + + +#ifndef HAVE_MPI + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + jPoint = geometry->vertex[iMarker][iVertex]->GetDonorPoint(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Adjoint variables w/o reconstruction ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + Psi_i[iVar] = node[iPoint]->GetSolution(iVar); + Psi_j[iVar] = node[jPoint]->GetSolution(iVar); + } + + /*--- If equivalent area or nearfield pressure condition ---*/ + + if ((config->GetKind_ObjFunc() == EQUIVALENT_AREA) || + (config->GetKind_ObjFunc() == NEARFIELD_PRESSURE)) { + + /*--- Identify the inner and the outer point (based on the normal direction) ---*/ + + if (Normal[nDim-1] < 0.0) { Pin = iPoint; Pout = jPoint; } + else { Pout = iPoint; Pin = jPoint; } + + for (iVar = 0; iVar < nVar; iVar++) { + Psi_out[iVar] = node[Pout]->GetSolution(iVar); + Psi_in[iVar] = node[Pin]->GetSolution(iVar); + MeanPsi[iVar] = 0.5*(Psi_out[iVar] + Psi_in[iVar]); + } + + IntBoundary_Jump = node[iPoint]->GetIntBoundary_Jump(); + + /*--- Inner point ---*/ + + if (iPoint == Pin) { + for (iVar = 0; iVar < nVar; iVar++) + Psi_in_ghost[iVar] = 2.0*MeanPsi[iVar] - Psi_in[iVar] - IntBoundary_Jump[iVar]; + numerics->SetAdjointVar(Psi_in, Psi_in_ghost); + } + + /*--- Outer point ---*/ + + if (iPoint == Pout) { + for (iVar = 0; iVar < nVar; iVar++) + Psi_out_ghost[iVar] = 2.0*MeanPsi[iVar] - Psi_out[iVar] + IntBoundary_Jump[iVar]; + numerics->SetAdjointVar(Psi_out, Psi_out_ghost); + } + + } + else { + + /*--- Just do a periodic BC ---*/ + + numerics->SetAdjointVar(Psi_i, Psi_j); + + } + + /*--- Conservative variables w/o reconstruction ---*/ + + V_i = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + V_j = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + numerics->SetPrimitive(V_i, V_j); + + /*--- Set Normal ---*/ + + geometry->vertex[iMarker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + numerics->SetNormal(Normal); + + + /*--- Compute residual ---*/ + + numerics->ComputeResidual(Res_Conv_i, Res_Conv_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + /*--- Add Residuals and Jacobians ---*/ + + LinSysRes.SubtractBlock(iPoint, Res_Conv_i); + if (implicit) Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + } + } + } + } + +#else + + int rank, jProcessor; + MPI_Status status; + //MPI_Status send_stat[1], recv_stat[1]; + //MPI_Request send_req[1], recv_req[1]; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + bool compute; + su2double *Buffer_Send_Psi = new su2double[nVar]; + su2double *Buffer_Receive_Psi = new su2double[nVar]; + + /*--- Do the send process, by the moment we are sending each + node individually, this must be changed ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Find the associate pair to the original node ---*/ + + jPoint = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; + jProcessor = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; + + if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; + else compute = true; + + /*--- We only send the information that belong to other boundary ---*/ + if (compute) { + + if (jProcessor != rank) { + + /*--- Copy the adjoint variable ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_Psi[iVar] = node[iPoint]->GetSolution(iVar); + + SU2_MPI::Bsend(Buffer_Send_Psi, nVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD); + + // SU2_MPI::Isend(Buffer_Send_Psi, nVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD, &send_req[0]); + + /*--- Wait for this set of non-blocking comm. to complete ---*/ + + // SU2_MPI::Waitall(1, send_req, send_stat); + + } + + } + + } + } + + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Find the associate pair to the original node ---*/ + + jPoint = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; + jProcessor = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; + + if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; + else compute = true; + + if (compute) { + + /*--- We only receive the information that belong to other boundary ---*/ + + if (jProcessor != rank) { + + SU2_MPI::Recv(Buffer_Receive_Psi, nVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &status); + + // SU2_MPI::Irecv(Buffer_Receive_Psi, nVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &recv_req[0]); + + /*--- Wait for the this set of non-blocking recv's to complete ---*/ + + // SU2_MPI::Waitall(1, recv_req, recv_stat); + + } + else { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_Psi[iVar] = node[jPoint]->GetSolution(iVar); + } + + /*--- Store the solution for both points ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + Psi_i[iVar] = node[iPoint]->GetSolution(iVar); + Psi_j[iVar] = Buffer_Receive_Psi[iVar]; + } + + /*--- If equivalent area or nearfield pressure condition ---*/ + + if ((config->GetKind_ObjFunc() == EQUIVALENT_AREA) || + (config->GetKind_ObjFunc() == NEARFIELD_PRESSURE)) { + + /*--- Identify the inner and the outer point (based on the normal direction) ---*/ + + if (Normal[nDim-1] < 0.0) { Pin = iPoint; Pout = jPoint; } + else { Pout = iPoint; Pin = jPoint; } + + IntBoundary_Jump = node[iPoint]->GetIntBoundary_Jump(); + + /*--- Inner point ---*/ + + if (iPoint == Pin) { + for (iVar = 0; iVar < nVar; iVar++) { + Psi_in[iVar] = Psi_i[iVar]; Psi_out[iVar] = Psi_j[iVar]; + MeanPsi[iVar] = 0.5*(Psi_out[iVar] + Psi_in[iVar]); + Psi_in_ghost[iVar] = 2.0*MeanPsi[iVar] - Psi_in[iVar] - IntBoundary_Jump[iVar]; + } + numerics->SetAdjointVar(Psi_in, Psi_in_ghost); + } + + /*--- Outer point ---*/ + + if (iPoint == Pout) { + for (iVar = 0; iVar < nVar; iVar++) { + Psi_in[iVar] = Psi_j[iVar]; Psi_out[iVar] = Psi_i[iVar]; + MeanPsi[iVar] = 0.5*(Psi_out[iVar] + Psi_in[iVar]); + Psi_out_ghost[iVar] = 2.0*MeanPsi[iVar] - Psi_out[iVar] + IntBoundary_Jump[iVar]; + } + numerics->SetAdjointVar(Psi_out, Psi_out_ghost); + } + } + else { + + /*--- Just do a periodic BC ---*/ + + numerics->SetAdjointVar(Psi_i, Psi_j); + + } + + /*--- Conservative variables w/o reconstruction (the same at both points) ---*/ + + V_i = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + V_j = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + numerics->SetPrimitive(V_i, V_j); + + /*--- Set Normal ---*/ + + geometry->vertex[iMarker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + numerics->SetNormal(Normal); + + /*--- Compute residual ---*/ + + numerics->ComputeResidual(Res_Conv_i, Res_Conv_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + /*--- Add Residuals and Jacobians ---*/ + + LinSysRes.SubtractBlock(iPoint, Res_Conv_i); + if (implicit) Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + } + } + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + + delete[] Buffer_Send_Psi; + delete[] Buffer_Receive_Psi; + +#endif + + delete[] Normal; + delete[] Psi_i; + delete[] Psi_j; + delete[] Psi_out; + delete[] Psi_in; + delete[] MeanPsi; + delete[] Psi_out_ghost; + delete[] Psi_in_ghost; + + +} + +void CAdjEulerSolver::BC_Far_Field(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned long iVertex, iPoint, Point_Normal; + unsigned short iVar, iDim; + su2double *Normal, *V_domain, *V_infty, *Psi_domain, *Psi_infty; + + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + bool grid_movement = config->GetGrid_Movement(); + + Normal = new su2double[nDim]; + Psi_domain = new su2double[nVar]; Psi_infty = new su2double[nVar]; + + /*--- Loop over all the vertices ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- If the node belongs to the domain ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Index of the closest interior node ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Set the normal vector ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + /*--- Allocate the value at the infinity ---*/ + + V_infty = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); + + /*--- Retrieve solution at the farfield boundary node ---*/ + + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + conv_numerics->SetPrimitive(V_domain, V_infty); + + /*--- Adjoint flow solution at the wall ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); + Psi_infty[iVar] = 0.0; + } + conv_numerics->SetAdjointVar(Psi_domain, Psi_infty); + + /*--- Grid Movement ---*/ + + if (grid_movement) + conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[iPoint]->GetGridVel()); + + /*--- Compute the upwind flux ---*/ + + conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + /*--- Add and Subtract Residual ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual_i); + + /*--- Implicit contribution to the residual ---*/ + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + /*--- Viscous residual contribution, it doesn't work ---*/ + + if (config->GetViscous()) { + + /*--- Points in edge, coordinates and normal vector---*/ + + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + visc_numerics->SetNormal(Normal); + + /*--- Conservative variables w/o reconstruction and adjoint variables w/o reconstruction---*/ + + visc_numerics->SetPrimitive(V_domain, V_infty); + visc_numerics->SetAdjointVar(Psi_domain, Psi_infty); + + /*--- Gradient and limiter of Adjoint Variables ---*/ + + visc_numerics->SetAdjointVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); + + /*--- Compute residual ---*/ + + visc_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + /*--- Update adjoint viscous residual ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual_i); + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + } + + } + } + + delete [] Normal; + delete [] Psi_domain; delete [] Psi_infty; +} + +void CAdjEulerSolver::BC_Supersonic_Inlet(CGeometry *geometry, CSolver **solver_container, + CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + unsigned short iVar, iDim; + unsigned long iVertex, iPoint, Point_Normal; + su2double *V_inlet, *V_domain, *Normal, *Psi_domain, *Psi_inlet; + + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + bool grid_movement = config->GetGrid_Movement(); + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + + Normal = new su2double[nDim]; + Psi_domain = new su2double[nVar]; Psi_inlet = new su2double[nVar]; + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check that the node belongs to the domain (i.e., not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + /*--- Allocate the value at the inlet ---*/ + + V_inlet = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); + + /*--- Retrieve solution at the boundary node ---*/ + + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + /*--- Adjoint flow solution at the boundary ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); + + /*--- Construct the flow & adjoint states at the inlet ---*/ + /*--- Supersonic Inlet: All characteristic are exiting: using nearest neighbor to set value ---*/ + for (iVar = 0; iVar < nVar; iVar++) + Psi_inlet[iVar] = Psi_domain[iVar]; + + /*--- Set the flow and adjoint states in the solver ---*/ + + conv_numerics->SetPrimitive(V_domain, V_inlet); + conv_numerics->SetAdjointVar(Psi_domain, Psi_inlet); + + /*--- Grid Movement ---*/ + + if (grid_movement) + conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), + geometry->node[iPoint]->GetGridVel()); + + /*--- Compute the residual using an upwind scheme ---*/ + + conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, + Jacobian_ji, Jacobian_jj, config); + + /*--- Add and Subtract Residual ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual_i); + + /*--- Implicit contribution to the residual ---*/ + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + /*--- Viscous residual contribution, it doesn't work ---*/ + + if (config->GetViscous()) { + + /*--- Index of the closest interior node ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Points in edge, coordinates and normal vector---*/ + + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + visc_numerics->SetNormal(Normal); + + /*--- Conservative variables w/o reconstruction and adjoint variables w/o reconstruction---*/ + + visc_numerics->SetPrimitive(V_domain, V_inlet); + visc_numerics->SetAdjointVar(Psi_domain, Psi_inlet); + + /*--- Gradient and limiter of Adjoint Variables ---*/ + + visc_numerics->SetAdjointVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); + + /*--- Compute residual ---*/ + + visc_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + /*--- Update adjoint viscous residual ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual_i); + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + } + } + } + + /*--- Free locally allocated memory ---*/ + + delete [] Normal; + delete [] Psi_domain; delete [] Psi_inlet; + +} + +void CAdjEulerSolver::BC_Supersonic_Outlet(CGeometry *geometry, CSolver **solver_container, + CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + unsigned short iVar, iDim; + unsigned long iVertex, iPoint, Point_Normal; + su2double *V_outlet, *V_domain, *Normal, *Psi_domain, *Psi_outlet; + + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + bool grid_movement = config->GetGrid_Movement(); + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + + Normal = new su2double[nDim]; + Psi_domain = new su2double[nVar]; Psi_outlet = new su2double[nVar]; + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check that the node belongs to the domain (i.e., not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + /*--- Allocate the value at the inlet ---*/ + + V_outlet = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); + + /*--- Retrieve solution at the boundary node ---*/ + + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + /*--- Adjoint flow solution at the boundary ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); + + /*--- Construct the flow & adjoint states at the inlet ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Psi_outlet[iVar] = 0.0; + + /*--- Set the flow and adjoint states in the solver ---*/ + + conv_numerics->SetPrimitive(V_domain, V_outlet); + conv_numerics->SetAdjointVar(Psi_domain, Psi_outlet); + + /*--- Grid Movement ---*/ + + if (grid_movement) + conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), + geometry->node[iPoint]->GetGridVel()); + + /*--- Compute the residual using an upwind scheme ---*/ + + conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, + Jacobian_ji, Jacobian_jj, config); + + /*--- Add and Subtract Residual ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual_i); + + /*--- Implicit contribution to the residual ---*/ + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + /*--- Viscous residual contribution (check again, Point_Normal was not being initialized before) ---*/ + + if (config->GetViscous()) { + + /*--- Index of the closest interior node ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Points in edge, coordinates and normal vector---*/ + + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + visc_numerics->SetNormal(Normal); + + /*--- Conservative variables w/o reconstruction and adjoint variables w/o reconstruction---*/ + + visc_numerics->SetPrimitive(V_domain, V_outlet); + visc_numerics->SetAdjointVar(Psi_domain, Psi_outlet); + + /*--- Gradient and limiter of Adjoint Variables ---*/ + + visc_numerics->SetAdjointVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); + + /*--- Compute residual ---*/ + + visc_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + /*--- Update adjoint viscous residual ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual_i); + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + } + } + } + + /*--- Free locally allocated memory ---*/ + + delete [] Normal; + delete [] Psi_domain; delete [] Psi_outlet; + +} + +void CAdjEulerSolver::BC_Inlet(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned short iVar, iDim; + unsigned long iVertex, iPoint, Point_Normal; + su2double Velocity[3], bcn, phin, Area, UnitNormal[3], + ProjGridVel, *GridVel; + su2double *V_inlet, *V_domain, *Normal, *Psi_domain, *Psi_inlet; + + unsigned short Kind_Inlet = config->GetKind_Inlet(); + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool grid_movement = config->GetGrid_Movement(); + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + + Normal = new su2double[nDim]; + Psi_domain = new su2double[nVar]; Psi_inlet = new su2double[nVar]; + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check that the node belongs to the domain (i.e., not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Area += Normal[iDim]*Normal[iDim]; + Area = sqrt (Area); + + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] = Normal[iDim]/Area; + + /*--- Allocate the value at the inlet ---*/ + + V_inlet = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); + + /*--- Retrieve solution at the boundary node ---*/ + + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + /*--- Adjoint flow solution at the boundary ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); + + /*--- Construct the flow & adjoint states at the inlet ---*/ + if (compressible) { + + /*--- Subsonic, compressible inflow: first build the flow state + using the same method as the direct problem. Then, based on + those conservative values, compute the characteristic-based + adjoint boundary condition. The boundary update to be applied + depends on whether total conditions or mass flow are specified. ---*/ + + switch (Kind_Inlet) { + + /*--- Total properties have been specified at the inlet. ---*/ + case TOTAL_CONDITIONS: + + /*--- Adjoint solution at the inlet. Set to zero for now + but should be replaced with derived expression for this type of + inlet. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + Psi_inlet[iVar] = 0.0; + + break; + + /*--- Mass flow has been specified at the inlet. ---*/ + case MASS_FLOW: + + /*--- Get primitives from current inlet state. ---*/ + for (iDim = 0; iDim < nDim; iDim++) + Velocity[iDim] = solver_container[FLOW_SOL]->node[iPoint]->GetVelocity(iDim); + + /*--- Retrieve current adjoint solution values at the boundary ---*/ + for (iVar = 0; iVar < nVar; iVar++) + Psi_inlet[iVar] = node[iPoint]->GetSolution(iVar); + + /*--- Some terms needed for the adjoint BC ---*/ + bcn = 0.0; phin = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + bcn -= (Gamma/Gamma_Minus_One)*Velocity[iDim]*UnitNormal[iDim]; + phin += Psi_domain[iDim+1]*UnitNormal[iDim]; + } + + /*--- Extra boundary term for grid movement ---*/ + if (grid_movement) { + ProjGridVel = 0.0; + GridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + ProjGridVel += GridVel[iDim]*UnitNormal[iDim]; + bcn -= (1.0/Gamma_Minus_One)*ProjGridVel; + } + + /*--- Impose value for PsiE based on hand-derived expression. ---*/ + Psi_inlet[nVar-1] = -phin*(1.0/bcn); + + break; + } + + } + + if (incompressible || freesurface) { + + /*--- Adjoint solution at the inlet ---*/ + + Psi_inlet[0] = node[iPoint]->GetSolution(0); + for (iDim = 0; iDim < nDim; iDim++) + Psi_inlet[iDim+1] = 0.0; + + } + + /*--- Set the flow and adjoint states in the solver ---*/ + + conv_numerics->SetPrimitive(V_domain, V_inlet); + conv_numerics->SetAdjointVar(Psi_domain, Psi_inlet); + + /*--- Grid Movement ---*/ + + if (grid_movement) + conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), + geometry->node[iPoint]->GetGridVel()); + + /*--- Compute the residual using an upwind scheme ---*/ + + conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, + Jacobian_ji, Jacobian_jj, config); + + /*--- Add and Subtract Residual ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual_i); + + /*--- Implicit contribution to the residual ---*/ + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + /*--- Viscous residual contribution, it doesn't work ---*/ + + if (config->GetViscous()) { + /*--- Index of the closest interior node ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Points in edge, coordinates and normal vector---*/ + + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + visc_numerics->SetNormal(Normal); + + /*--- Conservative variables w/o reconstruction and adjoint variables w/o reconstruction---*/ + + visc_numerics->SetPrimitive(V_domain, V_inlet); + visc_numerics->SetAdjointVar(Psi_domain, Psi_inlet); + + /*--- Gradient and limiter of Adjoint Variables ---*/ + + visc_numerics->SetAdjointVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); + + /*--- Compute residual ---*/ + + visc_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + /*--- Update adjoint viscous residual ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual_i); + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + } + } + } + + /*--- Free locally allocated memory ---*/ + + delete [] Normal; + delete [] Psi_domain; delete [] Psi_inlet; + +} + +void CAdjEulerSolver::BC_Outlet(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned short iVar, iDim; + unsigned long iVertex, iPoint, Point_Normal; + su2double Pressure=0.0, P_Exit=0.0, Velocity[3], Velocity2 = 0.0; + su2double Density=0.0, Height=0.0; + su2double Vn = 0.0, SoundSpeed = 0.0, LevelSet=0.0, Vn_Exit=0.0, + Riemann=0.0, Entropy=0.0, Density_Outlet = 0.0, Vn_rel=0.0; + su2double Area, UnitNormal[3]; + su2double *V_outlet, *V_domain, *Psi_domain, *Psi_outlet, *Normal; + su2double Mach_Exit_Normal=0.0; + su2double a1=0.0; /*Placeholder terms to simplify expression/ repeated terms*/ + su2double ProjGridVel = 0.0; + su2double densgrad, pressgrad, velgrad; + + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool grid_movement = config->GetGrid_Movement(); + su2double FreeSurface_Zero = config->GetFreeSurface_Zero(); + su2double PressFreeSurface = solver_container[FLOW_SOL]->GetPressure_Inf(); + su2double epsilon = config->GetFreeSurface_Thickness(); + su2double RatioDensity = config->GetRatioDensity(); + su2double Froude = config->GetFroude(); + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + + Psi_domain = new su2double [nVar]; Psi_outlet = new su2double [nVar]; + Normal = new su2double[nDim]; + + /*--- Loop over all the vertices ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- If the node belong to the domain ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Area += Normal[iDim]*Normal[iDim]; + Area = sqrt (Area); + + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] = Normal[iDim]/Area; + + /*--- Set the normal point ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Allocate the value at the outlet ---*/ + + V_outlet = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); + + /*--- Retrieve solution at the boundary node ---*/ + + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + /*--- Adjoint flow solution at the boundary ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); + + /*--- Construct the flow & adjoint states at the outlet ---*/ + + if (compressible) { + + /*--- Retrieve the specified back pressure for this outlet, Non-dim. the inputs if necessary. ---*/ + + P_Exit = config->GetOutlet_Pressure(Marker_Tag); + P_Exit = P_Exit/config->GetPressure_Ref(); + + /*--- Check whether the flow is supersonic at the exit. The type + of boundary update depends on this. ---*/ + + Density = V_domain[nDim+2]; + Velocity2 = 0.0; Vn = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity[iDim] = V_domain[iDim+1]; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + Vn += Velocity[iDim]*UnitNormal[iDim]; + } + /*--- Extra boundary term for grid movement ---*/ + if (grid_movement) { + su2double *GridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + ProjGridVel += GridVel[iDim]*UnitNormal[iDim]; + } + + + Pressure = V_domain[nDim+1]; + SoundSpeed = sqrt(Pressure*Gamma/Density); + Mach_Exit_Normal = Vn/SoundSpeed; + + /*--- Set Adjoint variables to 0 initially ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + Psi_outlet[iVar] = 0.0; + } + + if (Mach_Exit_Normal >= 1.0) { + /*If there is no objective term defined on the outlet, all Psi are 0 (inviscid case) */ + Vn_Exit = Vn; /* Vn_Exit comes from Reiman conditions in subsonic case*/ + Vn_rel = Vn_Exit-ProjGridVel; + /*-- Some common terms --*/ + a1 = SoundSpeed*SoundSpeed/(Vn_rel)/Gamma_Minus_One; + //a4 = Density*Vn_rel*(pow(SoundSpeed,2.0)-pow(Vn_rel,2.0)); + + /*--- Objective-dependent additions to energy term ---*/ + switch (config->GetKind_ObjFunc()){ + case OUTLET_CHAIN_RULE: + velgrad = 0.0; + for (iDim=0; iDimGetCoeff_ObjChainRule(iDim+1)*Area; + densgrad = config->GetCoeff_ObjChainRule(0)*Area; + pressgrad = config->GetCoeff_ObjChainRule(4)*Area; + Psi_outlet[nDim+1]= (Gamma_Minus_One*Mach_Exit_Normal/(pow(Mach_Exit_Normal,2.0)-1)/SoundSpeed)* + (pressgrad-velgrad/Density/Vn_rel+densgrad/pow(Vn_rel,2.0)); + break; + case AVG_TOTAL_PRESSURE: + /*--- Total Pressure term. NOTE: this is AREA averaged + * Additional terms are added later (as they are common between subsonic, + * supersonic equations) ---*/ + Velocity2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity2 += Velocity[iDim]*Velocity[iDim]; + } + Psi_outlet[nDim+1]+=Gamma_Minus_One*Velocity2/(Vn_rel*SoundSpeed*(pow(Vn_rel,2.0)-pow(SoundSpeed,2.0))); + break; + case AVG_OUTLET_PRESSURE: + /*Area averaged static pressure*/ + /*--- Note: further terms are NOT added later for this case, only energy term is modified ---*/ + Psi_outlet[nDim+1]+=Gamma_Minus_One*Vn_rel/(pow(Vn_rel,2.0)-pow(SoundSpeed,2.0)); + break; + default: + break; + } + } else { + /*---Subsonic Case: Psi-rho E term from volume, objective-specific terms which are common + * between subsonic and supersonic cases are added later ---*/ + /*--- Compute Riemann constant ---*/ + Entropy = Pressure*pow(1.0/Density, Gamma); + Riemann = Vn + 2.0*SoundSpeed/Gamma_Minus_One; + + /*--- Compute the new fictious state at the outlet ---*/ + Density = pow(P_Exit/Entropy,1.0/Gamma); + SoundSpeed = sqrt(Gamma*P_Exit/Density); + Vn_Exit = Riemann - 2.0*SoundSpeed/Gamma_Minus_One; + /*--- Update velocity terms ---*/ + Vn_rel = Vn_Exit-ProjGridVel; + Velocity2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity[iDim] = Velocity[iDim] + (Vn_Exit-Vn)*UnitNormal[iDim]; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + } + + /*--- Extra boundary term for grid movement ---*/ + + if (grid_movement) { + su2double ProjGridVel = 0.0; + su2double *GridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + ProjGridVel += GridVel[iDim]*UnitNormal[iDim]; +// Ubn = ProjGridVel; + } + + /*--- Shorthand for repeated term in the boundary conditions ---*/ + + //a1 = Gamma*(P_Exit/(Density*Gamma_Minus_One))/(Vn-Ubn); + a1 = sqrt(Gamma*P_Exit/Density)/(Gamma_Minus_One); + + /*--- Impose values for PsiRho & Phi using PsiE from domain. ---*/ + + Psi_outlet[nVar-1] = Psi_domain[nVar-1]; + + + } + + /*--- When Psi_outlet[nVar-1] is not 0, the other terms of Psi_outlet must be updated ---*/ + /*--- This occurs when subsonic, or for certain objective functions ---*/ + if ( Psi_outlet[nVar-1]!=0.0 ){ + /*--- Shorthand for repeated term in the boundary conditions ---*/ + a1 = SoundSpeed*SoundSpeed/(Vn_rel)/Gamma_Minus_One; + Psi_outlet[0] += Psi_outlet[nVar-1]*(Velocity2*0.5+Vn_Exit*a1); + for (iDim = 0; iDim < nDim; iDim++) { + Psi_outlet[iDim+1] += -Psi_outlet[nVar-1]*(a1*UnitNormal[iDim] + Velocity[iDim]); + } + } + + } + if (incompressible || freesurface) { + + if (freesurface) { + + /*--- Density computation at the exit using the level set function ---*/ + + Height = geometry->node[iPoint]->GetCoord(nDim-1); + LevelSet = Height - FreeSurface_Zero; + + /*--- Pressure computation the density at the exit (imposed) ---*/ + + if (LevelSet < -epsilon) Density_Outlet = config->GetDensity_FreeStreamND(); + if (LevelSet > epsilon) Density_Outlet = RatioDensity*config->GetDensity_FreeStreamND(); + V_outlet[0] = PressFreeSurface + Density_Outlet*((FreeSurface_Zero-Height)/(Froude*Froude)); + + /*--- Neumann condition in the interface for the pressure and density ---*/ + + if (fabs(LevelSet) <= epsilon) { + V_outlet[0] = solver_container[FLOW_SOL]->node[Point_Normal]->GetSolution(0); + Density_Outlet = solver_container[FLOW_SOL]->node[Point_Normal]->GetDensityInc(); + } + + } + + else { + + /*--- Imposed pressure and density ---*/ + + Density_Outlet = solver_container[FLOW_SOL]->GetDensity_Inf(); + V_outlet[0] = solver_container[FLOW_SOL]->GetPressure_Inf(); + + } + + /*--- Neumann condition for the velocity ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + V_outlet[iDim+1] = node[Point_Normal]->GetSolution(iDim+1); + + /*--- Adjoint flow solution at the outlet (hard-coded for size[3] again?) ---*/ + + Psi_outlet[2] = 0.0; + su2double coeff = (2.0*V_domain[1])/ solver_container[FLOW_SOL]->node[Point_Normal]->GetBetaInc2(); + Psi_outlet[1] = node[Point_Normal]->GetSolution(1); + Psi_outlet[0] = -coeff*Psi_outlet[1]; + + } + + /*--- Add terms for objective functions where additions are needed outside the energy term + * Terms which are added to the energy term are taken care of in the supersonic section above ---*/ + switch (config->GetKind_ObjFunc()){ + case MASS_FLOW_RATE: + /*--- For mass_flow objective function add B.C. contribution ---*/ + Psi_outlet[0]+=1; + break; + case OUTLET_CHAIN_RULE: + /* repeated term */ + a1 = 1.0/Density/pow(Vn_rel,2.0); + velgrad = 0.0; + + for (iDim=0; iDimGetCoeff_ObjChainRule(iDim+1)*Area; + densgrad = Density*config->GetCoeff_ObjChainRule(0)*Area; + Psi_outlet[0]+=((Vn_rel+Vn)*densgrad-Vn_rel*velgrad)*a1; + for (iDim=0; iDimGetCoeff_ObjChainRule(iDim+1)*Area); + + break; + case AVG_TOTAL_PRESSURE: + /*--- For total pressure objective function. NOTE: this is AREA averaged term---*/ + a1 = 1.0/2.0/pow(Vn_rel,2.0); + Velocity2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity[iDim] = Velocity[iDim] + (Vn_Exit-Vn)*UnitNormal[iDim]; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + } + Psi_outlet[0]+=0; //2.0*Velocity2/Vn_rel; + for (iDim = 0; iDim < nDim; iDim++) { + Psi_outlet[iDim+1] +=(Velocity[iDim]/Vn_rel-UnitNormal[iDim]*Velocity2*a1); + } + break; + default: + break; + } + + /*--- Set the flow and adjoint states in the solver ---*/ + + conv_numerics->SetPrimitive(V_domain, V_outlet); + conv_numerics->SetAdjointVar(Psi_domain, Psi_outlet); + + /*--- Grid Movement ---*/ + + if (grid_movement) + conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), + geometry->node[iPoint]->GetGridVel()); + + conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, + Jacobian_ji, Jacobian_jj, config); + + /*--- Add and Subtract Residual ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual_i); + + /*--- Implicit contribution to the residual ---*/ + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + /*--- Viscous residual contribution, it doesn't work ---*/ + + if (config->GetViscous()) { + + /*--- Set laminar and eddy viscosity at the infinity ---*/ + if (compressible) { + V_outlet[nDim+5] = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); + V_outlet[nDim+6] = solver_container[FLOW_SOL]->node[iPoint]->GetEddyViscosity(); + } + if (incompressible || freesurface) { + V_outlet[nDim+3] = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosityInc(); + V_outlet[nDim+4] = solver_container[FLOW_SOL]->node[iPoint]->GetEddyViscosityInc(); + } + + /*--- Points in edge, coordinates and normal vector---*/ + visc_numerics->SetNormal(Normal); + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + + + /*--- Conservative variables w/o reconstruction and adjoint variables w/o reconstruction---*/ + + visc_numerics->SetPrimitive(V_domain, V_outlet); + visc_numerics->SetAdjointVar(Psi_domain, Psi_outlet); + + /*--- Turbulent kinetic energy ---*/ + if (config->GetKind_Turb_Model() == SST) + visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); + + + /*--- Gradient and limiter of Adjoint Variables ---*/ + + visc_numerics->SetAdjointVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); + + /*--- Compute residual ---*/ + + visc_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + /*--- Update adjoint viscous residual ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual_i); + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + } + } + } + + /*--- Free locally allocated memory ---*/ + + delete [] Normal; + delete [] Psi_domain; delete [] Psi_outlet; + +} + +void CAdjEulerSolver::BC_Engine_Inflow(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + su2double *Normal, *V_domain, *V_inflow, *Psi_domain, *Psi_inflow, P_Fan; + su2double Velocity[3] = {0.0,0.0,0.0}, Velocity2, Density, Vn; + su2double UnitNormal[3] = {0.0,0.0,0.0}, Area, a1; + unsigned short iVar, iDim; + unsigned long iVertex, iPoint; + + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + + Normal = new su2double[nDim]; + Psi_domain = new su2double[nVar]; Psi_inflow = new su2double[nVar]; + + /*--- Loop over all the vertices ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- If the node belong to the domain ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Area += Normal[iDim]*Normal[iDim]; + Area = sqrt (Area); + + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] = Normal[iDim]/Area; + + /*--- Allocate the value at the inflow ---*/ + + V_inflow = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); + + /*--- Retrieve solution at the boundary node ---*/ + + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + /*--- Adjoint flow solution at the boundary ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); + + /*--- Subsonic flow is assumed. ---*/ + + P_Fan = config->GetInflow_Pressure(Marker_Tag); + Density = V_domain[nDim+2]; + Velocity2 = 0.0; Vn = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity[iDim] = V_domain[iDim+1]; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + Vn += Velocity[iDim]*UnitNormal[iDim]; + } + + /*--- Shorthand for repeated term in the boundary conditions ---*/ + + a1 = Gamma*(P_Fan/(Density*Gamma_Minus_One))/Vn; + + /*--- Impose values for PsiRho & Phi using PsiE from domain. ---*/ + + Psi_inflow[nVar-1] = Psi_domain[nVar-1]; + Psi_inflow[0] = 0.5*Psi_inflow[nVar-1]*Velocity2; + for (iDim = 0; iDim < nDim; iDim++) { + Psi_inflow[0] += Psi_inflow[nVar-1]*a1*Velocity[iDim]*UnitNormal[iDim]; + Psi_inflow[iDim+1] = -Psi_inflow[nVar-1]*(a1*UnitNormal[iDim] + Velocity[iDim]); + } + + /*--- Set the flow and adjoint states in the solver ---*/ + + conv_numerics->SetPrimitive(V_domain, V_inflow); + conv_numerics->SetAdjointVar(Psi_domain, Psi_inflow); + + /*--- Compute the residual ---*/ + + conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, + Jacobian_ji, Jacobian_jj, config); + + /*--- Add and Subtract Residual ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual_i); + + /*--- Implicit contribution to the residual ---*/ + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + } + } + + /*--- Free locally allocated memory ---*/ + + delete [] Normal; + delete [] Psi_domain; delete [] Psi_inflow; + +} + +void CAdjEulerSolver::BC_Engine_Bleed(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + su2double *Normal, *V_domain, *V_inflow, *Psi_domain, *Psi_inflow, P_Fan; + su2double Velocity[3] = {0.0,0.0,0.0}, Velocity2, Density, Vn; + su2double UnitNormal[3] = {0.0,0.0,0.0}, Area, a1; + unsigned short iVar, iDim; + unsigned long iVertex, iPoint; + + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + + Normal = new su2double[nDim]; + Psi_domain = new su2double[nVar]; Psi_inflow = new su2double[nVar]; + + /*--- Loop over all the vertices ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- If the node belong to the domain ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Area += Normal[iDim]*Normal[iDim]; + Area = sqrt (Area); + + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] = Normal[iDim]/Area; + + /*--- Allocate the value at the inflow ---*/ + + V_inflow = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); + + /*--- Retrieve solution at the boundary node ---*/ + + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + /*--- Adjoint flow solution at the boundary ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); + + /*--- Subsonic flow is assumed. ---*/ + + P_Fan = config->GetInflow_Pressure(Marker_Tag); + Density = V_domain[nDim+2]; + Velocity2 = 0.0; Vn = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity[iDim] = V_domain[iDim+1]; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + Vn += Velocity[iDim]*UnitNormal[iDim]; + } + + /*--- Shorthand for repeated term in the boundary conditions ---*/ + + a1 = Gamma*(P_Fan/(Density*Gamma_Minus_One))/Vn; + + /*--- Impose values for PsiRho & Phi using PsiE from domain. ---*/ + + Psi_inflow[nVar-1] = Psi_domain[nVar-1]; + Psi_inflow[0] = 0.5*Psi_inflow[nVar-1]*Velocity2; + for (iDim = 0; iDim < nDim; iDim++) { + Psi_inflow[0] += Psi_inflow[nVar-1]*a1*Velocity[iDim]*UnitNormal[iDim]; + Psi_inflow[iDim+1] = -Psi_inflow[nVar-1]*(a1*UnitNormal[iDim] + Velocity[iDim]); + } + + /*--- Set the flow and adjoint states in the solver ---*/ + + conv_numerics->SetPrimitive(V_domain, V_inflow); + conv_numerics->SetAdjointVar(Psi_domain, Psi_inflow); + + /*--- Compute the residual ---*/ + + conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, + Jacobian_ji, Jacobian_jj, config); + + /*--- Add and Subtract Residual ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual_i); + + /*--- Implicit contribution to the residual ---*/ + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + } + } + + /*--- Free locally allocated memory ---*/ + + delete [] Normal; + delete [] Psi_domain; delete [] Psi_inflow; + +} + +void CAdjEulerSolver::BC_Engine_Exhaust(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned long iVertex, iPoint, Point_Normal; + su2double *Normal, *V_domain, *V_exhaust, *Psi_domain, *Psi_exhaust; + unsigned short iVar, iDim; + + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + + Normal = new su2double[nDim]; + Psi_domain = new su2double[nVar]; Psi_exhaust = new su2double[nVar]; + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check that the node belongs to the domain (i.e., not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + /*--- Index of the closest interior node ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Allocate the value at the exhaust ---*/ + + V_exhaust = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); + + /*--- Retrieve solution at the boundary node ---*/ + + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + /*--- Adjoint flow solution at the boundary ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Psi_domain[iVar] = node[iPoint]->GetSolution(iVar); + + /*--- Adjoint flow solution at the exhaust (this should be improved using characteristics bc) ---*/ + + Psi_exhaust[0] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Psi_exhaust[iDim+1] = node[Point_Normal]->GetSolution(iDim+1); + Psi_exhaust[nDim+1] = 0.0; + + /*--- Set the flow and adjoint states in the solver ---*/ + + conv_numerics->SetPrimitive(V_domain, V_exhaust); + conv_numerics->SetAdjointVar(Psi_domain, Psi_exhaust); + + /*--- Compute the residual using an upwind scheme ---*/ + + conv_numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + /*--- Add and Subtract Residual ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual_i); + + /*--- Implicit contribution to the residual ---*/ + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + + } + } + + delete [] Normal; + delete [] Psi_domain; delete [] Psi_exhaust; + +} + +void CAdjEulerSolver::SetResidual_DualTime(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iRKStep, + unsigned short iMesh, unsigned short RunTime_EqSystem) { + unsigned short iVar, jVar; + unsigned long iPoint; + su2double *U_time_nM1, *U_time_n, *U_time_nP1, Volume_nM1, Volume_n, Volume_nP1, TimeStep; + + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + bool FlowEq = (RunTime_EqSystem == RUNTIME_FLOW_SYS); + bool AdjEq = (RunTime_EqSystem == RUNTIME_ADJFLOW_SYS); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool Grid_Movement = config->GetGrid_Movement(); + + /*--- loop over points ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Solution at time n-1, n and n+1 ---*/ + U_time_nM1 = node[iPoint]->GetSolution_time_n1(); + U_time_n = node[iPoint]->GetSolution_time_n(); + U_time_nP1 = node[iPoint]->GetSolution(); + + /*--- Volume at time n-1 and n ---*/ + if (Grid_Movement) { + Volume_nM1 = geometry->node[iPoint]->GetVolume_nM1(); + Volume_n = geometry->node[iPoint]->GetVolume_n(); + Volume_nP1 = geometry->node[iPoint]->GetVolume(); + } + else { + Volume_nM1 = geometry->node[iPoint]->GetVolume(); + Volume_n = geometry->node[iPoint]->GetVolume(); + Volume_nP1 = geometry->node[iPoint]->GetVolume(); + } + + /*--- Time Step ---*/ + TimeStep = config->GetDelta_UnstTimeND(); + + /*--- Compute Residual ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Residual[iVar] = ( U_time_nP1[iVar]*Volume_nP1 - U_time_n[iVar]*Volume_n ) / TimeStep; + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + Residual[iVar] = ( 3.0*U_time_nP1[iVar]*Volume_nP1 - 4.0*U_time_n[iVar]*Volume_n + + 1.0*U_time_nM1[iVar]*Volume_nM1 ) / (2.0*TimeStep); + } + + if (((incompressible || freesurface) && FlowEq) || ((incompressible || freesurface) && AdjEq)) Residual[0] = 0.0; + + /*--- Add Residual ---*/ + LinSysRes.AddBlock(iPoint, Residual); + + if (implicit) { + for (iVar = 0; iVar < nVar; iVar++) { + for (jVar = 0; jVar < nVar; jVar++) + Jacobian_i[iVar][jVar] = 0.0; + + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Jacobian_i[iVar][iVar] = Volume_nP1 / TimeStep; + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + Jacobian_i[iVar][iVar] = (Volume_nP1*3.0)/(2.0*TimeStep); + } + if (((incompressible || freesurface) && FlowEq) || + ((incompressible || freesurface) && AdjEq)) Jacobian_i[0][0] = 0.0; + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + } + } + +} + +CAdjNSSolver::CAdjNSSolver(void) : CAdjEulerSolver() { } + +CAdjNSSolver::CAdjNSSolver(CGeometry *geometry, CConfig *config, unsigned short iMesh) : CAdjEulerSolver() { + unsigned long iPoint, index, iVertex; + string text_line, mesh_filename; + unsigned short iDim, iVar, iMarker, nLineLets; + ifstream restart_file; + string filename, AdjExt; + su2double dull_val, Area=0.0, *Normal = NULL, myArea_Monitored; + bool restart = config->GetRestart(); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Norm heat flux objective test ---*/ + + pnorm = 10; + + /*--- Set the gamma value ---*/ + + Gamma = config->GetGamma(); + Gamma_Minus_One = Gamma - 1.0; + + /*--- Define geometry constants in the solver structure ---*/ + + nDim = geometry->GetnDim(); + nMarker = config->GetnMarker_All(); + nPoint = geometry->GetnPoint(); + nPointDomain = geometry->GetnPointDomain(); + + if (compressible) { nVar = nDim + 2; } + if (incompressible) { nVar = nDim + 1; } + if (freesurface) { nVar = nDim + 1; } + + node = new CVariable*[nPoint]; + + /*--- Define some auxiliary arrays related to the residual ---*/ + + Point_Max = new unsigned long[nVar]; for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; + Point_Max_Coord = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Point_Max_Coord[iVar] = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; + } + Residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; + Residual_RMS = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_RMS[iVar] = 0.0; + Residual_Max = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_Max[iVar] = 0.0; + Residual_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_i[iVar] = 0.0; + Residual_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_j[iVar] = 0.0; + Res_Conv_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Conv_i[iVar] = 0.0; + Res_Visc_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Visc_i[iVar] = 0.0; + Res_Conv_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Conv_j[iVar] = 0.0; + Res_Visc_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Visc_j[iVar] = 0.0; + + /*--- Define some auxiliary arrays related to the solution ---*/ + + Solution = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; + Solution_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_i[iVar] = 0.0; + Solution_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_j[iVar] = 0.0; + + /*--- Define some auxiliary arrays related to the flow solution ---*/ + + FlowPrimVar_i = new su2double[nDim+7]; for (iVar = 0; iVar < nDim+7; iVar++) FlowPrimVar_i[iVar] = 0.0; + FlowPrimVar_j = new su2double[nDim+7]; for (iVar = 0; iVar < nDim+7; iVar++) FlowPrimVar_j[iVar] = 0.0; + + /*--- Define some auxiliary vectors related to the geometry ---*/ + + Vector = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = 0.0; + Vector_i = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_i[iDim] = 0.0; + Vector_j = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_j[iDim] = 0.0; + + /*--- Point to point Jacobians. These are always defined because + they are also used for sensitivity calculations. ---*/ + + Jacobian_i = new su2double* [nVar]; + Jacobian_j = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Jacobian_i[iVar] = new su2double [nVar]; + Jacobian_j[iVar] = new su2double [nVar]; + } + + /*--- Solution and residual vectors ---*/ + + LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); + LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); + + /*--- Jacobians and vector structures for implicit computations ---*/ + + if (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT) { + Jacobian_ii = new su2double*[nVar]; + Jacobian_ij = new su2double*[nVar]; + Jacobian_ji = new su2double*[nVar]; + Jacobian_jj = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Jacobian_ii[iVar] = new su2double[nVar]; + Jacobian_ij[iVar] = new su2double[nVar]; + Jacobian_ji[iVar] = new su2double[nVar]; + Jacobian_jj[iVar] = new su2double[nVar]; + } + if (rank == MASTER_NODE) + cout << "Initialize Jacobian structure (Adjoint N-S). MG level: " << iMesh <<"." << endl; + Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); + + if ((config->GetKind_Linear_Solver_Prec() == LINELET) || + (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { + nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); + if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; + } + + } else { + if (rank == MASTER_NODE) + cout << "Explicit scheme. No Jacobian structure (Adjoint N-S). MG level: " << iMesh <<"." << endl; + } + + /*--- Array structures for computation of gradients by least squares ---*/ + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { + /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ + Smatrix = new su2double* [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Smatrix[iDim] = new su2double [nDim]; + /*--- c vector := transpose(WA)*(Wb) ---*/ + cvector = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + cvector[iVar] = new su2double [nDim]; + } + + /*--- Sensitivity definition and coefficient on all markers ---*/ + CSensitivity = new su2double* [nMarker]; + for (iMarker=0; iMarkernVertex[iMarker]]; + } + Sens_Geo = new su2double[nMarker]; + Sens_Mach = new su2double[nMarker]; + Sens_AoA = new su2double[nMarker]; + Sens_Press = new su2double[nMarker]; + Sens_Temp = new su2double[nMarker]; + Sens_BPress = new su2double[nMarker]; + + /*--- Initialize sensitivities to zero ---*/ + for (iMarker = 0; iMarker < nMarker; iMarker++) { + Sens_Geo[iMarker] = 0.0; + Sens_Mach[iMarker] = 0.0; + Sens_AoA[iMarker] = 0.0; + Sens_Press[iMarker] = 0.0; + Sens_Temp[iMarker] = 0.0; + Sens_BPress[iMarker] = 0.0; + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) + CSensitivity[iMarker][iVertex] = 0.0; + } + + /*--- Initialize the adjoint variables to zero (infinity state) ---*/ + PsiRho_Inf = 0.0; + if ((config->GetKind_ObjFunc() == TOTAL_HEATFLUX) || + (config->GetKind_ObjFunc() == MAXIMUM_HEATFLUX) || + (config->GetKind_ObjFunc() == INVERSE_DESIGN_HEATFLUX)) + PsiE_Inf = -1.0; + else + PsiE_Inf = 0.0; + Phi_Inf = new su2double [nDim]; + Phi_Inf[0] = 0.0; Phi_Inf[1] = 0.0; + if (nDim == 3) Phi_Inf[2] = 0.0; + + if (!restart || (iMesh != MESH_0)) { + /*--- Restart the solution from infinity ---*/ + for (iPoint = 0; iPoint < nPoint; iPoint++) + node[iPoint] = new CAdjNSVariable(PsiRho_Inf, Phi_Inf, PsiE_Inf, nDim, nVar, config); + } + else { + + /*--- Restart the solution from file information ---*/ + mesh_filename = config->GetSolution_AdjFileName(); + filename = config->GetObjFunc_Extension(mesh_filename); + + restart_file.open(filename.data(), ios::in); + + /*--- In case there is no file ---*/ + if (restart_file.fail()) { + if (rank == MASTER_NODE) + cout << "There is no adjoint restart file!! " << filename.data() << "."<< endl; + exit(EXIT_FAILURE); + } + + /*--- In case this is a parallel simulation, we need to perform the + Global2Local index transformation first. ---*/ + long *Global2Local; + Global2Local = new long[geometry->GetGlobal_nPointDomain()]; + /*--- First, set all indices to a negative value by default ---*/ + for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) { + Global2Local[iPoint] = -1; + } + /*--- Now fill array with the transform values only for local points ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; + } + + /*--- Read all lines in the restart file ---*/ + long iPoint_Local; unsigned long iPoint_Global = 0; + + /*--- The first line is the header ---*/ + getline (restart_file, text_line); + + while (getline (restart_file, text_line)) { + istringstream point_line(text_line); + + /*--- Retrieve local index. If this node from the restart file lives + on a different processor, the value of iPoint_Local will be -1. + Otherwise, the local index for this node on the current processor + will be returned and used to instantiate the vars. ---*/ + iPoint_Local = Global2Local[iPoint_Global]; + if (iPoint_Local >= 0) { + if (compressible) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3] >> Solution[4]; + } + if (incompressible) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; + } + if (freesurface) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; + } + node[iPoint_Local] = new CAdjNSVariable(Solution, nDim, nVar, config); + } + iPoint_Global++; + } + + /*--- Instantiate the variable class with an arbitrary solution + at any halo/periodic nodes. The initial solution can be arbitrary, + because a send/recv is performed immediately in the solver. ---*/ + for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { + node[iPoint] = new CAdjNSVariable(Solution, nDim, nVar, config); + } + + /*--- Close the restart file ---*/ + restart_file.close(); + + /*--- Free memory needed for the transformation ---*/ + delete [] Global2Local; + } + + /*--- Calculate area monitored for area-averaged-outflow-quantity-based objectives ---*/ + myArea_Monitored = 0.0; + if (config->GetKind_ObjFunc()==OUTLET_CHAIN_RULE || config->GetKind_ObjFunc()==AVG_TOTAL_PRESSURE || + config->GetKind_ObjFunc()==AVG_OUTLET_PRESSURE){ + for (iMarker =0; iMarker < config->GetnMarker_All(); iMarker++){ + if (config->GetMarker_All_Monitoring(iMarker) == YES){ + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if (geometry->node[iPoint]->GetDomain()) { + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Area += Normal[iDim]*Normal[iDim]; + myArea_Monitored += sqrt (Area); + } + } + } + } + } +#ifdef HAVE_MPI + Area_Monitored = 0.0; + SU2_MPI::Allreduce(&myArea_Monitored, &Area_Monitored, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); +#else + Area_Monitored = myArea_Monitored; +#endif + + /*--- MPI solution ---*/ + Set_MPI_Solution(geometry, config); + +} + +CAdjNSSolver::~CAdjNSSolver(void) { + +} + + +void CAdjNSSolver::SetTime_Step(CGeometry *geometry, CSolver **solver_container, CConfig *config, + unsigned short iMesh, unsigned long Iteration) { + + /*--- Use the flow solution to update the time step + * The time step depends on the characteristic velocity, which is the same + * for the adjoint and flow solutions, albeit in the opposite direction. ---*/ + solver_container[FLOW_SOL]->SetTime_Step(geometry, solver_container, config, iMesh, Iteration); +} + +void CAdjNSSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { + + unsigned long iPoint, ErrorCounter = 0; + su2double SharpEdge_Distance; + bool RightSol = true; + +#ifdef HAVE_MPI + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Retrieve information about the spatial and temporal integration for the + adjoint equations (note that the flow problem may use different methods). ---*/ + + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + bool limiter = (config->GetSpatialOrder_AdjFlow() == SECOND_ORDER_LIMITER); + bool center_jst = (config->GetKind_Centered_AdjFlow() == JST); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool engine = ((config->GetnMarker_EngineInflow() != 0) || (config->GetnMarker_EngineBleed() != 0) || (config->GetnMarker_EngineExhaust() != 0)); + + /*--- Compute nacelle inflow and exhaust properties ---*/ + + if (engine) { GetEngine_Properties(geometry, config, iMesh, Output); } + + /*--- Residual initialization ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint ++) { + + /*--- Get the distance form a sharp edge ---*/ + + SharpEdge_Distance = geometry->node[iPoint]->GetSharpEdge_Distance(); + + /*--- Initialize the non-physical points vector ---*/ + + node[iPoint]->SetNon_Physical(false); + + /*--- Set the primitive variables incompressible and compressible + adjoint variables ---*/ + + if (compressible) RightSol = node[iPoint]->SetPrimVar_Compressible(SharpEdge_Distance, false, config); + if (incompressible) RightSol = node[iPoint]->SetPrimVar_Incompressible(SharpEdge_Distance, false, config); + if (freesurface) RightSol = node[iPoint]->SetPrimVar_FreeSurface(SharpEdge_Distance, false, config); + if (!RightSol) { node[iPoint]->SetNon_Physical(true); ErrorCounter++; } + + /*--- Initialize the convective residual vector ---*/ + + LinSysRes.SetBlock_Zero(iPoint); + + } + + /*--- Compute gradients adj for solution reconstruction and viscous term ---*/ + + if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); + + /*--- Limiter computation (upwind reconstruction) ---*/ + + if (limiter) SetSolution_Limiter(geometry, config); + + /*--- Compute gradients adj for viscous term coupling ---*/ + + if ((config->GetKind_Solver() == ADJ_RANS) && (!config->GetFrozen_Visc())) { + if (config->GetKind_Gradient_Method() == GREEN_GAUSS) solver_container[ADJTURB_SOL]->SetSolution_Gradient_GG(geometry, config); + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) solver_container[ADJTURB_SOL]->SetSolution_Gradient_LS(geometry, config); + } + + /*--- Artificial dissipation for centered schemes ---*/ + + if (center_jst && (iMesh == MESH_0)) { + SetDissipation_Switch(geometry, config); + SetUndivided_Laplacian(geometry, config); + } + + /*--- Initialize the Jacobian for implicit integration ---*/ + + if (implicit) Jacobian.SetValZero(); + + /*--- Error message ---*/ + + if (config->GetConsole_Output_Verb() == VERB_HIGH) { +#ifdef HAVE_MPI + unsigned long MyErrorCounter = ErrorCounter; ErrorCounter = 0; + SU2_MPI::Allreduce(&MyErrorCounter, &ErrorCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); +#endif + if (iMesh == MESH_0) config->SetNonphysical_Points(ErrorCounter); + } + +} + +void CAdjNSSolver::Viscous_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config, unsigned short iMesh, unsigned short iRKStep) { + unsigned long iPoint, jPoint, iEdge; + + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Points in edge, coordinates and normal vector---*/ + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + + numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[jPoint]->GetCoord()); + numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); + + /*--- Primitive variables w/o reconstruction and adjoint variables w/o reconstruction---*/ + + numerics->SetPrimitive(solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(), + solver_container[FLOW_SOL]->node[jPoint]->GetPrimitive()); + + numerics->SetAdjointVar(node[iPoint]->GetSolution(), node[jPoint]->GetSolution()); + + /*--- Gradient and limiter of Adjoint Variables ---*/ + + numerics->SetAdjointVarGradient(node[iPoint]->GetGradient(), node[jPoint]->GetGradient()); + + /*--- Compute residual ---*/ + + numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + /*--- Update adjoint viscous residual ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual_i); + LinSysRes.AddBlock(jPoint, Residual_j); + + if (implicit) { + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + Jacobian.SubtractBlock(iPoint, jPoint, Jacobian_ij); + Jacobian.AddBlock(jPoint, iPoint, Jacobian_ji); + Jacobian.AddBlock(jPoint, jPoint, Jacobian_jj); + } + + } + +} + +void CAdjNSSolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, + CConfig *config, unsigned short iMesh) { + + unsigned long iPoint, jPoint, iEdge; + + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + bool rotating_frame = config->GetRotating_Frame(); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + + /*--- Loop over all the points, note that we are supposing that primitive and + adjoint gradients have been computed previously ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Primitive variables w/o reconstruction, and its gradient ---*/ + + numerics->SetPrimitive(solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(), NULL); + + numerics->SetPrimVarGradient(solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(), NULL); + + /*--- Gradient of adjoint variables ---*/ + + numerics->SetAdjointVarGradient(node[iPoint]->GetGradient(), NULL); + numerics->SetAdjointVarLimiter(node[iPoint]->GetLimiter(), NULL); + + /*--- Set volume ---*/ + + numerics->SetVolume(geometry->node[iPoint]->GetVolume()); + + /*--- If turbulence computation we must add some coupling terms to the NS adjoint eq. ---*/ + + if ((config->GetKind_Solver() == ADJ_RANS) && (!config->GetFrozen_Visc())) { + + /*--- Turbulent variables w/o reconstruction and its gradient ---*/ + + numerics->SetTurbVar(solver_container[TURB_SOL]->node[iPoint]->GetSolution(), NULL); + + numerics->SetTurbVarGradient(solver_container[TURB_SOL]->node[iPoint]->GetGradient(), NULL); + + /*--- Turbulent adjoint variables w/o reconstruction and its gradient ---*/ + + numerics->SetTurbAdjointVar(solver_container[ADJTURB_SOL]->node[iPoint]->GetSolution(), NULL); + + numerics->SetTurbAdjointGradient(solver_container[ADJTURB_SOL]->node[iPoint]->GetGradient(), NULL); + + /*--- Set distance to the surface ---*/ + + numerics->SetDistance(geometry->node[iPoint]->GetWall_Distance(), 0.0); + + } + + /*--- Compute residual ---*/ + + numerics->ComputeResidual(Residual, config); + + /*--- Add to the residual ---*/ + + LinSysRes.AddBlock(iPoint, Residual); + + } + + /*--- If turbulence computation we must add some coupling terms to the NS adjoint eq. ---*/ + + if ((config->GetKind_Solver() == ADJ_RANS) && (!config->GetFrozen_Visc())) { + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Points in edge, and normal vector ---*/ + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + second_numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); + + /*--- Conservative variables w/o reconstruction ---*/ + + second_numerics->SetConservative(solver_container[FLOW_SOL]->node[iPoint]->GetSolution(), + solver_container[FLOW_SOL]->node[jPoint]->GetSolution()); + + /*--- Gradient of primitive variables w/o reconstruction ---*/ + + second_numerics->SetPrimVarGradient(solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(), + solver_container[FLOW_SOL]->node[jPoint]->GetGradient_Primitive()); + + /*--- Viscosity ---*/ + + second_numerics->SetLaminarViscosity(solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(), + solver_container[FLOW_SOL]->node[jPoint]->GetLaminarViscosity()); + + /*--- Turbulent variables w/o reconstruction ---*/ + + second_numerics->SetTurbVar(solver_container[TURB_SOL]->node[iPoint]->GetSolution(), + solver_container[TURB_SOL]->node[jPoint]->GetSolution()); + + /*--- Turbulent adjoint variables w/o reconstruction ---*/ + + second_numerics->SetTurbAdjointVar(solver_container[ADJTURB_SOL]->node[iPoint]->GetSolution(), + solver_container[ADJTURB_SOL]->node[jPoint]->GetSolution()); + + /*--- Set distance to the surface ---*/ + + second_numerics->SetDistance(geometry->node[iPoint]->GetWall_Distance(), geometry->node[jPoint]->GetWall_Distance()); + + /*--- Update adjoint viscous residual ---*/ + + second_numerics->ComputeResidual(Residual, config); + + LinSysRes.AddBlock(iPoint, Residual); + LinSysRes.SubtractBlock(jPoint, Residual); + } + + } + + // WARNING: The rotating frame source term has been placed in the second + // source term container since the section below is commented. This needs a + // permanent fix asap! + + if (rotating_frame) { + + /*--- Loop over all points ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Load the adjoint variables ---*/ + second_numerics->SetAdjointVar(node[iPoint]->GetSolution(), + node[iPoint]->GetSolution()); + + /*--- Load the volume of the dual mesh cell ---*/ + second_numerics->SetVolume(geometry->node[iPoint]->GetVolume()); + + /*--- Compute the adjoint rotating frame source residual ---*/ + second_numerics->ComputeResidual(Residual, Jacobian_i, config); + + /*--- Add the source residual to the total ---*/ + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Add the implicit Jacobian contribution ---*/ + if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + } + } + + if (freesurface) { +// for (iPoint = 0; iPoint < nPointDomain; iPoint++) { +// +// su2double Volume = geometry->node[iPoint]->GetVolume(); +// su2double **Gradient = solver_container[ADJLEVELSET_SOL]->node[iPoint]->GetGradient(); +// su2double coeff = solver_container[LEVELSET_SOL]->node[iPoint]->GetSolution(0) / solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); +// +// Residual[0] = 0.0; +// for (iDim = 0; iDim < nDim; iDim++) { +// Residual[iDim+1] = coeff*Gradient[0][iDim]*Volume; +// } +// +// LinSysRes.AddBlock(iPoint, Residual); +// +// } + } + +} + +void CAdjNSSolver::Viscous_Sensitivity(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config) { + + unsigned long iVertex, iPoint; + unsigned short iDim, jDim, iMarker, iPos, jPos; + su2double *d = NULL, **PsiVar_Grad = NULL, **PrimVar_Grad = NULL, div_phi, *Normal = NULL, Area, + normal_grad_psi5, normal_grad_T, sigma_partial, Laminar_Viscosity = 0.0, heat_flux_factor, LevelSet, Target_LevelSet, temp_sens = 0.0, *Psi = NULL, *U = NULL, Enthalpy, **GridVel_Grad, gradPsi5_v, psi5_tau_partial, psi5_tau_grad_vel, source_v_1, Density, Pressure = 0.0, div_vel, val_turb_ke, vartheta, vartheta_partial, psi5_p_div_vel, Omega[3], rho_v[3] = {0.0,0.0,0.0}, CrossProduct[3], delta[3][3] = {{1.0, 0.0, 0.0},{0.0,1.0,0.0},{0.0,0.0,1.0}}, r, ru, rv, rw, rE, p, T, dp_dr, dp_dru, dp_drv, dp_drw, dp_drE, dH_dr, dH_dru, dH_drv, dH_drw, dH_drE, H, D[3][3], Dd[3], Mach_Inf, eps, scale = 1.0; + su2double RefVel2, RefDensity, Mach2Vel, *Velocity_Inf, factor; + + su2double *USens = new su2double[nVar]; + su2double *UnitNormal = new su2double[nDim]; + su2double *normal_grad_vel = new su2double[nDim]; + su2double *tang_deriv_psi5 = new su2double[nDim]; + su2double *tang_deriv_T = new su2double[nDim]; + su2double **Sigma = new su2double* [nDim]; + + for (iDim = 0; iDim < nDim; iDim++) + Sigma[iDim] = new su2double [nDim]; + + su2double *normal_grad_gridvel = new su2double[nDim]; + su2double *normal_grad_v_ux =new su2double[nDim]; + su2double **Sigma_Psi5v = new su2double* [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Sigma_Psi5v[iDim] = new su2double [nDim]; + su2double **tau = new su2double* [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + tau[iDim] = new su2double [nDim]; + su2double *Velocity = new su2double[nDim]; + + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool rotating_frame = config->GetRotating_Frame(); + bool grid_movement = config->GetGrid_Movement(); + su2double RefAreaCoeff = config->GetRefAreaCoeff(); + su2double Mach_Motion = config->GetMach_Motion(); + unsigned short ObjFunc = config->GetKind_ObjFunc(); + su2double Gas_Constant = config->GetGas_ConstantND(); + su2double Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; + su2double Prandtl_Lam = config->GetPrandtl_Lam(); + + if (config->GetSystemMeasurements() == US) scale = 1.0/12.0; + else scale = 1.0; + + /*--- Compute non-dimensional factor. 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. ---*/ + + if (grid_movement) { + Mach2Vel = sqrt(Gamma*Gas_Constant*config->GetTemperature_FreeStreamND()); + RefVel2 = (Mach_Motion*Mach2Vel)*(Mach_Motion*Mach2Vel); + } + else { + Velocity_Inf = config->GetVelocity_FreeStreamND(); + RefVel2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + RefVel2 += Velocity_Inf[iDim]*Velocity_Inf[iDim]; + } + + RefDensity = config->GetDensity_FreeStreamND(); + + factor = 1.0/(0.5*RefDensity*RefAreaCoeff*RefVel2); + + if ((ObjFunc == INVERSE_DESIGN_HEATFLUX) || (ObjFunc == FREE_SURFACE) || + (ObjFunc == TOTAL_HEATFLUX) || (ObjFunc == MAXIMUM_HEATFLUX) || + (ObjFunc == MASS_FLOW_RATE) ) factor = 1.0; + + if ((ObjFunc == AVG_TOTAL_PRESSURE) || (ObjFunc == AVG_OUTLET_PRESSURE) || + (ObjFunc == OUTLET_CHAIN_RULE)) factor = 1.0/Area_Monitored; + + + /*--- Compute gradient of the grid velocity, if applicable ---*/ + + if (grid_movement) + SetGridVel_Gradient(geometry, config); + + Total_Sens_Geo = 0.0; + Total_Sens_Mach = 0.0; + Total_Sens_AoA = 0.0; + Total_Sens_Press = 0.0; + Total_Sens_Temp = 0.0; + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + Sens_Geo[iMarker] = 0.0; + + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL)) { + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + PsiVar_Grad = node[iPoint]->GetGradient(); + PrimVar_Grad = solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(); + + if (compressible) Laminar_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); + if (incompressible || freesurface) Laminar_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosityInc(); + + heat_flux_factor = Cp * Laminar_Viscosity / Prandtl_Lam; + + /*--- Compute face area and the unit normal to the surface ---*/ + + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) { Area += Normal[iDim]*Normal[iDim]; } Area = sqrt(Area); + for (iDim = 0; iDim < nDim; iDim++) { UnitNormal[iDim] = Normal[iDim] / Area; } + + /*--- Compute the sensitivity related to the temperature ---*/ + + if (compressible) { + + normal_grad_psi5 = 0.0; normal_grad_T = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + normal_grad_psi5 += PsiVar_Grad[nVar-1][iDim]*UnitNormal[iDim]; + normal_grad_T += PrimVar_Grad[0][iDim]*UnitNormal[iDim]; + } + + temp_sens = 0.0; + if (config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) { + + /*--- Heat Flux Term: temp_sens = (\partial_tg \psi_5)\cdot (k \partial_tg T) ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + tang_deriv_psi5[iDim] = PsiVar_Grad[nVar-1][iDim] - normal_grad_psi5*UnitNormal[iDim]; + tang_deriv_T[iDim] = PrimVar_Grad[0][iDim] - normal_grad_T*UnitNormal[iDim]; + } + for (iDim = 0; iDim < nDim; iDim++) + temp_sens += heat_flux_factor * tang_deriv_psi5[iDim] * tang_deriv_T[iDim]; + + } else if (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) { + + /*--- Isothermal Term: temp_sens = - k * \partial_n(\psi_5) * \partial_n(T) ---*/ + + temp_sens = - heat_flux_factor * normal_grad_psi5 * normal_grad_T; + + } + } + if (incompressible || freesurface) { + + /*--- Incompressible case ---*/ + + temp_sens = 0.0; + + } + + /*--- Term: sigma_partial = \Sigma_{ji} n_i \partial_n v_j ---*/ + + if (compressible) { + div_phi = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + div_phi += PsiVar_Grad[iDim+1][iDim]; + for (jDim = 0; jDim < nDim; jDim++) + Sigma[iDim][jDim] = Laminar_Viscosity * (PsiVar_Grad[iDim+1][jDim]+PsiVar_Grad[jDim+1][iDim]); + } + for (iDim = 0; iDim < nDim; iDim++) + Sigma[iDim][iDim] -= TWO3*Laminar_Viscosity * div_phi; + } + if (incompressible || freesurface) { + for (iDim = 0; iDim < nDim; iDim++) { + for (jDim = 0; jDim < nDim; jDim++) + Sigma[iDim][jDim] = Laminar_Viscosity * PsiVar_Grad[jDim+1][iDim]; + } + } + + for (iDim = 0; iDim < nDim; iDim++) { + normal_grad_vel[iDim] = 0.0; + for (jDim = 0; jDim < nDim; jDim++) + normal_grad_vel[iDim] += PrimVar_Grad[iDim+1][jDim]*UnitNormal[jDim]; + } + + sigma_partial = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + for (jDim = 0; jDim < nDim; jDim++) + sigma_partial += UnitNormal[iDim]*Sigma[iDim][jDim]*normal_grad_vel[jDim]; + + /*--- Compute additional terms in the surface sensitivity for + moving walls in a rotating frame or dynamic mesh problem. ---*/ + + if (grid_movement) { + + Psi = node[iPoint]->GetSolution(); + U = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); + Density = U[0]; + if (compressible) Pressure = solver_container[FLOW_SOL]->node[iPoint]->GetPressure(); + if (incompressible || freesurface) Pressure = solver_container[FLOW_SOL]->node[iPoint]->GetPressureInc(); + Enthalpy = solver_container[FLOW_SOL]->node[iPoint]->GetEnthalpy(); + + /*--- Turbulent kinetic energy ---*/ + + if (config->GetKind_Turb_Model() == SST) + val_turb_ke = solver_container[TURB_SOL]->node[iPoint]->GetSolution(0); + else + val_turb_ke = 0.0; + + div_vel = 0.0; + for (iDim = 0 ; iDim < nDim; iDim++) { + Velocity[iDim] = U[iDim+1]/Density; + div_vel += PrimVar_Grad[iDim+1][iDim]; + } + + for (iDim = 0 ; iDim < nDim; iDim++) + for (jDim = 0 ; jDim < nDim; jDim++) + tau[iDim][jDim] = Laminar_Viscosity*(PrimVar_Grad[jDim+1][iDim] + PrimVar_Grad[iDim+1][jDim]) + - TWO3*Laminar_Viscosity*div_vel*delta[iDim][jDim] + - TWO3*Density*val_turb_ke*delta[iDim][jDim]; + + /*--- Form normal_grad_gridvel = \partial_n (u_omega) ---*/ + + GridVel_Grad = geometry->node[iPoint]->GetGridVel_Grad(); + for (iDim = 0; iDim < nDim; iDim++) { + normal_grad_gridvel[iDim] = 0.0; + for (jDim = 0; jDim < nDim; jDim++) + normal_grad_gridvel[iDim] += GridVel_Grad[iDim][jDim]*UnitNormal[jDim]; + } + + /*--- Form normal_grad_v_ux = \partial_n (v - u_omega) ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + normal_grad_v_ux[iDim] = normal_grad_vel[iDim] - normal_grad_gridvel[iDim]; + + /*--- Form Sigma_Psi5v ---*/ + + gradPsi5_v = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + gradPsi5_v += PsiVar_Grad[nDim+1][iDim]*Velocity[iDim]; + for (jDim = 0; jDim < nDim; jDim++) + Sigma_Psi5v[iDim][jDim] = Laminar_Viscosity * (PsiVar_Grad[nDim+1][iDim]*Velocity[jDim]+PsiVar_Grad[nDim+1][jDim]*Velocity[iDim]); + } + for (iDim = 0; iDim < nDim; iDim++) + Sigma_Psi5v[iDim][iDim] -= TWO3*Laminar_Viscosity * gradPsi5_v; + + + /*--- Now compute terms of the surface sensitivity ---*/ + + /*--- Form vartheta_partial = \vartheta * \partial_n (v - u_x) . n ---*/ + vartheta = Density*Psi[0] + Density*Enthalpy*Psi[nDim+1]; + for (iDim = 0; iDim < nDim; iDim++) { + vartheta += U[iDim+1]*Psi[iDim+1]; + } + vartheta_partial = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + vartheta_partial += vartheta * normal_grad_v_ux[iDim] * UnitNormal[iDim]; + + /*--- Form sigma_partial = n_i ( \Sigma_Phi_{ij} + \Sigma_Psi5v_{ij} ) \partial_n (v - u_x)_j ---*/ + + sigma_partial = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + for (jDim = 0; jDim < nDim; jDim++) + sigma_partial += UnitNormal[iDim]*(Sigma[iDim][jDim]+Sigma_Psi5v[iDim][jDim])*normal_grad_v_ux[jDim]; + + /*--- Form psi5_tau_partial = \Psi_5 * \partial_n (v - u_x)_i * tau_{ij} * n_j ---*/ + + psi5_tau_partial = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + for (jDim = 0; jDim < nDim; jDim++) + psi5_tau_partial -= Psi[nDim+1]*normal_grad_v_ux[iDim]*tau[iDim][jDim]*UnitNormal[jDim]; + + /*--- Form psi5_p_div_vel = ---*/ + + psi5_p_div_vel = -Psi[nDim+1]*Pressure*div_vel; + + /*--- Form psi5_tau_grad_vel = \Psi_5 * tau_{ij} : \nabla( v ) ---*/ + + psi5_tau_grad_vel = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + for (jDim = 0; jDim < nDim; jDim++) + psi5_tau_grad_vel += Psi[nDim+1]*tau[iDim][jDim]*PrimVar_Grad[iDim+1][jDim]; + + /*--- Retrieve the angular velocity vector ---*/ + + source_v_1 = 0.0; + if (rotating_frame) { + + Omega[0] = (config->GetRotation_Rate_X(ZONE_0)/config->GetOmega_Ref()); + Omega[1] = (config->GetRotation_Rate_Y(ZONE_0)/config->GetOmega_Ref()); + Omega[2] = (config->GetRotation_Rate_Z(ZONE_0)/config->GetOmega_Ref()); + + /*--- Calculate momentum source terms as: rho * ( Omega X V ) ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + rho_v[iDim] = U[iDim+1]; + if (nDim == 2) rho_v[2] = 0.0; + + CrossProduct[0] = Omega[1]*rho_v[2] - Omega[2]*rho_v[1]; + CrossProduct[1] = Omega[2]*rho_v[0] - Omega[0]*rho_v[2]; + CrossProduct[2] = Omega[0]*rho_v[1] - Omega[1]*rho_v[0]; + + + for (iDim = 0; iDim < nDim; iDim++) { + source_v_1 += Psi[iDim+1]*CrossProduct[iDim]; + } + } + + /*--- For simplicity, store all additional terms within sigma_partial ---*/ + + sigma_partial = sigma_partial + vartheta_partial + psi5_tau_partial + psi5_p_div_vel + psi5_tau_grad_vel + source_v_1; + + } + + /*--- Compute additional term in the surface sensitivity for free surface problem. ---*/ + + if (freesurface) { + LevelSet = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(nDim+1); + Target_LevelSet = geometry->node[iPoint]->GetCoord(nDim-1); + sigma_partial += 0.5*(Target_LevelSet - LevelSet)*(Target_LevelSet - LevelSet); + } + + /*--- Compute sensitivity for each surface point ---*/ + + CSensitivity[iMarker][iVertex] = (sigma_partial - temp_sens) * Area * scale * factor; + + /*--- Change the sign of the sensitivity if the normal has been flipped --*/ + + if (geometry->node[iPoint]->GetFlip_Orientation()) + CSensitivity[iMarker][iVertex] = -CSensitivity[iMarker][iVertex]; + + /*--- If sharp edge, set the sensitivity to 0 on that region ---*/ + + if (config->GetSens_Remove_Sharp()) { + eps = config->GetLimiterCoeff()*config->GetRefElemLength(); + if ( geometry->node[iPoint]->GetSharpEdge_Distance() < config->GetSharpEdgesCoeff()*eps ) + CSensitivity[iMarker][iVertex] = 0.0; + } + + Sens_Geo[iMarker] -= CSensitivity[iMarker][iVertex]; + + } + } + + Total_Sens_Geo += Sens_Geo[iMarker]; + + } + } + + /*--- Farfield Sensitivity (Mach, AoA, Press, Temp), only for compressible flows ---*/ + + if (compressible) { + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) == FAR_FIELD || config->GetMarker_All_KindBC(iMarker) == INLET_FLOW || + config->GetMarker_All_KindBC(iMarker) == SUPERSONIC_INLET || config->GetMarker_All_KindBC(iMarker) == SUPERSONIC_OUTLET || + config->GetMarker_All_KindBC(iMarker) == ENGINE_INFLOW ) { + + Sens_Mach[iMarker] = 0.0; + Sens_AoA[iMarker] = 0.0; + Sens_Press[iMarker] = 0.0; + Sens_Temp[iMarker] = 0.0; + Sens_BPress[iMarker] = 0.0; + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + Psi = node[iPoint]->GetSolution(); + U = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + + Mach_Inf = config->GetMach(); + if (grid_movement) Mach_Inf = config->GetMach_Motion(); + + r = U[0]; ru = U[1]; rv = U[2]; + if (nDim == 2) { rw = 0.0; rE = U[3]; } + else { rw = U[3]; rE = U[4]; } + p = Gamma_Minus_One*(rE-(ru*ru + rv*rv + rw*rw)/(2*r)); + + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; + Area = sqrt(Area); + for (iDim = 0; iDim < nDim; iDim++) UnitNormal[iDim] = -Normal[iDim]/Area; + + H = (rE + p)/r; + + dp_dr = Gamma_Minus_One*(ru*ru + rv*rv + rw*rw)/(2*r*r); + dp_dru = -Gamma_Minus_One*ru/r; + dp_drv = -Gamma_Minus_One*rv/r; + if (nDim == 2) { dp_drw = 0.0; dp_drE = Gamma_Minus_One; } + else { dp_drw = -Gamma_Minus_One*rw/r; dp_drE = Gamma_Minus_One; } + + dH_dr = (-H + dp_dr)/r; dH_dru = dp_dru/r; dH_drv = dp_drv/r; + if (nDim == 2) { dH_drw = 0.0; dH_drE = (1 + dp_drE)/r; } + else { dH_drw = dp_drw/r; dH_drE = (1 + dp_drE)/r; } + + if (nDim == 2) { + Jacobian_j[0][0] = 0.0; + Jacobian_j[1][0] = Area*UnitNormal[0]; + Jacobian_j[2][0] = Area*UnitNormal[1]; + Jacobian_j[3][0] = 0.0; + + Jacobian_j[0][1] = (-(ru*ru)/(r*r) + dp_dr)*Area*UnitNormal[0] + (-(ru*rv)/(r*r))*Area*UnitNormal[1]; + Jacobian_j[1][1] = (2*ru/r + dp_dru)*Area*UnitNormal[0] + (rv/r)*Area*UnitNormal[1]; + Jacobian_j[2][1] = (dp_drv)*Area*UnitNormal[0] + (ru/r)*Area*UnitNormal[1]; + Jacobian_j[3][1] = (dp_drE)*Area*UnitNormal[0]; + + Jacobian_j[0][2] = (-(ru*rv)/(r*r))*Area*UnitNormal[0] + (-(rv*rv)/(r*r) + dp_dr)*Area*UnitNormal[1]; + Jacobian_j[1][2] = (rv/r)*Area*UnitNormal[0] + (dp_dru)*Area*UnitNormal[1]; + Jacobian_j[2][2] = (ru/r)*Area*UnitNormal[0] + (2*rv/r + dp_drv)*Area*UnitNormal[1]; + Jacobian_j[3][2] = (dp_drE)*Area*UnitNormal[1]; + + Jacobian_j[0][3] = (ru*dH_dr)*Area*UnitNormal[0] + (rv*dH_dr)*Area*UnitNormal[1]; + Jacobian_j[1][3] = (H + ru*dH_dru)*Area*UnitNormal[0] + (rv*dH_dru)*Area*UnitNormal[1]; + Jacobian_j[2][3] = (ru*dH_drv)*Area*UnitNormal[0] + (H + rv*dH_drv)*Area*UnitNormal[1]; + Jacobian_j[3][3] = (ru*dH_drE)*Area*UnitNormal[0] + (rv*dH_drE)*Area*UnitNormal[1]; + } + else { + Jacobian_j[0][0] = 0.0; + Jacobian_j[1][0] = Area*UnitNormal[0]; + Jacobian_j[2][0] = Area*UnitNormal[1]; + Jacobian_j[3][0] = Area*UnitNormal[2]; + Jacobian_j[4][0] = 0.0; + + Jacobian_j[0][1] = (-(ru*ru)/(r*r) + dp_dr)*Area*UnitNormal[0] + (-(ru*rv)/(r*r))*Area*UnitNormal[1] + (-(ru*rw)/(r*r))*Area*UnitNormal[2]; + Jacobian_j[1][1] = (2*ru/r + dp_dru)*Area*UnitNormal[0] + (rv/r)*Area*UnitNormal[1] + (rw/r)*Area*UnitNormal[2]; + Jacobian_j[2][1] = (dp_drv)*Area*UnitNormal[0] + (ru/r)*Area*UnitNormal[1]; + Jacobian_j[3][1] = (dp_drw)*Area*UnitNormal[0] + (ru/r)*Area*UnitNormal[2]; + Jacobian_j[4][1] = (dp_drE)*Area*UnitNormal[0]; + + Jacobian_j[0][2] = (-(ru*rv)/(r*r))*Area*UnitNormal[0] + (-(rv*rv)/(r*r) + dp_dr)*Area*UnitNormal[1] + (-(rv*rw)/(r*r))*Area*UnitNormal[2]; + Jacobian_j[1][2] = (rv/r)*Area*UnitNormal[0] + (dp_dru)*Area*UnitNormal[1]; + Jacobian_j[2][2] = (ru/r)*Area*UnitNormal[0] + (2*rv/r + dp_drv)*Area*UnitNormal[1] + (rw/r)*Area*UnitNormal[2]; + Jacobian_j[3][2] = (dp_drw)*Area*UnitNormal[1] + (rv/r)*Area*UnitNormal[2]; + Jacobian_j[4][2] = (dp_drE)*Area*UnitNormal[1]; + + Jacobian_j[0][3] = (-(ru*rw)/(r*r))*Area*UnitNormal[0] + (-(rv*rw)/(r*r))*Area*UnitNormal[1] + (-(rw*rw)/(r*r) + dp_dr)*Area*UnitNormal[2]; + Jacobian_j[1][3] = (rw/r)*Area*UnitNormal[0] + (dp_dru)*Area*UnitNormal[2]; + Jacobian_j[2][3] = (rw/r)*Area*UnitNormal[1] + (dp_drv)*Area*UnitNormal[2]; + Jacobian_j[3][3] = (ru/r)*Area*UnitNormal[0] + (rv/r)*Area*UnitNormal[1] + (2*rw/r + dp_drw)*Area*UnitNormal[2]; + Jacobian_j[4][3] = (dp_drE)*Area*UnitNormal[2]; + + Jacobian_j[0][4] = (ru*dH_dr)*Area*UnitNormal[0] + (rv*dH_dr)*Area*UnitNormal[1] + (rw*dH_dr)*Area*UnitNormal[2]; + Jacobian_j[1][4] = (H + ru*dH_dru)*Area*UnitNormal[0] + (rv*dH_dru)*Area*UnitNormal[1] + (rw*dH_dru)*Area*UnitNormal[2]; + Jacobian_j[2][4] = (ru*dH_drv)*Area*UnitNormal[0] + (H + rv*dH_drv)*Area*UnitNormal[1] + (rw*dH_drv)*Area*UnitNormal[2]; + Jacobian_j[3][4] = (ru*dH_drw)*Area*UnitNormal[0] + (rv*dH_drw)*Area*UnitNormal[1] + (H + rw*dH_drw)*Area*UnitNormal[2]; + Jacobian_j[4][4] = (ru*dH_drE)*Area*UnitNormal[0] + (rv*dH_drE)*Area*UnitNormal[1] + (rw*dH_drE)*Area*UnitNormal[2]; + } + + /*--- Mach number sensitivity ---*/ + + USens[0] = 0.0; USens[1] = ru/Mach_Inf; USens[2] = rv/Mach_Inf; + if (nDim == 2) { USens[3] = Gamma*Mach_Inf*p; } + else { USens[3] = rw/Mach_Inf; USens[4] = Gamma*Mach_Inf*p; } + for (iPos = 0; iPos < nVar; iPos++) { + for (jPos = 0; jPos < nVar; jPos++) { + Sens_Mach[iMarker] += Psi[iPos]*Jacobian_j[jPos][iPos]*USens[jPos]; + } + } + + /*--- AoA sensitivity ---*/ + + USens[0] = 0.0; + if (nDim == 2) { USens[1] = -rv; USens[2] = ru; USens[3] = 0.0; } + else { USens[1] = -rw; USens[2] = 0.0; USens[3] = ru; USens[4] = 0.0; } + for (iPos = 0; iPos < nVar; iPos++) { + for (jPos = 0; jPos < nVar; jPos++) { + Sens_AoA[iMarker] += Psi[iPos]*Jacobian_j[jPos][iPos]*USens[jPos]; + } + } + + /*--- Pressure sensitivity ---*/ + + USens[0] = r/p; USens[1] = ru/p; USens[2] = rv/p; + if (nDim == 2) { USens[3] = rE/p; } + else { USens[3] = rw/p; USens[4] = rE/p; } + for (iPos = 0; iPos < nVar; iPos++) { + for (jPos = 0; jPos < nVar; jPos++) { + Sens_Press[iMarker] += Psi[iPos]*Jacobian_j[jPos][iPos]*USens[jPos]; + } + } + + /*--- Temperature sensitivity ---*/ + + T = p/(r*Gas_Constant); + USens[0] = -r/T; USens[1] = 0.5*ru/T; USens[2] = 0.5*rv/T; + if (nDim == 2) { USens[3] = (ru*ru + rv*rv + rw*rw)/(r*T); } + else { USens[3] = 0.5*rw/T; USens[4] = (ru*ru + rv*rv + rw*rw)/(r*T); } + for (iPos = 0; iPos < nVar; iPos++) { + for (jPos = 0; jPos < nVar; jPos++) { + Sens_Temp[iMarker] += Psi[iPos]*Jacobian_j[jPos][iPos]*USens[jPos]; + } + } + } + } + + Total_Sens_Mach -= Sens_Mach[iMarker] * scale * factor; + Total_Sens_AoA -= Sens_AoA[iMarker] * scale * factor; + Total_Sens_Press -= Sens_Press[iMarker] * scale * factor; + Total_Sens_Temp -= Sens_Temp[iMarker] * scale * factor; + + } + + } + + /*--- Explicit contribution from objective function quantity ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL)) { + + Sens_Mach[iMarker] = 0.0; + Sens_AoA[iMarker] = 0.0; + Sens_Press[iMarker] = 0.0; + Sens_Temp[iMarker] = 0.0; + Sens_BPress[iMarker] = 0.0; + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + p = solver_container[FLOW_SOL]->node[iPoint]->GetPressure(); + + Mach_Inf = config->GetMach(); + if (grid_movement) Mach_Inf = config->GetMach_Motion(); + + d = node[iPoint]->GetForceProj_Vector(); + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; + Area = sqrt(Area); + for (iDim = 0; iDim < nDim; iDim++) UnitNormal[iDim] = -Normal[iDim]/Area; + + /*--- Mach number sensitivity ---*/ + + for (iPos = 0; iPos < nDim; iPos++) Dd[iPos] = -(2.0/Mach_Inf)*d[iPos]; + for (iPos = 0; iPos < nDim; iPos++) Sens_Mach[iMarker] += p*Dd[iPos]*Area*UnitNormal[iPos]; + + /*--- AoA sensitivity ---*/ + + if (config->GetKind_ObjFunc() == DRAG_COEFFICIENT || + config->GetKind_ObjFunc() == LIFT_COEFFICIENT || + config->GetKind_ObjFunc() == SIDEFORCE_COEFFICIENT || + config->GetKind_ObjFunc() == EQUIVALENT_AREA || + config->GetKind_ObjFunc() == NEARFIELD_PRESSURE) { + if (nDim == 2) { + D[0][0] = 0.0; D[0][1] = -1.0; + D[1][0] = 1.0; D[1][1] = 0.0; + } + else { + D[0][0] = 0.0; D[0][1] = 0.0; D[0][2] = -1.0; + D[1][0] = 0.0; D[1][1] = 0.0; D[1][2] = 0.0; + D[2][0] = 1.0; D[2][1] = 0.0; D[2][2] = 0.0; + } + for (iPos = 0; iPos < nDim; iPos++) Dd[iPos] = 0.0; + for (iPos = 0; iPos < nDim; iPos++) { + for (jPos = 0; jPos < nDim; jPos++) + Dd[iPos] += D[iPos][jPos]*d[jPos]; + } + } + + /*--- Coefficients with no explicit AoA dependece ---*/ + + else { + for (iPos = 0; iPosGetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool grid_movement = config->GetGrid_Movement(); + + su2double Prandtl_Lam = config->GetPrandtl_Lam(); + su2double Prandtl_Turb = config->GetPrandtl_Turb(); + + su2double *Psi = new su2double[nVar]; + su2double **Tau = new su2double*[nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Tau[iDim] = new su2double [nDim]; + su2double *Velocity = new su2double[nDim]; + su2double *Normal = new su2double[nDim]; + su2double *Edge_Vector = new su2double[nDim]; + su2double **GradPhi = new su2double*[nDim]; + for (iDim = 0; iDim < nDim; iDim++) + GradPhi[iDim] = new su2double [nDim]; + su2double *GradPsiE = new su2double [nDim]; + + /*--- Loop over all of the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + + /*--- Initialize the convective & viscous residuals to zero ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + Res_Conv_i[iVar] = 0.0; Res_Visc_i[iVar] = 0.0; + if (implicit) { for (jVar = 0; jVar < nVar; jVar ++) Jacobian_ii[iVar][jVar] = 0.0; } + } + + /*--- Retrieve adjoint solution at the wall boundary node ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Psi[iVar] = node[iPoint]->GetSolution(iVar); + + /*--- Get the force projection vector (based on the objective function) ---*/ + + d = node[iPoint]->GetForceProj_Vector(); + + /*--- Set the adjoint velocity BC ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { phi[iDim] = d[iDim]; } + + /*--- Correct the adjoint velocity BC for dynamic meshes ---*/ + + if (grid_movement) { + GridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + phi[iDim] -= Psi[nDim+1]*GridVel[iDim]; + } + + /*--- Impose the value of the adjoint velocity as a strong boundary + condition (Dirichlet). Fix the adjoint velocity and remove any addtional + contribution to the residual at this node. ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + node[iPoint]->SetSolution_Old(iDim+1, phi[iDim]); + + for (iDim = 0; iDim < nDim; iDim++) + LinSysRes.SetBlock_Zero(iPoint, iDim+1); + node[iPoint]->SetVel_ResTruncError_Zero(); + + /*--- Compute additional contributions to the adjoint density and energy + equations which will be added to the residual (weak imposition) ---*/ + + if (compressible) { + + /*--- Energy residual due to the convective term ---*/ + + l1psi = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + l1psi += Normal[iDim]*d[iDim]; + Res_Conv_i[nDim+1] = l1psi*Gamma_Minus_One; + + /*--- Flux contribution and Jacobian contributions for moving + walls. Note that these are only for the adjoint density and + adjoint energy equations (the adjoint vel. uses a strong BC). ---*/ + + if (grid_movement) { + + /*--- Get the grid velocity at this node and impose v = u_wall ---*/ + + GridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) Velocity[iDim] = GridVel[iDim]; + + /*--- Get some additional quantities from the flow solution ---*/ + + Density = solver_container[FLOW_SOL]->node[iPoint]->GetDensity(); + if (compressible) { + Pressure = solver_container[FLOW_SOL]->node[iPoint]->GetPressure(); + Enthalpy = solver_container[FLOW_SOL]->node[iPoint]->GetEnthalpy(); + Laminar_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); + Eddy_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetEddyViscosity(); // Should be zero at the wall + } + if (incompressible || freesurface) { + Pressure = solver_container[FLOW_SOL]->node[iPoint]->GetPressureInc(); + Laminar_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosityInc(); + Eddy_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetEddyViscosityInc(); // Should be zero at the wall + } + + ViscDens = (Laminar_Viscosity + Eddy_Viscosity) / Density; + XiDens = Gamma * (Laminar_Viscosity/Prandtl_Lam + Eddy_Viscosity/Prandtl_Turb) / Density; + + /*--- Compute projections, velocity squared divided by two, and + other inner products. Note that we are imposing v = u_wall from + the direct problem and that phi = d - \psi_5 * v ---*/ + + ProjGridVel = 0.0; sq_vel = 0.0; + vartheta = Psi[0] + Psi[nDim+1]*Enthalpy; + for (iDim = 0; iDim < nDim; iDim++) { + ProjGridVel += GridVel[iDim]*Normal[iDim]; + sq_vel += 0.5*GridVel[iDim]*GridVel[iDim]; + vartheta += GridVel[iDim]*phi[iDim]; + } + + /*--- Convective flux at the wall node (adjoint density) ---*/ + + Res_Conv_i[0] = -vartheta*ProjGridVel + l1psi*Gamma_Minus_One*sq_vel; + + /*--- Implicit contributions from convective part ---*/ + + if (implicit) { + Jacobian_ii[0][0] += -ProjGridVel; + Jacobian_ii[0][nVar-1] += -ProjGridVel * Enthalpy; + } + + /*--- Viscous flux contributions at the wall node. Impose dPhiE_dn = 0 + (adiabatic walls with frozen viscosity). ---*/ + + dPhiE_dn = 0.0; + + /*--- Store the adjoint velocity and energy gradients for clarity ---*/ + + PsiVar_Grad = node[iPoint]->GetGradient(); + for (iDim = 0; iDim < nDim; iDim++) { + GradPsiE[iDim] = PsiVar_Grad[nVar-1][iDim]; + for (jDim = 0; jDim < nDim; jDim++) + GradPhi[iDim][jDim] = PsiVar_Grad[iDim+1][jDim]; + } + + if (nDim == 2) { + + /*--- Compute the adjoint stress tensor ---*/ + + Sigma_xx = ViscDens * (FOUR3 * GradPhi[0][0] - TWO3 * GradPhi[1][1]); + Sigma_yy = ViscDens * (-TWO3 * GradPhi[0][0] + FOUR3 * GradPhi[1][1]); + Sigma_xy = ViscDens * (GradPhi[1][0] + GradPhi[0][1]); + Sigma_xx5 = ViscDens * ( FOUR3 * Velocity[0] * GradPsiE[0] - TWO3 * Velocity[1] * GradPsiE[1]); + Sigma_yy5 = ViscDens * (- TWO3 * Velocity[0] * GradPsiE[0] + FOUR3 * Velocity[1] * GradPsiE[1]); + Sigma_xy5 = ViscDens * (Velocity[0] * GradPsiE[1] + Velocity[1] * GradPsiE[0]); + Sigma_5 = XiDens * dPhiE_dn; + eta_xx = Sigma_xx + Sigma_xx5; + eta_yy = Sigma_yy + Sigma_yy5; + eta_xy = Sigma_xy + Sigma_xy5; + + /*--- Viscous flux at the wall node (adjoint density & energy only) ---*/ + + Res_Visc_i[0] = - (Velocity[0] * Normal[0] * eta_xx + Velocity[1] * Normal[1] * eta_yy + + (Velocity[0] * Normal[1] + Velocity[1] * Normal[0]) * eta_xy + - (sq_vel - Pressure/(Density*Gamma_Minus_One)) * Sigma_5); + Res_Visc_i[nDim+1] = Sigma_5; + + /*--- Computation of the Jacobians at Point i---*/ + + if (implicit) { + + /*--- Compute closest normal neighbor ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Get coordinates of i & nearest normal and compute distance ---*/ + + Coord_i = geometry->node[iPoint]->GetCoord(); + Coord_j = geometry->node[Point_Normal]->GetCoord(); + dist_ij_2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Edge_Vector[iDim] = Coord_j[iDim]-Coord_i[iDim]; + dist_ij_2 += Edge_Vector[iDim]*Edge_Vector[iDim]; + } + + dSigmaxx_phi1 = -FOUR3 * ViscDens * Edge_Vector[0]/dist_ij_2; + dSigmaxx_phi2 = TWO3 * ViscDens * Edge_Vector[1]/dist_ij_2; + dSigmayy_phi1 = TWO3 * ViscDens * Edge_Vector[0]/dist_ij_2; + dSigmayy_phi2 = -FOUR3 * ViscDens * Edge_Vector[1]/dist_ij_2; + dSigmaxy_phi1 = -ViscDens * Edge_Vector[1]/dist_ij_2; + dSigmaxy_phi2 = -ViscDens * Edge_Vector[0]/dist_ij_2; + +// dSigmaxx5_psi5 = -ViscDens * ( FOUR3*Velocity[0]*Edge_Vector[0] - TWO3*Velocity[1]*Edge_Vector[1] )/dist_ij_2; +// dSigmayy5_psi5 = -ViscDens * (- TWO3*Velocity[0]*Edge_Vector[0] + FOUR3*Velocity[1]*Edge_Vector[1] )/dist_ij_2; +// dSigmaxy5_psi5 = -ViscDens * ( Velocity[0]*Edge_Vector[1] + Velocity[1]*Edge_Vector[0] )/dist_ij_2; + dSigma5_psi5 = -XiDens * ( Edge_Vector[0]*Normal[0] + Edge_Vector[1]*Normal[1] )/dist_ij_2; + + Jacobian_ii[0][0] += 0.0; + Jacobian_ii[0][1] += -( Velocity[0]*Normal[0]*dSigmaxx_phi1 + Velocity[1]*Normal[1]*dSigmayy_phi1 + + (Velocity[0]*Normal[1] + Velocity[1]*Normal[0])*dSigmaxy_phi1 ); + Jacobian_ii[0][2] += -( Velocity[0]*Normal[0]*dSigmaxx_phi2 + Velocity[1]*Normal[1]*dSigmayy_phi2 + + (Velocity[0]*Normal[1] + Velocity[1]*Normal[0])*dSigmaxy_phi2 ); + Jacobian_ii[0][3] += (sq_vel - Pressure/(Density*Gamma_Minus_One)) * dSigma5_psi5; + + Jacobian_ii[3][0] += 0.0; + Jacobian_ii[3][1] += 0.0; + Jacobian_ii[3][2] += 0.0; + Jacobian_ii[3][3] += dSigma5_psi5; + + } + + + } else if (nDim == 3) { + + /*--- Compute the adjoint stress tensor ---*/ + Sigma_xx = ViscDens * (FOUR3 * GradPhi[0][0] - TWO3 * GradPhi[1][1] - TWO3 * GradPhi[2][2]); + Sigma_yy = ViscDens * (-TWO3 * GradPhi[0][0] + FOUR3 * GradPhi[1][1] - TWO3 * GradPhi[2][2]); + Sigma_zz = ViscDens * (-TWO3 * GradPhi[0][0] - TWO3 * GradPhi[1][1] + FOUR3 * GradPhi[2][2]); + Sigma_xy = ViscDens * (GradPhi[1][0] + GradPhi[0][1]); + Sigma_xz = ViscDens * (GradPhi[2][0] + GradPhi[0][2]); + Sigma_yz = ViscDens * (GradPhi[2][1] + GradPhi[1][2]); + Sigma_xx5 = ViscDens * ( FOUR3 * Velocity[0] * GradPsiE[0] - TWO3 * Velocity[1] * GradPsiE[1] - TWO3 * Velocity[2] * GradPsiE[2]); + Sigma_yy5 = ViscDens * (- TWO3 * Velocity[0] * GradPsiE[0] + FOUR3 * Velocity[1] * GradPsiE[1] - TWO3 * Velocity[2] * GradPsiE[2]); + Sigma_zz5 = ViscDens * (- TWO3 * Velocity[0] * GradPsiE[0] - TWO3 * Velocity[1] * GradPsiE[1] + FOUR3 * Velocity[2] * GradPsiE[2]); + Sigma_xy5 = ViscDens * (Velocity[0] * GradPsiE[1] + Velocity[1] * GradPsiE[0]); + Sigma_xz5 = ViscDens * (Velocity[0] * GradPsiE[2] + Velocity[2] * GradPsiE[0]); + Sigma_yz5 = ViscDens * (Velocity[1] * GradPsiE[2] + Velocity[2] * GradPsiE[1]); + Sigma_5 = XiDens * dPhiE_dn; + eta_xx = Sigma_xx + Sigma_xx5; eta_yy = Sigma_yy + Sigma_yy5; eta_zz = Sigma_zz + Sigma_zz5; + eta_xy = Sigma_xy + Sigma_xy5; eta_xz = Sigma_xz + Sigma_xz5; eta_yz = Sigma_yz + Sigma_yz5; + + /*--- Viscous flux at the wall node (adjoint density & energy only) ---*/ + + Res_Visc_i[0] = - (Velocity[0] * Normal[0] * eta_xx + Velocity[1] * Normal[1] * eta_yy + Velocity[2] * Normal[2] * eta_zz + + (Velocity[0] * Normal[1] + Velocity[1] * Normal[0]) * eta_xy + + (Velocity[0] * Normal[2] + Velocity[2] * Normal[0]) * eta_xz + + (Velocity[2] * Normal[1] + Velocity[1] * Normal[2]) * eta_yz + - (sq_vel - Pressure/(Density*Gamma_Minus_One)) * Sigma_5); + Res_Visc_i[nDim+1] = Sigma_5; + + /*--- Computation of the Jacobians at Point i---*/ + + if (implicit) { + + /*--- Compute closest normal neighbor ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Get coordinates of i & nearest normal and compute distance ---*/ + + Coord_i = geometry->node[iPoint]->GetCoord(); + Coord_j = geometry->node[Point_Normal]->GetCoord(); + dist_ij_2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Edge_Vector[iDim] = Coord_j[iDim]-Coord_i[iDim]; + dist_ij_2 += Edge_Vector[iDim]*Edge_Vector[iDim]; + } + + dSigmaxx_phi1 = -FOUR3 * ViscDens * Edge_Vector[0]/dist_ij_2; + dSigmaxx_phi2 = TWO3 * ViscDens * Edge_Vector[1]/dist_ij_2; + dSigmaxx_phi3 = TWO3 * ViscDens * Edge_Vector[2]/dist_ij_2; + dSigmayy_phi1 = TWO3 * ViscDens * Edge_Vector[0]/dist_ij_2; + dSigmayy_phi2 = -FOUR3 * ViscDens * Edge_Vector[1]/dist_ij_2; + dSigmayy_phi3 = TWO3 * ViscDens * Edge_Vector[2]/dist_ij_2; + dSigmazz_phi1 = TWO3 * ViscDens * Edge_Vector[0]/dist_ij_2; + dSigmazz_phi2 = TWO3 * ViscDens * Edge_Vector[1]/dist_ij_2; + dSigmazz_phi3 = -FOUR3 * ViscDens * Edge_Vector[2]/dist_ij_2; + dSigmaxy_phi1 = -ViscDens * Edge_Vector[1]/dist_ij_2; + dSigmaxy_phi2 = -ViscDens * Edge_Vector[0]/dist_ij_2; + dSigmaxy_phi3 = 0; + dSigmaxz_phi1 = -ViscDens * Edge_Vector[2]/dist_ij_2; + dSigmaxz_phi2 = 0; + dSigmaxz_phi3 = -ViscDens * Edge_Vector[0]/dist_ij_2; + dSigmayz_phi1 = 0; + dSigmayz_phi2 = -ViscDens * Edge_Vector[2]/dist_ij_2; + dSigmayz_phi3 = -ViscDens * Edge_Vector[1]/dist_ij_2; + +// dSigmaxx5_psi5 = -ViscDens * ( FOUR3*Velocity[0]*Edge_Vector[0] - TWO3*Velocity[1]*Edge_Vector[1] - TWO3*Velocity[2]*Edge_Vector[2])/dist_ij_2; +// dSigmayy5_psi5 = -ViscDens * (- TWO3*Velocity[0]*Edge_Vector[0] + FOUR3*Velocity[1]*Edge_Vector[1] - TWO3*Velocity[2]*Edge_Vector[2])/dist_ij_2; +// dSigmazz5_psi5 = -ViscDens * (- TWO3*Velocity[0]*Edge_Vector[0] - TWO3*Velocity[1]*Edge_Vector[1] + FOUR3*Velocity[2]*Edge_Vector[2])/dist_ij_2; +// dSigmaxy5_psi5 = -ViscDens * ( Velocity[0]*Edge_Vector[1] + Velocity[1]*Edge_Vector[0] )/dist_ij_2; +// dSigmaxz5_psi5 = -ViscDens * ( Velocity[0]*Edge_Vector[2] + Velocity[2]*Edge_Vector[0] )/dist_ij_2; +// dSigmayz5_psi5 = -ViscDens * ( Velocity[1]*Edge_Vector[2] + Velocity[2]*Edge_Vector[1] )/dist_ij_2; + dSigma5_psi5 = -XiDens * ( Edge_Vector[0]*Normal[0] + Edge_Vector[1]*Normal[1] + Edge_Vector[2]*Normal[2] )/dist_ij_2; + + Jacobian_ii[0][0] += 0.0; + Jacobian_ii[0][1] += -( Velocity[0]*Normal[0]*dSigmaxx_phi1 + Velocity[1]*Normal[1]*dSigmayy_phi1 + Velocity[2]*Normal[2]*dSigmazz_phi1 + + (Velocity[0]*Normal[1] + Velocity[1]*Normal[0])*dSigmaxy_phi1 + + (Velocity[0]*Normal[2] + Velocity[2]*Normal[0])*dSigmaxz_phi1 + + (Velocity[2]*Normal[1] + Velocity[1]*Normal[2])*dSigmayz_phi1 ); + Jacobian_ii[0][2] += -( Velocity[0]*Normal[0]*dSigmaxx_phi2 + Velocity[1]*Normal[1]*dSigmayy_phi2 + Velocity[2]*Normal[2]*dSigmazz_phi2 + + (Velocity[0]*Normal[1] + Velocity[1]*Normal[0])*dSigmaxy_phi2 + + (Velocity[0]*Normal[2] + Velocity[2]*Normal[0])*dSigmaxz_phi2 + + (Velocity[2]*Normal[1] + Velocity[1]*Normal[2])*dSigmayz_phi2 ); + Jacobian_ii[0][3] += -( Velocity[0]*Normal[0]*dSigmaxx_phi3 + Velocity[1]*Normal[1]*dSigmayy_phi3 + Velocity[2]*Normal[2]*dSigmazz_phi3 + + (Velocity[0]*Normal[1] + Velocity[1]*Normal[0])*dSigmaxy_phi3 + + (Velocity[0]*Normal[2] + Velocity[2]*Normal[0])*dSigmaxz_phi3 + + (Velocity[2]*Normal[1] + Velocity[1]*Normal[2])*dSigmayz_phi3 ); + Jacobian_ii[0][4] += (sq_vel - Pressure/(Density*Gamma_Minus_One)) * dSigma5_psi5; + + Jacobian_ii[4][0] += 0.0; + Jacobian_ii[4][1] += 0.0; + Jacobian_ii[4][2] += 0.0; + Jacobian_ii[4][3] += 0.0; + Jacobian_ii[4][4] += dSigma5_psi5; + + } + } + } + } + + if (incompressible || freesurface) { + + /*--- Pressure residual due to the convective term ---*/ + + l1psi = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + l1psi += Normal[iDim]*d[iDim]; + Res_Conv_i[0] = l1psi; + } + + /*--- Convective contribution to the residual at the wall ---*/ + + LinSysRes.SubtractBlock(iPoint, Res_Conv_i); + + /*--- Viscous contribution to the residual at the wall ---*/ + + LinSysRes.SubtractBlock(iPoint, Res_Visc_i); + + /*--- Enforce the no-slip boundary condition in a strong way by + modifying the velocity-rows of the Jacobian (1 on the diagonal). ---*/ + + if (implicit) { + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + for (iVar = 1; iVar <= nDim; iVar++) { + total_index = iPoint*nVar+iVar; + Jacobian.DeleteValsRowi(total_index); + } + } + + } + + } + + for (iDim = 0; iDim < nDim; iDim++) + delete [] Tau[iDim]; + delete [] Tau; + delete [] Psi; + delete [] Velocity; + delete [] Normal; + delete [] Edge_Vector; + delete [] GradPsiE; + for (iDim = 0; iDim < nDim; iDim++) + delete [] GradPhi[iDim]; + delete [] GradPhi; + +} + + +void CAdjNSSolver::BC_Isothermal_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned long iVertex, iPoint, total_index; + unsigned short iDim, iVar, jVar, jDim; + su2double *d, q, *U, l1psi, dVisc_T, rho, pressure, div_phi, + force_stress, Sigma_5, **PsiVar_Grad, phi[3] = {0.0,0.0,0.0}; + su2double phis1, phis2, sq_vel, ProjVel, Enthalpy, *GridVel, phi_u, d_n; + su2double Energy, ViscDens, XiDens, Density, SoundSpeed, Pressure, dPhiE_dn, Laminar_Viscosity, Eddy_Viscosity, + Sigma_xx, Sigma_yy, Sigma_zz, Sigma_xy, Sigma_xz, Sigma_yz, + Sigma_xx5, Sigma_yy5, Sigma_zz5, Sigma_xy5, Sigma_xz5, + Sigma_yz5, eta_xx, eta_yy, eta_zz, eta_xy, eta_xz, eta_yz; + su2double kGTdotn; + + su2double *Psi = new su2double[nVar]; + su2double **Tau = new su2double* [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Tau[iDim] = new su2double [nDim]; + su2double *Velocity = new su2double[nDim]; + su2double *Normal = new su2double[nDim]; + + su2double **GradPhi = new su2double* [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + GradPhi[iDim] = new su2double [nDim]; + su2double *GradPsiE = new su2double [nDim]; + su2double *GradT;// = new su2double[nDim]; + su2double *GradP; + su2double *GradDens; + su2double *dPoRho2 = new su2double[nDim]; + + bool implicit = (config->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool grid_movement = config->GetGrid_Movement(); + bool heat_flux_obj = ((config->GetKind_ObjFunc() == TOTAL_HEATFLUX) || + (config->GetKind_ObjFunc() == MAXIMUM_HEATFLUX) || + (config->GetKind_ObjFunc() == INVERSE_DESIGN_HEATFLUX)); + + su2double Prandtl_Lam = config->GetPrandtl_Lam(); + su2double Prandtl_Turb = config->GetPrandtl_Turb(); + su2double Gas_Constant = config->GetGas_ConstantND(); + su2double Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; + su2double Thermal_Conductivity; + su2double invrho3; + su2double Volume; + su2double mu2; + su2double gpsiAv2; + su2double gpsi5n; + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Initialize the convective & viscous residuals to zero ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + Res_Conv_i[iVar] = 0.0; + Res_Visc_i[iVar] = 0.0; + if (implicit) { + for (jVar = 0; jVar < nVar; jVar ++) + Jacobian_ii[iVar][jVar] = 0.0; + } + } + + /*--- Retrieve adjoint solution at the wall boundary node ---*/ + for (iVar = 0; iVar < nVar; iVar++) + Psi[iVar] = node[iPoint]->GetSolution(iVar); + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + Volume = geometry->node[iPoint]->GetVolume(); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + + /*--- Get the force projection vector (based on the objective function) ---*/ + d = node[iPoint]->GetForceProj_Vector(); + + /*--- Adjustments to strong boundary condition for dynamic meshes ---*/ + if ( grid_movement) { + GridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) { + phi[iDim] = d[iDim] - Psi[nVar-1]*GridVel[iDim]; + } + } else { + for (iDim = 0; iDim < nDim; iDim++) { + phi[iDim] = d[iDim]; + } + } + + /*--- Strong BC imposition for the adjoint velocity equations ---*/ + for (iDim = 0; iDim < nDim; iDim++) + LinSysRes.SetBlock_Zero(iPoint, iDim+1); + node[iPoint]->SetVel_ResTruncError_Zero(); + for (iDim = 0; iDim < nDim; iDim++) + node[iPoint]->SetSolution_Old(iDim+1, phi[iDim]); + if (implicit) { + for (iVar = 1; iVar <= nDim; iVar++) { + total_index = iPoint*nVar+iVar; + Jacobian.DeleteValsRowi(total_index); + } + } + + /*--- Get transport coefficient information ---*/ + Laminar_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); + Eddy_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetEddyViscosity(); + Thermal_Conductivity = Cp * ( Laminar_Viscosity/Prandtl_Lam + +Eddy_Viscosity/Prandtl_Turb); + +// GradV = solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(); + + /*--- Calculate Dirichlet condition for energy equation ---*/ + if (!heat_flux_obj) { + q = 0.0; + } + else { + GradT = solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive()[0]; + kGTdotn = 0; +// Xi = solver_container[FLOW_SOL]->GetTotal_MaxHeatFlux(); +// Xi = 1.0; + for (iDim = 0; iDim < nDim; iDim++) + kGTdotn += Thermal_Conductivity*GradT[iDim]*Normal[iDim]; + //q = - Xi * pnorm * pow(kGTdotn, pnorm-1.0); + q = -1.0; + } + + /*--- Strong BC enforcement of the energy equation ---*/ + LinSysRes.SetBlock_Zero(iPoint, nVar-1); + node[iPoint]->SetEnergy_ResTruncError_Zero(); + node[iPoint]->SetSolution_Old(nDim+1, q); + if (implicit) { + iVar = nDim+1; + total_index = iPoint*nVar+iVar; + Jacobian.DeleteValsRowi(total_index); + } + + /*--- Additional contributions to adjoint density (weak imposition) ---*/ + if (compressible) { + + /*--- Acquire gradient information ---*/ + PsiVar_Grad = node[iPoint]->GetGradient(); + GradP = solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive()[nVar-1]; + GradDens = solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive()[nVar]; + + /*--- Acqure flow information ---*/ + rho = solver_container[FLOW_SOL]->node[iPoint]->GetDensity(); + pressure = solver_container[FLOW_SOL]->node[iPoint]->GetPressure(); + invrho3 = (1.0/rho)*(1.0/rho)*(1.0/rho); + + /*--- Calculate supporting quantities ---*/ + mu2 = Thermal_Conductivity/Cp; + gpsiAv2 = 0.0; + gpsi5n = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + dPoRho2[iDim] = (GradP[iDim]*rho - 2.0*GradDens[iDim]*pressure)*invrho3; + gpsiAv2 += -mu2*Gamma/Gamma_Minus_One * PsiVar_Grad[nVar-1][iDim]*dPoRho2[iDim]; + gpsi5n += PsiVar_Grad[nVar-1][iDim]*Normal[iDim]; + } + + /*--- Apply first order term to boundary ---*/ + Res_Conv_i[0] = gpsiAv2*Volume; + + /*--- Apply second order term to boundary ---*/ + Res_Visc_i[0] = -mu2*Gamma/(rho*Gamma_Minus_One)*(pressure/rho)*gpsi5n; + + /*--- Components of the effective and adjoint stress tensors ---*/ + PsiVar_Grad = node[iPoint]->GetGradient(); + div_phi = 0; + for (iDim = 0; iDim < nDim; iDim++) { + div_phi += PsiVar_Grad[iDim+1][iDim]; + for (jDim = 0; jDim < nDim; jDim++) + Tau[iDim][jDim] = (PsiVar_Grad[iDim+1][jDim]+PsiVar_Grad[jDim+1][iDim]); + } + for (iDim = 0; iDim < nDim; iDim++) + Tau[iDim][iDim] -= TWO3*div_phi; + + /*--- force_stress = n_i \Tau_{ij} d_j ---*/ + force_stress = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + for (jDim = 0; jDim < nDim; jDim++) + force_stress += Normal[iDim]*Tau[iDim][jDim]*d[jDim]; + + /*--- \partial \mu_dyn \partial T ---*/ +// mu_dyn = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); +// Temp = solver_container[FLOW_SOL]->node[iPoint]->GetTemperature(); + dVisc_T = 0.0; // dVisc_T = mu_dyn*(Temp+3.0*mu2)/(2.0*Temp*(Temp+mu2)); + + /*--- \Sigma_5 Check Area computation for Res_Conv[0] ---*/ + Sigma_5 = (Gamma/Cp)*dVisc_T*force_stress; + + /*--- Imposition of residuals ---*/ + rho = solver_container[FLOW_SOL]->node[iPoint]->GetDensity(); + pressure = solver_container[FLOW_SOL]->node[iPoint]->GetPressure(); + Res_Conv_i[0] = pressure*Sigma_5/(Gamma_Minus_One*rho*rho); + + /*--- Flux contribution and Jacobian contributions for moving + walls. Note that these are only for the adjoint density and + adjoint energy equations (the adjoint vel. uses a strong BC). ---*/ + if (grid_movement) { + + /*--- Get the appropriate grid velocity at this node ---*/ + GridVel = geometry->node[iPoint]->GetGridVel(); + + /*--- Get the enthalpy from the direct solution ---*/ + Enthalpy = solver_container[FLOW_SOL]->node[iPoint]->GetEnthalpy(); + + /*--- Compute projections, velocity squared divided by two, and + other inner products. Note that we are imposing v = u_wall from + the direct problem and that phi = d - \psi_5 * v ---*/ + ProjVel = 0.0; sq_vel = 0.0; phi_u = 0.0; d_n = 0.0; + phis1 = 0.0; phis2 = Psi[0] + Enthalpy * Psi[nVar-1]; + for (iDim = 0; iDim < nDim; iDim++) { + ProjVel += GridVel[iDim]*Normal[iDim]; + sq_vel += 0.5*GridVel[iDim]*GridVel[iDim]; + phis1 += Normal[iDim]*phi[iDim]; + phis2 += GridVel[iDim]*phi[iDim]; + phi_u += GridVel[iDim]*phi[iDim]; + d_n += d[iDim]*Normal[iDim]; + } +// phis1 += ProjVel * Psi[nVar-1]; + + /*--- Convective flux at the wall node (adjoint density & energy only) ---*/ + + /*--- Version 1 (full) ---*/ + //Res_Conv_i[0] = ProjVel * Psi[0] - phis2 * ProjVel + phis1 * Gamma_Minus_One * sq_vel - ProjVel*Psi[0]; + //Res_Conv_i[nVar-1] = ProjVel * Psi[nVar-1] + phis1 * Gamma_Minus_One - ProjVel*Psi[nVar-1]; + + /*--- Simplified version ---*/ + Res_Conv_i[0] = -(Psi[0] + phi_u + Psi[nVar-1]*Enthalpy)*ProjVel + d_n*Gamma_Minus_One*sq_vel; + + /*--- TO DO: Implicit contributions for convective part ---*/ + + + /*--- Viscous flux contributions at the wall node ---*/ + U = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); + Laminar_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); + Eddy_Viscosity = solver_container[FLOW_SOL]->node[iPoint]->GetEddyViscosity(); // Should be zero at the wall + Density = U[0]; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity[iDim] = GridVel[iDim]; + } + Energy = U[nDim+1] / Density; + SoundSpeed = sqrt(Gamma*Gamma_Minus_One*(Energy-sq_vel)); + Pressure = (SoundSpeed * SoundSpeed * Density) / Gamma; + ViscDens = (Laminar_Viscosity + Eddy_Viscosity) / Density; + XiDens = Gamma * (Laminar_Viscosity/Prandtl_Lam + Eddy_Viscosity/Prandtl_Turb) / Density; + + /*--- Average of the derivatives of the adjoint variables ---*/ + PsiVar_Grad = node[iPoint]->GetGradient(); + + for (iDim = 0; iDim < nDim; iDim++) { + GradPsiE[iDim] = PsiVar_Grad[nVar-1][iDim]; + for (jDim = 0; jDim < nDim; jDim++) + GradPhi[iDim][jDim] = PsiVar_Grad[iDim+1][jDim]; + } + + /*--- Impose dPhiE_dn = 0 (adiabatic walls with frozen viscosity). Note + that this is where a different adjoint boundary condition for temperature + could be imposed. ---*/ + dPhiE_dn = 0.0; + + if (nDim ==2) { + + /*--- Compute the adjoint stress tensor ---*/ + Sigma_xx = ViscDens * (FOUR3 * GradPhi[0][0] - TWO3 * GradPhi[1][1]); + Sigma_yy = ViscDens * (-TWO3 * GradPhi[0][0] + FOUR3 * GradPhi[1][1]); + Sigma_xy = ViscDens * (GradPhi[1][0] + GradPhi[0][1]); + Sigma_xx5 = ViscDens * ( FOUR3 * Velocity[0] * GradPsiE[0] - TWO3 * Velocity[1] * GradPsiE[1]); + Sigma_yy5 = ViscDens * (- TWO3 * Velocity[0] * GradPsiE[0] + FOUR3 * Velocity[1] * GradPsiE[1]); + Sigma_xy5 = ViscDens * (Velocity[0] * GradPsiE[1] + Velocity[1] * GradPsiE[0]); + Sigma_5 = XiDens * dPhiE_dn; + eta_xx = Sigma_xx + Sigma_xx5; + eta_yy = Sigma_yy + Sigma_yy5; + eta_xy = Sigma_xy + Sigma_xy5; + + /*--- Viscous flux at the wall node (adjoint density & energy only) ---*/ + Res_Visc_i[0] = - (Velocity[0] * Normal[0] * eta_xx + Velocity[1] * Normal[1] * eta_yy + + (Velocity[0] * Normal[1] + Velocity[1] * Normal[0]) * eta_xy + - (sq_vel - Pressure/(Density*Gamma_Minus_One)) * Sigma_5); + Res_Visc_i[1] = 0.0; + Res_Visc_i[2] = 0.0; + + } else if (nDim == 3) { + + /*--- Compute the adjoint stress tensor ---*/ + Sigma_xx = ViscDens * (FOUR3 * GradPhi[0][0] - TWO3 * GradPhi[1][1] - TWO3 * GradPhi[2][2]); + Sigma_yy = ViscDens * (-TWO3 * GradPhi[0][0] + FOUR3 * GradPhi[1][1] - TWO3 * GradPhi[2][2]); + Sigma_zz = ViscDens * (-TWO3 * GradPhi[0][0] - TWO3 * GradPhi[1][1] + FOUR3 * GradPhi[2][2]); + Sigma_xy = ViscDens * (GradPhi[1][0] + GradPhi[0][1]); + Sigma_xz = ViscDens * (GradPhi[2][0] + GradPhi[0][2]); + Sigma_yz = ViscDens * (GradPhi[2][1] + GradPhi[1][2]); + Sigma_xx5 = ViscDens * ( FOUR3 * Velocity[0] * GradPsiE[0] - TWO3 * Velocity[1] * GradPsiE[1] - TWO3 * Velocity[2] * GradPsiE[2]); + Sigma_yy5 = ViscDens * (- TWO3 * Velocity[0] * GradPsiE[0] + FOUR3 * Velocity[1] * GradPsiE[1] - TWO3 * Velocity[2] * GradPsiE[2]); + Sigma_zz5 = ViscDens * (- TWO3 * Velocity[0] * GradPsiE[0] - TWO3 * Velocity[1] * GradPsiE[1] + FOUR3 * Velocity[2] * GradPsiE[2]); + Sigma_xy5 = ViscDens * (Velocity[0] * GradPsiE[1] + Velocity[1] * GradPsiE[0]); + Sigma_xz5 = ViscDens * (Velocity[0] * GradPsiE[2] + Velocity[2] * GradPsiE[0]); + Sigma_yz5 = ViscDens * (Velocity[1] * GradPsiE[2] + Velocity[2] * GradPsiE[1]); + Sigma_5 = XiDens * dPhiE_dn; + eta_xx = Sigma_xx + Sigma_xx5; eta_yy = Sigma_yy + Sigma_yy5; eta_zz = Sigma_zz + Sigma_zz5; + eta_xy = Sigma_xy + Sigma_xy5; eta_xz = Sigma_xz + Sigma_xz5; eta_yz = Sigma_yz + Sigma_yz5; + + /*--- Viscous flux at the wall node (adjoint density & energy only) ---*/ + Res_Visc_i[0] = - (Velocity[0] * Normal[0] * eta_xx + Velocity[1] * Normal[1] * eta_yy + Velocity[2] * Normal[2] * eta_zz + + (Velocity[0] * Normal[1] + Velocity[1] * Normal[0]) * eta_xy + + (Velocity[0] * Normal[2] + Velocity[2] * Normal[0]) * eta_xz + + (Velocity[2] * Normal[1] + Velocity[1] * Normal[2]) * eta_yz + - (sq_vel - Pressure/(Density*Gamma_Minus_One)) * Sigma_5); + Res_Visc_i[1] = 0.0; + Res_Visc_i[2] = 0.0; + Res_Visc_i[3] = 0.0; + } + } + } + + if (incompressible) { + + /*--- Pressure residual due to the convective term ---*/ + l1psi = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + l1psi += Normal[iDim]*d[iDim]; + Res_Conv_i[0] = l1psi; + + } + + /*--- Update convective and viscous residuals ---*/ + LinSysRes.AddBlock(iPoint, Res_Conv_i); + LinSysRes.SubtractBlock(iPoint, Res_Visc_i); + if (implicit) { + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_ii); + } + + } + + } + + for (iDim = 0; iDim < nDim; iDim++) + delete [] Tau[iDim]; + delete [] Tau; + delete [] Psi; + delete [] Velocity; + delete [] Normal; + delete [] GradPsiE; + for (iDim = 0; iDim < nDim; iDim++) + delete [] GradPhi[iDim]; + delete [] GradPhi; + delete [] dPoRho2; +} + diff --git a/SU2_CFD/src/solver_adjoint_turbulent.cpp b/SU2_CFD/src/solver_adjoint_turbulent.cpp index 700a3d68e75..604cc435aeb 100644 --- a/SU2_CFD/src/solver_adjoint_turbulent.cpp +++ b/SU2_CFD/src/solver_adjoint_turbulent.cpp @@ -1,882 +1,882 @@ -/*! - * \file solution_adjoint_turbulent.cpp - * \brief Main subrotuines for solving adjoint problems (Euler, Navier-Stokes, etc.). - * \author F. Palacios, A. Bueno, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/solver_structure.hpp" - -CAdjTurbSolver::CAdjTurbSolver(void) : CSolver() {} - -CAdjTurbSolver::CAdjTurbSolver(CGeometry *geometry, CConfig *config, unsigned short iMesh) : CSolver() { - unsigned long iPoint; - unsigned short iDim, iVar, nLineLets; - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - nDim = geometry->GetnDim(); - Gamma = config->GetGamma(); - Gamma_Minus_One = Gamma - 1.0; - - /*--- Dimension of the problem ---*/ - switch (config->GetKind_Turb_Model()) { - case SA : nVar = 1; break; - case SA_NEG : nVar = 1; break; - case SST : nVar = 2; break; - } - - nPoint = geometry->GetnPoint(); - nPointDomain = geometry->GetnPointDomain(); - - Residual = new su2double [nVar]; Residual_RMS = new su2double[nVar]; - Residual_i = new su2double [nVar]; Residual_j = new su2double [nVar]; - Residual_Max = new su2double [nVar]; Point_Max = new unsigned long[nVar]; - Point_Max_Coord = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Point_Max_Coord[iVar] = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; - } - - Solution = new su2double [nVar]; - Solution_i = new su2double [nVar]; - Solution_j = new su2double [nVar]; - - /*--- Define some auxiliar vector related with the geometry ---*/ - Vector_i = new su2double[nDim]; Vector_j = new su2double[nDim]; - - /*--- Define some auxiliar vector related with the flow solution ---*/ - FlowSolution_i = new su2double [nDim+2]; FlowSolution_j = new su2double [nDim+2]; - - /*--- Point to point Jacobians ---*/ - Jacobian_ii = new su2double* [nVar]; - Jacobian_ij = new su2double* [nVar]; - Jacobian_ji = new su2double* [nVar]; - Jacobian_jj = new su2double* [nVar]; - for (unsigned short iVar = 0; iVar < nVar; iVar++) { - Jacobian_ii[iVar] = new su2double [nVar]; - Jacobian_ij[iVar] = new su2double [nVar]; - Jacobian_ji[iVar] = new su2double [nVar]; - Jacobian_jj[iVar] = new su2double [nVar]; - } - - /*--- Initialization of the structure of the whole Jacobian ---*/ - Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); - - if ((config->GetKind_Linear_Solver_Prec() == LINELET) || - (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { - nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); - if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; - } - - Jacobian.SetValZero(); - LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); - - /*--- Computation of gradients by least squares ---*/ - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { - /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ - Smatrix = new su2double* [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Smatrix[iDim] = new su2double [nDim]; - /*--- c vector := transpose(WA)*(Wb) ---*/ - cvector = new su2double* [nVar+1]; - for (iVar = 0; iVar < nVar+1; iVar++) - cvector[iVar] = new su2double [nDim]; - } - - /*--- Far-Field values and initizalization ---*/ - node = new CVariable* [nPoint]; - bool restart = config->GetRestart(); - - if (!restart || (iMesh != MESH_0)) { - PsiNu_Inf = 0.0; - for (iPoint = 0; iPoint < nPoint; iPoint++) { - node[iPoint] = new CAdjTurbVariable(PsiNu_Inf, nDim, nVar, config); - } - } - else { - unsigned long index; - su2double dull_val; - string filename, AdjExt, text_line; - ifstream restart_file; - - /*--- Restart the solution from file information ---*/ - string mesh_filename = config->GetSolution_AdjFileName(); - filename = config->GetObjFunc_Extension(mesh_filename); - - restart_file.open(filename.data(), ios::in); - - /*--- In case there is no file ---*/ - if (restart_file.fail()) { - if (rank == MASTER_NODE) - cout << "There is no adjoint restart file!! " << filename.data() << "."<< endl; - exit(EXIT_FAILURE); - } - - /*--- In case this is a parallel simulation, we need to perform the - Global2Local index transformation first. ---*/ - long *Global2Local; - Global2Local = new long[geometry->GetGlobal_nPointDomain()]; - /*--- First, set all indices to a negative value by default ---*/ - for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) { - Global2Local[iPoint] = -1; - } - /*--- Now fill array with the transform values only for local points ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; - } - - /*--- Read all lines in the restart file ---*/ - long iPoint_Local; unsigned long iPoint_Global = 0; - - /*--- The first line is the header ---*/ - getline (restart_file, text_line); - - while (getline (restart_file, text_line)) { - istringstream point_line(text_line); - - /*--- Retrieve local index. If this node from the restart file lives - on a different processor, the value of iPoint_Local will be -1. - Otherwise, the local index for this node on the current processor - will be returned and used to instantiate the vars. ---*/ - iPoint_Local = Global2Local[iPoint_Global]; - if (iPoint_Local >= 0) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; - node[iPoint_Local] = new CAdjTurbVariable(Solution[0], nDim, nVar, config); - } - iPoint_Global++; - } - - /*--- Instantiate the variable class with an arbitrary solution - at any halo/periodic nodes. The initial solution can be arbitrary, - because a send/recv is performed immediately in the solver. ---*/ - for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { - node[iPoint] = new CAdjTurbVariable(Solution[0], nDim, nVar, config); - } - - /*--- Close the restart file ---*/ - restart_file.close(); - - /*--- Free memory needed for the transformation ---*/ - delete [] Global2Local; - } - - /*--- MPI solution ---*/ - Set_MPI_Solution(geometry, config); - -} - -CAdjTurbSolver::~CAdjTurbSolver(void) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) { - delete [] Jacobian_ii[iVar]; - delete [] Jacobian_ij[iVar]; - delete [] Jacobian_ji[iVar]; - delete [] Jacobian_jj[iVar]; - } - - delete [] Jacobian_ii; - delete [] Jacobian_ij; - delete [] Jacobian_ji; - delete [] Jacobian_jj; - -} - -void CAdjTurbSolver::Set_MPI_Solution(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iMarker, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_U = new su2double [nBufferR_Vector]; - Buffer_Send_U = new su2double[nBufferS_Vector]; - - /*--- Copy the solution that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution(iVar); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_U; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - - /*--- Copy conservative variables. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetSolution(iVar, Buffer_Receive_U[iVar*nVertexR+iVertex]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_U; - - } - - } - -} - -void CAdjTurbSolver::Set_MPI_Solution_Old(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iMarker, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_U = new su2double [nBufferR_Vector]; - Buffer_Send_U = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution_Old(iVar); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); - -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_U; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - - /*--- Copy transformed conserved variables back into buffer. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetSolution_Old(iVar, Buffer_Receive_U[iVar*nVertexR+iVertex]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_U; - - } - - } -} - -void CAdjTurbSolver::Set_MPI_Solution_Gradient(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, - *Buffer_Receive_Gradient = NULL, *Buffer_Send_Gradient = NULL; - - su2double **Gradient = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - Gradient[iVar] = new su2double[nDim]; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar*nDim; nBufferR_Vector = nVertexR*nVar*nDim; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_Gradient = new su2double [nBufferR_Vector]; - Buffer_Send_Gradient = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Gradient[iDim*nVar*nVertexS+iVar*nVertexS+iVertex] = node[iPoint]->GetGradient(iVar, iDim); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Gradient, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_Gradient, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex] = Buffer_Send_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_Gradient; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Gradient[iVar][iDim] = Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; - - /*--- Need to rotate the gradients for all conserved variables. ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - if (nDim == 2) { - Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; - } - else { - Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][2] = rotMatrix[2][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; - } - } - - /*--- Store the received information ---*/ - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - node[iPoint]->SetGradient(iVar, iDim, Gradient[iVar][iDim]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_Gradient; - - } - - } - - for (iVar = 0; iVar < nVar; iVar++) - delete [] Gradient[iVar]; - delete [] Gradient; - -} - -void CAdjTurbSolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned long iPoint, iVertex; - - for (iVertex = 0; iVertexnVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - if (geometry->node[iPoint]->GetDomain()) { - - Solution[0] = 0.0; - - /*--- Set the solution values and zero the residual ---*/ - node[iPoint]->SetSolution_Old(Solution); - LinSysRes.SetBlock_Zero(iPoint); - - /*--- Change rows of the Jacobian (includes 1 in the diagonal) ---*/ - Jacobian.DeleteValsRowi(iPoint); - - } - } - -} - -void CAdjTurbSolver::BC_Isothermal_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned long iPoint, iVertex; - - for (iVertex = 0; iVertexnVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - if (geometry->node[iPoint]->GetDomain()) { - - Solution[0] = 0.0; - - /*--- Set the solution values and zero the residual ---*/ - node[iPoint]->SetSolution_Old(Solution); - LinSysRes.SetBlock_Zero(iPoint); - - /*--- Change rows of the Jacobian (includes 1 in the diagonal) ---*/ - Jacobian.DeleteValsRowi(iPoint); - - } - } - -} - -void CAdjTurbSolver::BC_Far_Field(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - unsigned long iPoint, iVertex; - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Set Normal ---*/ - conv_numerics->SetNormal(geometry->vertex[val_marker][iVertex]->GetNormal()); - - /*--- Set Conservative variables (for convection) ---*/ - su2double* U_i = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); - conv_numerics->SetConservative(U_i, NULL); - - /*--- Turbulent adjoint variables w/o reconstruction ---*/ - su2double* TurbPsi_i = node[iPoint]->GetSolution(); - conv_numerics->SetTurbAdjointVar(TurbPsi_i, NULL); - - /*--- Add Residuals and Jacobians ---*/ - conv_numerics->ComputeResidual(Residual, Jacobian_ii, NULL, config); - LinSysRes.AddBlock(iPoint, Residual); - Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); - - } - -} - -void CAdjTurbSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { - unsigned long iPoint; - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - - /*--- Initialize the residual vector ---*/ - LinSysRes.SetBlock_Zero(iPoint); - - } - - - /*--- Initialize the Jacobian matrices ---*/ - Jacobian.SetValZero(); - - /*--- Gradient of the adjoint turbulent variables ---*/ - if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); - - /*--- Gradient of the turbulent variables ---*/ - if (config->GetKind_Gradient_Method() == GREEN_GAUSS) solver_container[TURB_SOL]->SetSolution_Gradient_GG(geometry, config); - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) solver_container[TURB_SOL]->SetSolution_Gradient_LS(geometry, config); - -} - -void CAdjTurbSolver::Upwind_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, unsigned short iMesh) { - - unsigned long iEdge, iPoint, jPoint; - su2double *U_i, *U_j, *TurbPsi_i, *TurbPsi_j, **TurbVar_Grad_i, **TurbVar_Grad_j; -// su2double *Limiter_i = NULL, *Limiter_j = NULL, **Gradient_i, **Gradient_j, Project_Grad_i, Project_Grad_j; -// unsigned short iDim, iVar; - - bool second_order = ((config->GetSpatialOrder() == SECOND_ORDER) || (config->GetSpatialOrder() == SECOND_ORDER_LIMITER)); - bool limiter = (config->GetSpatialOrder() == SECOND_ORDER_LIMITER); - - if (second_order) { - if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); - if (limiter) SetSolution_Limiter(geometry, config); - } - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Points in edge ---*/ - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - - /*--- Conservative variables w/o reconstruction ---*/ - U_i = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); - U_j = solver_container[FLOW_SOL]->node[jPoint]->GetSolution(); - numerics->SetConservative(U_i, U_j); - - /*--- Set normal vectors and length ---*/ - numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); - - /*--- Turbulent adjoint variables w/o reconstruction ---*/ - TurbPsi_i = node[iPoint]->GetSolution(); - TurbPsi_j = node[jPoint]->GetSolution(); - numerics->SetTurbAdjointVar(TurbPsi_i, TurbPsi_j); - - /*--- Gradient of turbulent variables w/o reconstruction ---*/ - TurbVar_Grad_i = solver_container[TURB_SOL]->node[iPoint]->GetGradient(); - TurbVar_Grad_j = solver_container[TURB_SOL]->node[jPoint]->GetGradient(); - numerics->SetTurbVarGradient(TurbVar_Grad_i, TurbVar_Grad_j); - -// if (second_order) { -// -// /*--- Conservative solution using gradient reconstruction ---*/ -// for (iDim = 0; iDim < nDim; iDim++) { -// Vector_i[iDim] = 0.5*(geometry->node[jPoint]->GetCoord(iDim) - geometry->node[iPoint]->GetCoord(iDim)); -// Vector_j[iDim] = 0.5*(geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim)); -// } -// Gradient_i = solver_container[FLOW_SOL]->node[iPoint]->GetGradient(); -// Gradient_j = solver_container[FLOW_SOL]->node[jPoint]->GetGradient(); -// for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { -// Project_Grad_i = 0; Project_Grad_j = 0; -// for (iDim = 0; iDim < nDim; iDim++) { -// Project_Grad_i += Vector_i[iDim]*Gradient_i[iVar][iDim]; -// Project_Grad_j += Vector_j[iDim]*Gradient_j[iVar][iDim]; -// } -// FlowSolution_i[iVar] = U_i[iVar] + Project_Grad_i; -// FlowSolution_j[iVar] = U_j[iVar] + Project_Grad_j; -// } -// numerics->SetConservative(FlowSolution_i, FlowSolution_j); -// -// /*--- Adjoint turbulent variables using gradient reconstruction ---*/ -// Gradient_i = node[iPoint]->GetGradient(); Gradient_j = node[jPoint]->GetGradient(); -// if (limiter) { Limiter_i = node[iPoint]->GetLimiter(); Limiter_j = node[jPoint]->GetLimiter(); } -// for (iVar = 0; iVar < nVar; iVar++) { -// Project_Grad_i = 0; Project_Grad_j = 0; -// for (iDim = 0; iDim < nDim; iDim++) { -// Project_Grad_i += Vector_i[iDim]*Gradient_i[iVar][iDim]; -// Project_Grad_j += Vector_j[iDim]*Gradient_j[iVar][iDim]; -// } -// if (limiter) { -// Solution_i[iVar] = TurbPsi_i[iVar] + Project_Grad_i*Limiter_i[iVar]; -// Solution_j[iVar] = TurbPsi_j[iVar] + Project_Grad_j*Limiter_j[iVar]; -// } -// else { -// Solution_i[iVar] = TurbPsi_i[iVar] + Project_Grad_i; -// Solution_j[iVar] = TurbPsi_j[iVar] + Project_Grad_j; -// } -// } -// numerics->SetTurbVar(Solution_i, Solution_j); -// -// } - - /*--- Set normal vectors and length ---*/ - numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); - - numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - /*--- Add and Subtract Residual ---*/ - LinSysRes.AddBlock(iPoint, Residual_i); - LinSysRes.AddBlock(jPoint, Residual_j); - Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); - Jacobian.AddBlock(iPoint, jPoint, Jacobian_ij); - Jacobian.AddBlock(jPoint, iPoint, Jacobian_ji); - Jacobian.AddBlock(jPoint, jPoint, Jacobian_jj); - - } - -} - -void CAdjTurbSolver::Viscous_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, - unsigned short iMesh, unsigned short iRKStep) { - unsigned long iEdge, iPoint, jPoint; - su2double *Coord_i, *Coord_j; - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Points in edge ---*/ - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - - /*--- Points coordinates, and set normal vectors and length ---*/ - Coord_i = geometry->node[iPoint]->GetCoord(); - Coord_j = geometry->node[jPoint]->GetCoord(); - numerics->SetCoord(Coord_i, Coord_j); - numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); - - /*--- Conservative variables w/o reconstruction, turbulent variables w/o reconstruction, - and turbulent adjoint variables w/o reconstruction ---*/ - numerics->SetConservative(solver_container[FLOW_SOL]->node[iPoint]->GetSolution(), solver_container[FLOW_SOL]->node[jPoint]->GetSolution()); - numerics->SetTurbVar(solver_container[TURB_SOL]->node[iPoint]->GetSolution(), solver_container[TURB_SOL]->node[jPoint]->GetSolution()); - numerics->SetTurbAdjointVar(node[iPoint]->GetSolution(), node[jPoint]->GetSolution()); - - /*--- Viscosity ---*/ - numerics->SetLaminarViscosity(solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(), - solver_container[FLOW_SOL]->node[jPoint]->GetLaminarViscosity()); - - /*--- Turbulent adjoint variables w/o reconstruction ---*/ - numerics->SetTurbAdjointGradient(node[iPoint]->GetGradient(), node[jPoint]->GetGradient()); - - /*--- Compute residual in a non-conservative way, and update ---*/ - numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); - - /*--- Update adjoint viscous residual ---*/ - LinSysRes.AddBlock(iPoint, Residual_i); - LinSysRes.AddBlock(jPoint, Residual_j); - - Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); - Jacobian.AddBlock(iPoint, jPoint, Jacobian_ij); - Jacobian.AddBlock(jPoint, iPoint, Jacobian_ji); - Jacobian.AddBlock(jPoint, jPoint, Jacobian_jj); - - } - -} - -void CAdjTurbSolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, CConfig *config, unsigned short iMesh) { - unsigned long iPoint; - su2double *U_i, **GradPrimVar_i, *TurbVar_i; - su2double **TurbVar_Grad_i, *TurbPsi_i, **PsiVar_Grad_i; // Gradients - - /*--- Piecewise source term ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Conservative variables w/o reconstruction ---*/ - U_i = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); - numerics->SetConservative(U_i, NULL); - - /*--- Gradient of primitive variables w/o reconstruction ---*/ - GradPrimVar_i = solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(); - numerics->SetPrimVarGradient(GradPrimVar_i, NULL); - - /*--- Laminar viscosity of the fluid ---*/ - numerics->SetLaminarViscosity(solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(), 0.0); - - /*--- Turbulent variables w/o reconstruction ---*/ - TurbVar_i = solver_container[TURB_SOL]->node[iPoint]->GetSolution(); - numerics->SetTurbVar(TurbVar_i, NULL); - - /*--- Gradient of Turbulent Variables w/o reconstruction ---*/ - TurbVar_Grad_i = solver_container[TURB_SOL]->node[iPoint]->GetGradient(); - numerics->SetTurbVarGradient(TurbVar_Grad_i, NULL); - - /*--- Turbulent adjoint variables w/o reconstruction ---*/ - TurbPsi_i = node[iPoint]->GetSolution(); - numerics->SetTurbAdjointVar(TurbPsi_i, NULL); - - /*--- Gradient of Adjoint flow variables w/o reconstruction - (for non-conservative terms depending on gradients of flow adjoint vars.) ---*/ - PsiVar_Grad_i = solver_container[ADJFLOW_SOL]->node[iPoint]->GetGradient(); - numerics->SetAdjointVarGradient(PsiVar_Grad_i, NULL); - - /*--- Set volume and distances to the surface ---*/ - numerics->SetVolume(geometry->node[iPoint]->GetVolume()); - numerics->SetDistance(geometry->node[iPoint]->GetWall_Distance(), 0.0); - - /*--- Add and Subtract Residual ---*/ - numerics->ComputeResidual(Residual, Jacobian_ii, NULL, config); - LinSysRes.AddBlock(iPoint, Residual); - Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); - - } - -// /*--- Conservative Source Term ---*/ -// su2double **TurbVar_Grad_j; -// unsigned long jPoint, iEdge; -// -// for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { -// -// /*--- Points in edge ---*/ -// iPoint = geometry->edge[iEdge]->GetNode(0); -// jPoint = geometry->edge[iEdge]->GetNode(1); -// -// /*--- Gradient of turbulent variables w/o reconstruction ---*/ -// TurbVar_Grad_i = solver_container[TURB_SOL]->node[iPoint]->GetGradient(); -// TurbVar_Grad_j = solver_container[TURB_SOL]->node[jPoint]->GetGradient(); -// second_numerics->SetTurbVarGradient(TurbVar_Grad_i, TurbVar_Grad_j); -// -// /*--- Turbulent adjoint variables w/o reconstruction ---*/ -// TurbPsi_i = node[iPoint]->GetSolution(); -// TurbPsi_j = node[jPoint]->GetSolution(); -// second_numerics->SetTurbAdjointVar(TurbPsi_i, TurbPsi_j); -// -// /*--- Set normal vectors and length ---*/ -// second_numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); -// -// /*--- Add and Subtract Residual ---*/ -// second_numerics->ComputeResidual(Residual, Jacobian_ii, Jacobian_jj, config); -// LinSysRes.AddBlock(iPoint, Residual); -// LinSysRes.SubtractBlock(jPoint, Residual); -// Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); -// Jacobian.AddBlock(iPoint, jPoint, Jacobian_jj); -// Jacobian.SubtractBlock(jPoint, iPoint, Jacobian_ii); -// Jacobian.SubtractBlock(jPoint, jPoint, Jacobian_jj); -// -// } - -} - -void CAdjTurbSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { - - unsigned short iVar; - unsigned long iPoint, total_index; - su2double Delta, Vol; - - /*--- Set maximum residual to zero ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - SetRes_RMS(iVar, 0.0); - SetRes_Max(iVar, 0.0, 0); - } - - /*--- Build implicit system ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - - /*--- Read the volume ---*/ - - Vol = geometry->node[iPoint]->GetVolume(); - - /*--- Modify matrix diagonal to assure diagonal dominance ---*/ - - Delta = Vol / (config->GetCFLRedCoeff_AdjTurb()*solver_container[FLOW_SOL]->node[iPoint]->GetDelta_Time()); - - Jacobian.AddVal2Diag(iPoint, Delta); - - /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - LinSysRes[total_index] = -LinSysRes[total_index]; - LinSysSol[total_index] = 0.0; - AddRes_RMS(iVar, LinSysRes[total_index]*LinSysRes[total_index]); - AddRes_Max(iVar, fabs(LinSysRes[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); - } - - } - - /*--- Initialize residual and solution at the ghost points ---*/ - - for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar + iVar; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - } - } - - /*--- Solve or smooth the linear system ---*/ - - CSysSolve system; - system.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); - - /*--- Update solution (system written in terms of increments) ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->AddSolution(iVar, LinSysSol[iPoint*nVar+iVar]); - } - - /*--- MPI solution ---*/ - - Set_MPI_Solution(geometry, config); - - /*--- Compute the root mean square residual ---*/ - - SetResidual_RMS(geometry, config); - -} +/*! + * \file solution_adjoint_turbulent.cpp + * \brief Main subrotuines for solving adjoint problems (Euler, Navier-Stokes, etc.). + * \author F. Palacios, A. Bueno, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/solver_structure.hpp" + +CAdjTurbSolver::CAdjTurbSolver(void) : CSolver() {} + +CAdjTurbSolver::CAdjTurbSolver(CGeometry *geometry, CConfig *config, unsigned short iMesh) : CSolver() { + unsigned long iPoint; + unsigned short iDim, iVar, nLineLets; + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + nDim = geometry->GetnDim(); + Gamma = config->GetGamma(); + Gamma_Minus_One = Gamma - 1.0; + + /*--- Dimension of the problem ---*/ + switch (config->GetKind_Turb_Model()) { + case SA : nVar = 1; break; + case SA_NEG : nVar = 1; break; + case SST : nVar = 2; break; + } + + nPoint = geometry->GetnPoint(); + nPointDomain = geometry->GetnPointDomain(); + + Residual = new su2double [nVar]; Residual_RMS = new su2double[nVar]; + Residual_i = new su2double [nVar]; Residual_j = new su2double [nVar]; + Residual_Max = new su2double [nVar]; Point_Max = new unsigned long[nVar]; + Point_Max_Coord = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Point_Max_Coord[iVar] = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; + } + + Solution = new su2double [nVar]; + Solution_i = new su2double [nVar]; + Solution_j = new su2double [nVar]; + + /*--- Define some auxiliar vector related with the geometry ---*/ + Vector_i = new su2double[nDim]; Vector_j = new su2double[nDim]; + + /*--- Define some auxiliar vector related with the flow solution ---*/ + FlowSolution_i = new su2double [nDim+2]; FlowSolution_j = new su2double [nDim+2]; + + /*--- Point to point Jacobians ---*/ + Jacobian_ii = new su2double* [nVar]; + Jacobian_ij = new su2double* [nVar]; + Jacobian_ji = new su2double* [nVar]; + Jacobian_jj = new su2double* [nVar]; + for (unsigned short iVar = 0; iVar < nVar; iVar++) { + Jacobian_ii[iVar] = new su2double [nVar]; + Jacobian_ij[iVar] = new su2double [nVar]; + Jacobian_ji[iVar] = new su2double [nVar]; + Jacobian_jj[iVar] = new su2double [nVar]; + } + + /*--- Initialization of the structure of the whole Jacobian ---*/ + Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); + + if ((config->GetKind_Linear_Solver_Prec() == LINELET) || + (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { + nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); + if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; + } + + Jacobian.SetValZero(); + LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); + LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); + + /*--- Computation of gradients by least squares ---*/ + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { + /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ + Smatrix = new su2double* [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Smatrix[iDim] = new su2double [nDim]; + /*--- c vector := transpose(WA)*(Wb) ---*/ + cvector = new su2double* [nVar+1]; + for (iVar = 0; iVar < nVar+1; iVar++) + cvector[iVar] = new su2double [nDim]; + } + + /*--- Far-Field values and initizalization ---*/ + node = new CVariable* [nPoint]; + bool restart = config->GetRestart(); + + if (!restart || (iMesh != MESH_0)) { + PsiNu_Inf = 0.0; + for (iPoint = 0; iPoint < nPoint; iPoint++) { + node[iPoint] = new CAdjTurbVariable(PsiNu_Inf, nDim, nVar, config); + } + } + else { + unsigned long index; + su2double dull_val; + string filename, AdjExt, text_line; + ifstream restart_file; + + /*--- Restart the solution from file information ---*/ + string mesh_filename = config->GetSolution_AdjFileName(); + filename = config->GetObjFunc_Extension(mesh_filename); + + restart_file.open(filename.data(), ios::in); + + /*--- In case there is no file ---*/ + if (restart_file.fail()) { + if (rank == MASTER_NODE) + cout << "There is no adjoint restart file!! " << filename.data() << "."<< endl; + exit(EXIT_FAILURE); + } + + /*--- In case this is a parallel simulation, we need to perform the + Global2Local index transformation first. ---*/ + long *Global2Local; + Global2Local = new long[geometry->GetGlobal_nPointDomain()]; + /*--- First, set all indices to a negative value by default ---*/ + for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) { + Global2Local[iPoint] = -1; + } + /*--- Now fill array with the transform values only for local points ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; + } + + /*--- Read all lines in the restart file ---*/ + long iPoint_Local; unsigned long iPoint_Global = 0; + + /*--- The first line is the header ---*/ + getline (restart_file, text_line); + + while (getline (restart_file, text_line)) { + istringstream point_line(text_line); + + /*--- Retrieve local index. If this node from the restart file lives + on a different processor, the value of iPoint_Local will be -1. + Otherwise, the local index for this node on the current processor + will be returned and used to instantiate the vars. ---*/ + iPoint_Local = Global2Local[iPoint_Global]; + if (iPoint_Local >= 0) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; + node[iPoint_Local] = new CAdjTurbVariable(Solution[0], nDim, nVar, config); + } + iPoint_Global++; + } + + /*--- Instantiate the variable class with an arbitrary solution + at any halo/periodic nodes. The initial solution can be arbitrary, + because a send/recv is performed immediately in the solver. ---*/ + for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { + node[iPoint] = new CAdjTurbVariable(Solution[0], nDim, nVar, config); + } + + /*--- Close the restart file ---*/ + restart_file.close(); + + /*--- Free memory needed for the transformation ---*/ + delete [] Global2Local; + } + + /*--- MPI solution ---*/ + Set_MPI_Solution(geometry, config); + +} + +CAdjTurbSolver::~CAdjTurbSolver(void) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) { + delete [] Jacobian_ii[iVar]; + delete [] Jacobian_ij[iVar]; + delete [] Jacobian_ji[iVar]; + delete [] Jacobian_jj[iVar]; + } + + delete [] Jacobian_ii; + delete [] Jacobian_ij; + delete [] Jacobian_ji; + delete [] Jacobian_jj; + +} + +void CAdjTurbSolver::Set_MPI_Solution(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iMarker, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_U = new su2double [nBufferR_Vector]; + Buffer_Send_U = new su2double[nBufferS_Vector]; + + /*--- Copy the solution that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution(iVar); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_U; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + + /*--- Copy conservative variables. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetSolution(iVar, Buffer_Receive_U[iVar*nVertexR+iVertex]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_U; + + } + + } + +} + +void CAdjTurbSolver::Set_MPI_Solution_Old(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iMarker, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_U = new su2double [nBufferR_Vector]; + Buffer_Send_U = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution_Old(iVar); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); + +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_U; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + + /*--- Copy transformed conserved variables back into buffer. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetSolution_Old(iVar, Buffer_Receive_U[iVar*nVertexR+iVertex]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_U; + + } + + } +} + +void CAdjTurbSolver::Set_MPI_Solution_Gradient(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, + *Buffer_Receive_Gradient = NULL, *Buffer_Send_Gradient = NULL; + + su2double **Gradient = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + Gradient[iVar] = new su2double[nDim]; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar*nDim; nBufferR_Vector = nVertexR*nVar*nDim; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_Gradient = new su2double [nBufferR_Vector]; + Buffer_Send_Gradient = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Gradient[iDim*nVar*nVertexS+iVar*nVertexS+iVertex] = node[iPoint]->GetGradient(iVar, iDim); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Gradient, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_Gradient, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex] = Buffer_Send_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_Gradient; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Gradient[iVar][iDim] = Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; + + /*--- Need to rotate the gradients for all conserved variables. ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + if (nDim == 2) { + Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; + } + else { + Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][2] = rotMatrix[2][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; + } + } + + /*--- Store the received information ---*/ + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + node[iPoint]->SetGradient(iVar, iDim, Gradient[iVar][iDim]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_Gradient; + + } + + } + + for (iVar = 0; iVar < nVar; iVar++) + delete [] Gradient[iVar]; + delete [] Gradient; + +} + +void CAdjTurbSolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned long iPoint, iVertex; + + for (iVertex = 0; iVertexnVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ + if (geometry->node[iPoint]->GetDomain()) { + + Solution[0] = 0.0; + + /*--- Set the solution values and zero the residual ---*/ + node[iPoint]->SetSolution_Old(Solution); + LinSysRes.SetBlock_Zero(iPoint); + + /*--- Change rows of the Jacobian (includes 1 in the diagonal) ---*/ + Jacobian.DeleteValsRowi(iPoint); + + } + } + +} + +void CAdjTurbSolver::BC_Isothermal_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned long iPoint, iVertex; + + for (iVertex = 0; iVertexnVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ + if (geometry->node[iPoint]->GetDomain()) { + + Solution[0] = 0.0; + + /*--- Set the solution values and zero the residual ---*/ + node[iPoint]->SetSolution_Old(Solution); + LinSysRes.SetBlock_Zero(iPoint); + + /*--- Change rows of the Jacobian (includes 1 in the diagonal) ---*/ + Jacobian.DeleteValsRowi(iPoint); + + } + } + +} + +void CAdjTurbSolver::BC_Far_Field(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + unsigned long iPoint, iVertex; + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Set Normal ---*/ + conv_numerics->SetNormal(geometry->vertex[val_marker][iVertex]->GetNormal()); + + /*--- Set Conservative variables (for convection) ---*/ + su2double* U_i = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); + conv_numerics->SetConservative(U_i, NULL); + + /*--- Turbulent adjoint variables w/o reconstruction ---*/ + su2double* TurbPsi_i = node[iPoint]->GetSolution(); + conv_numerics->SetTurbAdjointVar(TurbPsi_i, NULL); + + /*--- Add Residuals and Jacobians ---*/ + conv_numerics->ComputeResidual(Residual, Jacobian_ii, NULL, config); + LinSysRes.AddBlock(iPoint, Residual); + Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); + + } + +} + +void CAdjTurbSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { + unsigned long iPoint; + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + + /*--- Initialize the residual vector ---*/ + LinSysRes.SetBlock_Zero(iPoint); + + } + + + /*--- Initialize the Jacobian matrices ---*/ + Jacobian.SetValZero(); + + /*--- Gradient of the adjoint turbulent variables ---*/ + if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); + + /*--- Gradient of the turbulent variables ---*/ + if (config->GetKind_Gradient_Method() == GREEN_GAUSS) solver_container[TURB_SOL]->SetSolution_Gradient_GG(geometry, config); + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) solver_container[TURB_SOL]->SetSolution_Gradient_LS(geometry, config); + +} + +void CAdjTurbSolver::Upwind_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, unsigned short iMesh) { + + unsigned long iEdge, iPoint, jPoint; + su2double *U_i, *U_j, *TurbPsi_i, *TurbPsi_j, **TurbVar_Grad_i, **TurbVar_Grad_j; +// su2double *Limiter_i = NULL, *Limiter_j = NULL, **Gradient_i, **Gradient_j, Project_Grad_i, Project_Grad_j; +// unsigned short iDim, iVar; + + bool second_order = ((config->GetSpatialOrder() == SECOND_ORDER) || (config->GetSpatialOrder() == SECOND_ORDER_LIMITER)); + bool limiter = (config->GetSpatialOrder() == SECOND_ORDER_LIMITER); + + if (second_order) { + if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); + if (limiter) SetSolution_Limiter(geometry, config); + } + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Points in edge ---*/ + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + + /*--- Conservative variables w/o reconstruction ---*/ + U_i = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); + U_j = solver_container[FLOW_SOL]->node[jPoint]->GetSolution(); + numerics->SetConservative(U_i, U_j); + + /*--- Set normal vectors and length ---*/ + numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); + + /*--- Turbulent adjoint variables w/o reconstruction ---*/ + TurbPsi_i = node[iPoint]->GetSolution(); + TurbPsi_j = node[jPoint]->GetSolution(); + numerics->SetTurbAdjointVar(TurbPsi_i, TurbPsi_j); + + /*--- Gradient of turbulent variables w/o reconstruction ---*/ + TurbVar_Grad_i = solver_container[TURB_SOL]->node[iPoint]->GetGradient(); + TurbVar_Grad_j = solver_container[TURB_SOL]->node[jPoint]->GetGradient(); + numerics->SetTurbVarGradient(TurbVar_Grad_i, TurbVar_Grad_j); + +// if (second_order) { +// +// /*--- Conservative solution using gradient reconstruction ---*/ +// for (iDim = 0; iDim < nDim; iDim++) { +// Vector_i[iDim] = 0.5*(geometry->node[jPoint]->GetCoord(iDim) - geometry->node[iPoint]->GetCoord(iDim)); +// Vector_j[iDim] = 0.5*(geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim)); +// } +// Gradient_i = solver_container[FLOW_SOL]->node[iPoint]->GetGradient(); +// Gradient_j = solver_container[FLOW_SOL]->node[jPoint]->GetGradient(); +// for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { +// Project_Grad_i = 0; Project_Grad_j = 0; +// for (iDim = 0; iDim < nDim; iDim++) { +// Project_Grad_i += Vector_i[iDim]*Gradient_i[iVar][iDim]; +// Project_Grad_j += Vector_j[iDim]*Gradient_j[iVar][iDim]; +// } +// FlowSolution_i[iVar] = U_i[iVar] + Project_Grad_i; +// FlowSolution_j[iVar] = U_j[iVar] + Project_Grad_j; +// } +// numerics->SetConservative(FlowSolution_i, FlowSolution_j); +// +// /*--- Adjoint turbulent variables using gradient reconstruction ---*/ +// Gradient_i = node[iPoint]->GetGradient(); Gradient_j = node[jPoint]->GetGradient(); +// if (limiter) { Limiter_i = node[iPoint]->GetLimiter(); Limiter_j = node[jPoint]->GetLimiter(); } +// for (iVar = 0; iVar < nVar; iVar++) { +// Project_Grad_i = 0; Project_Grad_j = 0; +// for (iDim = 0; iDim < nDim; iDim++) { +// Project_Grad_i += Vector_i[iDim]*Gradient_i[iVar][iDim]; +// Project_Grad_j += Vector_j[iDim]*Gradient_j[iVar][iDim]; +// } +// if (limiter) { +// Solution_i[iVar] = TurbPsi_i[iVar] + Project_Grad_i*Limiter_i[iVar]; +// Solution_j[iVar] = TurbPsi_j[iVar] + Project_Grad_j*Limiter_j[iVar]; +// } +// else { +// Solution_i[iVar] = TurbPsi_i[iVar] + Project_Grad_i; +// Solution_j[iVar] = TurbPsi_j[iVar] + Project_Grad_j; +// } +// } +// numerics->SetTurbVar(Solution_i, Solution_j); +// +// } + + /*--- Set normal vectors and length ---*/ + numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); + + numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + /*--- Add and Subtract Residual ---*/ + LinSysRes.AddBlock(iPoint, Residual_i); + LinSysRes.AddBlock(jPoint, Residual_j); + Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); + Jacobian.AddBlock(iPoint, jPoint, Jacobian_ij); + Jacobian.AddBlock(jPoint, iPoint, Jacobian_ji); + Jacobian.AddBlock(jPoint, jPoint, Jacobian_jj); + + } + +} + +void CAdjTurbSolver::Viscous_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, + unsigned short iMesh, unsigned short iRKStep) { + unsigned long iEdge, iPoint, jPoint; + su2double *Coord_i, *Coord_j; + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Points in edge ---*/ + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + + /*--- Points coordinates, and set normal vectors and length ---*/ + Coord_i = geometry->node[iPoint]->GetCoord(); + Coord_j = geometry->node[jPoint]->GetCoord(); + numerics->SetCoord(Coord_i, Coord_j); + numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); + + /*--- Conservative variables w/o reconstruction, turbulent variables w/o reconstruction, + and turbulent adjoint variables w/o reconstruction ---*/ + numerics->SetConservative(solver_container[FLOW_SOL]->node[iPoint]->GetSolution(), solver_container[FLOW_SOL]->node[jPoint]->GetSolution()); + numerics->SetTurbVar(solver_container[TURB_SOL]->node[iPoint]->GetSolution(), solver_container[TURB_SOL]->node[jPoint]->GetSolution()); + numerics->SetTurbAdjointVar(node[iPoint]->GetSolution(), node[jPoint]->GetSolution()); + + /*--- Viscosity ---*/ + numerics->SetLaminarViscosity(solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(), + solver_container[FLOW_SOL]->node[jPoint]->GetLaminarViscosity()); + + /*--- Turbulent adjoint variables w/o reconstruction ---*/ + numerics->SetTurbAdjointGradient(node[iPoint]->GetGradient(), node[jPoint]->GetGradient()); + + /*--- Compute residual in a non-conservative way, and update ---*/ + numerics->ComputeResidual(Residual_i, Residual_j, Jacobian_ii, Jacobian_ij, Jacobian_ji, Jacobian_jj, config); + + /*--- Update adjoint viscous residual ---*/ + LinSysRes.AddBlock(iPoint, Residual_i); + LinSysRes.AddBlock(jPoint, Residual_j); + + Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); + Jacobian.AddBlock(iPoint, jPoint, Jacobian_ij); + Jacobian.AddBlock(jPoint, iPoint, Jacobian_ji); + Jacobian.AddBlock(jPoint, jPoint, Jacobian_jj); + + } + +} + +void CAdjTurbSolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, CConfig *config, unsigned short iMesh) { + unsigned long iPoint; + su2double *U_i, **GradPrimVar_i, *TurbVar_i; + su2double **TurbVar_Grad_i, *TurbPsi_i, **PsiVar_Grad_i; // Gradients + + /*--- Piecewise source term ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Conservative variables w/o reconstruction ---*/ + U_i = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); + numerics->SetConservative(U_i, NULL); + + /*--- Gradient of primitive variables w/o reconstruction ---*/ + GradPrimVar_i = solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(); + numerics->SetPrimVarGradient(GradPrimVar_i, NULL); + + /*--- Laminar viscosity of the fluid ---*/ + numerics->SetLaminarViscosity(solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(), 0.0); + + /*--- Turbulent variables w/o reconstruction ---*/ + TurbVar_i = solver_container[TURB_SOL]->node[iPoint]->GetSolution(); + numerics->SetTurbVar(TurbVar_i, NULL); + + /*--- Gradient of Turbulent Variables w/o reconstruction ---*/ + TurbVar_Grad_i = solver_container[TURB_SOL]->node[iPoint]->GetGradient(); + numerics->SetTurbVarGradient(TurbVar_Grad_i, NULL); + + /*--- Turbulent adjoint variables w/o reconstruction ---*/ + TurbPsi_i = node[iPoint]->GetSolution(); + numerics->SetTurbAdjointVar(TurbPsi_i, NULL); + + /*--- Gradient of Adjoint flow variables w/o reconstruction + (for non-conservative terms depending on gradients of flow adjoint vars.) ---*/ + PsiVar_Grad_i = solver_container[ADJFLOW_SOL]->node[iPoint]->GetGradient(); + numerics->SetAdjointVarGradient(PsiVar_Grad_i, NULL); + + /*--- Set volume and distances to the surface ---*/ + numerics->SetVolume(geometry->node[iPoint]->GetVolume()); + numerics->SetDistance(geometry->node[iPoint]->GetWall_Distance(), 0.0); + + /*--- Add and Subtract Residual ---*/ + numerics->ComputeResidual(Residual, Jacobian_ii, NULL, config); + LinSysRes.AddBlock(iPoint, Residual); + Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); + + } + +// /*--- Conservative Source Term ---*/ +// su2double **TurbVar_Grad_j; +// unsigned long jPoint, iEdge; +// +// for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { +// +// /*--- Points in edge ---*/ +// iPoint = geometry->edge[iEdge]->GetNode(0); +// jPoint = geometry->edge[iEdge]->GetNode(1); +// +// /*--- Gradient of turbulent variables w/o reconstruction ---*/ +// TurbVar_Grad_i = solver_container[TURB_SOL]->node[iPoint]->GetGradient(); +// TurbVar_Grad_j = solver_container[TURB_SOL]->node[jPoint]->GetGradient(); +// second_numerics->SetTurbVarGradient(TurbVar_Grad_i, TurbVar_Grad_j); +// +// /*--- Turbulent adjoint variables w/o reconstruction ---*/ +// TurbPsi_i = node[iPoint]->GetSolution(); +// TurbPsi_j = node[jPoint]->GetSolution(); +// second_numerics->SetTurbAdjointVar(TurbPsi_i, TurbPsi_j); +// +// /*--- Set normal vectors and length ---*/ +// second_numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); +// +// /*--- Add and Subtract Residual ---*/ +// second_numerics->ComputeResidual(Residual, Jacobian_ii, Jacobian_jj, config); +// LinSysRes.AddBlock(iPoint, Residual); +// LinSysRes.SubtractBlock(jPoint, Residual); +// Jacobian.AddBlock(iPoint, iPoint, Jacobian_ii); +// Jacobian.AddBlock(iPoint, jPoint, Jacobian_jj); +// Jacobian.SubtractBlock(jPoint, iPoint, Jacobian_ii); +// Jacobian.SubtractBlock(jPoint, jPoint, Jacobian_jj); +// +// } + +} + +void CAdjTurbSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { + + unsigned short iVar; + unsigned long iPoint, total_index; + su2double Delta, Vol; + + /*--- Set maximum residual to zero ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + SetRes_RMS(iVar, 0.0); + SetRes_Max(iVar, 0.0, 0); + } + + /*--- Build implicit system ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + + /*--- Read the volume ---*/ + + Vol = geometry->node[iPoint]->GetVolume(); + + /*--- Modify matrix diagonal to assure diagonal dominance ---*/ + + Delta = Vol / (config->GetCFLRedCoeff_AdjTurb()*solver_container[FLOW_SOL]->node[iPoint]->GetDelta_Time()); + + Jacobian.AddVal2Diag(iPoint, Delta); + + /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + LinSysRes[total_index] = -LinSysRes[total_index]; + LinSysSol[total_index] = 0.0; + AddRes_RMS(iVar, LinSysRes[total_index]*LinSysRes[total_index]); + AddRes_Max(iVar, fabs(LinSysRes[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); + } + + } + + /*--- Initialize residual and solution at the ghost points ---*/ + + for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar + iVar; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + } + } + + /*--- Solve or smooth the linear system ---*/ + + CSysSolve system; + system.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); + + /*--- Update solution (system written in terms of increments) ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->AddSolution(iVar, LinSysSol[iPoint*nVar+iVar]); + } + + /*--- MPI solution ---*/ + + Set_MPI_Solution(geometry, config); + + /*--- Compute the root mean square residual ---*/ + + SetResidual_RMS(geometry, config); + +} diff --git a/SU2_CFD/src/solver_direct_elasticity.cpp b/SU2_CFD/src/solver_direct_elasticity.cpp index 515247d0f8c..283719f9210 100644 --- a/SU2_CFD/src/solver_direct_elasticity.cpp +++ b/SU2_CFD/src/solver_direct_elasticity.cpp @@ -1,2437 +1,2437 @@ -/*! - * \file solution_direct_elasticity.cpp - * \brief Main subrotuines for solving the linear elasticity equation. - * \author F. Palacios, R. Sanchez - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/solver_structure.hpp" - -CFEASolver::CFEASolver(void) : CSolver() { } - -CFEASolver::CFEASolver(CGeometry *geometry, CConfig *config) : CSolver() { - - unsigned long iPoint; - unsigned short iVar, jVar, NodesElement = 0, nLineLets; - unsigned short iDim; - su2double dull_val; - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - nPoint = geometry->GetnPoint(); - nPointDomain = geometry->GetnPointDomain(); - nDim = geometry->GetnDim(); - node = new CVariable*[nPoint]; - - - WAitken_Dyn = 0.0; - WAitken_Dyn_tn1 = 0.0; - - SetFSI_ConvValue(0,0.0); - SetFSI_ConvValue(1,0.0); - - nVar = nDim; - - if (nDim == 2) NodesElement = 4; - if (nDim == 3) NodesElement = 8; - - /*--- Define some auxiliary vectors related to the residual ---*/ - - Residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; - Residual_RMS = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_RMS[iVar] = 0.0; - Residual_Max = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_Max[iVar] = 0.0; - Point_Max = new unsigned long[nVar]; for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; - Point_Max_Coord = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Point_Max_Coord[iVar] = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; - } - - /*--- Define some auxiliary vectors related to the solution ---*/ - - Solution = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; - - /*--- Element aux stiffness matrix definition ---*/ - - StiffMatrix_Elem = new su2double*[NodesElement*nDim]; - for (iVar = 0; iVar < NodesElement*nDim; iVar++) { - StiffMatrix_Elem[iVar] = new su2double [NodesElement*nDim]; - for (jVar = 0; jVar < NodesElement*nDim; jVar++) { - StiffMatrix_Elem[iVar][jVar] = 0.0; - } - } - - /*--- Node aux stiffness matrix definition ---*/ - - StiffMatrix_Node = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - StiffMatrix_Node[iVar] = new su2double [nVar]; - for (jVar = 0; jVar < nVar; jVar++) { - StiffMatrix_Node[iVar][jVar] = 0.0; - } - } - - /*--- Element aux mass matrix definition ---*/ - - MassMatrix_Elem = new su2double*[NodesElement*nDim]; - for (iVar = 0; iVar < NodesElement*nDim; iVar++) { - MassMatrix_Elem[iVar] = new su2double [NodesElement*nDim]; - for (jVar = 0; jVar < NodesElement*nDim; jVar++) { - MassMatrix_Elem[iVar][jVar] = 0.0; - } - } - - /*--- Node aux mass matrix definition ---*/ - - MassMatrix_Node = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - MassMatrix_Node[iVar] = new su2double [nVar]; - for (jVar = 0; jVar < nVar; jVar++) { - MassMatrix_Node[iVar][jVar] = 0.0; - } - } - - /*--- Node aux mass matrix definition ---*/ - - MassMatrix_Node_Int = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - MassMatrix_Node_Int[iVar] = new su2double [nVar]; - for (jVar = 0; jVar < nVar; jVar++) { - MassMatrix_Node_Int[iVar][jVar] = 0.0; - } - } - - /*--- Element aux damping matrix definition ---*/ - - DampMatrix_Elem = new su2double*[NodesElement*nDim]; - for (iVar = 0; iVar < NodesElement*nDim; iVar++) { - DampMatrix_Elem[iVar] = new su2double [NodesElement*nDim]; - for (jVar = 0; jVar < NodesElement*nDim; jVar++) { - DampMatrix_Elem[iVar][jVar] = 0.0; - } - } - - /*--- Node aux damping matrix definition ---*/ - - DampMatrix_Node = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - DampMatrix_Node[iVar] = new su2double [nVar]; - for (jVar = 0; jVar < nVar; jVar++) { - DampMatrix_Node[iVar][jVar] = 0.0; - } - } - - /*--- Initialization of integration constants ---*/ - - for (iVar = 0; iVar < 8; iVar++){ - a_dt[iVar]=0.0; - } - - - - /*--- DESTRUCT THIS! ---*/ - - /*--- Element aux dead load vector definition ---*/ - DeadLoadVector_Elem = new su2double [NodesElement*nDim]; - - /*--- Node aux dead load vector definition ---*/ - DeadLoadVector_Node = new su2double [nVar]; - - - /*--- Initialization of matrix structures ---*/ - - if (rank == MASTER_NODE) cout << "Initialize Stiffness structure (Linear Elasticity)." << endl; - - if (nDim==2){ - unsigned short form2d; - form2d=config->GetElas2D_Formulation(); - if (form2d==0) cout << "Plane stress model for 2D structural analysis (Linear Elasticity)." << endl; - if (form2d==1) cout << "Plane strain model for 2D structural analysis (Linear Elasticity)." << endl; - } - - StiffMatrixSpace.Initialize(nPoint, nPointDomain, nVar, nVar, false, geometry, config); - StiffMatrixTime.Initialize(nPoint, nPointDomain, nVar, nVar, false, geometry, config); - MassMatrix.Initialize(nPoint, nPointDomain, nVar, nVar, false, geometry, config); - DampMatrix.Initialize(nPoint, nPointDomain, nVar, nVar, false, geometry, config); - - if (rank == MASTER_NODE) cout << "Initialize Jacobian structure (Linear Elasticity)." << endl; - Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, false, geometry, config); - - if ((config->GetKind_Linear_Solver_Prec() == LINELET) || - (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { - nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); - if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; - } - - /*--- Initialization of linear solver structures ---*/ - - LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysAux.Initialize(nPoint, nPointDomain, nVar, 0.0); - - TimeRes_Aux.Initialize(nPoint, nPointDomain, nVar, 0.0); - TimeRes.Initialize(nPoint, nPointDomain, nVar, 0.0); - - - /*--- Computation of gradients by least squares ---*/ - - Smatrix = new su2double* [nDim]; - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Smatrix[iDim] = new su2double [nDim]; - - cvector = new su2double* [nVar]; - for (unsigned short iVar = 0; iVar < nVar; iVar++) - cvector[iVar] = new su2double [nDim]; - - /*--- Check for a restart, initialize from zero otherwise ---*/ - - bool restart = (config->GetRestart() || config->GetRestart_Flow()); - - if (!restart) { - for (iPoint = 0; iPoint < nPoint; iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; - node[iPoint] = new CFEAVariable(Solution, nDim, nVar, config); - } - } - else { - unsigned long index; - string text_line, mesh_filename; - ifstream restart_file; - - /*--- Restart the solution from file information ---*/ - - mesh_filename = config->GetSolution_FlowFileName(); - restart_file.open(mesh_filename.data(), ios::in); - - /*--- In case there is no file ---*/ - - if (restart_file.fail()) { - cout << "There is no fea restart file!!" << endl; - exit(EXIT_FAILURE); - } - - /*--- In case this is a parallel simulation, we need to perform the - Global2Local index transformation first. ---*/ - - long *Global2Local; - Global2Local = new long[geometry->GetGlobal_nPointDomain()]; - - /*--- First, set all indices to a negative value by default ---*/ - - for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) { - Global2Local[iPoint] = -1; - } - - /*--- Now fill array with the transform values only for local points ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { - Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; - } - - /*--- Read all lines in the restart file ---*/ - - long iPoint_Local; unsigned long iPoint_Global = 0; - - /*--- The first line is the header ---*/ - - getline (restart_file, text_line); - - while (getline (restart_file, text_line)) { - istringstream point_line(text_line); - - /*--- Retrieve local index. If this node from the restart file lives - on a different processor, the value of iPoint_Local will be -1. - Otherwise, the local index for this node on the current processor - will be returned and used to instantiate the vars. ---*/ - - iPoint_Local = Global2Local[iPoint_Global]; - if (iPoint_Local >= 0) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2]; - node[iPoint_Local] = new CFEAVariable(Solution, nDim, nVar, config); - } - iPoint_Global++; - } - - /*--- Instantiate the variable class with an arbitrary solution - at any halo/periodic nodes. The initial solution can be arbitrary, - because a send/recv is performed immediately in the solver. ---*/ - - for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { - node[iPoint] = new CFEAVariable(Solution, nDim, nVar, config); - } - - /*--- Close the restart file ---*/ - - restart_file.close(); - - /*--- Free memory needed for the transformation ---*/ - - delete [] Global2Local; - } - -} - -CFEASolver::~CFEASolver(void) { - - unsigned short iVar, iDim, NodesElement = 0; - - if (nDim == 2) NodesElement = 4; - if (nDim == 3) NodesElement = 8; - - delete [] Residual; - delete [] Residual_Max; - delete [] Solution; - - for (iVar = 0; iVar < NodesElement*nDim; iVar++) - delete [] StiffMatrix_Elem[iVar]; - - for (iVar = 0; iVar < nVar; iVar++) - delete [] StiffMatrix_Node[iVar]; - - for (iVar = 0; iVar < NodesElement*nDim; iVar++) - delete [] MassMatrix_Elem[iVar]; - - for (iVar = 0; iVar < nVar; iVar++) - delete [] MassMatrix_Elem[iVar]; - - for (iVar = 0; iVar < NodesElement*nDim; iVar++) - delete [] DampMatrix_Elem[iVar]; - - for (iVar = 0; iVar < nVar; iVar++) - delete [] DampMatrix_Elem[iVar]; - - delete [] StiffMatrix_Elem; - delete [] StiffMatrix_Node; - delete [] MassMatrix_Elem; - delete [] MassMatrix_Node; - delete [] DampMatrix_Elem; - delete [] DampMatrix_Node; - - /*--- Computation of gradients by least-squares ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - delete [] Smatrix[iDim]; - delete [] Smatrix; - - for (iVar = 0; iVar < nVar; iVar++) - delete [] cvector[iVar]; - delete [] cvector; - - -} - - - -void CFEASolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, CNumerics **numerics, unsigned short iMesh, unsigned long Iteration, unsigned short RunTime_EqSystem, bool Output) { - - GetSurface_Pressure(geometry, config); - - unsigned long ExtIter = config->GetExtIter(); - - /*--- Set residuals and auxiliar variables to zero ---*/ - - Initialize_SystemMatrix(geometry, solver_container, config); - - bool dynamic = (config->GetDynamic_Analysis() == DYNAMIC); - - if (ExtIter == 0){ - - if (!dynamic){ - Compute_StiffMatrix(geometry, solver_container, numerics[VISC_TERM], config); - } - else if (dynamic){ - /*--- Compute the integration constants ---*/ - Compute_IntegrationConstants(geometry, solver_container, numerics[VISC_TERM], config); - - /*--- Compute the stiffness and mass matrices ---*/ - Compute_StiffMassMatrix(geometry, solver_container, numerics[VISC_TERM], config); - - // Compute_StiffMassDampMatrix(geometry, solver_container, numerics[VISC_TERM], config); - } - - } - -} - -void CFEASolver::Initialize_SystemMatrix(CGeometry *geometry, CSolver **solver_container, CConfig *config) { - - unsigned long iPoint; - bool dynamic = (config->GetDynamic_Analysis() == DYNAMIC); - unsigned long ExtIter = config->GetExtIter(); - bool fsi = config->GetFSI_Simulation(); - - if (!fsi) { - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { - LinSysRes.SetBlock_Zero(iPoint); - LinSysAux.SetBlock_Zero(iPoint); - } - - /*--- Set matrix entries to zero ---*/ - - /*--- Static calculation ---*/ - - if (dynamic && ExtIter == 0){ - - StiffMatrixSpace.SetValZero(); - StiffMatrixTime.SetValZero(); - - MassMatrix.SetValZero(); - DampMatrix.SetValZero(); - - } - - /*--- Dynamic calculation ---*/ - else if (!dynamic){ - - StiffMatrixSpace.SetValZero(); - Jacobian.SetValZero(); - - } - - } - - else { - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { - LinSysAux.SetBlock_Zero(iPoint); - } - - /*--- Set matrix entries to zero ---*/ - - /*--- Static calculation ---*/ - - if (dynamic && ExtIter == 0){ - - StiffMatrixSpace.SetValZero(); - StiffMatrixTime.SetValZero(); - - MassMatrix.SetValZero(); - DampMatrix.SetValZero(); - - } - - /*--- Dynamic calculation ---*/ - else if (!dynamic){ - - StiffMatrixSpace.SetValZero(); - Jacobian.SetValZero(); - - } - - } - - -} - -void CFEASolver::Compute_IntegrationConstants(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config) { - - su2double Delta_t= config->GetDelta_DynTime(); - su2double delta = config->GetNewmark_delta(), alpha = config->GetNewmark_alpha(); - - /*--- Integration constants for Newmark scheme ---*/ - - a_dt[0]= 1 / (alpha*pow(Delta_t,2.0)); - a_dt[1]= delta / (alpha*Delta_t); - a_dt[2]= 1 / (alpha*Delta_t); - a_dt[3]= 1 /(2*alpha) - 1; - a_dt[4]= delta/alpha - 1; - a_dt[5]= (Delta_t/2) * (delta/alpha - 2); - a_dt[6]= Delta_t * (1-delta); - a_dt[7]= delta * Delta_t; - -} - -void CFEASolver::Compute_StiffMatrix(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config) { - - unsigned short iVar, jVar, nNodes = 0, iNodes, iDim, jDim, form2d; - unsigned long iElem, PointCorners[8]; - su2double CoordCorners[8][3]; - - form2d=config->GetElas2D_Formulation(); - - /*--- Loops over all the elements ---*/ - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) nNodes = 3; - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) nNodes = 4; - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) nNodes = 4; - if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) nNodes = 5; - if (geometry->elem[iElem]->GetVTK_Type() == PRISM) nNodes = 6; - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) nNodes = 8; - - /*--- For the number of nodes, we get the coordinates from the connectivity matrix ---*/ - - for (iNodes = 0; iNodes < nNodes; iNodes++) { - PointCorners[iNodes] = geometry->elem[iElem]->GetNode(iNodes); - for (iDim = 0; iDim < nDim; iDim++) { - CoordCorners[iNodes][iDim] = geometry->node[PointCorners[iNodes]]->GetCoord(iDim); - } - } - - /*--- We set the element stiffness matrix ---*/ - - if (nDim == 2) numerics->SetFEA_StiffMatrix2D(StiffMatrix_Elem, CoordCorners, nNodes, form2d); - if (nDim == 3) numerics->SetFEA_StiffMatrix3D(StiffMatrix_Elem, CoordCorners, nNodes); - - /*--- Initialization of the auxiliar matrix ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - StiffMatrix_Node[iVar][jVar] = 0.0; - - /*--- Transform the stiffness matrix into the - contributions for the individual nodes relative to each other. ---*/ - - for (iVar = 0; iVar < nNodes; iVar++) { - for (jVar = 0; jVar < nNodes; jVar++) { - for (iDim = 0; iDim < nVar; iDim++) { - for (jDim = 0; jDim < nVar; jDim++) { - StiffMatrix_Node[iDim][jDim] = StiffMatrix_Elem[(iVar*nDim)+iDim][(jVar*nDim)+jDim]; - } - } - StiffMatrixSpace.AddBlock(PointCorners[iVar], PointCorners[jVar], StiffMatrix_Node); - } - } - - } - -} - -void CFEASolver::Compute_StiffMassMatrix(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config) { - - unsigned short iVar, jVar, nNodes = 0, iNodes, iDim, jDim, form2d; - unsigned long iElem, PointCorners[8]; - su2double CoordCorners[8][3]; - - form2d=config->GetElas2D_Formulation(); - - /*--- Loops over all the elements ---*/ - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) nNodes = 3; - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) nNodes = 4; - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) nNodes = 4; - if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) nNodes = 5; - if (geometry->elem[iElem]->GetVTK_Type() == PRISM) nNodes = 6; - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) nNodes = 8; - - /*--- For the number of nodes, we get the coordinates from the connectivity matrix ---*/ - - for (iNodes = 0; iNodes < nNodes; iNodes++) { - PointCorners[iNodes] = geometry->elem[iElem]->GetNode(iNodes); - for (iDim = 0; iDim < nDim; iDim++) { - CoordCorners[iNodes][iDim] = geometry->node[PointCorners[iNodes]]->GetCoord(iDim); - } - } - - /*--- We set the element stiffness matrix ---*/ - - /*--- This solves the problem but... why? ---*/ - for (iVar = 0; iVar < nNodes*nDim; iVar++) { - StiffMatrix_Elem[iVar] = new su2double [nNodes*nDim]; - for (jVar = 0; jVar < nNodes*nDim; jVar++) { - StiffMatrix_Elem[iVar][jVar] = 0.0; - } - } - - if (nDim == 2) numerics->SetFEA_StiffMassMatrix2D(StiffMatrix_Elem, MassMatrix_Elem, CoordCorners, nNodes, form2d); - if (nDim == 3) numerics->SetFEA_StiffMassMatrix3D(StiffMatrix_Elem, MassMatrix_Elem, CoordCorners, nNodes); - - /*--- Initialization of the auxiliar matrix ---*/ - - for (iVar = 0; iVar < nVar; iVar++){ - for (jVar = 0; jVar < nVar; jVar++){ - StiffMatrix_Node[iVar][jVar] = 0.0; - MassMatrix_Node[iVar][jVar] = 0.0; - } - } - - /*--- Transform the stiffness and mass matrices into the - contributions for the individual nodes relative to each other. ---*/ - - for (iVar = 0; iVar < nNodes; iVar++) { - for (jVar = 0; jVar < nNodes; jVar++) { - for (iDim = 0; iDim < nVar; iDim++) { - for (jDim = 0; jDim < nVar; jDim++) { - StiffMatrix_Node[iDim][jDim] = StiffMatrix_Elem[(iVar*nDim)+iDim][(jVar*nDim)+jDim]; - MassMatrix_Node[iDim][jDim] = MassMatrix_Elem[(iVar*nDim)+iDim][(jVar*nDim)+jDim]; - MassMatrix_Node_Int[iDim][jDim] = a_dt[0] * MassMatrix_Elem[(iVar*nDim)+iDim][(jVar*nDim)+jDim]; - } - } - MassMatrix.AddBlock(PointCorners[iVar], PointCorners[jVar], MassMatrix_Node); - StiffMatrixTime.AddBlock(PointCorners[iVar], PointCorners[jVar], StiffMatrix_Node); - StiffMatrixTime.AddBlock(PointCorners[iVar], PointCorners[jVar], MassMatrix_Node_Int); - } - } - - } - -} - -void CFEASolver::Compute_StiffMassDampMatrix(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config) { - - cout << "Here we will compute the damping matrix." << endl; -} - - -void CFEASolver::SetSolution_time_n(CGeometry *geometry, CConfig *config) { - - bool dynamic = (config->GetDynamic_Analysis() == DYNAMIC); - - if (dynamic){ - for(unsigned long iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - // The loop is over nPoints so the boundaries are also updated - node[iPoint]->SetSolution_time_n(); - node[iPoint]->SetSolution_Vel_time_n(); - node[iPoint]->SetSolution_Accel_time_n(); - } - } - -} - - - - - -void CFEASolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, - CConfig *config, unsigned short iMesh) { - - /*--- Compute body forces load vector ---*/ - - - - /*--- Compute initial stresses effect ---*/ - - -} - -void CFEASolver::Viscous_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config, unsigned short iMesh, unsigned short iRKStep) { - -} - - -/*-------------------------------------------------------------------------------------------------- - * Definition of new boundary conditions - ---------------------------------------------------------------------------------------------------*/ - -void CFEASolver::BC_Clamped(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, - unsigned short val_marker) { - - unsigned long iPoint, iVertex; - unsigned short iVar, jVar; - - bool dynamic = (config->GetDynamic_Analysis() == DYNAMIC); - - su2double **mIdentity, **mZeros; // Variables to delete blocks in the jacobian - - mIdentity = new su2double *[nDim]; // Number of rows, allocate memory for each - for(int iMat=0; iMatGetElasticyMod(); - if (iMat==jMat) mIdentity[iMat][jMat]=1.0; - else mIdentity[iMat][jMat]=0; - } - } - - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - /*--- Get node index ---*/ - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - if (nDim == 2) { - Solution[0] = 0.0; Solution[1] = 0.0; - Residual[0] = 0.0; Residual[1] = 0.0; - } - else { - Solution[0] = 0.0; Solution[1] = 0.0; Solution[2] = 0.0; - Residual[0] = 0.0; Residual[1] = 0.0; Residual[2] = 0.0; - } - - node[iPoint]->SetSolution(Solution); - - if (dynamic){ - node[iPoint]->SetSolution_Vel(Solution); - node[iPoint]->SetSolution_Accel(Solution); - } - - LinSysRes.SetBlock(iPoint, Residual); - - /*--- Set the boundary clamped condition ---*/ - - /*--- If the problem is dynamic ---*/ - - if(dynamic){ - - /*--- Enforce that in the previous time step all nodes had 0 U, U', U'' ---*/ - - node[iPoint]->SetSolution_time_n(Solution); - node[iPoint]->SetSolution_Vel_time_n(Solution); - node[iPoint]->SetSolution_Accel_time_n(Solution); - - /*--- Delete the rows for a particular node ---*/ - for (jVar = 0; jVar < nPoint; jVar++){ - if (iPoint==jVar) { - StiffMatrixTime.SetBlock(iPoint,jVar,mIdentity); - MassMatrix.SetBlock(iPoint,jVar,mIdentity); - } - else { - StiffMatrixTime.SetBlock(iPoint,jVar,mZeros); - MassMatrix.SetBlock(iPoint,jVar,mZeros); - } - } - - /*--- Delete the columns for a particular node ---*/ - for (iVar = 0; iVar < nPoint; iVar++){ - if (iVar==iPoint) { - StiffMatrixTime.SetBlock(iVar,iPoint,mIdentity); - MassMatrix.SetBlock(iVar,iPoint,mIdentity); - } - else { - StiffMatrixTime.SetBlock(iVar,iPoint,mZeros); - MassMatrix.SetBlock(iVar,iPoint,mZeros); - } - } - - } - - /*--- If the problem is static ---*/ - - else{ - - /*--- Delete the rows for a particular node ---*/ - for (jVar = 0; jVar < nPoint; jVar++){ - if (iPoint==jVar) { - Jacobian.SetBlock(iPoint,jVar,mIdentity); - StiffMatrixSpace.SetBlock(iPoint,jVar,mIdentity); - } - else { - Jacobian.SetBlock(iPoint,jVar,mZeros); - StiffMatrixSpace.SetBlock(iPoint,jVar,mZeros); - } - } - - /*--- Delete the columns for a particular node ---*/ - for (iVar = 0; iVar < nPoint; iVar++){ - if (iVar==iPoint) { - Jacobian.SetBlock(iVar,iPoint,mIdentity); - StiffMatrixSpace.SetBlock(iPoint,jVar,mIdentity); - } - else { - Jacobian.SetBlock(iVar,iPoint,mZeros); - StiffMatrixSpace.SetBlock(iPoint,jVar,mZeros); - } - } - - } - - } - - -} - - -void CFEASolver::BC_Clamped_Post(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, - unsigned short val_marker) { - - unsigned long iPoint, iVertex; - - su2double **mIdentity, **mZeros; // Variables to delete blocks in the jacobian - - - mIdentity = new su2double *[nDim]; // Number of rows, allocate memory for each - for(int iMat=0; iMatnVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - if (nDim == 2) { - Solution[0] = 0.0; Solution[1] = 0.0; - Residual[0] = 0.0; Residual[1] = 0.0; - } - else { - Solution[0] = 0.0; Solution[1] = 0.0; Solution[2] = 0.0; - Residual[0] = 0.0; Residual[1] = 0.0; Residual[2] = 0.0; - } - - node[iPoint]->SetSolution(Solution); - node[iPoint]->SetSolution_Old(Solution); - - - /*--- Re-set the displacement condition ---*/ - LinSysRes.SetBlock(iPoint, Residual); - - } - -} - - -void CFEASolver::BC_Normal_Displacement(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, - unsigned short val_marker) { - unsigned long iPoint, iVertex, total_index; - unsigned short iVar, iDim; - su2double *Normal, Area, UnitaryNormal[3] = {0.0,0.0,0.0}; - - su2double TotalDispl = config->GetDispl_Value(config->GetMarker_All_TagBound(val_marker)); - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - Normal = geometry->vertex[val_marker][iVertex]->GetNormal(); - - /*--- Compute area, and unitary normal ---*/ - - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); - for (iDim = 0; iDim < nDim; iDim++) UnitaryNormal[iDim] = Normal[iDim]/Area; - - if (config->GetUnsteady_Simulation() == STEADY) { - if (nDim == 2) { - Solution[0] = TotalDispl*UnitaryNormal[0]; Solution[1] = TotalDispl*UnitaryNormal[1]; - Residual[0] = TotalDispl*UnitaryNormal[0]; Residual[1] = TotalDispl*UnitaryNormal[1]; - } - else { - Solution[0] = TotalDispl*UnitaryNormal[0]; Solution[1] = TotalDispl*UnitaryNormal[1]; Solution[2] = TotalDispl*UnitaryNormal[2]; - Residual[0] = TotalDispl*UnitaryNormal[0]; Residual[1] = TotalDispl*UnitaryNormal[1]; Residual[2] = TotalDispl*UnitaryNormal[2]; - } - } - else { - if (nDim == 2) { - Solution[0] = TotalDispl*UnitaryNormal[0]; Solution[1] = TotalDispl*UnitaryNormal[1]; - Solution[2] = 0.0; Solution[3] = 0.0; - Residual[0] = 0.0; Residual[1] = 0.0; - Residual[2] = 0.0; Residual[3] = 0.0; - } - else { - Solution[0] = TotalDispl*UnitaryNormal[0]; Solution[1] = TotalDispl*UnitaryNormal[1]; Solution[2] = TotalDispl*UnitaryNormal[2]; - Solution[3] = 0.0; Solution[4] = 0.0; Solution[5] = 0.0; - Residual[0] = 0.0; Residual[1] = 0.0; Residual[2] = 0.0; - Residual[3] = 0.0; Residual[4] = 0.0; Residual[5] = 0.0; - } - } - - node[iPoint]->SetSolution(Solution); - node[iPoint]->SetSolution_Old(Solution); - - LinSysRes.SetBlock(iPoint, Residual); - - /*--- Set the dirichlet condition ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - Jacobian.DeleteValsRowi(total_index); - } - - } -} - -void CFEASolver::BC_Normal_Load(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, - unsigned short val_marker) { - - su2double a[3], b[3]; - unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0; - su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL; - su2double Normal_Elem[3] = {0.0, 0.0, 0.0}; - //su2double Length_Elem = 0.0, Area_Elem = 0.0; - unsigned short iDim; - - su2double TotalLoad = config->GetLoad_Value(config->GetMarker_All_TagBound(val_marker)); - - for (iElem = 0; iElem < geometry->GetnElem_Bound(val_marker); iElem++) { - - Point_0 = geometry->bound[val_marker][iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); - Point_1 = geometry->bound[val_marker][iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); - if (nDim == 3) { Point_2 = geometry->bound[val_marker][iElem]->GetNode(2); Coord_2 = geometry->node[Point_2]->GetCoord(); } - - /*--- Compute area (3D), and length of the surfaces (2D) ---*/ - - if (nDim == 2) { - - for (iDim = 0; iDim < nDim; iDim++) a[iDim] = Coord_0[iDim]-Coord_1[iDim]; - - //Length_Elem = sqrt(a[0]*a[0]+a[1]*a[1]); - Normal_Elem[0] = a[1]; - Normal_Elem[1] = -(a[0]); - - } - - if (nDim == 3) { - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = Coord_0[iDim]-Coord_2[iDim]; - b[iDim] = Coord_1[iDim]-Coord_2[iDim]; - } - - //Area_Elem = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); - - Normal_Elem[0] = -(0.5*(a[1]*b[2]-a[2]*b[1])); - Normal_Elem[1] = -(-0.5*(a[0]*b[2]-a[2]*b[0])); - Normal_Elem[2] = -(0.5*(a[0]*b[1]-a[1]*b[0])); - - } - - - if (nDim == 2) { - Residual[0] = (1.0/2.0)*TotalLoad*Normal_Elem[0]; Residual[1] = (1.0/2.0)*TotalLoad*Normal_Elem[1]; - LinSysRes.AddBlock(Point_0, Residual); - Residual[0] = (1.0/2.0)*TotalLoad*Normal_Elem[0]; Residual[1] = (1.0/2.0)*TotalLoad*Normal_Elem[1]; - LinSysRes.AddBlock(Point_1, Residual); - } - - else { - Residual[0] = (1.0/3.0)*TotalLoad*Normal_Elem[0]; Residual[1] = (1.0/3.0)*TotalLoad*Normal_Elem[1]; Residual[2] = (1.0/3.0)*TotalLoad*Normal_Elem[2]; - LinSysRes.AddBlock(Point_0, Residual); - - Residual[0] = (1.0/3.0)*TotalLoad*Normal_Elem[0]; Residual[1] = (1.0/3.0)*TotalLoad*Normal_Elem[1]; Residual[2] = (1.0/3.0)*TotalLoad*Normal_Elem[2]; - LinSysRes.AddBlock(Point_1, Residual); - - Residual[0] = (1.0/3.0)*TotalLoad*Normal_Elem[0]; Residual[1] = (1.0/3.0)*TotalLoad*Normal_Elem[1]; Residual[2] = (1.0/3.0)*TotalLoad*Normal_Elem[2]; - LinSysRes.AddBlock(Point_2, Residual); - } - - } - -} - - -void CFEASolver::BC_Dir_Load(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, - unsigned short val_marker) { - - su2double a[3] = {0.0, 0.0, 0.0}, b[3] = {0.0, 0.0, 0.0}; - su2double AC[3] = {0.0, 0.0, 0.0}, BD[3] = {0.0, 0.0, 0.0}; - unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, Point_3=0; - su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, *Coord_3= NULL; - su2double Length_Elem = 0.0, Area_Elem = 0.0; -// su2double Normal_Elem[3] = {0.0, 0.0, 0.0}; - unsigned short iDim; - - su2double LoadDirVal = config->GetLoad_Dir_Value(config->GetMarker_All_TagBound(val_marker)); - su2double LoadDirMult = config->GetLoad_Dir_Multiplier(config->GetMarker_All_TagBound(val_marker)); - su2double *Load_Dir_Local= config->GetLoad_Dir(config->GetMarker_All_TagBound(val_marker)); - - su2double TotalLoad; - - bool Gradual_Load = config->GetGradual_Load(); - su2double CurrentTime=config->GetCurrent_DynTime(); - su2double ModAmpl, NonModAmpl; - - bool Ramp_Load = config->GetRamp_Load(); - su2double Ramp_Time = config->GetRamp_Time(); - - if (Ramp_Load){ - ModAmpl=LoadDirVal*LoadDirMult*CurrentTime/Ramp_Time; - NonModAmpl=LoadDirVal*LoadDirMult; - TotalLoad=min(ModAmpl,NonModAmpl); - } - else if (Gradual_Load){ - ModAmpl=2*((1/(1+exp(-1*CurrentTime)))-0.5); - TotalLoad=ModAmpl*LoadDirVal*LoadDirMult; - } - else{ - TotalLoad=LoadDirVal*LoadDirMult; - } - - /*--- Compute the norm of the vector that was passed in the config file ---*/ - su2double Norm = 0.0; - if (nDim==2) Norm=sqrt(Load_Dir_Local[0]*Load_Dir_Local[0]+Load_Dir_Local[1]*Load_Dir_Local[1]); - if (nDim==3) Norm=sqrt(Load_Dir_Local[0]*Load_Dir_Local[0]+Load_Dir_Local[1]*Load_Dir_Local[1]+Load_Dir_Local[2]*Load_Dir_Local[2]); - - for (iElem = 0; iElem < geometry->GetnElem_Bound(val_marker); iElem++) { - - Point_0 = geometry->bound[val_marker][iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); - Point_1 = geometry->bound[val_marker][iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); - - /*--- Compute area (3D), and length of the surfaces (2D) ---*/ - - if (nDim == 2) { - - for (iDim = 0; iDim < nDim; iDim++) a[iDim] = Coord_0[iDim]-Coord_1[iDim]; - - Length_Elem = sqrt(a[0]*a[0]+a[1]*a[1]); -// Normal_Elem[0] = a[1]; -// Normal_Elem[1] = -(a[0]); - - } else { - - Point_2 = geometry->bound[val_marker][iElem]->GetNode(2); - Coord_2 = geometry->node[Point_2]->GetCoord(); - - if (geometry->bound[val_marker][iElem]->GetVTK_Type() == TRIANGLE){ - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = Coord_1[iDim]-Coord_0[iDim]; - b[iDim] = Coord_2[iDim]-Coord_0[iDim]; - } - - su2double Ni=0 , Nj=0, Nk=0; - - Ni=a[1]*b[2]-a[2]*b[1]; - Nj=-a[0]*b[2]+a[2]*b[0]; - Nk=a[0]*b[1]-a[1]*b[0]; - - Area_Elem = 0.5*sqrt(Ni*Ni+Nj*Nj+Nk*Nk); - - //Area_Elem = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); - - } else if (geometry->bound[val_marker][iElem]->GetVTK_Type() == QUADRILATERAL){ - - Point_3 = geometry->bound[val_marker][iElem]->GetNode(3); - Coord_3 = geometry->node[Point_3]->GetCoord(); - - for (iDim = 0; iDim < nDim; iDim++) { - AC[iDim] = Coord_2[iDim]-Coord_0[iDim]; - BD[iDim] = Coord_3[iDim]-Coord_1[iDim]; - } - - su2double Ni=0 , Nj=0, Nk=0; - - Ni=AC[1]*BD[2]-AC[2]*BD[1]; - Nj=-AC[0]*BD[2]+AC[2]*BD[0]; - Nk=AC[0]*BD[1]-AC[1]*BD[0]; - - Area_Elem = 0.5*sqrt(Ni*Ni+Nj*Nj+Nk*Nk); - - } - } - - if (nDim == 2) { - - Residual[0] = (1.0/2.0)*Length_Elem*TotalLoad*Load_Dir_Local[0]/Norm; - Residual[1] = (1.0/2.0)*Length_Elem*TotalLoad*Load_Dir_Local[1]/Norm; - - LinSysRes.AddBlock(Point_0, Residual); - LinSysRes.AddBlock(Point_1, Residual); - - } - - else { - if (geometry->bound[val_marker][iElem]->GetVTK_Type() == TRIANGLE){ - - Residual[0] = (1.0/3.0)*Area_Elem*TotalLoad*Load_Dir_Local[0]/Norm; - Residual[1] = (1.0/3.0)*Area_Elem*TotalLoad*Load_Dir_Local[1]/Norm; - Residual[2] = (1.0/3.0)*Area_Elem*TotalLoad*Load_Dir_Local[2]/Norm; - - LinSysRes.AddBlock(Point_0, Residual); - LinSysRes.AddBlock(Point_1, Residual); - LinSysRes.AddBlock(Point_2, Residual); - } - else if (geometry->bound[val_marker][iElem]->GetVTK_Type() == QUADRILATERAL){ - - Residual[0] = (1.0/4.0)*Area_Elem*TotalLoad*Load_Dir_Local[0]/Norm; - Residual[1] = (1.0/4.0)*Area_Elem*TotalLoad*Load_Dir_Local[1]/Norm; - Residual[2] = (1.0/4.0)*Area_Elem*TotalLoad*Load_Dir_Local[2]/Norm; - - LinSysRes.AddBlock(Point_0, Residual); - LinSysRes.AddBlock(Point_1, Residual); - LinSysRes.AddBlock(Point_2, Residual); - LinSysRes.AddBlock(Point_3, Residual); - - } - - } - - } - -} - -void CFEASolver::BC_Sine_Load(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, - unsigned short val_marker) { - - su2double a[3] = {0.0, 0.0, 0.0}, b[3] = {0.0, 0.0, 0.0}; - su2double AC[3] = {0.0, 0.0, 0.0}, BD[3] = {0.0, 0.0, 0.0}; - unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, Point_3=0; - su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, *Coord_3= NULL; - su2double Length_Elem = 0.0, Area_Elem = 0.0; -// su2double Normal_Elem[3] = {0.0, 0.0, 0.0}; - unsigned short iDim; - - su2double LoadAmplitude = config->GetLoad_Sine_Amplitude(config->GetMarker_All_TagBound(val_marker)); - su2double LoadFrequency = config->GetLoad_Sine_Frequency(config->GetMarker_All_TagBound(val_marker)); - su2double *Load_Dir_Local= config->GetLoad_Sine_Dir(config->GetMarker_All_TagBound(val_marker)); - - su2double CurrentTime=config->GetCurrent_DynTime(); - - su2double TotalLoad = LoadAmplitude*sin(2*PI_NUMBER*LoadFrequency*CurrentTime); - - /*--- Compute the norm of the vector that was passed in the config file ---*/ - su2double Norm = 0.0; - if (nDim==2) Norm=sqrt(Load_Dir_Local[0]*Load_Dir_Local[0]+Load_Dir_Local[1]*Load_Dir_Local[1]); - if (nDim==3) Norm=sqrt(Load_Dir_Local[0]*Load_Dir_Local[0]+Load_Dir_Local[1]*Load_Dir_Local[1]+Load_Dir_Local[2]*Load_Dir_Local[2]); - - for (iElem = 0; iElem < geometry->GetnElem_Bound(val_marker); iElem++) { - - Point_0 = geometry->bound[val_marker][iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); - Point_1 = geometry->bound[val_marker][iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); - - /*--- Compute area (3D), and length of the surfaces (2D) ---*/ - - if (nDim == 2) { - - for (iDim = 0; iDim < nDim; iDim++) a[iDim] = Coord_0[iDim]-Coord_1[iDim]; - - Length_Elem = sqrt(a[0]*a[0]+a[1]*a[1]); -// Normal_Elem[0] = a[1]; -// Normal_Elem[1] = -(a[0]); - - } else { // 3D - - Point_2 = geometry->bound[val_marker][iElem]->GetNode(2); - Coord_2 = geometry->node[Point_2]->GetCoord(); - - if (geometry->bound[val_marker][iElem]->GetVTK_Type() == TRIANGLE){ - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = Coord_1[iDim]-Coord_0[iDim]; - b[iDim] = Coord_2[iDim]-Coord_0[iDim]; - } - - su2double Ni=0 , Nj=0, Nk=0; - - Ni=a[1]*b[2]-a[2]*b[1]; - Nj=-a[0]*b[2]+a[2]*b[0]; - Nk=a[0]*b[1]-a[1]*b[0]; - - Area_Elem = 0.5*sqrt(Ni*Ni+Nj*Nj+Nk*Nk); - - - //Area_Elem = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); - - } else if (geometry->bound[val_marker][iElem]->GetVTK_Type() == QUADRILATERAL){ - - Point_3 = geometry->bound[val_marker][iElem]->GetNode(3); - Coord_3 = geometry->node[Point_3]->GetCoord(); - - for (iDim = 0; iDim < nDim; iDim++) { - AC[iDim] = Coord_2[iDim]-Coord_0[iDim]; - BD[iDim] = Coord_3[iDim]-Coord_1[iDim]; - } - - su2double Ni=0 , Nj=0, Nk=0; - - Ni=AC[1]*BD[2]-AC[2]*BD[1]; - Nj=-AC[0]*BD[2]+AC[2]*BD[0]; - Nk=AC[0]*BD[1]-AC[1]*BD[0]; - - Area_Elem = 0.5*sqrt(Ni*Ni+Nj*Nj+Nk*Nk); - - } - } - - if (nDim == 2) { - - Residual[0] = (1.0/2.0)*Length_Elem*TotalLoad*Load_Dir_Local[0]/Norm; - Residual[1] = (1.0/2.0)*Length_Elem*TotalLoad*Load_Dir_Local[1]/Norm; - - LinSysRes.AddBlock(Point_0, Residual); - LinSysRes.AddBlock(Point_1, Residual); - - } - - else { - if (geometry->bound[val_marker][iElem]->GetVTK_Type() == TRIANGLE){ - - Residual[0] = (1.0/3.0)*Area_Elem*TotalLoad*Load_Dir_Local[0]/Norm; - Residual[1] = (1.0/3.0)*Area_Elem*TotalLoad*Load_Dir_Local[1]/Norm; - Residual[2] = (1.0/3.0)*Area_Elem*TotalLoad*Load_Dir_Local[2]/Norm; - - LinSysRes.AddBlock(Point_0, Residual); - LinSysRes.AddBlock(Point_1, Residual); - LinSysRes.AddBlock(Point_2, Residual); - - - } - else if (geometry->bound[val_marker][iElem]->GetVTK_Type() == QUADRILATERAL){ - - Residual[0] = (1.0/4.0)*Area_Elem*TotalLoad*Load_Dir_Local[0]/Norm; - Residual[1] = (1.0/4.0)*Area_Elem*TotalLoad*Load_Dir_Local[1]/Norm; - Residual[2] = (1.0/4.0)*Area_Elem*TotalLoad*Load_Dir_Local[2]/Norm; - - LinSysRes.AddBlock(Point_0, Residual); - LinSysRes.AddBlock(Point_1, Residual); - LinSysRes.AddBlock(Point_2, Residual); - LinSysRes.AddBlock(Point_3, Residual); - - } - - } - - } - -} - -void CFEASolver::BC_Pressure(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, - unsigned short val_marker) { } - -void CFEASolver::BC_Flow_Load(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, - unsigned short val_marker) { } - - -void CFEASolver::Postprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, CNumerics **numerics_container, unsigned short iMesh) { - unsigned long iPoint, iElem; - su2double **Stress, VonMises_Stress=0.0, MaxVonMises_Stress = 0.0; - su2double Sxx=0.0,Syy=0.0,Szz=0.0,Sxy=0.0,Sxz=0.0,Syz=0.0,S1,S2; - - unsigned long PointCorners[8]; - unsigned short nNodes=0, iNodes, iDim, jDim, form2d; - su2double CoordCorners[8][3]; -// su2double CoordGauss[8][3]; - - /*--- Container of the shape functions ---*/ - CNumerics *numerics; - numerics=numerics_container[VISC_TERM]; - - /*--- Enforcement of displacement boundary conditions ---*/ - unsigned short MainSolver = config->GetContainerPosition(RUNTIME_FEA_SYS); - unsigned int iMarker; - - form2d=config->GetElas2D_Formulation(); - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - switch (config->GetMarker_All_KindBC(iMarker)) { - case CLAMPED_BOUNDARY: - solver_container[MainSolver]->BC_Clamped(geometry, solver_container, numerics_container[CONV_BOUND_TERM], config, iMarker); - break; - } - } - - /*--- Initialize the stress and the number of elements connected to each node ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint++) { - node[iPoint]->Initialize_Connectivity(); - for (iDim = 0; iDim < nDim; iDim++){ - for (jDim = 0; jDim < nDim; jDim++){ - node[iPoint]->SetStress(iDim, jDim, 0); - } - } - } - - /*--- Loops over all the elements ---*/ - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE){ nNodes = 3;} - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL){ nNodes = 4;} - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON){ nNodes = 4;} - if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID){ nNodes = 5;} - if (geometry->elem[iElem]->GetVTK_Type() == PRISM){ nNodes = 6;} - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON){ nNodes = 8;} - - /*--- For the number of nodes, we get the coordinates from the connectivity matrix ---*/ - - for (iNodes = 0; iNodes < nNodes; iNodes++) { - - /*--- Get the index of the nodes and saves it in PointCorners ---*/ - PointCorners[iNodes] = geometry->elem[iElem]->GetNode(iNodes); - - for (iDim = 0; iDim < nDim; iDim++) { - - /*--- Get the coordinates of the nodes and saves it in CoordCorners ---*/ - CoordCorners[iNodes][iDim] = geometry->node[PointCorners[iNodes]]->GetCoord(iDim); - - /*--- Initialization of the gauss coordinate matrix ---*/ -// CoordGauss[iNodes][iDim] = 0.0; - } - } - - /*----------------------------------------------------------------------------------*/ - /*--- We obtain the stresses in the element, from the finite element formulation ---*/ - /*----------------------------------------------------------------------------------*/ - - /*--- For a 2D element ---*/ - - if (nDim == 2) { - - su2double StressNodal[8][3], DispElement[8]; - - /*--- Set the element displacements vector, from the global solution ---*/ - - for (iNodes = 0; iNodes < nNodes; iNodes++) { - for (iDim = 0; iDim < nDim; iDim++) { - DispElement[nDim*iNodes+iDim]=node[PointCorners[iNodes]]->GetSolution(iDim); - } - } - - /*--- Obtain the stresses in the nodes ---*/ - numerics->GetFEA_StressNodal2D(StressNodal, DispElement, CoordCorners, nNodes, form2d); - - /*--- Add the value of the element stress extrapolated to the node to the value stored on the nodes ---*/ - /*--- At the same point, add a counter to take into account on how many elements connect to the node ---*/ - - for (iPoint = 0; iPoint < nNodes; iPoint++) { - - node[PointCorners[iPoint]]->AddStress(0, 0, StressNodal[iPoint][0]); - node[PointCorners[iPoint]]->AddStress(1, 1, StressNodal[iPoint][1]); - node[PointCorners[iPoint]]->AddStress(0, 1, StressNodal[iPoint][2]); - node[PointCorners[iPoint]]->AddStress(1, 0, StressNodal[iPoint][2]); - - node[PointCorners[iPoint]]->Upgrade_Connectivity(); - - } - - } - - /*--- For a 3D element ---*/ - - if (nDim == 3) { - - su2double StressNodal[8][6], DispElement[24]; - - /*--- Set the element displacements vector, from the global solution ---*/ - - for (iNodes = 0; iNodes < nNodes; iNodes++) { - for (iDim = 0; iDim < nDim; iDim++) { - DispElement[nDim*iNodes+iDim]=node[PointCorners[iNodes]]->GetSolution(iDim); - } - } - - /*--- Obtain the stresses in the gaussian points ---*/ - numerics->GetFEA_StressNodal3D(StressNodal, DispElement, CoordCorners, nNodes); - - /*--- Add the value of the element stress extrapolated to the node to the value stored on the nodes ---*/ - /*--- At the same point, add a counter to take into account on how many elements connect to the node ---*/ - - for (iPoint = 0; iPoint < nNodes; iPoint++) { - - node[PointCorners[iPoint]]->AddStress(0, 0, StressNodal[iPoint][0]); - node[PointCorners[iPoint]]->AddStress(1, 1, StressNodal[iPoint][1]); - node[PointCorners[iPoint]]->AddStress(2, 2, StressNodal[iPoint][2]); - - node[PointCorners[iPoint]]->AddStress(0, 1, StressNodal[iPoint][3]); - node[PointCorners[iPoint]]->AddStress(1, 0, StressNodal[iPoint][3]); - - node[PointCorners[iPoint]]->AddStress(0, 2, StressNodal[iPoint][4]); - node[PointCorners[iPoint]]->AddStress(2, 0, StressNodal[iPoint][4]); - - node[PointCorners[iPoint]]->AddStress(1, 2, StressNodal[iPoint][5]); - node[PointCorners[iPoint]]->AddStress(2, 1, StressNodal[iPoint][5]); - - node[PointCorners[iPoint]]->Upgrade_Connectivity(); - - } - - } - - } - - - /*--- Variable to store the number of elements connected to each node ---*/ - - su2double nElPerNode=0; - - /*--- For the number of nodes in the mesh ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint++) { - - /*--- Get the stresses, added up from all the elements that connect to the node ---*/ - - Stress = node[iPoint]->GetStress(); - nElPerNode = node[iPoint]->Get_Connectivity(); - - /*--- Compute the stress averaged from all the elements connecting to the node and the Von Mises stress ---*/ - - if (geometry->GetnDim() == 2) { - - Sxx=Stress[0][0]/nElPerNode; - Syy=Stress[1][1]/nElPerNode; - Sxy=Stress[0][1]/nElPerNode; - - S1=(Sxx+Syy)/2+sqrt(((Sxx-Syy)/2)*((Sxx-Syy)/2)+Sxy*Sxy); - S2=(Sxx+Syy)/2-sqrt(((Sxx-Syy)/2)*((Sxx-Syy)/2)+Sxy*Sxy); - - VonMises_Stress = sqrt(S1*S1+S2*S2-2*S1*S2); - - } - else if (geometry->GetnDim() == 3) { - - Sxx = Stress[0][0]/nElPerNode; - Syy = Stress[1][1]/nElPerNode; - Szz = Stress[2][2]/nElPerNode; - - Sxy = Stress[0][1]/nElPerNode; - Sxz = Stress[0][2]/nElPerNode; - Syz = Stress[1][2]/nElPerNode; - - VonMises_Stress = sqrt(0.5*( pow(Sxx - Syy, 2.0) - + pow(Syy - Szz, 2.0) - + pow(Szz - Sxx, 2.0) - + 6.0*(Sxy*Sxy+Sxz*Sxz+Syz*Syz) - )); - - } - - node[iPoint]->SetVonMises_Stress(VonMises_Stress); - - /*--- Compute the maximum value of the Von Mises Stress ---*/ - - MaxVonMises_Stress = max(MaxVonMises_Stress, VonMises_Stress); - - /*--- Set the new value of the stress, averaged from the number of elements ---*/ - - node[iPoint]->SetStress(0, 0, Sxx); - node[iPoint]->SetStress(1, 1, Syy); - node[iPoint]->SetStress(0, 1, Sxy); - node[iPoint]->SetStress(1, 0, Sxy); - - if (geometry->GetnDim() == 3) { - node[iPoint]->SetStress(2, 2, Szz); - node[iPoint]->SetStress(0, 2, Sxz); - node[iPoint]->SetStress(2, 0, Sxz); - node[iPoint]->SetStress(1, 2, Syz); - node[iPoint]->SetStress(2, 1, Syz); - } - - } - -#ifdef HAVE_MPI - - /*--- Compute MaxVonMises_Stress using all the nodes ---*/ - - su2double MyMaxVonMises_Stress = MaxVonMises_Stress; MaxVonMises_Stress = 0.0; - SU2_MPI::Allreduce(&MyMaxVonMises_Stress, &MaxVonMises_Stress, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); - -#endif - - /*--- Set the value of the MaxVonMises_Stress as the CFEA coeffient ---*/ - - Total_CFEA = MaxVonMises_Stress; - -} - -void CFEASolver::SetResidual_DualTime(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iRKStep, - unsigned short iMesh, unsigned short RunTime_EqSystem) { } - -void CFEASolver::ImplicitNewmark_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { - - - unsigned short iVar; - unsigned long iPoint, total_index, IterLinSol; - - bool dynamic = (config->GetDynamic_Analysis() == DYNAMIC); - - unsigned long ExtIter = config->GetExtIter(); - - su2double *PointTimeRes = NULL; - - unsigned short check=0; - - if ((dynamic) && (ExtIter == 0) && (check==0)){ - - /*--- Build implicit system ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - LinSysSol[total_index] = 0.0; - } - - } - - /*--- Initialize residual and solution at the ghost points ---*/ - - for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { - - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar + iVar; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - } - - } - - - /*--- Solve the linear dynamic system ---*/ - - CSysSolve femSystem; - IterLinSol = femSystem.Solve(MassMatrix, LinSysRes, LinSysSol, geometry, config); - SetIterLinSolver(IterLinSol); - - /*--- Update solution and (if dynamic) advance velocity and acceleration vectors in time ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - for (iVar = 0; iVar < nVar; iVar++) { - - /*--- Acceleration for t=0 ---*/ - node[iPoint]->SetSolution(iVar, 0.0); - node[iPoint]->SetSolution_Vel(iVar, 0.0); - node[iPoint]->SetSolution_Accel(iVar, LinSysSol[iPoint*nVar+iVar]); - - } - - } - - } - else{ - - /*--- Build implicit system ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - LinSysSol[total_index] = 0.0; - } - - } - - /*--- Initialize residual and solution at the ghost points ---*/ - - for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { - - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar + iVar; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - } - - } - - /*--- If dynamic analysis ---*/ - - if (dynamic){ - - /*--- Get mass term ---*/ - - /*--- Loop over all points, and set aux vector TimeRes_Aux = a0*U+a2*U'+a3*U'' ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - for (iVar = 0; iVar < nVar; iVar++){ - - Residual[iVar] = a_dt[0]*node[iPoint]->GetSolution_time_n(iVar)+ //a0*U(t) - a_dt[2]*node[iPoint]->GetSolution_Vel_time_n(iVar)+ //a2*U'(t) - a_dt[3]*node[iPoint]->GetSolution_Accel_time_n(iVar); //a3*U''(t) - - } - - TimeRes_Aux.SetBlock(iPoint, Residual); - - } - - /*--- Once computed, compute M*TimeRes_Aux ---*/ - - MassMatrix.MatrixVectorProduct(TimeRes_Aux,TimeRes,geometry,config); - - /*--- Add the components of M*TimeRes_Aux to the residual R(t+dt) ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - PointTimeRes = TimeRes.GetBlock(iPoint); - - LinSysRes.AddBlock(iPoint, PointTimeRes); - - } - - // su2double *check; - // for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { - // check = LinSysRes.GetBlock(iPoint); // This avoids the problem in the corner, but... - // cout << check[0] << "\t" << check[1] << endl; - // } - - /*--- Solve the linear dynamic system ---*/ - - CSysSolve femSystem; - IterLinSol = femSystem.Solve(StiffMatrixTime, LinSysRes, LinSysSol, geometry, config); - SetIterLinSolver(IterLinSol); - } - else { - - /*--- Solve the linear static system ---*/ - - CSysSolve femSystem; - IterLinSol = femSystem.Solve(StiffMatrixSpace, LinSysRes, LinSysSol, geometry, config); - SetIterLinSolver(IterLinSol); - } - - - - /*--- Update solution and (if dynamic) advance velocity and acceleration vectors in time ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - for (iVar = 0; iVar < nVar; iVar++) { - - /*--- Displacements component of the solution ---*/ - - node[iPoint]->SetSolution(iVar, LinSysSol[iPoint*nVar+iVar]); - - } - - if (dynamic){ - - for (iVar = 0; iVar < nVar; iVar++) { - - /*--- Acceleration component of the solution ---*/ - /*--- U''(t+dt) = a0*(U(t+dt)-U(t))+a2*(U'(t))+a3*(U''(t)) ---*/ - - Solution[iVar]=a_dt[0]*(node[iPoint]->GetSolution(iVar) - - node[iPoint]->GetSolution_time_n(iVar)) - - a_dt[2]* node[iPoint]->GetSolution_Vel_time_n(iVar) - - a_dt[3]* node[iPoint]->GetSolution_Accel_time_n(iVar); - - } - - /*--- Set the acceleration in the node structure ---*/ - - node[iPoint]->SetSolution_Accel(Solution); - - for (iVar = 0; iVar < nVar; iVar++) { - - /*--- Velocity component of the solution ---*/ - /*--- U'(t+dt) = U'(t)+ a6*(U''(t)) + a7*(U''(t+dt)) ---*/ - - Solution[iVar]=node[iPoint]->GetSolution_Vel_time_n(iVar)+ - a_dt[6]* node[iPoint]->GetSolution_Accel_time_n(iVar) + - a_dt[7]* node[iPoint]->GetSolution_Accel(iVar); - - } - - /*--- Set the velocity in the node structure ---*/ - - node[iPoint]->SetSolution_Vel(Solution); - - } - - } - - /*--- MPI solution ---*/ - - Set_MPI_Solution(geometry, config); - - /*--- Compute the residual Ax-f ---*/ - - if (dynamic){ - - StiffMatrixTime.ComputeResidual(LinSysSol, LinSysRes, LinSysAux); - - } - else { - - StiffMatrixSpace.ComputeResidual(LinSysSol, LinSysRes, LinSysAux); - - } - - /*--- Compute the reactions ---*/ - - /*--- Set maximum residual to zero ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - SetRes_RMS(iVar, 0.0); - SetRes_Max(iVar, 0.0, 0); - } - - /*--- Compute the residual ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - AddRes_RMS(iVar, LinSysAux[total_index]*LinSysAux[total_index]); - AddRes_Max(iVar, fabs(LinSysAux[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); - } - } - - /*--- Compute the root mean square residual ---*/ - - SetResidual_RMS(geometry, config); - - } - -} - -void CFEASolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { - - unsigned short iVar; - unsigned long iPoint, total_index, IterLinSol; - - /*--- Build implicit system ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - LinSysSol[total_index] = 0.0; - } - - } - - /*--- Initialize residual and solution at the ghost points ---*/ - for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar + iVar; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - } - } - - /*--- Solve or smooth the linear system ---*/ - - CSysSolve system; - IterLinSol = system.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); - SetIterLinSolver(IterLinSol); - - /*--- MPI solution ---*/ - - Set_MPI_Solution(geometry, config); - - /*--- Compute the residual Ax-f ---*/ - - Jacobian.ComputeResidual(LinSysSol, LinSysRes, LinSysAux); - - /*--- Set maximum residual to zero ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - SetRes_RMS(iVar, 0.0); - SetRes_Max(iVar, 0.0, 0); - } - - /*--- Compute the residual ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - AddRes_RMS(iVar, LinSysAux[total_index]*LinSysAux[total_index]); - AddRes_Max(iVar, fabs(LinSysAux[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); - } - } - - /*--- Compute the root mean square residual ---*/ - - SetResidual_RMS(geometry, config); - -} - -void CFEASolver::SetInitialCondition(CGeometry **geometry, CSolver ***solver_container, CConfig *config, unsigned long ExtIter) { - unsigned long iPoint; - - bool restart = (config->GetRestart() || config->GetRestart_Flow()); - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - - /*--- Problem dimension and physical time step ---*/ - unsigned short nDim = geometry[MESH_0]->GetnDim(); - - for (iPoint = 0; iPoint < geometry[MESH_0]->GetnPoint(); iPoint++) { - - /*--- Set initial boundary condition at the first iteration ---*/ - if ((ExtIter == 0) && (!restart)) { - - if (config->GetUnsteady_Simulation() == STEADY) { - if (nDim == 2) { Solution[0] = 0.0; Solution[1] = 0.0; } - else { Solution[0] = 0.0; Solution[1] = 0.0; Solution[2] = 0.0; } - } - else { - if (nDim == 2) { Solution[0] = 0.0; Solution[1] = 0.0; Solution[2] = 0.0; Solution[3] = 0.0; } - else { Solution[0] = 0.0; Solution[1] = 0.0; Solution[2] = 0.0; Solution[3] = 0.0; Solution[4] = 0.0; Solution[5] = 0.0; } - } - - node[iPoint]->SetSolution(Solution); - - if (dual_time) { - node[iPoint]->Set_Solution_time_n(); - node[iPoint]->Set_Solution_time_n1(); - } - - } - } -} - -void CFEASolver::GetSurface_Pressure(CGeometry *geometry, CConfig *config) { - - unsigned short iMarker, icommas, iDim; - unsigned long iVertex, iPoint, iExtIter; - su2double Pressure = 0.0, Dist, Coord[3]; - string text_line; - string::size_type position; - ifstream Surface_file; - char buffer[50], cstr[200]; - - int rank = MASTER_NODE; - int size = SINGLE_NODE; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); -#endif - - /*--- Reset the value of the Flow_Pressure ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - node[iPoint]->SetFlow_Pressure(0.0); - - for (iExtIter = 0; iExtIter < config->GetnExtIter(); iExtIter++) { - - /*--- Prepare to read surface sensitivity files (CSV) ---*/ - - string surfadj_filename = config->GetSurfFlowCoeff_FileName(); - - /*--- Remove the domain number from the surface csv filename ---*/ - - if (size > SINGLE_NODE) { - if ((rank+1 >= 0) && (rank+1 < 10)) surfadj_filename.erase (surfadj_filename.end()-2, surfadj_filename.end()); - if ((rank+1 >= 10) && (rank+1 < 100)) surfadj_filename.erase (surfadj_filename.end()-3, surfadj_filename.end()); - if ((rank+1 >= 100) && (rank+1 < 1000)) surfadj_filename.erase (surfadj_filename.end()-4, surfadj_filename.end()); - if ((rank+1 >= 1000) && (rank+1 < 10000)) surfadj_filename.erase (surfadj_filename.end()-5, surfadj_filename.end()); - } - strcpy (cstr, surfadj_filename.c_str()); - - /*--- Write file name with extension if unsteady or steady ---*/ - - if ((config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) || - (config->GetUnsteady_Simulation() == TIME_SPECTRAL)) { - if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(iExtIter)); - if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(iExtIter)); - } - else SPRINTF (buffer, ".csv"); - - strcat (cstr, buffer); - - /*--- Open the surface file ---*/ - - Surface_file.open(cstr, ios::in); - - getline(Surface_file, text_line); - - /*--- Res the surface file ---*/ - - while (getline(Surface_file, text_line)) { - - /*--- Remove commas from the surface file ---*/ - - for (icommas = 0; icommas < 100; icommas++) { - position = text_line.find( ",", 0 ); - if (position!=string::npos) text_line.erase (position, 1); - } - - /*--- Read the file ---*/ - istringstream point_line(text_line); - if (nDim == 2) { point_line >> iPoint >> Coord[0] >> Coord[1] >> Pressure; } - if (nDim == 3) { point_line >> iPoint >> Coord[0] >> Coord[1] >> Coord[2] >> Pressure; } - - /*--- Compute the distance from the surface to the points in the .csv files ---*/ - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == PRESSURE_BOUNDARY) { - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - /*--- Compute the distance between the point and the grid points ---*/ - Dist = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Dist += (Coord[iDim]-geometry->node[iPoint]->GetCoord(iDim))*(Coord[iDim]-geometry->node[iPoint]->GetCoord(iDim)); - Dist = sqrt(Dist); - - /*--- Check the distance and set the pressure ---*/ - if (Dist < 1E-10) { node[iPoint]->SetFlow_Pressure(Pressure); } - - } - } - } - - } - - Surface_file.close(); - - } - -} - -void CFEASolver::SetFEA_Load(CSolver ***flow_solution, CGeometry **fea_geometry, CGeometry **flow_geometry, - CConfig *fea_config, CConfig *flow_config, CNumerics *fea_numerics) { - - // Unused variables - //unsigned short nVertexFEA; - //su2double *nodePress, *nodeShearStress, *tn_e; - //su2double Viscosity_Ref, Velocity_Ref, Density_Ref, Pressure_Ref; - //unsigned short markFEA, nMarkerFEA, iMarkerFEA; - - unsigned short nVertexFlow, iVertex, nMarkerFSIint, iDim, jDim; - unsigned short markFlow, iPoint, iMarkerFSIint; - unsigned short nMarkerFlow, iMarkerFlow; - unsigned long *nodeVertex, *donorVertex; - su2double **normalsVertex, **normalsVertex_Unit, **tn_f; - su2double factorForces; - - su2double *Velocity_ND, Density_ND, *Velocity_Real, Density_Real, Velocity2_Real, Velocity2_ND; - - bool compressible = (flow_config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (flow_config->GetKind_Regime() == INCOMPRESSIBLE); - - bool viscous_flow = ((flow_config->GetKind_Solver() == NAVIER_STOKES) || - (flow_config->GetKind_Solver() == RANS) ); - - su2double Pinf = 0.0; - - su2double ModAmpl; - su2double CurrentTime=fea_config->GetCurrent_DynTime(); - su2double Static_Time=fea_config->GetStatic_Time(); - - bool Ramp_Load = fea_config->GetRamp_Load(); - su2double Ramp_Time = fea_config->GetRamp_Time(); - - if (CurrentTime <= Static_Time){ - ModAmpl=0.0; - } - else if((CurrentTime > Static_Time) && - (CurrentTime <= (Static_Time + Ramp_Time)) && - (Ramp_Load)){ - ModAmpl=(CurrentTime-Static_Time)/Ramp_Time; - ModAmpl=max(ModAmpl,0.0); - ModAmpl=min(ModAmpl,1.0); - } - else{ - ModAmpl=1.0; - } - - /*--- Number of markers in the FSI interface ---*/ - nMarkerFSIint = (fea_config->GetMarker_n_FSIinterface())/2; - - /*--- Initialization of vectors of residuals ---*/ - /*--- WATCH OUT! This Shouldn't be here I think... For the dead load */ - - for (iPoint = 0; iPoint < fea_geometry[MESH_0]->GetnPoint(); iPoint ++) { - LinSysRes.SetBlock_Zero(iPoint); - } - - /*--- Redimensionalize the pressure ---*/ - - Velocity_Real = flow_config->GetVelocity_FreeStream(); - Density_Real = flow_config->GetDensity_FreeStream(); - - Velocity_ND = flow_config->GetVelocity_FreeStreamND(); - Density_ND = flow_config->GetDensity_FreeStreamND(); - - - Velocity2_Real = 0.0; - Velocity2_ND = 0.0; - for (iDim = 0; iDim < nDim; iDim++){ - Velocity2_Real += Velocity_Real[iDim]*Velocity_Real[iDim]; - Velocity2_ND += Velocity_ND[iDim]*Velocity_ND[iDim]; - } - - /*--- Unused Vars ---*/ - //Velocity_Ref = flow_config->GetVelocity_Ref(); - //Viscosity_Ref = flow_config->GetViscosity_Ref(); - //Density_Ref = flow_solution[MESH_0][FLOW_SOL]->GetDensity_Inf(); - //Pressure_Ref = flow_config->GetPressure_Ref(); - - factorForces = Density_Real*Velocity2_Real/(Density_ND*Velocity2_ND); - - /*--- Loop over all the markers on the interface ---*/ - - for (iMarkerFSIint=0; iMarkerFSIint < nMarkerFSIint; iMarkerFSIint++){ - - //nMarkerFEA=fea_geometry[MESH_0]->GetnMarker(); - nMarkerFlow=flow_geometry[MESH_0]->GetnMarker(); - - /*--- Identification of the markers ---*/ - - // markFEA = 0; - // for (iMarkerFEA=0; iMarkerFEA < nMarkerFEA; iMarkerFEA++){ - // if ( fea_config->GetMarker_All_FSIinterface(iMarkerFEA) == (iMarkerFSIint+1)){ - // markFEA=iMarkerFEA; - // } - // } - - markFlow = 0; - for (iMarkerFlow=0; iMarkerFlow < nMarkerFlow; iMarkerFlow++){ - if (flow_config->GetMarker_All_FSIinterface(iMarkerFlow) == (iMarkerFSIint+1)){ - markFlow=iMarkerFlow; - } - } - - - //nVertexFEA = fea_geometry[MESH_0]->GetnVertex(markFEA); - nVertexFlow = flow_geometry[MESH_0]->GetnVertex(markFlow); - - //nodePress = new su2double [nVertexFlow]; - //nodeShearStress = new su2double [nVertexFlow]; - nodeVertex = new unsigned long [nVertexFlow]; - donorVertex = new unsigned long [nVertexFlow]; - - //tn_e = new su2double [nVar*nDim]; - - tn_f = new su2double* [nVertexFlow]; - for (iVertex = 0; iVertex < nVertexFlow; iVertex++) { - tn_f[iVertex] = new su2double[nDim]; - } - - normalsVertex = new su2double* [nVertexFlow]; - for (iVertex = 0; iVertex < nVertexFlow; iVertex++) { - normalsVertex[iVertex] = new su2double[nDim]; - } - - normalsVertex_Unit = new su2double* [nVertexFlow]; - for (iVertex = 0; iVertex < nVertexFlow; iVertex++) { - normalsVertex_Unit[iVertex] = new su2double[nDim]; - } - - su2double **Grad_PrimVar = NULL; - su2double Viscosity = 0.0; - //su2double Density = 0.0; - su2double Tau[3][3]; - - su2double div_vel, Delta; - su2double Area; - - /*--- Loop over the nodes in the fluid mesh, calculate the tf vector (unitary) ---*/ - - su2double Pn = 0.0; - - /*--- Here, we are looping over the fluid, and we find the pointer to the structure (donorVertex) ---*/ - for (iVertex=0; iVertex < nVertexFlow; iVertex++){ - - // Node from the flow mesh - nodeVertex[iVertex]=flow_geometry[MESH_0]->vertex[markFlow][iVertex]->GetNode(); - - // Normals at the vertex: these normals go inside the fluid domain. - normalsVertex[iVertex]=flow_geometry[MESH_0]->vertex[markFlow][iVertex]->GetNormal(); - - // Unit normals - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) { - Area += normalsVertex[iVertex][iDim]*normalsVertex[iVertex][iDim]; - } - Area = sqrt(Area); - - for (iDim = 0; iDim < nDim; iDim++) { - normalsVertex_Unit[iVertex][iDim] = normalsVertex[iVertex][iDim]/Area; - } - - // Corresponding node on the structural mesh - donorVertex[iVertex]=flow_geometry[MESH_0]->vertex[markFlow][iVertex]->GetDonorPoint(); - - // Retrieve the values of pressure, viscosity and density - if (incompressible){ - - Pn=flow_solution[MESH_0][FLOW_SOL]->node[nodeVertex[iVertex]]->GetPressureInc(); - Pinf=flow_solution[MESH_0][FLOW_SOL]->GetPressure_Inf(); - - if (viscous_flow){ - - Grad_PrimVar = flow_solution[MESH_0][FLOW_SOL]->node[nodeVertex[iVertex]]->GetGradient_Primitive(); - Viscosity = flow_solution[MESH_0][FLOW_SOL]->node[nodeVertex[iVertex]]->GetLaminarViscosityInc(); - //Density = flow_solution[MESH_0][FLOW_SOL]->node[nodeVertex[iVertex]]->GetDensityInc(); - - } - } - else if (compressible){ - - Pn=flow_solution[MESH_0][FLOW_SOL]->node[nodeVertex[iVertex]]->GetPressure(); - Pinf=flow_solution[MESH_0][FLOW_SOL]->GetPressure_Inf(); - - if (viscous_flow){ - - Grad_PrimVar = flow_solution[MESH_0][FLOW_SOL]->node[nodeVertex[iVertex]]->GetGradient_Primitive(); - Viscosity = flow_solution[MESH_0][FLOW_SOL]->node[nodeVertex[iVertex]]->GetLaminarViscosity(); - //Density = flow_solution[MESH_0][FLOW_SOL]->node[nodeVertex[iVertex]]->GetDensity(); - - } - } - - // Calculate tn in the fluid nodes for the inviscid term --> Units of force (non-dimensional). - for (iDim = 0; iDim < nDim; iDim++) { - tn_f[iVertex][iDim] = -(Pn-Pinf)*normalsVertex[iVertex][iDim]; - } - - // Calculate tn in the fluid nodes for the viscous term - - if (viscous_flow){ - - // Divergence of the velocity - div_vel = 0.0; for (iDim = 0; iDim < nDim; iDim++) div_vel += Grad_PrimVar[iDim+1][iDim]; - if (incompressible) div_vel = 0.0; - - for (iDim = 0; iDim < nDim; iDim++) { - - for (jDim = 0 ; jDim < nDim; jDim++) { - // Dirac delta - Delta = 0.0; if (iDim == jDim) Delta = 1.0; - - // Viscous stress - Tau[iDim][jDim] = Viscosity*(Grad_PrimVar[jDim+1][iDim] + Grad_PrimVar[iDim+1][jDim]) - - TWO3*Viscosity*div_vel*Delta; - - // Viscous component in the tn vector --> Units of force (non-dimensional). - tn_f[iVertex][iDim] += Tau[iDim][jDim]*normalsVertex[iVertex][jDim]; - } - } - } - - // Rescale tn to SI units - - for (iDim = 0; iDim < nDim; iDim++) { - tn_f[iVertex][iDim] = tn_f[iVertex][iDim]*factorForces; - } - - // Apply time-dependent coefficient (static structure, ramp load, full load) - - for (iDim = 0; iDim < nDim; iDim++) { - tn_f[iVertex][iDim] = tn_f[iVertex][iDim]*ModAmpl; - } - - // This works only for matching meshes - - for (iDim = 0; iDim < nDim; iDim++){ - Residual[iDim]=tn_f[iVertex][iDim]; - } - - - - LinSysRes.AddBlock(donorVertex[iVertex], Residual); - - } - - } - -} - - -void CFEASolver::SetStruct_Displacement(CGeometry **fea_geometry, CConfig *fea_config, CSolver ***fea_solution) { - - - unsigned long iPoint, iDim; - unsigned long nPoint, nDim; - su2double *Coord, *VarCoord, *Displacement; - - - nPoint = fea_geometry[MESH_0]->GetnPoint(); - nDim = fea_geometry[MESH_0]->GetnDim(); - - VarCoord = new su2double [nDim]; - - for (iPoint=0; iPoint < nPoint; iPoint++){ - - Coord = fea_geometry[MESH_0]->node[iPoint]->GetCoord(); - - Displacement = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution(); - - for (iDim = 0; iDim < nDim; iDim++) - VarCoord[iDim] = (Coord[iDim]+Displacement[iDim]); - - fea_geometry[MESH_0]->node[iPoint]->SetCoord(VarCoord); - - } - -} - - -void CFEASolver::PredictStruct_Displacement(CGeometry **fea_geometry, CConfig *fea_config, CSolver ***fea_solution) { - - unsigned short predOrder=fea_config->GetPredictorOrder(); - su2double Delta_t= fea_config->GetDelta_DynTime(); - unsigned long iPoint, iDim; - unsigned long nPoint, nDim; - su2double *solDisp, *solVel, *solVel_tn, *valPred, *checkPred; - - nPoint = fea_geometry[MESH_0]->GetnPoint(); - nDim = fea_geometry[MESH_0]->GetnDim(); - - solDisp=new su2double [nDim]; - solVel=new su2double [nDim]; - solVel_tn=new su2double [nDim]; - valPred=new su2double [nDim]; - checkPred=new su2double [nDim]; - - for (iPoint=0; iPointnode[iPoint]->SetSolution_Pred(); - else if (predOrder==1) { - - solDisp = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution(); - solVel = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_Vel(); - valPred = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_Pred(); - - for (iDim = 0; iDim < nDim; iDim++){ - valPred[iDim] = solDisp[iDim] + Delta_t*solVel[iDim]; - } - - // fea_solution[MESH_0][FEA_SOL]->node[iPoint]->SetSolution_Pred(valPred); - - - } - else if (predOrder==2) { - - solDisp = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution(); - solVel = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_Vel(); - solVel_tn = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_Vel_time_n(); - valPred = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_Pred(); - - for (iDim = 0; iDim < nDim; iDim++){ - valPred[iDim] = solDisp[iDim] + 0.5*Delta_t*(3*solVel[iDim]-solVel_tn[iDim]); - } - - // fea_solution[MESH_0][FEA_SOL]->node[iPoint]->SetSolution_Pred(valPred); - - } - else { - cout<< "Higher order predictor not implemented. Solving with order 0." << endl; - fea_solution[MESH_0][FEA_SOL]->node[iPoint]->SetSolution_Pred(); - } - } - - delete [] solDisp; - delete [] solVel; - delete [] solVel_tn; - delete [] valPred; - delete [] checkPred; - -} - -void CFEASolver::ComputeAitken_Coefficient(CGeometry **fea_geometry, CConfig *fea_config, CSolver ***fea_solution, unsigned long iFSIIter) { - - unsigned long iPoint, iDim; - unsigned long nPoint, nDim; - su2double *dispPred, *dispCalc, *dispPred_Old, *dispCalc_Old; - su2double deltaU[3] = {0.0, 0.0, 0.0}, deltaU_p1[3] = {0.0, 0.0, 0.0}; - su2double delta_deltaU[3] = {0.0, 0.0, 0.0}; - su2double numAitk, denAitk; - su2double CurrentTime=fea_config->GetCurrent_DynTime(); - su2double Static_Time=fea_config->GetStatic_Time(); - su2double WAitkDyn_tn1, WAitkDyn_Max, WAitkDyn; - - nPoint = fea_geometry[MESH_0]->GetnPoint(); - nDim = fea_geometry[MESH_0]->GetnDim(); - - //su2double WAitken=fea_config->GetAitkenStatRelax(); - - dispPred =new su2double [nDim]; - dispPred_Old=new su2double [nDim]; - dispCalc =new su2double [nDim]; - dispCalc_Old=new su2double [nDim]; - - numAitk = 0.0; - denAitk = 0.0; - - ofstream historyFile_FSI; - bool writeHistFSI = fea_config->GetWrite_Conv_FSI(); - if (writeHistFSI){ - char cstrFSI[200]; - string filenameHistFSI = fea_config->GetConv_FileName_FSI(); - strcpy (cstrFSI, filenameHistFSI.data()); - historyFile_FSI.open (cstrFSI, std::ios_base::app); - } - - - /*--- Only when there is movement, and a dynamic coefficient is requested, it makes sense to compute the Aitken's coefficient ---*/ - - if (CurrentTime > Static_Time) { - - if (iFSIIter == 0){ - - WAitkDyn_tn1 = GetWAitken_Dyn_tn1(); - WAitkDyn_Max = fea_config->GetAitkenDynMaxInit(); - - WAitkDyn = min(WAitkDyn_tn1, WAitkDyn_Max); - - /*--- Temporal fix, only for now ---*/ - WAitkDyn = max(WAitkDyn, 0.1); - - SetWAitken_Dyn(WAitkDyn); - if (writeHistFSI){ - historyFile_FSI << " " << endl ; - historyFile_FSI << setiosflags(ios::fixed) << setprecision(4) << CurrentTime << "," ; - historyFile_FSI << setiosflags(ios::fixed) << setprecision(1) << iFSIIter << "," ; - historyFile_FSI << setiosflags(ios::scientific) << setprecision(4) << WAitkDyn ; - } - - } - else{ - - for (iPoint=0; iPointnode[iPoint]->GetSolution_Pred(); - dispPred_Old = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_Pred_Old(); - dispCalc = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution(); - dispCalc_Old = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_Old(); - - for (iDim = 0; iDim < nDim; iDim++){ - - /*--- Compute the deltaU and deltaU_n+1 ---*/ - deltaU[iDim] = dispCalc_Old[iDim] - dispPred_Old[iDim]; - deltaU_p1[iDim] = dispCalc[iDim] - dispPred[iDim]; - - /*--- Compute the difference ---*/ - delta_deltaU[iDim] = deltaU_p1[iDim] - deltaU[iDim]; - - /*--- Add numerator and denominator ---*/ - numAitk += deltaU[iDim] * delta_deltaU[iDim]; - denAitk += delta_deltaU[iDim] * delta_deltaU[iDim]; - - } - - } - - WAitkDyn = GetWAitken_Dyn(); - - if (denAitk > 1E-8){ - WAitkDyn = - 1.0 * WAitkDyn * numAitk / denAitk ; - } - - WAitkDyn = max(WAitkDyn, 0.1); - WAitkDyn = min(WAitkDyn, 1.0); - - SetWAitken_Dyn(WAitkDyn); - - if (writeHistFSI){ - historyFile_FSI << setiosflags(ios::fixed) << setprecision(4) << CurrentTime << "," ; - historyFile_FSI << setiosflags(ios::fixed) << setprecision(1) << iFSIIter << "," ; - historyFile_FSI << setiosflags(ios::scientific) << setprecision(4) << WAitkDyn << "," ; - } - - } - - } - - if (writeHistFSI){historyFile_FSI.close();} - - delete [] dispPred; - delete [] dispPred_Old; - delete [] dispCalc; - delete [] dispCalc_Old; - -} - -void CFEASolver::SetAitken_Relaxation(CGeometry **fea_geometry, CConfig *fea_config, CSolver ***fea_solution) { - - unsigned long iPoint, iDim; - unsigned long nPoint, nDim; - unsigned short RelaxMethod_FSI; - su2double *dispPred, *dispCalc; - su2double WAitken; - su2double CurrentTime=fea_config->GetCurrent_DynTime(); - su2double Static_Time=fea_config->GetStatic_Time(); - - nPoint = fea_geometry[MESH_0]->GetnPoint(); - nDim = fea_geometry[MESH_0]->GetnDim(); - - dispPred=new su2double [nDim]; - dispCalc=new su2double [nDim]; - - RelaxMethod_FSI = fea_config->GetRelaxation_Method_FSI(); - - /*--- Only when there is movement it makes sense to update the solutions... ---*/ - - if (CurrentTime > Static_Time) { - - if (RelaxMethod_FSI == NO_RELAXATION){ - WAitken = 1.0; - } - else if (RelaxMethod_FSI == FIXED_PARAMETER){ - WAitken = fea_config->GetAitkenStatRelax(); - } - else if (RelaxMethod_FSI == AITKEN_DYNAMIC){ - WAitken = GetWAitken_Dyn(); - } - else { - WAitken = 1.0; - cout << "No relaxation parameter used. " << endl; - } - - - for (iPoint=0; iPointnode[iPoint]->GetSolution_Pred(); - dispCalc = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution(); - - /*--- Set predicted solution as the old predicted solution ---*/ - fea_solution[MESH_0][FEA_SOL]->node[iPoint]->SetSolution_Pred_Old(); - - /*--- Set calculated solution as the old solution (needed for dynamic Aitken relaxation) ---*/ - fea_solution[MESH_0][FEA_SOL]->node[iPoint]->SetSolution_Old(dispCalc); - - /*--- Apply the Aitken relaxation ---*/ - for (iDim = 0; iDim < nDim; iDim++){ - dispPred[iDim] = (1.0 - WAitken)*dispPred[iDim] + WAitken*dispCalc[iDim]; - } - - /*--- Set obtained solution as the new predicted solution ---*/ - /*--- As dispPred is the pointer to the solution_Pred, we don't need to do this... ---*/ - //fea_solution[MESH_0][FEA_SOL]->node[iPoint]->SetSolution_Pred(dispPred); - - } - - } - - delete [] dispCalc; - delete [] dispPred; - -} - -void CFEASolver::Update_StructSolution(CGeometry **fea_geometry, CConfig *fea_config, CSolver ***fea_solution) { - - su2double *valSolutionPred; - - for (unsigned long iPoint=0; iPointGetnPoint(); iPoint++){ - - valSolutionPred = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_Pred(); - - fea_solution[MESH_0][FEA_SOL]->node[iPoint]->SetSolution(valSolutionPred); - - } - -} - - - - +/*! + * \file solution_direct_elasticity.cpp + * \brief Main subrotuines for solving the linear elasticity equation. + * \author F. Palacios, R. Sanchez + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/solver_structure.hpp" + +CFEASolver::CFEASolver(void) : CSolver() { } + +CFEASolver::CFEASolver(CGeometry *geometry, CConfig *config) : CSolver() { + + unsigned long iPoint; + unsigned short iVar, jVar, NodesElement = 0, nLineLets; + unsigned short iDim; + su2double dull_val; + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + nPoint = geometry->GetnPoint(); + nPointDomain = geometry->GetnPointDomain(); + nDim = geometry->GetnDim(); + node = new CVariable*[nPoint]; + + + WAitken_Dyn = 0.0; + WAitken_Dyn_tn1 = 0.0; + + SetFSI_ConvValue(0,0.0); + SetFSI_ConvValue(1,0.0); + + nVar = nDim; + + if (nDim == 2) NodesElement = 4; + if (nDim == 3) NodesElement = 8; + + /*--- Define some auxiliary vectors related to the residual ---*/ + + Residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; + Residual_RMS = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_RMS[iVar] = 0.0; + Residual_Max = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_Max[iVar] = 0.0; + Point_Max = new unsigned long[nVar]; for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; + Point_Max_Coord = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Point_Max_Coord[iVar] = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; + } + + /*--- Define some auxiliary vectors related to the solution ---*/ + + Solution = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; + + /*--- Element aux stiffness matrix definition ---*/ + + StiffMatrix_Elem = new su2double*[NodesElement*nDim]; + for (iVar = 0; iVar < NodesElement*nDim; iVar++) { + StiffMatrix_Elem[iVar] = new su2double [NodesElement*nDim]; + for (jVar = 0; jVar < NodesElement*nDim; jVar++) { + StiffMatrix_Elem[iVar][jVar] = 0.0; + } + } + + /*--- Node aux stiffness matrix definition ---*/ + + StiffMatrix_Node = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + StiffMatrix_Node[iVar] = new su2double [nVar]; + for (jVar = 0; jVar < nVar; jVar++) { + StiffMatrix_Node[iVar][jVar] = 0.0; + } + } + + /*--- Element aux mass matrix definition ---*/ + + MassMatrix_Elem = new su2double*[NodesElement*nDim]; + for (iVar = 0; iVar < NodesElement*nDim; iVar++) { + MassMatrix_Elem[iVar] = new su2double [NodesElement*nDim]; + for (jVar = 0; jVar < NodesElement*nDim; jVar++) { + MassMatrix_Elem[iVar][jVar] = 0.0; + } + } + + /*--- Node aux mass matrix definition ---*/ + + MassMatrix_Node = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + MassMatrix_Node[iVar] = new su2double [nVar]; + for (jVar = 0; jVar < nVar; jVar++) { + MassMatrix_Node[iVar][jVar] = 0.0; + } + } + + /*--- Node aux mass matrix definition ---*/ + + MassMatrix_Node_Int = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + MassMatrix_Node_Int[iVar] = new su2double [nVar]; + for (jVar = 0; jVar < nVar; jVar++) { + MassMatrix_Node_Int[iVar][jVar] = 0.0; + } + } + + /*--- Element aux damping matrix definition ---*/ + + DampMatrix_Elem = new su2double*[NodesElement*nDim]; + for (iVar = 0; iVar < NodesElement*nDim; iVar++) { + DampMatrix_Elem[iVar] = new su2double [NodesElement*nDim]; + for (jVar = 0; jVar < NodesElement*nDim; jVar++) { + DampMatrix_Elem[iVar][jVar] = 0.0; + } + } + + /*--- Node aux damping matrix definition ---*/ + + DampMatrix_Node = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + DampMatrix_Node[iVar] = new su2double [nVar]; + for (jVar = 0; jVar < nVar; jVar++) { + DampMatrix_Node[iVar][jVar] = 0.0; + } + } + + /*--- Initialization of integration constants ---*/ + + for (iVar = 0; iVar < 8; iVar++){ + a_dt[iVar]=0.0; + } + + + + /*--- DESTRUCT THIS! ---*/ + + /*--- Element aux dead load vector definition ---*/ + DeadLoadVector_Elem = new su2double [NodesElement*nDim]; + + /*--- Node aux dead load vector definition ---*/ + DeadLoadVector_Node = new su2double [nVar]; + + + /*--- Initialization of matrix structures ---*/ + + if (rank == MASTER_NODE) cout << "Initialize Stiffness structure (Linear Elasticity)." << endl; + + if (nDim==2){ + unsigned short form2d; + form2d=config->GetElas2D_Formulation(); + if (form2d==0) cout << "Plane stress model for 2D structural analysis (Linear Elasticity)." << endl; + if (form2d==1) cout << "Plane strain model for 2D structural analysis (Linear Elasticity)." << endl; + } + + StiffMatrixSpace.Initialize(nPoint, nPointDomain, nVar, nVar, false, geometry, config); + StiffMatrixTime.Initialize(nPoint, nPointDomain, nVar, nVar, false, geometry, config); + MassMatrix.Initialize(nPoint, nPointDomain, nVar, nVar, false, geometry, config); + DampMatrix.Initialize(nPoint, nPointDomain, nVar, nVar, false, geometry, config); + + if (rank == MASTER_NODE) cout << "Initialize Jacobian structure (Linear Elasticity)." << endl; + Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, false, geometry, config); + + if ((config->GetKind_Linear_Solver_Prec() == LINELET) || + (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { + nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); + if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; + } + + /*--- Initialization of linear solver structures ---*/ + + LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); + LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); + LinSysAux.Initialize(nPoint, nPointDomain, nVar, 0.0); + + TimeRes_Aux.Initialize(nPoint, nPointDomain, nVar, 0.0); + TimeRes.Initialize(nPoint, nPointDomain, nVar, 0.0); + + + /*--- Computation of gradients by least squares ---*/ + + Smatrix = new su2double* [nDim]; + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Smatrix[iDim] = new su2double [nDim]; + + cvector = new su2double* [nVar]; + for (unsigned short iVar = 0; iVar < nVar; iVar++) + cvector[iVar] = new su2double [nDim]; + + /*--- Check for a restart, initialize from zero otherwise ---*/ + + bool restart = (config->GetRestart() || config->GetRestart_Flow()); + + if (!restart) { + for (iPoint = 0; iPoint < nPoint; iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; + node[iPoint] = new CFEAVariable(Solution, nDim, nVar, config); + } + } + else { + unsigned long index; + string text_line, mesh_filename; + ifstream restart_file; + + /*--- Restart the solution from file information ---*/ + + mesh_filename = config->GetSolution_FlowFileName(); + restart_file.open(mesh_filename.data(), ios::in); + + /*--- In case there is no file ---*/ + + if (restart_file.fail()) { + cout << "There is no fea restart file!!" << endl; + exit(EXIT_FAILURE); + } + + /*--- In case this is a parallel simulation, we need to perform the + Global2Local index transformation first. ---*/ + + long *Global2Local; + Global2Local = new long[geometry->GetGlobal_nPointDomain()]; + + /*--- First, set all indices to a negative value by default ---*/ + + for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) { + Global2Local[iPoint] = -1; + } + + /*--- Now fill array with the transform values only for local points ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { + Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; + } + + /*--- Read all lines in the restart file ---*/ + + long iPoint_Local; unsigned long iPoint_Global = 0; + + /*--- The first line is the header ---*/ + + getline (restart_file, text_line); + + while (getline (restart_file, text_line)) { + istringstream point_line(text_line); + + /*--- Retrieve local index. If this node from the restart file lives + on a different processor, the value of iPoint_Local will be -1. + Otherwise, the local index for this node on the current processor + will be returned and used to instantiate the vars. ---*/ + + iPoint_Local = Global2Local[iPoint_Global]; + if (iPoint_Local >= 0) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2]; + node[iPoint_Local] = new CFEAVariable(Solution, nDim, nVar, config); + } + iPoint_Global++; + } + + /*--- Instantiate the variable class with an arbitrary solution + at any halo/periodic nodes. The initial solution can be arbitrary, + because a send/recv is performed immediately in the solver. ---*/ + + for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { + node[iPoint] = new CFEAVariable(Solution, nDim, nVar, config); + } + + /*--- Close the restart file ---*/ + + restart_file.close(); + + /*--- Free memory needed for the transformation ---*/ + + delete [] Global2Local; + } + +} + +CFEASolver::~CFEASolver(void) { + + unsigned short iVar, iDim, NodesElement = 0; + + if (nDim == 2) NodesElement = 4; + if (nDim == 3) NodesElement = 8; + + delete [] Residual; + delete [] Residual_Max; + delete [] Solution; + + for (iVar = 0; iVar < NodesElement*nDim; iVar++) + delete [] StiffMatrix_Elem[iVar]; + + for (iVar = 0; iVar < nVar; iVar++) + delete [] StiffMatrix_Node[iVar]; + + for (iVar = 0; iVar < NodesElement*nDim; iVar++) + delete [] MassMatrix_Elem[iVar]; + + for (iVar = 0; iVar < nVar; iVar++) + delete [] MassMatrix_Elem[iVar]; + + for (iVar = 0; iVar < NodesElement*nDim; iVar++) + delete [] DampMatrix_Elem[iVar]; + + for (iVar = 0; iVar < nVar; iVar++) + delete [] DampMatrix_Elem[iVar]; + + delete [] StiffMatrix_Elem; + delete [] StiffMatrix_Node; + delete [] MassMatrix_Elem; + delete [] MassMatrix_Node; + delete [] DampMatrix_Elem; + delete [] DampMatrix_Node; + + /*--- Computation of gradients by least-squares ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + delete [] Smatrix[iDim]; + delete [] Smatrix; + + for (iVar = 0; iVar < nVar; iVar++) + delete [] cvector[iVar]; + delete [] cvector; + + +} + + + +void CFEASolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, CNumerics **numerics, unsigned short iMesh, unsigned long Iteration, unsigned short RunTime_EqSystem, bool Output) { + + GetSurface_Pressure(geometry, config); + + unsigned long ExtIter = config->GetExtIter(); + + /*--- Set residuals and auxiliar variables to zero ---*/ + + Initialize_SystemMatrix(geometry, solver_container, config); + + bool dynamic = (config->GetDynamic_Analysis() == DYNAMIC); + + if (ExtIter == 0){ + + if (!dynamic){ + Compute_StiffMatrix(geometry, solver_container, numerics[VISC_TERM], config); + } + else if (dynamic){ + /*--- Compute the integration constants ---*/ + Compute_IntegrationConstants(geometry, solver_container, numerics[VISC_TERM], config); + + /*--- Compute the stiffness and mass matrices ---*/ + Compute_StiffMassMatrix(geometry, solver_container, numerics[VISC_TERM], config); + + // Compute_StiffMassDampMatrix(geometry, solver_container, numerics[VISC_TERM], config); + } + + } + +} + +void CFEASolver::Initialize_SystemMatrix(CGeometry *geometry, CSolver **solver_container, CConfig *config) { + + unsigned long iPoint; + bool dynamic = (config->GetDynamic_Analysis() == DYNAMIC); + unsigned long ExtIter = config->GetExtIter(); + bool fsi = config->GetFSI_Simulation(); + + if (!fsi) { + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { + LinSysRes.SetBlock_Zero(iPoint); + LinSysAux.SetBlock_Zero(iPoint); + } + + /*--- Set matrix entries to zero ---*/ + + /*--- Static calculation ---*/ + + if (dynamic && ExtIter == 0){ + + StiffMatrixSpace.SetValZero(); + StiffMatrixTime.SetValZero(); + + MassMatrix.SetValZero(); + DampMatrix.SetValZero(); + + } + + /*--- Dynamic calculation ---*/ + else if (!dynamic){ + + StiffMatrixSpace.SetValZero(); + Jacobian.SetValZero(); + + } + + } + + else { + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { + LinSysAux.SetBlock_Zero(iPoint); + } + + /*--- Set matrix entries to zero ---*/ + + /*--- Static calculation ---*/ + + if (dynamic && ExtIter == 0){ + + StiffMatrixSpace.SetValZero(); + StiffMatrixTime.SetValZero(); + + MassMatrix.SetValZero(); + DampMatrix.SetValZero(); + + } + + /*--- Dynamic calculation ---*/ + else if (!dynamic){ + + StiffMatrixSpace.SetValZero(); + Jacobian.SetValZero(); + + } + + } + + +} + +void CFEASolver::Compute_IntegrationConstants(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config) { + + su2double Delta_t= config->GetDelta_DynTime(); + su2double delta = config->GetNewmark_delta(), alpha = config->GetNewmark_alpha(); + + /*--- Integration constants for Newmark scheme ---*/ + + a_dt[0]= 1 / (alpha*pow(Delta_t,2.0)); + a_dt[1]= delta / (alpha*Delta_t); + a_dt[2]= 1 / (alpha*Delta_t); + a_dt[3]= 1 /(2*alpha) - 1; + a_dt[4]= delta/alpha - 1; + a_dt[5]= (Delta_t/2) * (delta/alpha - 2); + a_dt[6]= Delta_t * (1-delta); + a_dt[7]= delta * Delta_t; + +} + +void CFEASolver::Compute_StiffMatrix(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config) { + + unsigned short iVar, jVar, nNodes = 0, iNodes, iDim, jDim, form2d; + unsigned long iElem, PointCorners[8]; + su2double CoordCorners[8][3]; + + form2d=config->GetElas2D_Formulation(); + + /*--- Loops over all the elements ---*/ + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) nNodes = 3; + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) nNodes = 4; + if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) nNodes = 4; + if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) nNodes = 5; + if (geometry->elem[iElem]->GetVTK_Type() == PRISM) nNodes = 6; + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) nNodes = 8; + + /*--- For the number of nodes, we get the coordinates from the connectivity matrix ---*/ + + for (iNodes = 0; iNodes < nNodes; iNodes++) { + PointCorners[iNodes] = geometry->elem[iElem]->GetNode(iNodes); + for (iDim = 0; iDim < nDim; iDim++) { + CoordCorners[iNodes][iDim] = geometry->node[PointCorners[iNodes]]->GetCoord(iDim); + } + } + + /*--- We set the element stiffness matrix ---*/ + + if (nDim == 2) numerics->SetFEA_StiffMatrix2D(StiffMatrix_Elem, CoordCorners, nNodes, form2d); + if (nDim == 3) numerics->SetFEA_StiffMatrix3D(StiffMatrix_Elem, CoordCorners, nNodes); + + /*--- Initialization of the auxiliar matrix ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + StiffMatrix_Node[iVar][jVar] = 0.0; + + /*--- Transform the stiffness matrix into the + contributions for the individual nodes relative to each other. ---*/ + + for (iVar = 0; iVar < nNodes; iVar++) { + for (jVar = 0; jVar < nNodes; jVar++) { + for (iDim = 0; iDim < nVar; iDim++) { + for (jDim = 0; jDim < nVar; jDim++) { + StiffMatrix_Node[iDim][jDim] = StiffMatrix_Elem[(iVar*nDim)+iDim][(jVar*nDim)+jDim]; + } + } + StiffMatrixSpace.AddBlock(PointCorners[iVar], PointCorners[jVar], StiffMatrix_Node); + } + } + + } + +} + +void CFEASolver::Compute_StiffMassMatrix(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config) { + + unsigned short iVar, jVar, nNodes = 0, iNodes, iDim, jDim, form2d; + unsigned long iElem, PointCorners[8]; + su2double CoordCorners[8][3]; + + form2d=config->GetElas2D_Formulation(); + + /*--- Loops over all the elements ---*/ + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) nNodes = 3; + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) nNodes = 4; + if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) nNodes = 4; + if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) nNodes = 5; + if (geometry->elem[iElem]->GetVTK_Type() == PRISM) nNodes = 6; + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) nNodes = 8; + + /*--- For the number of nodes, we get the coordinates from the connectivity matrix ---*/ + + for (iNodes = 0; iNodes < nNodes; iNodes++) { + PointCorners[iNodes] = geometry->elem[iElem]->GetNode(iNodes); + for (iDim = 0; iDim < nDim; iDim++) { + CoordCorners[iNodes][iDim] = geometry->node[PointCorners[iNodes]]->GetCoord(iDim); + } + } + + /*--- We set the element stiffness matrix ---*/ + + /*--- This solves the problem but... why? ---*/ + for (iVar = 0; iVar < nNodes*nDim; iVar++) { + StiffMatrix_Elem[iVar] = new su2double [nNodes*nDim]; + for (jVar = 0; jVar < nNodes*nDim; jVar++) { + StiffMatrix_Elem[iVar][jVar] = 0.0; + } + } + + if (nDim == 2) numerics->SetFEA_StiffMassMatrix2D(StiffMatrix_Elem, MassMatrix_Elem, CoordCorners, nNodes, form2d); + if (nDim == 3) numerics->SetFEA_StiffMassMatrix3D(StiffMatrix_Elem, MassMatrix_Elem, CoordCorners, nNodes); + + /*--- Initialization of the auxiliar matrix ---*/ + + for (iVar = 0; iVar < nVar; iVar++){ + for (jVar = 0; jVar < nVar; jVar++){ + StiffMatrix_Node[iVar][jVar] = 0.0; + MassMatrix_Node[iVar][jVar] = 0.0; + } + } + + /*--- Transform the stiffness and mass matrices into the + contributions for the individual nodes relative to each other. ---*/ + + for (iVar = 0; iVar < nNodes; iVar++) { + for (jVar = 0; jVar < nNodes; jVar++) { + for (iDim = 0; iDim < nVar; iDim++) { + for (jDim = 0; jDim < nVar; jDim++) { + StiffMatrix_Node[iDim][jDim] = StiffMatrix_Elem[(iVar*nDim)+iDim][(jVar*nDim)+jDim]; + MassMatrix_Node[iDim][jDim] = MassMatrix_Elem[(iVar*nDim)+iDim][(jVar*nDim)+jDim]; + MassMatrix_Node_Int[iDim][jDim] = a_dt[0] * MassMatrix_Elem[(iVar*nDim)+iDim][(jVar*nDim)+jDim]; + } + } + MassMatrix.AddBlock(PointCorners[iVar], PointCorners[jVar], MassMatrix_Node); + StiffMatrixTime.AddBlock(PointCorners[iVar], PointCorners[jVar], StiffMatrix_Node); + StiffMatrixTime.AddBlock(PointCorners[iVar], PointCorners[jVar], MassMatrix_Node_Int); + } + } + + } + +} + +void CFEASolver::Compute_StiffMassDampMatrix(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config) { + + cout << "Here we will compute the damping matrix." << endl; +} + + +void CFEASolver::SetSolution_time_n(CGeometry *geometry, CConfig *config) { + + bool dynamic = (config->GetDynamic_Analysis() == DYNAMIC); + + if (dynamic){ + for(unsigned long iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + // The loop is over nPoints so the boundaries are also updated + node[iPoint]->SetSolution_time_n(); + node[iPoint]->SetSolution_Vel_time_n(); + node[iPoint]->SetSolution_Accel_time_n(); + } + } + +} + + + + + +void CFEASolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, + CConfig *config, unsigned short iMesh) { + + /*--- Compute body forces load vector ---*/ + + + + /*--- Compute initial stresses effect ---*/ + + +} + +void CFEASolver::Viscous_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config, unsigned short iMesh, unsigned short iRKStep) { + +} + + +/*-------------------------------------------------------------------------------------------------- + * Definition of new boundary conditions + ---------------------------------------------------------------------------------------------------*/ + +void CFEASolver::BC_Clamped(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, + unsigned short val_marker) { + + unsigned long iPoint, iVertex; + unsigned short iVar, jVar; + + bool dynamic = (config->GetDynamic_Analysis() == DYNAMIC); + + su2double **mIdentity, **mZeros; // Variables to delete blocks in the jacobian + + mIdentity = new su2double *[nDim]; // Number of rows, allocate memory for each + for(int iMat=0; iMatGetElasticyMod(); + if (iMat==jMat) mIdentity[iMat][jMat]=1.0; + else mIdentity[iMat][jMat]=0; + } + } + + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + /*--- Get node index ---*/ + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + if (nDim == 2) { + Solution[0] = 0.0; Solution[1] = 0.0; + Residual[0] = 0.0; Residual[1] = 0.0; + } + else { + Solution[0] = 0.0; Solution[1] = 0.0; Solution[2] = 0.0; + Residual[0] = 0.0; Residual[1] = 0.0; Residual[2] = 0.0; + } + + node[iPoint]->SetSolution(Solution); + + if (dynamic){ + node[iPoint]->SetSolution_Vel(Solution); + node[iPoint]->SetSolution_Accel(Solution); + } + + LinSysRes.SetBlock(iPoint, Residual); + + /*--- Set the boundary clamped condition ---*/ + + /*--- If the problem is dynamic ---*/ + + if(dynamic){ + + /*--- Enforce that in the previous time step all nodes had 0 U, U', U'' ---*/ + + node[iPoint]->SetSolution_time_n(Solution); + node[iPoint]->SetSolution_Vel_time_n(Solution); + node[iPoint]->SetSolution_Accel_time_n(Solution); + + /*--- Delete the rows for a particular node ---*/ + for (jVar = 0; jVar < nPoint; jVar++){ + if (iPoint==jVar) { + StiffMatrixTime.SetBlock(iPoint,jVar,mIdentity); + MassMatrix.SetBlock(iPoint,jVar,mIdentity); + } + else { + StiffMatrixTime.SetBlock(iPoint,jVar,mZeros); + MassMatrix.SetBlock(iPoint,jVar,mZeros); + } + } + + /*--- Delete the columns for a particular node ---*/ + for (iVar = 0; iVar < nPoint; iVar++){ + if (iVar==iPoint) { + StiffMatrixTime.SetBlock(iVar,iPoint,mIdentity); + MassMatrix.SetBlock(iVar,iPoint,mIdentity); + } + else { + StiffMatrixTime.SetBlock(iVar,iPoint,mZeros); + MassMatrix.SetBlock(iVar,iPoint,mZeros); + } + } + + } + + /*--- If the problem is static ---*/ + + else{ + + /*--- Delete the rows for a particular node ---*/ + for (jVar = 0; jVar < nPoint; jVar++){ + if (iPoint==jVar) { + Jacobian.SetBlock(iPoint,jVar,mIdentity); + StiffMatrixSpace.SetBlock(iPoint,jVar,mIdentity); + } + else { + Jacobian.SetBlock(iPoint,jVar,mZeros); + StiffMatrixSpace.SetBlock(iPoint,jVar,mZeros); + } + } + + /*--- Delete the columns for a particular node ---*/ + for (iVar = 0; iVar < nPoint; iVar++){ + if (iVar==iPoint) { + Jacobian.SetBlock(iVar,iPoint,mIdentity); + StiffMatrixSpace.SetBlock(iPoint,jVar,mIdentity); + } + else { + Jacobian.SetBlock(iVar,iPoint,mZeros); + StiffMatrixSpace.SetBlock(iPoint,jVar,mZeros); + } + } + + } + + } + + +} + + +void CFEASolver::BC_Clamped_Post(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, + unsigned short val_marker) { + + unsigned long iPoint, iVertex; + + su2double **mIdentity, **mZeros; // Variables to delete blocks in the jacobian + + + mIdentity = new su2double *[nDim]; // Number of rows, allocate memory for each + for(int iMat=0; iMatnVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + if (nDim == 2) { + Solution[0] = 0.0; Solution[1] = 0.0; + Residual[0] = 0.0; Residual[1] = 0.0; + } + else { + Solution[0] = 0.0; Solution[1] = 0.0; Solution[2] = 0.0; + Residual[0] = 0.0; Residual[1] = 0.0; Residual[2] = 0.0; + } + + node[iPoint]->SetSolution(Solution); + node[iPoint]->SetSolution_Old(Solution); + + + /*--- Re-set the displacement condition ---*/ + LinSysRes.SetBlock(iPoint, Residual); + + } + +} + + +void CFEASolver::BC_Normal_Displacement(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, + unsigned short val_marker) { + unsigned long iPoint, iVertex, total_index; + unsigned short iVar, iDim; + su2double *Normal, Area, UnitaryNormal[3] = {0.0,0.0,0.0}; + + su2double TotalDispl = config->GetDispl_Value(config->GetMarker_All_TagBound(val_marker)); + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + Normal = geometry->vertex[val_marker][iVertex]->GetNormal(); + + /*--- Compute area, and unitary normal ---*/ + + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); + for (iDim = 0; iDim < nDim; iDim++) UnitaryNormal[iDim] = Normal[iDim]/Area; + + if (config->GetUnsteady_Simulation() == STEADY) { + if (nDim == 2) { + Solution[0] = TotalDispl*UnitaryNormal[0]; Solution[1] = TotalDispl*UnitaryNormal[1]; + Residual[0] = TotalDispl*UnitaryNormal[0]; Residual[1] = TotalDispl*UnitaryNormal[1]; + } + else { + Solution[0] = TotalDispl*UnitaryNormal[0]; Solution[1] = TotalDispl*UnitaryNormal[1]; Solution[2] = TotalDispl*UnitaryNormal[2]; + Residual[0] = TotalDispl*UnitaryNormal[0]; Residual[1] = TotalDispl*UnitaryNormal[1]; Residual[2] = TotalDispl*UnitaryNormal[2]; + } + } + else { + if (nDim == 2) { + Solution[0] = TotalDispl*UnitaryNormal[0]; Solution[1] = TotalDispl*UnitaryNormal[1]; + Solution[2] = 0.0; Solution[3] = 0.0; + Residual[0] = 0.0; Residual[1] = 0.0; + Residual[2] = 0.0; Residual[3] = 0.0; + } + else { + Solution[0] = TotalDispl*UnitaryNormal[0]; Solution[1] = TotalDispl*UnitaryNormal[1]; Solution[2] = TotalDispl*UnitaryNormal[2]; + Solution[3] = 0.0; Solution[4] = 0.0; Solution[5] = 0.0; + Residual[0] = 0.0; Residual[1] = 0.0; Residual[2] = 0.0; + Residual[3] = 0.0; Residual[4] = 0.0; Residual[5] = 0.0; + } + } + + node[iPoint]->SetSolution(Solution); + node[iPoint]->SetSolution_Old(Solution); + + LinSysRes.SetBlock(iPoint, Residual); + + /*--- Set the dirichlet condition ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + Jacobian.DeleteValsRowi(total_index); + } + + } +} + +void CFEASolver::BC_Normal_Load(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, + unsigned short val_marker) { + + su2double a[3], b[3]; + unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0; + su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL; + su2double Normal_Elem[3] = {0.0, 0.0, 0.0}; + //su2double Length_Elem = 0.0, Area_Elem = 0.0; + unsigned short iDim; + + su2double TotalLoad = config->GetLoad_Value(config->GetMarker_All_TagBound(val_marker)); + + for (iElem = 0; iElem < geometry->GetnElem_Bound(val_marker); iElem++) { + + Point_0 = geometry->bound[val_marker][iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); + Point_1 = geometry->bound[val_marker][iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); + if (nDim == 3) { Point_2 = geometry->bound[val_marker][iElem]->GetNode(2); Coord_2 = geometry->node[Point_2]->GetCoord(); } + + /*--- Compute area (3D), and length of the surfaces (2D) ---*/ + + if (nDim == 2) { + + for (iDim = 0; iDim < nDim; iDim++) a[iDim] = Coord_0[iDim]-Coord_1[iDim]; + + //Length_Elem = sqrt(a[0]*a[0]+a[1]*a[1]); + Normal_Elem[0] = a[1]; + Normal_Elem[1] = -(a[0]); + + } + + if (nDim == 3) { + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = Coord_0[iDim]-Coord_2[iDim]; + b[iDim] = Coord_1[iDim]-Coord_2[iDim]; + } + + //Area_Elem = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); + + Normal_Elem[0] = -(0.5*(a[1]*b[2]-a[2]*b[1])); + Normal_Elem[1] = -(-0.5*(a[0]*b[2]-a[2]*b[0])); + Normal_Elem[2] = -(0.5*(a[0]*b[1]-a[1]*b[0])); + + } + + + if (nDim == 2) { + Residual[0] = (1.0/2.0)*TotalLoad*Normal_Elem[0]; Residual[1] = (1.0/2.0)*TotalLoad*Normal_Elem[1]; + LinSysRes.AddBlock(Point_0, Residual); + Residual[0] = (1.0/2.0)*TotalLoad*Normal_Elem[0]; Residual[1] = (1.0/2.0)*TotalLoad*Normal_Elem[1]; + LinSysRes.AddBlock(Point_1, Residual); + } + + else { + Residual[0] = (1.0/3.0)*TotalLoad*Normal_Elem[0]; Residual[1] = (1.0/3.0)*TotalLoad*Normal_Elem[1]; Residual[2] = (1.0/3.0)*TotalLoad*Normal_Elem[2]; + LinSysRes.AddBlock(Point_0, Residual); + + Residual[0] = (1.0/3.0)*TotalLoad*Normal_Elem[0]; Residual[1] = (1.0/3.0)*TotalLoad*Normal_Elem[1]; Residual[2] = (1.0/3.0)*TotalLoad*Normal_Elem[2]; + LinSysRes.AddBlock(Point_1, Residual); + + Residual[0] = (1.0/3.0)*TotalLoad*Normal_Elem[0]; Residual[1] = (1.0/3.0)*TotalLoad*Normal_Elem[1]; Residual[2] = (1.0/3.0)*TotalLoad*Normal_Elem[2]; + LinSysRes.AddBlock(Point_2, Residual); + } + + } + +} + + +void CFEASolver::BC_Dir_Load(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, + unsigned short val_marker) { + + su2double a[3] = {0.0, 0.0, 0.0}, b[3] = {0.0, 0.0, 0.0}; + su2double AC[3] = {0.0, 0.0, 0.0}, BD[3] = {0.0, 0.0, 0.0}; + unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, Point_3=0; + su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, *Coord_3= NULL; + su2double Length_Elem = 0.0, Area_Elem = 0.0; +// su2double Normal_Elem[3] = {0.0, 0.0, 0.0}; + unsigned short iDim; + + su2double LoadDirVal = config->GetLoad_Dir_Value(config->GetMarker_All_TagBound(val_marker)); + su2double LoadDirMult = config->GetLoad_Dir_Multiplier(config->GetMarker_All_TagBound(val_marker)); + su2double *Load_Dir_Local= config->GetLoad_Dir(config->GetMarker_All_TagBound(val_marker)); + + su2double TotalLoad; + + bool Gradual_Load = config->GetGradual_Load(); + su2double CurrentTime=config->GetCurrent_DynTime(); + su2double ModAmpl, NonModAmpl; + + bool Ramp_Load = config->GetRamp_Load(); + su2double Ramp_Time = config->GetRamp_Time(); + + if (Ramp_Load){ + ModAmpl=LoadDirVal*LoadDirMult*CurrentTime/Ramp_Time; + NonModAmpl=LoadDirVal*LoadDirMult; + TotalLoad=min(ModAmpl,NonModAmpl); + } + else if (Gradual_Load){ + ModAmpl=2*((1/(1+exp(-1*CurrentTime)))-0.5); + TotalLoad=ModAmpl*LoadDirVal*LoadDirMult; + } + else{ + TotalLoad=LoadDirVal*LoadDirMult; + } + + /*--- Compute the norm of the vector that was passed in the config file ---*/ + su2double Norm = 0.0; + if (nDim==2) Norm=sqrt(Load_Dir_Local[0]*Load_Dir_Local[0]+Load_Dir_Local[1]*Load_Dir_Local[1]); + if (nDim==3) Norm=sqrt(Load_Dir_Local[0]*Load_Dir_Local[0]+Load_Dir_Local[1]*Load_Dir_Local[1]+Load_Dir_Local[2]*Load_Dir_Local[2]); + + for (iElem = 0; iElem < geometry->GetnElem_Bound(val_marker); iElem++) { + + Point_0 = geometry->bound[val_marker][iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); + Point_1 = geometry->bound[val_marker][iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); + + /*--- Compute area (3D), and length of the surfaces (2D) ---*/ + + if (nDim == 2) { + + for (iDim = 0; iDim < nDim; iDim++) a[iDim] = Coord_0[iDim]-Coord_1[iDim]; + + Length_Elem = sqrt(a[0]*a[0]+a[1]*a[1]); +// Normal_Elem[0] = a[1]; +// Normal_Elem[1] = -(a[0]); + + } else { + + Point_2 = geometry->bound[val_marker][iElem]->GetNode(2); + Coord_2 = geometry->node[Point_2]->GetCoord(); + + if (geometry->bound[val_marker][iElem]->GetVTK_Type() == TRIANGLE){ + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = Coord_1[iDim]-Coord_0[iDim]; + b[iDim] = Coord_2[iDim]-Coord_0[iDim]; + } + + su2double Ni=0 , Nj=0, Nk=0; + + Ni=a[1]*b[2]-a[2]*b[1]; + Nj=-a[0]*b[2]+a[2]*b[0]; + Nk=a[0]*b[1]-a[1]*b[0]; + + Area_Elem = 0.5*sqrt(Ni*Ni+Nj*Nj+Nk*Nk); + + //Area_Elem = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); + + } else if (geometry->bound[val_marker][iElem]->GetVTK_Type() == QUADRILATERAL){ + + Point_3 = geometry->bound[val_marker][iElem]->GetNode(3); + Coord_3 = geometry->node[Point_3]->GetCoord(); + + for (iDim = 0; iDim < nDim; iDim++) { + AC[iDim] = Coord_2[iDim]-Coord_0[iDim]; + BD[iDim] = Coord_3[iDim]-Coord_1[iDim]; + } + + su2double Ni=0 , Nj=0, Nk=0; + + Ni=AC[1]*BD[2]-AC[2]*BD[1]; + Nj=-AC[0]*BD[2]+AC[2]*BD[0]; + Nk=AC[0]*BD[1]-AC[1]*BD[0]; + + Area_Elem = 0.5*sqrt(Ni*Ni+Nj*Nj+Nk*Nk); + + } + } + + if (nDim == 2) { + + Residual[0] = (1.0/2.0)*Length_Elem*TotalLoad*Load_Dir_Local[0]/Norm; + Residual[1] = (1.0/2.0)*Length_Elem*TotalLoad*Load_Dir_Local[1]/Norm; + + LinSysRes.AddBlock(Point_0, Residual); + LinSysRes.AddBlock(Point_1, Residual); + + } + + else { + if (geometry->bound[val_marker][iElem]->GetVTK_Type() == TRIANGLE){ + + Residual[0] = (1.0/3.0)*Area_Elem*TotalLoad*Load_Dir_Local[0]/Norm; + Residual[1] = (1.0/3.0)*Area_Elem*TotalLoad*Load_Dir_Local[1]/Norm; + Residual[2] = (1.0/3.0)*Area_Elem*TotalLoad*Load_Dir_Local[2]/Norm; + + LinSysRes.AddBlock(Point_0, Residual); + LinSysRes.AddBlock(Point_1, Residual); + LinSysRes.AddBlock(Point_2, Residual); + } + else if (geometry->bound[val_marker][iElem]->GetVTK_Type() == QUADRILATERAL){ + + Residual[0] = (1.0/4.0)*Area_Elem*TotalLoad*Load_Dir_Local[0]/Norm; + Residual[1] = (1.0/4.0)*Area_Elem*TotalLoad*Load_Dir_Local[1]/Norm; + Residual[2] = (1.0/4.0)*Area_Elem*TotalLoad*Load_Dir_Local[2]/Norm; + + LinSysRes.AddBlock(Point_0, Residual); + LinSysRes.AddBlock(Point_1, Residual); + LinSysRes.AddBlock(Point_2, Residual); + LinSysRes.AddBlock(Point_3, Residual); + + } + + } + + } + +} + +void CFEASolver::BC_Sine_Load(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, + unsigned short val_marker) { + + su2double a[3] = {0.0, 0.0, 0.0}, b[3] = {0.0, 0.0, 0.0}; + su2double AC[3] = {0.0, 0.0, 0.0}, BD[3] = {0.0, 0.0, 0.0}; + unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, Point_3=0; + su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, *Coord_3= NULL; + su2double Length_Elem = 0.0, Area_Elem = 0.0; +// su2double Normal_Elem[3] = {0.0, 0.0, 0.0}; + unsigned short iDim; + + su2double LoadAmplitude = config->GetLoad_Sine_Amplitude(config->GetMarker_All_TagBound(val_marker)); + su2double LoadFrequency = config->GetLoad_Sine_Frequency(config->GetMarker_All_TagBound(val_marker)); + su2double *Load_Dir_Local= config->GetLoad_Sine_Dir(config->GetMarker_All_TagBound(val_marker)); + + su2double CurrentTime=config->GetCurrent_DynTime(); + + su2double TotalLoad = LoadAmplitude*sin(2*PI_NUMBER*LoadFrequency*CurrentTime); + + /*--- Compute the norm of the vector that was passed in the config file ---*/ + su2double Norm = 0.0; + if (nDim==2) Norm=sqrt(Load_Dir_Local[0]*Load_Dir_Local[0]+Load_Dir_Local[1]*Load_Dir_Local[1]); + if (nDim==3) Norm=sqrt(Load_Dir_Local[0]*Load_Dir_Local[0]+Load_Dir_Local[1]*Load_Dir_Local[1]+Load_Dir_Local[2]*Load_Dir_Local[2]); + + for (iElem = 0; iElem < geometry->GetnElem_Bound(val_marker); iElem++) { + + Point_0 = geometry->bound[val_marker][iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); + Point_1 = geometry->bound[val_marker][iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); + + /*--- Compute area (3D), and length of the surfaces (2D) ---*/ + + if (nDim == 2) { + + for (iDim = 0; iDim < nDim; iDim++) a[iDim] = Coord_0[iDim]-Coord_1[iDim]; + + Length_Elem = sqrt(a[0]*a[0]+a[1]*a[1]); +// Normal_Elem[0] = a[1]; +// Normal_Elem[1] = -(a[0]); + + } else { // 3D + + Point_2 = geometry->bound[val_marker][iElem]->GetNode(2); + Coord_2 = geometry->node[Point_2]->GetCoord(); + + if (geometry->bound[val_marker][iElem]->GetVTK_Type() == TRIANGLE){ + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = Coord_1[iDim]-Coord_0[iDim]; + b[iDim] = Coord_2[iDim]-Coord_0[iDim]; + } + + su2double Ni=0 , Nj=0, Nk=0; + + Ni=a[1]*b[2]-a[2]*b[1]; + Nj=-a[0]*b[2]+a[2]*b[0]; + Nk=a[0]*b[1]-a[1]*b[0]; + + Area_Elem = 0.5*sqrt(Ni*Ni+Nj*Nj+Nk*Nk); + + + //Area_Elem = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); + + } else if (geometry->bound[val_marker][iElem]->GetVTK_Type() == QUADRILATERAL){ + + Point_3 = geometry->bound[val_marker][iElem]->GetNode(3); + Coord_3 = geometry->node[Point_3]->GetCoord(); + + for (iDim = 0; iDim < nDim; iDim++) { + AC[iDim] = Coord_2[iDim]-Coord_0[iDim]; + BD[iDim] = Coord_3[iDim]-Coord_1[iDim]; + } + + su2double Ni=0 , Nj=0, Nk=0; + + Ni=AC[1]*BD[2]-AC[2]*BD[1]; + Nj=-AC[0]*BD[2]+AC[2]*BD[0]; + Nk=AC[0]*BD[1]-AC[1]*BD[0]; + + Area_Elem = 0.5*sqrt(Ni*Ni+Nj*Nj+Nk*Nk); + + } + } + + if (nDim == 2) { + + Residual[0] = (1.0/2.0)*Length_Elem*TotalLoad*Load_Dir_Local[0]/Norm; + Residual[1] = (1.0/2.0)*Length_Elem*TotalLoad*Load_Dir_Local[1]/Norm; + + LinSysRes.AddBlock(Point_0, Residual); + LinSysRes.AddBlock(Point_1, Residual); + + } + + else { + if (geometry->bound[val_marker][iElem]->GetVTK_Type() == TRIANGLE){ + + Residual[0] = (1.0/3.0)*Area_Elem*TotalLoad*Load_Dir_Local[0]/Norm; + Residual[1] = (1.0/3.0)*Area_Elem*TotalLoad*Load_Dir_Local[1]/Norm; + Residual[2] = (1.0/3.0)*Area_Elem*TotalLoad*Load_Dir_Local[2]/Norm; + + LinSysRes.AddBlock(Point_0, Residual); + LinSysRes.AddBlock(Point_1, Residual); + LinSysRes.AddBlock(Point_2, Residual); + + + } + else if (geometry->bound[val_marker][iElem]->GetVTK_Type() == QUADRILATERAL){ + + Residual[0] = (1.0/4.0)*Area_Elem*TotalLoad*Load_Dir_Local[0]/Norm; + Residual[1] = (1.0/4.0)*Area_Elem*TotalLoad*Load_Dir_Local[1]/Norm; + Residual[2] = (1.0/4.0)*Area_Elem*TotalLoad*Load_Dir_Local[2]/Norm; + + LinSysRes.AddBlock(Point_0, Residual); + LinSysRes.AddBlock(Point_1, Residual); + LinSysRes.AddBlock(Point_2, Residual); + LinSysRes.AddBlock(Point_3, Residual); + + } + + } + + } + +} + +void CFEASolver::BC_Pressure(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, + unsigned short val_marker) { } + +void CFEASolver::BC_Flow_Load(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, + unsigned short val_marker) { } + + +void CFEASolver::Postprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, CNumerics **numerics_container, unsigned short iMesh) { + unsigned long iPoint, iElem; + su2double **Stress, VonMises_Stress=0.0, MaxVonMises_Stress = 0.0; + su2double Sxx=0.0,Syy=0.0,Szz=0.0,Sxy=0.0,Sxz=0.0,Syz=0.0,S1,S2; + + unsigned long PointCorners[8]; + unsigned short nNodes=0, iNodes, iDim, jDim, form2d; + su2double CoordCorners[8][3]; +// su2double CoordGauss[8][3]; + + /*--- Container of the shape functions ---*/ + CNumerics *numerics; + numerics=numerics_container[VISC_TERM]; + + /*--- Enforcement of displacement boundary conditions ---*/ + unsigned short MainSolver = config->GetContainerPosition(RUNTIME_FEA_SYS); + unsigned int iMarker; + + form2d=config->GetElas2D_Formulation(); + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + switch (config->GetMarker_All_KindBC(iMarker)) { + case CLAMPED_BOUNDARY: + solver_container[MainSolver]->BC_Clamped(geometry, solver_container, numerics_container[CONV_BOUND_TERM], config, iMarker); + break; + } + } + + /*--- Initialize the stress and the number of elements connected to each node ---*/ + for (iPoint = 0; iPoint < nPoint; iPoint++) { + node[iPoint]->Initialize_Connectivity(); + for (iDim = 0; iDim < nDim; iDim++){ + for (jDim = 0; jDim < nDim; jDim++){ + node[iPoint]->SetStress(iDim, jDim, 0); + } + } + } + + /*--- Loops over all the elements ---*/ + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE){ nNodes = 3;} + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL){ nNodes = 4;} + if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON){ nNodes = 4;} + if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID){ nNodes = 5;} + if (geometry->elem[iElem]->GetVTK_Type() == PRISM){ nNodes = 6;} + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON){ nNodes = 8;} + + /*--- For the number of nodes, we get the coordinates from the connectivity matrix ---*/ + + for (iNodes = 0; iNodes < nNodes; iNodes++) { + + /*--- Get the index of the nodes and saves it in PointCorners ---*/ + PointCorners[iNodes] = geometry->elem[iElem]->GetNode(iNodes); + + for (iDim = 0; iDim < nDim; iDim++) { + + /*--- Get the coordinates of the nodes and saves it in CoordCorners ---*/ + CoordCorners[iNodes][iDim] = geometry->node[PointCorners[iNodes]]->GetCoord(iDim); + + /*--- Initialization of the gauss coordinate matrix ---*/ +// CoordGauss[iNodes][iDim] = 0.0; + } + } + + /*----------------------------------------------------------------------------------*/ + /*--- We obtain the stresses in the element, from the finite element formulation ---*/ + /*----------------------------------------------------------------------------------*/ + + /*--- For a 2D element ---*/ + + if (nDim == 2) { + + su2double StressNodal[8][3], DispElement[8]; + + /*--- Set the element displacements vector, from the global solution ---*/ + + for (iNodes = 0; iNodes < nNodes; iNodes++) { + for (iDim = 0; iDim < nDim; iDim++) { + DispElement[nDim*iNodes+iDim]=node[PointCorners[iNodes]]->GetSolution(iDim); + } + } + + /*--- Obtain the stresses in the nodes ---*/ + numerics->GetFEA_StressNodal2D(StressNodal, DispElement, CoordCorners, nNodes, form2d); + + /*--- Add the value of the element stress extrapolated to the node to the value stored on the nodes ---*/ + /*--- At the same point, add a counter to take into account on how many elements connect to the node ---*/ + + for (iPoint = 0; iPoint < nNodes; iPoint++) { + + node[PointCorners[iPoint]]->AddStress(0, 0, StressNodal[iPoint][0]); + node[PointCorners[iPoint]]->AddStress(1, 1, StressNodal[iPoint][1]); + node[PointCorners[iPoint]]->AddStress(0, 1, StressNodal[iPoint][2]); + node[PointCorners[iPoint]]->AddStress(1, 0, StressNodal[iPoint][2]); + + node[PointCorners[iPoint]]->Upgrade_Connectivity(); + + } + + } + + /*--- For a 3D element ---*/ + + if (nDim == 3) { + + su2double StressNodal[8][6], DispElement[24]; + + /*--- Set the element displacements vector, from the global solution ---*/ + + for (iNodes = 0; iNodes < nNodes; iNodes++) { + for (iDim = 0; iDim < nDim; iDim++) { + DispElement[nDim*iNodes+iDim]=node[PointCorners[iNodes]]->GetSolution(iDim); + } + } + + /*--- Obtain the stresses in the gaussian points ---*/ + numerics->GetFEA_StressNodal3D(StressNodal, DispElement, CoordCorners, nNodes); + + /*--- Add the value of the element stress extrapolated to the node to the value stored on the nodes ---*/ + /*--- At the same point, add a counter to take into account on how many elements connect to the node ---*/ + + for (iPoint = 0; iPoint < nNodes; iPoint++) { + + node[PointCorners[iPoint]]->AddStress(0, 0, StressNodal[iPoint][0]); + node[PointCorners[iPoint]]->AddStress(1, 1, StressNodal[iPoint][1]); + node[PointCorners[iPoint]]->AddStress(2, 2, StressNodal[iPoint][2]); + + node[PointCorners[iPoint]]->AddStress(0, 1, StressNodal[iPoint][3]); + node[PointCorners[iPoint]]->AddStress(1, 0, StressNodal[iPoint][3]); + + node[PointCorners[iPoint]]->AddStress(0, 2, StressNodal[iPoint][4]); + node[PointCorners[iPoint]]->AddStress(2, 0, StressNodal[iPoint][4]); + + node[PointCorners[iPoint]]->AddStress(1, 2, StressNodal[iPoint][5]); + node[PointCorners[iPoint]]->AddStress(2, 1, StressNodal[iPoint][5]); + + node[PointCorners[iPoint]]->Upgrade_Connectivity(); + + } + + } + + } + + + /*--- Variable to store the number of elements connected to each node ---*/ + + su2double nElPerNode=0; + + /*--- For the number of nodes in the mesh ---*/ + for (iPoint = 0; iPoint < nPoint; iPoint++) { + + /*--- Get the stresses, added up from all the elements that connect to the node ---*/ + + Stress = node[iPoint]->GetStress(); + nElPerNode = node[iPoint]->Get_Connectivity(); + + /*--- Compute the stress averaged from all the elements connecting to the node and the Von Mises stress ---*/ + + if (geometry->GetnDim() == 2) { + + Sxx=Stress[0][0]/nElPerNode; + Syy=Stress[1][1]/nElPerNode; + Sxy=Stress[0][1]/nElPerNode; + + S1=(Sxx+Syy)/2+sqrt(((Sxx-Syy)/2)*((Sxx-Syy)/2)+Sxy*Sxy); + S2=(Sxx+Syy)/2-sqrt(((Sxx-Syy)/2)*((Sxx-Syy)/2)+Sxy*Sxy); + + VonMises_Stress = sqrt(S1*S1+S2*S2-2*S1*S2); + + } + else if (geometry->GetnDim() == 3) { + + Sxx = Stress[0][0]/nElPerNode; + Syy = Stress[1][1]/nElPerNode; + Szz = Stress[2][2]/nElPerNode; + + Sxy = Stress[0][1]/nElPerNode; + Sxz = Stress[0][2]/nElPerNode; + Syz = Stress[1][2]/nElPerNode; + + VonMises_Stress = sqrt(0.5*( pow(Sxx - Syy, 2.0) + + pow(Syy - Szz, 2.0) + + pow(Szz - Sxx, 2.0) + + 6.0*(Sxy*Sxy+Sxz*Sxz+Syz*Syz) + )); + + } + + node[iPoint]->SetVonMises_Stress(VonMises_Stress); + + /*--- Compute the maximum value of the Von Mises Stress ---*/ + + MaxVonMises_Stress = max(MaxVonMises_Stress, VonMises_Stress); + + /*--- Set the new value of the stress, averaged from the number of elements ---*/ + + node[iPoint]->SetStress(0, 0, Sxx); + node[iPoint]->SetStress(1, 1, Syy); + node[iPoint]->SetStress(0, 1, Sxy); + node[iPoint]->SetStress(1, 0, Sxy); + + if (geometry->GetnDim() == 3) { + node[iPoint]->SetStress(2, 2, Szz); + node[iPoint]->SetStress(0, 2, Sxz); + node[iPoint]->SetStress(2, 0, Sxz); + node[iPoint]->SetStress(1, 2, Syz); + node[iPoint]->SetStress(2, 1, Syz); + } + + } + +#ifdef HAVE_MPI + + /*--- Compute MaxVonMises_Stress using all the nodes ---*/ + + su2double MyMaxVonMises_Stress = MaxVonMises_Stress; MaxVonMises_Stress = 0.0; + SU2_MPI::Allreduce(&MyMaxVonMises_Stress, &MaxVonMises_Stress, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); + +#endif + + /*--- Set the value of the MaxVonMises_Stress as the CFEA coeffient ---*/ + + Total_CFEA = MaxVonMises_Stress; + +} + +void CFEASolver::SetResidual_DualTime(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iRKStep, + unsigned short iMesh, unsigned short RunTime_EqSystem) { } + +void CFEASolver::ImplicitNewmark_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { + + + unsigned short iVar; + unsigned long iPoint, total_index, IterLinSol; + + bool dynamic = (config->GetDynamic_Analysis() == DYNAMIC); + + unsigned long ExtIter = config->GetExtIter(); + + su2double *PointTimeRes = NULL; + + unsigned short check=0; + + if ((dynamic) && (ExtIter == 0) && (check==0)){ + + /*--- Build implicit system ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + LinSysSol[total_index] = 0.0; + } + + } + + /*--- Initialize residual and solution at the ghost points ---*/ + + for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { + + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar + iVar; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + } + + } + + + /*--- Solve the linear dynamic system ---*/ + + CSysSolve femSystem; + IterLinSol = femSystem.Solve(MassMatrix, LinSysRes, LinSysSol, geometry, config); + SetIterLinSolver(IterLinSol); + + /*--- Update solution and (if dynamic) advance velocity and acceleration vectors in time ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + for (iVar = 0; iVar < nVar; iVar++) { + + /*--- Acceleration for t=0 ---*/ + node[iPoint]->SetSolution(iVar, 0.0); + node[iPoint]->SetSolution_Vel(iVar, 0.0); + node[iPoint]->SetSolution_Accel(iVar, LinSysSol[iPoint*nVar+iVar]); + + } + + } + + } + else{ + + /*--- Build implicit system ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + LinSysSol[total_index] = 0.0; + } + + } + + /*--- Initialize residual and solution at the ghost points ---*/ + + for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { + + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar + iVar; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + } + + } + + /*--- If dynamic analysis ---*/ + + if (dynamic){ + + /*--- Get mass term ---*/ + + /*--- Loop over all points, and set aux vector TimeRes_Aux = a0*U+a2*U'+a3*U'' ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + for (iVar = 0; iVar < nVar; iVar++){ + + Residual[iVar] = a_dt[0]*node[iPoint]->GetSolution_time_n(iVar)+ //a0*U(t) + a_dt[2]*node[iPoint]->GetSolution_Vel_time_n(iVar)+ //a2*U'(t) + a_dt[3]*node[iPoint]->GetSolution_Accel_time_n(iVar); //a3*U''(t) + + } + + TimeRes_Aux.SetBlock(iPoint, Residual); + + } + + /*--- Once computed, compute M*TimeRes_Aux ---*/ + + MassMatrix.MatrixVectorProduct(TimeRes_Aux,TimeRes,geometry,config); + + /*--- Add the components of M*TimeRes_Aux to the residual R(t+dt) ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + PointTimeRes = TimeRes.GetBlock(iPoint); + + LinSysRes.AddBlock(iPoint, PointTimeRes); + + } + + // su2double *check; + // for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { + // check = LinSysRes.GetBlock(iPoint); // This avoids the problem in the corner, but... + // cout << check[0] << "\t" << check[1] << endl; + // } + + /*--- Solve the linear dynamic system ---*/ + + CSysSolve femSystem; + IterLinSol = femSystem.Solve(StiffMatrixTime, LinSysRes, LinSysSol, geometry, config); + SetIterLinSolver(IterLinSol); + } + else { + + /*--- Solve the linear static system ---*/ + + CSysSolve femSystem; + IterLinSol = femSystem.Solve(StiffMatrixSpace, LinSysRes, LinSysSol, geometry, config); + SetIterLinSolver(IterLinSol); + } + + + + /*--- Update solution and (if dynamic) advance velocity and acceleration vectors in time ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + for (iVar = 0; iVar < nVar; iVar++) { + + /*--- Displacements component of the solution ---*/ + + node[iPoint]->SetSolution(iVar, LinSysSol[iPoint*nVar+iVar]); + + } + + if (dynamic){ + + for (iVar = 0; iVar < nVar; iVar++) { + + /*--- Acceleration component of the solution ---*/ + /*--- U''(t+dt) = a0*(U(t+dt)-U(t))+a2*(U'(t))+a3*(U''(t)) ---*/ + + Solution[iVar]=a_dt[0]*(node[iPoint]->GetSolution(iVar) - + node[iPoint]->GetSolution_time_n(iVar)) - + a_dt[2]* node[iPoint]->GetSolution_Vel_time_n(iVar) - + a_dt[3]* node[iPoint]->GetSolution_Accel_time_n(iVar); + + } + + /*--- Set the acceleration in the node structure ---*/ + + node[iPoint]->SetSolution_Accel(Solution); + + for (iVar = 0; iVar < nVar; iVar++) { + + /*--- Velocity component of the solution ---*/ + /*--- U'(t+dt) = U'(t)+ a6*(U''(t)) + a7*(U''(t+dt)) ---*/ + + Solution[iVar]=node[iPoint]->GetSolution_Vel_time_n(iVar)+ + a_dt[6]* node[iPoint]->GetSolution_Accel_time_n(iVar) + + a_dt[7]* node[iPoint]->GetSolution_Accel(iVar); + + } + + /*--- Set the velocity in the node structure ---*/ + + node[iPoint]->SetSolution_Vel(Solution); + + } + + } + + /*--- MPI solution ---*/ + + Set_MPI_Solution(geometry, config); + + /*--- Compute the residual Ax-f ---*/ + + if (dynamic){ + + StiffMatrixTime.ComputeResidual(LinSysSol, LinSysRes, LinSysAux); + + } + else { + + StiffMatrixSpace.ComputeResidual(LinSysSol, LinSysRes, LinSysAux); + + } + + /*--- Compute the reactions ---*/ + + /*--- Set maximum residual to zero ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + SetRes_RMS(iVar, 0.0); + SetRes_Max(iVar, 0.0, 0); + } + + /*--- Compute the residual ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + AddRes_RMS(iVar, LinSysAux[total_index]*LinSysAux[total_index]); + AddRes_Max(iVar, fabs(LinSysAux[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); + } + } + + /*--- Compute the root mean square residual ---*/ + + SetResidual_RMS(geometry, config); + + } + +} + +void CFEASolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { + + unsigned short iVar; + unsigned long iPoint, total_index, IterLinSol; + + /*--- Build implicit system ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + LinSysSol[total_index] = 0.0; + } + + } + + /*--- Initialize residual and solution at the ghost points ---*/ + for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar + iVar; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + } + } + + /*--- Solve or smooth the linear system ---*/ + + CSysSolve system; + IterLinSol = system.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); + SetIterLinSolver(IterLinSol); + + /*--- MPI solution ---*/ + + Set_MPI_Solution(geometry, config); + + /*--- Compute the residual Ax-f ---*/ + + Jacobian.ComputeResidual(LinSysSol, LinSysRes, LinSysAux); + + /*--- Set maximum residual to zero ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + SetRes_RMS(iVar, 0.0); + SetRes_Max(iVar, 0.0, 0); + } + + /*--- Compute the residual ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + AddRes_RMS(iVar, LinSysAux[total_index]*LinSysAux[total_index]); + AddRes_Max(iVar, fabs(LinSysAux[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); + } + } + + /*--- Compute the root mean square residual ---*/ + + SetResidual_RMS(geometry, config); + +} + +void CFEASolver::SetInitialCondition(CGeometry **geometry, CSolver ***solver_container, CConfig *config, unsigned long ExtIter) { + unsigned long iPoint; + + bool restart = (config->GetRestart() || config->GetRestart_Flow()); + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + + /*--- Problem dimension and physical time step ---*/ + unsigned short nDim = geometry[MESH_0]->GetnDim(); + + for (iPoint = 0; iPoint < geometry[MESH_0]->GetnPoint(); iPoint++) { + + /*--- Set initial boundary condition at the first iteration ---*/ + if ((ExtIter == 0) && (!restart)) { + + if (config->GetUnsteady_Simulation() == STEADY) { + if (nDim == 2) { Solution[0] = 0.0; Solution[1] = 0.0; } + else { Solution[0] = 0.0; Solution[1] = 0.0; Solution[2] = 0.0; } + } + else { + if (nDim == 2) { Solution[0] = 0.0; Solution[1] = 0.0; Solution[2] = 0.0; Solution[3] = 0.0; } + else { Solution[0] = 0.0; Solution[1] = 0.0; Solution[2] = 0.0; Solution[3] = 0.0; Solution[4] = 0.0; Solution[5] = 0.0; } + } + + node[iPoint]->SetSolution(Solution); + + if (dual_time) { + node[iPoint]->Set_Solution_time_n(); + node[iPoint]->Set_Solution_time_n1(); + } + + } + } +} + +void CFEASolver::GetSurface_Pressure(CGeometry *geometry, CConfig *config) { + + unsigned short iMarker, icommas, iDim; + unsigned long iVertex, iPoint, iExtIter; + su2double Pressure = 0.0, Dist, Coord[3]; + string text_line; + string::size_type position; + ifstream Surface_file; + char buffer[50], cstr[200]; + + int rank = MASTER_NODE; + int size = SINGLE_NODE; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); +#endif + + /*--- Reset the value of the Flow_Pressure ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + node[iPoint]->SetFlow_Pressure(0.0); + + for (iExtIter = 0; iExtIter < config->GetnExtIter(); iExtIter++) { + + /*--- Prepare to read surface sensitivity files (CSV) ---*/ + + string surfadj_filename = config->GetSurfFlowCoeff_FileName(); + + /*--- Remove the domain number from the surface csv filename ---*/ + + if (size > SINGLE_NODE) { + if ((rank+1 >= 0) && (rank+1 < 10)) surfadj_filename.erase (surfadj_filename.end()-2, surfadj_filename.end()); + if ((rank+1 >= 10) && (rank+1 < 100)) surfadj_filename.erase (surfadj_filename.end()-3, surfadj_filename.end()); + if ((rank+1 >= 100) && (rank+1 < 1000)) surfadj_filename.erase (surfadj_filename.end()-4, surfadj_filename.end()); + if ((rank+1 >= 1000) && (rank+1 < 10000)) surfadj_filename.erase (surfadj_filename.end()-5, surfadj_filename.end()); + } + strcpy (cstr, surfadj_filename.c_str()); + + /*--- Write file name with extension if unsteady or steady ---*/ + + if ((config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) || + (config->GetUnsteady_Simulation() == TIME_SPECTRAL)) { + if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(iExtIter)); + if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(iExtIter)); + } + else SPRINTF (buffer, ".csv"); + + strcat (cstr, buffer); + + /*--- Open the surface file ---*/ + + Surface_file.open(cstr, ios::in); + + getline(Surface_file, text_line); + + /*--- Res the surface file ---*/ + + while (getline(Surface_file, text_line)) { + + /*--- Remove commas from the surface file ---*/ + + for (icommas = 0; icommas < 100; icommas++) { + position = text_line.find( ",", 0 ); + if (position!=string::npos) text_line.erase (position, 1); + } + + /*--- Read the file ---*/ + istringstream point_line(text_line); + if (nDim == 2) { point_line >> iPoint >> Coord[0] >> Coord[1] >> Pressure; } + if (nDim == 3) { point_line >> iPoint >> Coord[0] >> Coord[1] >> Coord[2] >> Pressure; } + + /*--- Compute the distance from the surface to the points in the .csv files ---*/ + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == PRESSURE_BOUNDARY) { + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + /*--- Compute the distance between the point and the grid points ---*/ + Dist = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Dist += (Coord[iDim]-geometry->node[iPoint]->GetCoord(iDim))*(Coord[iDim]-geometry->node[iPoint]->GetCoord(iDim)); + Dist = sqrt(Dist); + + /*--- Check the distance and set the pressure ---*/ + if (Dist < 1E-10) { node[iPoint]->SetFlow_Pressure(Pressure); } + + } + } + } + + } + + Surface_file.close(); + + } + +} + +void CFEASolver::SetFEA_Load(CSolver ***flow_solution, CGeometry **fea_geometry, CGeometry **flow_geometry, + CConfig *fea_config, CConfig *flow_config, CNumerics *fea_numerics) { + + // Unused variables + //unsigned short nVertexFEA; + //su2double *nodePress, *nodeShearStress, *tn_e; + //su2double Viscosity_Ref, Velocity_Ref, Density_Ref, Pressure_Ref; + //unsigned short markFEA, nMarkerFEA, iMarkerFEA; + + unsigned short nVertexFlow, iVertex, nMarkerFSIint, iDim, jDim; + unsigned short markFlow, iPoint, iMarkerFSIint; + unsigned short nMarkerFlow, iMarkerFlow; + unsigned long *nodeVertex, *donorVertex; + su2double **normalsVertex, **normalsVertex_Unit, **tn_f; + su2double factorForces; + + su2double *Velocity_ND, Density_ND, *Velocity_Real, Density_Real, Velocity2_Real, Velocity2_ND; + + bool compressible = (flow_config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (flow_config->GetKind_Regime() == INCOMPRESSIBLE); + + bool viscous_flow = ((flow_config->GetKind_Solver() == NAVIER_STOKES) || + (flow_config->GetKind_Solver() == RANS) ); + + su2double Pinf = 0.0; + + su2double ModAmpl; + su2double CurrentTime=fea_config->GetCurrent_DynTime(); + su2double Static_Time=fea_config->GetStatic_Time(); + + bool Ramp_Load = fea_config->GetRamp_Load(); + su2double Ramp_Time = fea_config->GetRamp_Time(); + + if (CurrentTime <= Static_Time){ + ModAmpl=0.0; + } + else if((CurrentTime > Static_Time) && + (CurrentTime <= (Static_Time + Ramp_Time)) && + (Ramp_Load)){ + ModAmpl=(CurrentTime-Static_Time)/Ramp_Time; + ModAmpl=max(ModAmpl,0.0); + ModAmpl=min(ModAmpl,1.0); + } + else{ + ModAmpl=1.0; + } + + /*--- Number of markers in the FSI interface ---*/ + nMarkerFSIint = (fea_config->GetMarker_n_FSIinterface())/2; + + /*--- Initialization of vectors of residuals ---*/ + /*--- WATCH OUT! This Shouldn't be here I think... For the dead load */ + + for (iPoint = 0; iPoint < fea_geometry[MESH_0]->GetnPoint(); iPoint ++) { + LinSysRes.SetBlock_Zero(iPoint); + } + + /*--- Redimensionalize the pressure ---*/ + + Velocity_Real = flow_config->GetVelocity_FreeStream(); + Density_Real = flow_config->GetDensity_FreeStream(); + + Velocity_ND = flow_config->GetVelocity_FreeStreamND(); + Density_ND = flow_config->GetDensity_FreeStreamND(); + + + Velocity2_Real = 0.0; + Velocity2_ND = 0.0; + for (iDim = 0; iDim < nDim; iDim++){ + Velocity2_Real += Velocity_Real[iDim]*Velocity_Real[iDim]; + Velocity2_ND += Velocity_ND[iDim]*Velocity_ND[iDim]; + } + + /*--- Unused Vars ---*/ + //Velocity_Ref = flow_config->GetVelocity_Ref(); + //Viscosity_Ref = flow_config->GetViscosity_Ref(); + //Density_Ref = flow_solution[MESH_0][FLOW_SOL]->GetDensity_Inf(); + //Pressure_Ref = flow_config->GetPressure_Ref(); + + factorForces = Density_Real*Velocity2_Real/(Density_ND*Velocity2_ND); + + /*--- Loop over all the markers on the interface ---*/ + + for (iMarkerFSIint=0; iMarkerFSIint < nMarkerFSIint; iMarkerFSIint++){ + + //nMarkerFEA=fea_geometry[MESH_0]->GetnMarker(); + nMarkerFlow=flow_geometry[MESH_0]->GetnMarker(); + + /*--- Identification of the markers ---*/ + + // markFEA = 0; + // for (iMarkerFEA=0; iMarkerFEA < nMarkerFEA; iMarkerFEA++){ + // if ( fea_config->GetMarker_All_FSIinterface(iMarkerFEA) == (iMarkerFSIint+1)){ + // markFEA=iMarkerFEA; + // } + // } + + markFlow = 0; + for (iMarkerFlow=0; iMarkerFlow < nMarkerFlow; iMarkerFlow++){ + if (flow_config->GetMarker_All_FSIinterface(iMarkerFlow) == (iMarkerFSIint+1)){ + markFlow=iMarkerFlow; + } + } + + + //nVertexFEA = fea_geometry[MESH_0]->GetnVertex(markFEA); + nVertexFlow = flow_geometry[MESH_0]->GetnVertex(markFlow); + + //nodePress = new su2double [nVertexFlow]; + //nodeShearStress = new su2double [nVertexFlow]; + nodeVertex = new unsigned long [nVertexFlow]; + donorVertex = new unsigned long [nVertexFlow]; + + //tn_e = new su2double [nVar*nDim]; + + tn_f = new su2double* [nVertexFlow]; + for (iVertex = 0; iVertex < nVertexFlow; iVertex++) { + tn_f[iVertex] = new su2double[nDim]; + } + + normalsVertex = new su2double* [nVertexFlow]; + for (iVertex = 0; iVertex < nVertexFlow; iVertex++) { + normalsVertex[iVertex] = new su2double[nDim]; + } + + normalsVertex_Unit = new su2double* [nVertexFlow]; + for (iVertex = 0; iVertex < nVertexFlow; iVertex++) { + normalsVertex_Unit[iVertex] = new su2double[nDim]; + } + + su2double **Grad_PrimVar = NULL; + su2double Viscosity = 0.0; + //su2double Density = 0.0; + su2double Tau[3][3]; + + su2double div_vel, Delta; + su2double Area; + + /*--- Loop over the nodes in the fluid mesh, calculate the tf vector (unitary) ---*/ + + su2double Pn = 0.0; + + /*--- Here, we are looping over the fluid, and we find the pointer to the structure (donorVertex) ---*/ + for (iVertex=0; iVertex < nVertexFlow; iVertex++){ + + // Node from the flow mesh + nodeVertex[iVertex]=flow_geometry[MESH_0]->vertex[markFlow][iVertex]->GetNode(); + + // Normals at the vertex: these normals go inside the fluid domain. + normalsVertex[iVertex]=flow_geometry[MESH_0]->vertex[markFlow][iVertex]->GetNormal(); + + // Unit normals + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) { + Area += normalsVertex[iVertex][iDim]*normalsVertex[iVertex][iDim]; + } + Area = sqrt(Area); + + for (iDim = 0; iDim < nDim; iDim++) { + normalsVertex_Unit[iVertex][iDim] = normalsVertex[iVertex][iDim]/Area; + } + + // Corresponding node on the structural mesh + donorVertex[iVertex]=flow_geometry[MESH_0]->vertex[markFlow][iVertex]->GetDonorPoint(); + + // Retrieve the values of pressure, viscosity and density + if (incompressible){ + + Pn=flow_solution[MESH_0][FLOW_SOL]->node[nodeVertex[iVertex]]->GetPressureInc(); + Pinf=flow_solution[MESH_0][FLOW_SOL]->GetPressure_Inf(); + + if (viscous_flow){ + + Grad_PrimVar = flow_solution[MESH_0][FLOW_SOL]->node[nodeVertex[iVertex]]->GetGradient_Primitive(); + Viscosity = flow_solution[MESH_0][FLOW_SOL]->node[nodeVertex[iVertex]]->GetLaminarViscosityInc(); + //Density = flow_solution[MESH_0][FLOW_SOL]->node[nodeVertex[iVertex]]->GetDensityInc(); + + } + } + else if (compressible){ + + Pn=flow_solution[MESH_0][FLOW_SOL]->node[nodeVertex[iVertex]]->GetPressure(); + Pinf=flow_solution[MESH_0][FLOW_SOL]->GetPressure_Inf(); + + if (viscous_flow){ + + Grad_PrimVar = flow_solution[MESH_0][FLOW_SOL]->node[nodeVertex[iVertex]]->GetGradient_Primitive(); + Viscosity = flow_solution[MESH_0][FLOW_SOL]->node[nodeVertex[iVertex]]->GetLaminarViscosity(); + //Density = flow_solution[MESH_0][FLOW_SOL]->node[nodeVertex[iVertex]]->GetDensity(); + + } + } + + // Calculate tn in the fluid nodes for the inviscid term --> Units of force (non-dimensional). + for (iDim = 0; iDim < nDim; iDim++) { + tn_f[iVertex][iDim] = -(Pn-Pinf)*normalsVertex[iVertex][iDim]; + } + + // Calculate tn in the fluid nodes for the viscous term + + if (viscous_flow){ + + // Divergence of the velocity + div_vel = 0.0; for (iDim = 0; iDim < nDim; iDim++) div_vel += Grad_PrimVar[iDim+1][iDim]; + if (incompressible) div_vel = 0.0; + + for (iDim = 0; iDim < nDim; iDim++) { + + for (jDim = 0 ; jDim < nDim; jDim++) { + // Dirac delta + Delta = 0.0; if (iDim == jDim) Delta = 1.0; + + // Viscous stress + Tau[iDim][jDim] = Viscosity*(Grad_PrimVar[jDim+1][iDim] + Grad_PrimVar[iDim+1][jDim]) - + TWO3*Viscosity*div_vel*Delta; + + // Viscous component in the tn vector --> Units of force (non-dimensional). + tn_f[iVertex][iDim] += Tau[iDim][jDim]*normalsVertex[iVertex][jDim]; + } + } + } + + // Rescale tn to SI units + + for (iDim = 0; iDim < nDim; iDim++) { + tn_f[iVertex][iDim] = tn_f[iVertex][iDim]*factorForces; + } + + // Apply time-dependent coefficient (static structure, ramp load, full load) + + for (iDim = 0; iDim < nDim; iDim++) { + tn_f[iVertex][iDim] = tn_f[iVertex][iDim]*ModAmpl; + } + + // This works only for matching meshes + + for (iDim = 0; iDim < nDim; iDim++){ + Residual[iDim]=tn_f[iVertex][iDim]; + } + + + + LinSysRes.AddBlock(donorVertex[iVertex], Residual); + + } + + } + +} + + +void CFEASolver::SetStruct_Displacement(CGeometry **fea_geometry, CConfig *fea_config, CSolver ***fea_solution) { + + + unsigned long iPoint, iDim; + unsigned long nPoint, nDim; + su2double *Coord, *VarCoord, *Displacement; + + + nPoint = fea_geometry[MESH_0]->GetnPoint(); + nDim = fea_geometry[MESH_0]->GetnDim(); + + VarCoord = new su2double [nDim]; + + for (iPoint=0; iPoint < nPoint; iPoint++){ + + Coord = fea_geometry[MESH_0]->node[iPoint]->GetCoord(); + + Displacement = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution(); + + for (iDim = 0; iDim < nDim; iDim++) + VarCoord[iDim] = (Coord[iDim]+Displacement[iDim]); + + fea_geometry[MESH_0]->node[iPoint]->SetCoord(VarCoord); + + } + +} + + +void CFEASolver::PredictStruct_Displacement(CGeometry **fea_geometry, CConfig *fea_config, CSolver ***fea_solution) { + + unsigned short predOrder=fea_config->GetPredictorOrder(); + su2double Delta_t= fea_config->GetDelta_DynTime(); + unsigned long iPoint, iDim; + unsigned long nPoint, nDim; + su2double *solDisp, *solVel, *solVel_tn, *valPred, *checkPred; + + nPoint = fea_geometry[MESH_0]->GetnPoint(); + nDim = fea_geometry[MESH_0]->GetnDim(); + + solDisp=new su2double [nDim]; + solVel=new su2double [nDim]; + solVel_tn=new su2double [nDim]; + valPred=new su2double [nDim]; + checkPred=new su2double [nDim]; + + for (iPoint=0; iPointnode[iPoint]->SetSolution_Pred(); + else if (predOrder==1) { + + solDisp = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution(); + solVel = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_Vel(); + valPred = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_Pred(); + + for (iDim = 0; iDim < nDim; iDim++){ + valPred[iDim] = solDisp[iDim] + Delta_t*solVel[iDim]; + } + + // fea_solution[MESH_0][FEA_SOL]->node[iPoint]->SetSolution_Pred(valPred); + + + } + else if (predOrder==2) { + + solDisp = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution(); + solVel = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_Vel(); + solVel_tn = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_Vel_time_n(); + valPred = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_Pred(); + + for (iDim = 0; iDim < nDim; iDim++){ + valPred[iDim] = solDisp[iDim] + 0.5*Delta_t*(3*solVel[iDim]-solVel_tn[iDim]); + } + + // fea_solution[MESH_0][FEA_SOL]->node[iPoint]->SetSolution_Pred(valPred); + + } + else { + cout<< "Higher order predictor not implemented. Solving with order 0." << endl; + fea_solution[MESH_0][FEA_SOL]->node[iPoint]->SetSolution_Pred(); + } + } + + delete [] solDisp; + delete [] solVel; + delete [] solVel_tn; + delete [] valPred; + delete [] checkPred; + +} + +void CFEASolver::ComputeAitken_Coefficient(CGeometry **fea_geometry, CConfig *fea_config, CSolver ***fea_solution, unsigned long iFSIIter) { + + unsigned long iPoint, iDim; + unsigned long nPoint, nDim; + su2double *dispPred, *dispCalc, *dispPred_Old, *dispCalc_Old; + su2double deltaU[3] = {0.0, 0.0, 0.0}, deltaU_p1[3] = {0.0, 0.0, 0.0}; + su2double delta_deltaU[3] = {0.0, 0.0, 0.0}; + su2double numAitk, denAitk; + su2double CurrentTime=fea_config->GetCurrent_DynTime(); + su2double Static_Time=fea_config->GetStatic_Time(); + su2double WAitkDyn_tn1, WAitkDyn_Max, WAitkDyn; + + nPoint = fea_geometry[MESH_0]->GetnPoint(); + nDim = fea_geometry[MESH_0]->GetnDim(); + + //su2double WAitken=fea_config->GetAitkenStatRelax(); + + dispPred =new su2double [nDim]; + dispPred_Old=new su2double [nDim]; + dispCalc =new su2double [nDim]; + dispCalc_Old=new su2double [nDim]; + + numAitk = 0.0; + denAitk = 0.0; + + ofstream historyFile_FSI; + bool writeHistFSI = fea_config->GetWrite_Conv_FSI(); + if (writeHistFSI){ + char cstrFSI[200]; + string filenameHistFSI = fea_config->GetConv_FileName_FSI(); + strcpy (cstrFSI, filenameHistFSI.data()); + historyFile_FSI.open (cstrFSI, std::ios_base::app); + } + + + /*--- Only when there is movement, and a dynamic coefficient is requested, it makes sense to compute the Aitken's coefficient ---*/ + + if (CurrentTime > Static_Time) { + + if (iFSIIter == 0){ + + WAitkDyn_tn1 = GetWAitken_Dyn_tn1(); + WAitkDyn_Max = fea_config->GetAitkenDynMaxInit(); + + WAitkDyn = min(WAitkDyn_tn1, WAitkDyn_Max); + + /*--- Temporal fix, only for now ---*/ + WAitkDyn = max(WAitkDyn, 0.1); + + SetWAitken_Dyn(WAitkDyn); + if (writeHistFSI){ + historyFile_FSI << " " << endl ; + historyFile_FSI << setiosflags(ios::fixed) << setprecision(4) << CurrentTime << "," ; + historyFile_FSI << setiosflags(ios::fixed) << setprecision(1) << iFSIIter << "," ; + historyFile_FSI << setiosflags(ios::scientific) << setprecision(4) << WAitkDyn ; + } + + } + else{ + + for (iPoint=0; iPointnode[iPoint]->GetSolution_Pred(); + dispPred_Old = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_Pred_Old(); + dispCalc = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution(); + dispCalc_Old = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_Old(); + + for (iDim = 0; iDim < nDim; iDim++){ + + /*--- Compute the deltaU and deltaU_n+1 ---*/ + deltaU[iDim] = dispCalc_Old[iDim] - dispPred_Old[iDim]; + deltaU_p1[iDim] = dispCalc[iDim] - dispPred[iDim]; + + /*--- Compute the difference ---*/ + delta_deltaU[iDim] = deltaU_p1[iDim] - deltaU[iDim]; + + /*--- Add numerator and denominator ---*/ + numAitk += deltaU[iDim] * delta_deltaU[iDim]; + denAitk += delta_deltaU[iDim] * delta_deltaU[iDim]; + + } + + } + + WAitkDyn = GetWAitken_Dyn(); + + if (denAitk > 1E-8){ + WAitkDyn = - 1.0 * WAitkDyn * numAitk / denAitk ; + } + + WAitkDyn = max(WAitkDyn, 0.1); + WAitkDyn = min(WAitkDyn, 1.0); + + SetWAitken_Dyn(WAitkDyn); + + if (writeHistFSI){ + historyFile_FSI << setiosflags(ios::fixed) << setprecision(4) << CurrentTime << "," ; + historyFile_FSI << setiosflags(ios::fixed) << setprecision(1) << iFSIIter << "," ; + historyFile_FSI << setiosflags(ios::scientific) << setprecision(4) << WAitkDyn << "," ; + } + + } + + } + + if (writeHistFSI){historyFile_FSI.close();} + + delete [] dispPred; + delete [] dispPred_Old; + delete [] dispCalc; + delete [] dispCalc_Old; + +} + +void CFEASolver::SetAitken_Relaxation(CGeometry **fea_geometry, CConfig *fea_config, CSolver ***fea_solution) { + + unsigned long iPoint, iDim; + unsigned long nPoint, nDim; + unsigned short RelaxMethod_FSI; + su2double *dispPred, *dispCalc; + su2double WAitken; + su2double CurrentTime=fea_config->GetCurrent_DynTime(); + su2double Static_Time=fea_config->GetStatic_Time(); + + nPoint = fea_geometry[MESH_0]->GetnPoint(); + nDim = fea_geometry[MESH_0]->GetnDim(); + + dispPred=new su2double [nDim]; + dispCalc=new su2double [nDim]; + + RelaxMethod_FSI = fea_config->GetRelaxation_Method_FSI(); + + /*--- Only when there is movement it makes sense to update the solutions... ---*/ + + if (CurrentTime > Static_Time) { + + if (RelaxMethod_FSI == NO_RELAXATION){ + WAitken = 1.0; + } + else if (RelaxMethod_FSI == FIXED_PARAMETER){ + WAitken = fea_config->GetAitkenStatRelax(); + } + else if (RelaxMethod_FSI == AITKEN_DYNAMIC){ + WAitken = GetWAitken_Dyn(); + } + else { + WAitken = 1.0; + cout << "No relaxation parameter used. " << endl; + } + + + for (iPoint=0; iPointnode[iPoint]->GetSolution_Pred(); + dispCalc = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution(); + + /*--- Set predicted solution as the old predicted solution ---*/ + fea_solution[MESH_0][FEA_SOL]->node[iPoint]->SetSolution_Pred_Old(); + + /*--- Set calculated solution as the old solution (needed for dynamic Aitken relaxation) ---*/ + fea_solution[MESH_0][FEA_SOL]->node[iPoint]->SetSolution_Old(dispCalc); + + /*--- Apply the Aitken relaxation ---*/ + for (iDim = 0; iDim < nDim; iDim++){ + dispPred[iDim] = (1.0 - WAitken)*dispPred[iDim] + WAitken*dispCalc[iDim]; + } + + /*--- Set obtained solution as the new predicted solution ---*/ + /*--- As dispPred is the pointer to the solution_Pred, we don't need to do this... ---*/ + //fea_solution[MESH_0][FEA_SOL]->node[iPoint]->SetSolution_Pred(dispPred); + + } + + } + + delete [] dispCalc; + delete [] dispPred; + +} + +void CFEASolver::Update_StructSolution(CGeometry **fea_geometry, CConfig *fea_config, CSolver ***fea_solution) { + + su2double *valSolutionPred; + + for (unsigned long iPoint=0; iPointGetnPoint(); iPoint++){ + + valSolutionPred = fea_solution[MESH_0][FEA_SOL]->node[iPoint]->GetSolution_Pred(); + + fea_solution[MESH_0][FEA_SOL]->node[iPoint]->SetSolution(valSolutionPred); + + } + +} + + + + diff --git a/SU2_CFD/src/solver_direct_heat.cpp b/SU2_CFD/src/solver_direct_heat.cpp index dc31d81baa0..ddcd5f09f76 100644 --- a/SU2_CFD/src/solver_direct_heat.cpp +++ b/SU2_CFD/src/solver_direct_heat.cpp @@ -1,585 +1,585 @@ -/*! - * \file solution_direct_heat.cpp - * \brief Main subrotuines for solving the heat equation - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/solver_structure.hpp" - -CHeatSolver::CHeatSolver(void) : CSolver() { } - -CHeatSolver::CHeatSolver(CGeometry *geometry, CConfig *config) : CSolver() { - - unsigned short iDim, iVar, nLineLets; - unsigned long iPoint; - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - nPoint = geometry->GetnPoint(); - nPointDomain = geometry->GetnPointDomain(); - nDim = geometry->GetnDim(); - node = new CVariable*[nPoint]; - nVar = 1; - - Residual = new su2double[nVar]; Residual_RMS = new su2double[nVar]; - Solution = new su2double[nVar]; - Res_Sour = new su2double[nVar]; - Residual_Max = new su2double[nVar]; Point_Max = new unsigned long[nVar]; - Point_Max_Coord = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Point_Max_Coord[iVar] = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; - } - - /*--- Point to point stiffness matrix (only for triangles)---*/ - - StiffMatrix_Elem = new su2double*[nDim+1]; - for (iVar = 0; iVar < nDim+1; iVar++) { - StiffMatrix_Elem[iVar] = new su2double [nDim+1]; - } - - StiffMatrix_Node = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - StiffMatrix_Node[iVar] = new su2double [nVar]; - } - - /*--- Initialization of matrix structures ---*/ - - StiffMatrixSpace.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); - StiffMatrixTime.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); - if (rank == MASTER_NODE) cout << "Initialize Jacobian structure (Linear Elasticity)." << endl; - Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); - - if ((config->GetKind_Linear_Solver_Prec() == LINELET) || - (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { - nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); - if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; - } - - /*--- Initialization of linear solver structures ---*/ - - LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysAux.Initialize(nPoint, nPointDomain, nVar, 0.0); - - /*--- Heat coefficient for all of the markers ---*/ - - CHeat = new su2double[config->GetnMarker_All()]; - Total_CHeat = 0.0; - - /*--- Check for a restart (not really used), initialize from zero otherwise ---*/ - - bool restart = (config->GetRestart()); - if (!restart) { - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - - /*--- Zero initial condition for testing source terms & forcing BCs ---*/ - - Solution[0] = 0.0; - Solution[1] = 0.0; - - node[iPoint] = new CHeatVariable(Solution, nDim, nVar, config); - - /*--- Copy solution to old containers if using dual time ---*/ - - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) { - node[iPoint]->Set_Solution_time_n(); - } else if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) { - node[iPoint]->Set_Solution_time_n(); - node[iPoint]->Set_Solution_time_n1(); - } - - } - } else { - - cout << "Heat restart file not currently configured!!" << endl; - - string mesh_filename = config->GetSolution_FlowFileName(); - ifstream restart_file; - - char *cstr; cstr = new char [mesh_filename.size()+1]; - strcpy (cstr, mesh_filename.c_str()); - restart_file.open(cstr, ios::in); - - if (restart_file.fail()) { - cout << "There is no Heat restart file!!" << endl; - exit(EXIT_FAILURE); - } - unsigned long index; - string text_line; - - for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { - getline(restart_file, text_line); - istringstream point_line(text_line); - point_line >> index >> Solution[0] >> Solution[1]; - node[iPoint] = new CHeatVariable(Solution, nDim, nVar, config); - } - restart_file.close(); - - } - -} - -CHeatSolver::~CHeatSolver(void) { - - unsigned short iVar; - - delete [] Residual; - delete [] Residual_Max; - delete [] Solution; - - for (iVar = 0; iVar < nDim+1; iVar++) - delete [] StiffMatrix_Elem[iVar]; - - for (iVar = 0; iVar < nVar; iVar++) - delete [] StiffMatrix_Node[iVar]; - - delete [] StiffMatrix_Elem; - delete [] StiffMatrix_Node; - -} - -void CHeatSolver::Preprocessing(CGeometry *geometry, - CSolver **solver_container, - CConfig *config, - unsigned short iMesh, - unsigned short iRKStep, - unsigned short RunTime_EqSystem, bool Output) { - - unsigned long iPoint; - - /*--- Set residuals and matrix entries to zero ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { - LinSysSol.SetBlock_Zero(iPoint); - LinSysAux.SetBlock_Zero(iPoint); - LinSysRes.SetBlock_Zero(iPoint); - } - - /*--- Zero out the entries in the various matrices ---*/ - StiffMatrixSpace.SetValZero(); - StiffMatrixTime.SetValZero(); - Jacobian.SetValZero(); - -} - -void CHeatSolver::Source_Residual(CGeometry *geometry, - CSolver **solver_container, - CNumerics *numerics, CNumerics *second_numerics, - CConfig *config, - unsigned short iMesh) { - - if (config->GetUnsteady_Simulation() != STEADY) { - - unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, Point_3 = 0; - su2double a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}, c[3] = {0.0,0.0,0.0}, d[3] = {0.0,0.0,0.0}, Area_Local = 0.0, Volume_Local = 0.0, Time_Num; - su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, *Coord_3= NULL; - unsigned short iDim; - - /*--- Numerical time step (this system is uncoditional stable... a very big number can be used) ---*/ - if (config->GetUnsteady_Simulation() == TIME_STEPPING) Time_Num = config->GetDelta_UnstTimeND(); - else Time_Num = 1E30; - - /*--- Loop through elements to compute contributions from the matrix - blocks involving time. These contributions are also added to the - Jacobian w/ the time step. Spatial source terms are also computed. ---*/ - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - /*--- Get node numbers and their coordinate vectors ---*/ - - Point_0 = geometry->elem[iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); - Point_1 = geometry->elem[iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); - Point_2 = geometry->elem[iElem]->GetNode(2); Coord_2 = geometry->node[Point_2]->GetCoord(); - - /*--- Compute area and volume ---*/ - - if (nDim == 2) { - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = Coord_0[iDim]-Coord_2[iDim]; - b[iDim] = Coord_1[iDim]-Coord_2[iDim]; - } - Area_Local = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); - } - else { - Point_3 = geometry->elem[iElem]->GetNode(3); - Coord_3 = geometry->node[Point_3]->GetCoord(); - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = Coord_0[iDim]-Coord_2[iDim]; - b[iDim] = Coord_1[iDim]-Coord_2[iDim]; - c[iDim] = Coord_3[iDim]-Coord_2[iDim]; - } - d[0] = a[1]*b[2]-a[2]*b[1]; - d[1] = -(a[0]*b[2]-a[2]*b[0]); - d[2] = a[0]*b[1]-a[1]*b[0]; - Volume_Local = fabs(c[0]*d[0] + c[1]*d[1] + c[2]*d[2])/6.0; - } - - /*--- Block contributions to the Jacobian (includes time step) ---*/ - - if (nDim == 2) { StiffMatrix_Node[0][0] = (2.0/12.0)*(Area_Local/Time_Num); } - else { StiffMatrix_Node[0][0] = (2.0/20.0)*(Volume_Local/Time_Num); } - Jacobian.AddBlock(Point_0, Point_0, StiffMatrix_Node); - Jacobian.AddBlock(Point_1, Point_1, StiffMatrix_Node); - Jacobian.AddBlock(Point_2, Point_2, StiffMatrix_Node); - if (nDim == 3) Jacobian.AddBlock(Point_3, Point_3, StiffMatrix_Node); - - if (nDim == 2) { StiffMatrix_Node[0][0] = (1.0/12.0)*(Area_Local/Time_Num); } - else { StiffMatrix_Node[0][0] = (1.0/20.0)*(Volume_Local/Time_Num); } - - Jacobian.AddBlock(Point_0, Point_1, StiffMatrix_Node); - Jacobian.AddBlock(Point_0, Point_2, StiffMatrix_Node); - Jacobian.AddBlock(Point_1, Point_0, StiffMatrix_Node); - Jacobian.AddBlock(Point_1, Point_2, StiffMatrix_Node); - Jacobian.AddBlock(Point_2, Point_0, StiffMatrix_Node); - Jacobian.AddBlock(Point_2, Point_1, StiffMatrix_Node); - if (nDim == 3) { - Jacobian.AddBlock(Point_0, Point_3, StiffMatrix_Node); - Jacobian.AddBlock(Point_1, Point_3, StiffMatrix_Node); - Jacobian.AddBlock(Point_2, Point_3, StiffMatrix_Node); - Jacobian.AddBlock(Point_3, Point_0, StiffMatrix_Node); - Jacobian.AddBlock(Point_3, Point_1, StiffMatrix_Node); - Jacobian.AddBlock(Point_3, Point_2, StiffMatrix_Node); - } - - } - - } - -} - -void CHeatSolver::Viscous_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config, unsigned short iMesh, unsigned short iRKStep) { - - unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, Point_3 = 0, total_index, iPoint; - su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, *Coord_3 = NULL; - - if (nDim == 2 ) { - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - Point_0 = geometry->elem[iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); - Point_1 = geometry->elem[iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); - Point_2 = geometry->elem[iElem]->GetNode(2); Coord_2 = geometry->node[Point_2]->GetCoord(); - - numerics->SetCoord(Coord_0, Coord_1, Coord_2); - numerics->ComputeResidual(StiffMatrix_Elem, config); - - StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][0]; StiffMatrixSpace.AddBlock(Point_0, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_0, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][1]; StiffMatrixSpace.AddBlock(Point_0, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_1, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][2]; StiffMatrixSpace.AddBlock(Point_0, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_2, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][0]; StiffMatrixSpace.AddBlock(Point_1, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_0, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][1]; StiffMatrixSpace.AddBlock(Point_1, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_1, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][2]; StiffMatrixSpace.AddBlock(Point_1, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_2, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][0]; StiffMatrixSpace.AddBlock(Point_2, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_0, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][1]; StiffMatrixSpace.AddBlock(Point_2, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_1, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][2]; StiffMatrixSpace.AddBlock(Point_2, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_2, StiffMatrix_Node); - - } - } - - if (nDim == 3 ) { - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - Point_0 = geometry->elem[iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); - Point_1 = geometry->elem[iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); - Point_2 = geometry->elem[iElem]->GetNode(2); Coord_2 = geometry->node[Point_2]->GetCoord(); - Point_3 = geometry->elem[iElem]->GetNode(3); Coord_3 = geometry->node[Point_3]->GetCoord(); - - numerics->SetCoord(Coord_0, Coord_1, Coord_2, Coord_3); - numerics->ComputeResidual(StiffMatrix_Elem, config); - - StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][0]; StiffMatrixSpace.AddBlock(Point_0, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_0, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][1]; StiffMatrixSpace.AddBlock(Point_0, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_1, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][2]; StiffMatrixSpace.AddBlock(Point_0, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_2, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][3]; StiffMatrixSpace.AddBlock(Point_0, Point_3, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_3, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][0]; StiffMatrixSpace.AddBlock(Point_1, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_0, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][1]; StiffMatrixSpace.AddBlock(Point_1, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_1, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][2]; StiffMatrixSpace.AddBlock(Point_1, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_2, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][3]; StiffMatrixSpace.AddBlock(Point_1, Point_3, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_3, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][0]; StiffMatrixSpace.AddBlock(Point_2, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_0, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][1]; StiffMatrixSpace.AddBlock(Point_2, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_1, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][2]; StiffMatrixSpace.AddBlock(Point_2, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_2, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][3]; StiffMatrixSpace.AddBlock(Point_2, Point_3, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_3, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[3][0]; StiffMatrixSpace.AddBlock(Point_3, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_3, Point_0, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[3][1]; StiffMatrixSpace.AddBlock(Point_3, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_3, Point_1, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[3][2]; StiffMatrixSpace.AddBlock(Point_3, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_3, Point_2, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[3][3]; StiffMatrixSpace.AddBlock(Point_3, Point_3, StiffMatrix_Node); Jacobian.AddBlock(Point_3, Point_3, StiffMatrix_Node); - - } - } - - if (config->GetUnsteady_Simulation() != STEADY) { - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - total_index = iPoint*nVar; - LinSysSol[total_index] = node[iPoint]->GetSolution(0); - LinSysAux[total_index] = 0.0; - } - - StiffMatrixSpace.MatrixVectorProduct(LinSysSol, LinSysAux); - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - total_index = iPoint*nVar; - Residual[0] = LinSysAux[total_index]; - LinSysRes.SubtractBlock(iPoint, Residual); - } - } - -} - -void CHeatSolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { } - -void CHeatSolver::BC_Isothermal_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned long iPoint, iVertex, total_index; - su2double Twall; - - /*--- Identify the boundary ---*/ - - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - - /*--- Retrieve the specified wall temperature ---*/ - - Twall = config->GetIsothermal_Temperature(Marker_Tag); - - /*--- Set the solution at the boundary nodes and zero the residual ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - Solution[0] = Twall; - - node[iPoint]->SetSolution(Solution); - node[iPoint]->SetSolution_Old(Solution); - - /*--- Unsteady solution, the equation is solved in terms of increments ---*/ - if (config->GetUnsteady_Simulation() != STEADY) Residual[0] = 0.0; - - LinSysRes.SetBlock(iPoint, Residual); - LinSysSol.SetBlock(iPoint, Residual); - - total_index = iPoint*nVar; - Jacobian.DeleteValsRowi(total_index); - - } - -} - - -void CHeatSolver::SetResidual_DualTime(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iRKStep, - unsigned short iMesh, unsigned short RunTime_EqSystem) { - - unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, Point_3 = 0; - su2double a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}, c[3] = {0.0,0.0,0.0}, d[3] = {0.0,0.0,0.0}, Area_Local = 0.0, Volume_Local = 0.0, Time_Num; - su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, *Coord_3= NULL; - unsigned short iDim, iVar; - su2double TimeJac = 0.0; - - /*--- Numerical time step (this system is uncoditional stable... a very big number can be used) ---*/ - Time_Num = config->GetDelta_UnstTimeND(); - - /*--- Loop through elements to compute contributions from the matrix - blocks involving time. These contributions are also added to the - Jacobian w/ the time step. Spatial source terms are also computed. ---*/ - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - /*--- Get node numbers and their coordinate vectors ---*/ - - Point_0 = geometry->elem[iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); - Point_1 = geometry->elem[iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); - Point_2 = geometry->elem[iElem]->GetNode(2); Coord_2 = geometry->node[Point_2]->GetCoord(); - - /*--- Compute area and volume ---*/ - - if (nDim == 2) { - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = Coord_0[iDim]-Coord_2[iDim]; - b[iDim] = Coord_1[iDim]-Coord_2[iDim]; - } - Area_Local = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); - } - else { - Point_3 = geometry->elem[iElem]->GetNode(3); - Coord_3 = geometry->node[Point_3]->GetCoord(); - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = Coord_0[iDim]-Coord_2[iDim]; - b[iDim] = Coord_1[iDim]-Coord_2[iDim]; - c[iDim] = Coord_3[iDim]-Coord_2[iDim]; - } - d[0] = a[1]*b[2]-a[2]*b[1]; d[1] = -(a[0]*b[2]-a[2]*b[0]); d[2] = a[0]*b[1]-a[1]*b[0]; - Volume_Local = fabs(c[0]*d[0] + c[1]*d[1] + c[2]*d[2])/6.0; - } - - /*--- Block contributions to the Jacobian (includes time step) ---*/ - - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) TimeJac = 1.0/Time_Num; - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) TimeJac = 3.0/(2.0*Time_Num); - - if (nDim == 2) { StiffMatrix_Node[0][0] = (2.0/12.0)*(Area_Local*TimeJac); } - else { StiffMatrix_Node[0][0] = (2.0/20.0)*(Volume_Local*TimeJac); } - - Jacobian.AddBlock(Point_0, Point_0, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_0, Point_0, StiffMatrix_Node); - Jacobian.AddBlock(Point_1, Point_1, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_1, Point_1, StiffMatrix_Node); - Jacobian.AddBlock(Point_2, Point_2, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_2, Point_2, StiffMatrix_Node); - if (nDim == 3) { Jacobian.AddBlock(Point_3, Point_3, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_2, Point_2, StiffMatrix_Node); } - - if (nDim == 2) { StiffMatrix_Node[0][0] = (1.0/12.0)*(Area_Local*TimeJac); } - else { StiffMatrix_Node[0][0] = (1.0/20.0)*(Volume_Local*TimeJac); } - - Jacobian.AddBlock(Point_0, Point_1, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_0, Point_1, StiffMatrix_Node); - Jacobian.AddBlock(Point_0, Point_2, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_0, Point_2, StiffMatrix_Node); - Jacobian.AddBlock(Point_1, Point_0, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_1, Point_0, StiffMatrix_Node); - Jacobian.AddBlock(Point_1, Point_2, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_1, Point_2, StiffMatrix_Node); - Jacobian.AddBlock(Point_2, Point_0, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_2, Point_0, StiffMatrix_Node); - Jacobian.AddBlock(Point_2, Point_1, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_2, Point_1, StiffMatrix_Node); - if (nDim == 3) { - Jacobian.AddBlock(Point_0, Point_3, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_0, Point_3, StiffMatrix_Node); - Jacobian.AddBlock(Point_1, Point_3, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_1, Point_3, StiffMatrix_Node); - Jacobian.AddBlock(Point_2, Point_3, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_2, Point_3, StiffMatrix_Node); - Jacobian.AddBlock(Point_3, Point_0, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_3, Point_0, StiffMatrix_Node); - Jacobian.AddBlock(Point_3, Point_1, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_3, Point_1, StiffMatrix_Node); - Jacobian.AddBlock(Point_3, Point_2, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_3, Point_2, StiffMatrix_Node); - } - - } - - unsigned long iPoint, total_index; - su2double *U_time_nM1, *U_time_n, *U_time_nP1; - - /*--- loop over points ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Solution at time n-1, n and n+1 ---*/ - - U_time_nM1 = node[iPoint]->GetSolution_time_n1(); - U_time_n = node[iPoint]->GetSolution_time_n(); - U_time_nP1 = node[iPoint]->GetSolution(); - - /*--- Compute residual ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - LinSysSol[total_index] = ( U_time_nP1[iVar] - U_time_n[iVar] ); - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - LinSysSol[total_index] = ( U_time_nP1[iVar] - (4.0/3.0)*U_time_n[iVar] + (1.0/3.0)*U_time_nM1[iVar] ); - } - } - - /*--- Contribution to the residual ---*/ - - StiffMatrixTime.MatrixVectorProduct(LinSysSol, LinSysAux); - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - total_index = iPoint*nVar; - Residual[0] = LinSysAux[total_index]; - LinSysRes.SubtractBlock(iPoint, Residual); - } - -} - -void CHeatSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { - - unsigned short iVar; - unsigned long iPoint, total_index; - - /*--- Build implicit system ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - LinSysSol[total_index] = 0.0; - } - - } - - /*--- Initialize residual and solution at the ghost points ---*/ - - for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar + iVar; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - } - } - - /*--- Solve or smooth the linear system ---*/ - - CSysSolve system; - system.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); - - /*--- Update solution (system written in terms of increments) ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - if (config->GetUnsteady_Simulation() == STEADY) node[iPoint]->SetSolution(iVar, LinSysSol[iPoint*nVar+iVar]); - else node[iPoint]->AddSolution(iVar, LinSysSol[iPoint*nVar+iVar]); - } - } - - /*--- MPI solution ---*/ - - Set_MPI_Solution(geometry, config); - - /*--- Compute the residual Ax-f ---*/ - - Jacobian.ComputeResidual(LinSysSol, LinSysRes, LinSysAux); - - /*--- Set maximum residual to zero ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - SetRes_RMS(iVar, 0.0); - SetRes_Max(iVar, 0.0, 0); - } - - /*--- Compute the residual ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - AddRes_RMS(iVar, LinSysAux[total_index]*LinSysAux[total_index]); - AddRes_Max(iVar, fabs(LinSysAux[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); - } - } - - /*--- Compute the root mean square residual ---*/ - - SetResidual_RMS(geometry, config); - -} +/*! + * \file solution_direct_heat.cpp + * \brief Main subrotuines for solving the heat equation + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/solver_structure.hpp" + +CHeatSolver::CHeatSolver(void) : CSolver() { } + +CHeatSolver::CHeatSolver(CGeometry *geometry, CConfig *config) : CSolver() { + + unsigned short iDim, iVar, nLineLets; + unsigned long iPoint; + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + nPoint = geometry->GetnPoint(); + nPointDomain = geometry->GetnPointDomain(); + nDim = geometry->GetnDim(); + node = new CVariable*[nPoint]; + nVar = 1; + + Residual = new su2double[nVar]; Residual_RMS = new su2double[nVar]; + Solution = new su2double[nVar]; + Res_Sour = new su2double[nVar]; + Residual_Max = new su2double[nVar]; Point_Max = new unsigned long[nVar]; + Point_Max_Coord = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Point_Max_Coord[iVar] = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; + } + + /*--- Point to point stiffness matrix (only for triangles)---*/ + + StiffMatrix_Elem = new su2double*[nDim+1]; + for (iVar = 0; iVar < nDim+1; iVar++) { + StiffMatrix_Elem[iVar] = new su2double [nDim+1]; + } + + StiffMatrix_Node = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + StiffMatrix_Node[iVar] = new su2double [nVar]; + } + + /*--- Initialization of matrix structures ---*/ + + StiffMatrixSpace.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); + StiffMatrixTime.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); + if (rank == MASTER_NODE) cout << "Initialize Jacobian structure (Linear Elasticity)." << endl; + Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); + + if ((config->GetKind_Linear_Solver_Prec() == LINELET) || + (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { + nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); + if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; + } + + /*--- Initialization of linear solver structures ---*/ + + LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); + LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); + LinSysAux.Initialize(nPoint, nPointDomain, nVar, 0.0); + + /*--- Heat coefficient for all of the markers ---*/ + + CHeat = new su2double[config->GetnMarker_All()]; + Total_CHeat = 0.0; + + /*--- Check for a restart (not really used), initialize from zero otherwise ---*/ + + bool restart = (config->GetRestart()); + if (!restart) { + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + + /*--- Zero initial condition for testing source terms & forcing BCs ---*/ + + Solution[0] = 0.0; + Solution[1] = 0.0; + + node[iPoint] = new CHeatVariable(Solution, nDim, nVar, config); + + /*--- Copy solution to old containers if using dual time ---*/ + + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) { + node[iPoint]->Set_Solution_time_n(); + } else if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) { + node[iPoint]->Set_Solution_time_n(); + node[iPoint]->Set_Solution_time_n1(); + } + + } + } else { + + cout << "Heat restart file not currently configured!!" << endl; + + string mesh_filename = config->GetSolution_FlowFileName(); + ifstream restart_file; + + char *cstr; cstr = new char [mesh_filename.size()+1]; + strcpy (cstr, mesh_filename.c_str()); + restart_file.open(cstr, ios::in); + + if (restart_file.fail()) { + cout << "There is no Heat restart file!!" << endl; + exit(EXIT_FAILURE); + } + unsigned long index; + string text_line; + + for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { + getline(restart_file, text_line); + istringstream point_line(text_line); + point_line >> index >> Solution[0] >> Solution[1]; + node[iPoint] = new CHeatVariable(Solution, nDim, nVar, config); + } + restart_file.close(); + + } + +} + +CHeatSolver::~CHeatSolver(void) { + + unsigned short iVar; + + delete [] Residual; + delete [] Residual_Max; + delete [] Solution; + + for (iVar = 0; iVar < nDim+1; iVar++) + delete [] StiffMatrix_Elem[iVar]; + + for (iVar = 0; iVar < nVar; iVar++) + delete [] StiffMatrix_Node[iVar]; + + delete [] StiffMatrix_Elem; + delete [] StiffMatrix_Node; + +} + +void CHeatSolver::Preprocessing(CGeometry *geometry, + CSolver **solver_container, + CConfig *config, + unsigned short iMesh, + unsigned short iRKStep, + unsigned short RunTime_EqSystem, bool Output) { + + unsigned long iPoint; + + /*--- Set residuals and matrix entries to zero ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { + LinSysSol.SetBlock_Zero(iPoint); + LinSysAux.SetBlock_Zero(iPoint); + LinSysRes.SetBlock_Zero(iPoint); + } + + /*--- Zero out the entries in the various matrices ---*/ + StiffMatrixSpace.SetValZero(); + StiffMatrixTime.SetValZero(); + Jacobian.SetValZero(); + +} + +void CHeatSolver::Source_Residual(CGeometry *geometry, + CSolver **solver_container, + CNumerics *numerics, CNumerics *second_numerics, + CConfig *config, + unsigned short iMesh) { + + if (config->GetUnsteady_Simulation() != STEADY) { + + unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, Point_3 = 0; + su2double a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}, c[3] = {0.0,0.0,0.0}, d[3] = {0.0,0.0,0.0}, Area_Local = 0.0, Volume_Local = 0.0, Time_Num; + su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, *Coord_3= NULL; + unsigned short iDim; + + /*--- Numerical time step (this system is uncoditional stable... a very big number can be used) ---*/ + if (config->GetUnsteady_Simulation() == TIME_STEPPING) Time_Num = config->GetDelta_UnstTimeND(); + else Time_Num = 1E30; + + /*--- Loop through elements to compute contributions from the matrix + blocks involving time. These contributions are also added to the + Jacobian w/ the time step. Spatial source terms are also computed. ---*/ + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + /*--- Get node numbers and their coordinate vectors ---*/ + + Point_0 = geometry->elem[iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); + Point_1 = geometry->elem[iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); + Point_2 = geometry->elem[iElem]->GetNode(2); Coord_2 = geometry->node[Point_2]->GetCoord(); + + /*--- Compute area and volume ---*/ + + if (nDim == 2) { + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = Coord_0[iDim]-Coord_2[iDim]; + b[iDim] = Coord_1[iDim]-Coord_2[iDim]; + } + Area_Local = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); + } + else { + Point_3 = geometry->elem[iElem]->GetNode(3); + Coord_3 = geometry->node[Point_3]->GetCoord(); + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = Coord_0[iDim]-Coord_2[iDim]; + b[iDim] = Coord_1[iDim]-Coord_2[iDim]; + c[iDim] = Coord_3[iDim]-Coord_2[iDim]; + } + d[0] = a[1]*b[2]-a[2]*b[1]; + d[1] = -(a[0]*b[2]-a[2]*b[0]); + d[2] = a[0]*b[1]-a[1]*b[0]; + Volume_Local = fabs(c[0]*d[0] + c[1]*d[1] + c[2]*d[2])/6.0; + } + + /*--- Block contributions to the Jacobian (includes time step) ---*/ + + if (nDim == 2) { StiffMatrix_Node[0][0] = (2.0/12.0)*(Area_Local/Time_Num); } + else { StiffMatrix_Node[0][0] = (2.0/20.0)*(Volume_Local/Time_Num); } + Jacobian.AddBlock(Point_0, Point_0, StiffMatrix_Node); + Jacobian.AddBlock(Point_1, Point_1, StiffMatrix_Node); + Jacobian.AddBlock(Point_2, Point_2, StiffMatrix_Node); + if (nDim == 3) Jacobian.AddBlock(Point_3, Point_3, StiffMatrix_Node); + + if (nDim == 2) { StiffMatrix_Node[0][0] = (1.0/12.0)*(Area_Local/Time_Num); } + else { StiffMatrix_Node[0][0] = (1.0/20.0)*(Volume_Local/Time_Num); } + + Jacobian.AddBlock(Point_0, Point_1, StiffMatrix_Node); + Jacobian.AddBlock(Point_0, Point_2, StiffMatrix_Node); + Jacobian.AddBlock(Point_1, Point_0, StiffMatrix_Node); + Jacobian.AddBlock(Point_1, Point_2, StiffMatrix_Node); + Jacobian.AddBlock(Point_2, Point_0, StiffMatrix_Node); + Jacobian.AddBlock(Point_2, Point_1, StiffMatrix_Node); + if (nDim == 3) { + Jacobian.AddBlock(Point_0, Point_3, StiffMatrix_Node); + Jacobian.AddBlock(Point_1, Point_3, StiffMatrix_Node); + Jacobian.AddBlock(Point_2, Point_3, StiffMatrix_Node); + Jacobian.AddBlock(Point_3, Point_0, StiffMatrix_Node); + Jacobian.AddBlock(Point_3, Point_1, StiffMatrix_Node); + Jacobian.AddBlock(Point_3, Point_2, StiffMatrix_Node); + } + + } + + } + +} + +void CHeatSolver::Viscous_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config, unsigned short iMesh, unsigned short iRKStep) { + + unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, Point_3 = 0, total_index, iPoint; + su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, *Coord_3 = NULL; + + if (nDim == 2 ) { + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + Point_0 = geometry->elem[iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); + Point_1 = geometry->elem[iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); + Point_2 = geometry->elem[iElem]->GetNode(2); Coord_2 = geometry->node[Point_2]->GetCoord(); + + numerics->SetCoord(Coord_0, Coord_1, Coord_2); + numerics->ComputeResidual(StiffMatrix_Elem, config); + + StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][0]; StiffMatrixSpace.AddBlock(Point_0, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_0, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][1]; StiffMatrixSpace.AddBlock(Point_0, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_1, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][2]; StiffMatrixSpace.AddBlock(Point_0, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_2, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][0]; StiffMatrixSpace.AddBlock(Point_1, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_0, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][1]; StiffMatrixSpace.AddBlock(Point_1, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_1, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][2]; StiffMatrixSpace.AddBlock(Point_1, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_2, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][0]; StiffMatrixSpace.AddBlock(Point_2, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_0, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][1]; StiffMatrixSpace.AddBlock(Point_2, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_1, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][2]; StiffMatrixSpace.AddBlock(Point_2, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_2, StiffMatrix_Node); + + } + } + + if (nDim == 3 ) { + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + Point_0 = geometry->elem[iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); + Point_1 = geometry->elem[iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); + Point_2 = geometry->elem[iElem]->GetNode(2); Coord_2 = geometry->node[Point_2]->GetCoord(); + Point_3 = geometry->elem[iElem]->GetNode(3); Coord_3 = geometry->node[Point_3]->GetCoord(); + + numerics->SetCoord(Coord_0, Coord_1, Coord_2, Coord_3); + numerics->ComputeResidual(StiffMatrix_Elem, config); + + StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][0]; StiffMatrixSpace.AddBlock(Point_0, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_0, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][1]; StiffMatrixSpace.AddBlock(Point_0, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_1, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][2]; StiffMatrixSpace.AddBlock(Point_0, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_2, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][3]; StiffMatrixSpace.AddBlock(Point_0, Point_3, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_3, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][0]; StiffMatrixSpace.AddBlock(Point_1, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_0, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][1]; StiffMatrixSpace.AddBlock(Point_1, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_1, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][2]; StiffMatrixSpace.AddBlock(Point_1, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_2, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][3]; StiffMatrixSpace.AddBlock(Point_1, Point_3, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_3, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][0]; StiffMatrixSpace.AddBlock(Point_2, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_0, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][1]; StiffMatrixSpace.AddBlock(Point_2, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_1, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][2]; StiffMatrixSpace.AddBlock(Point_2, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_2, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][3]; StiffMatrixSpace.AddBlock(Point_2, Point_3, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_3, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[3][0]; StiffMatrixSpace.AddBlock(Point_3, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_3, Point_0, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[3][1]; StiffMatrixSpace.AddBlock(Point_3, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_3, Point_1, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[3][2]; StiffMatrixSpace.AddBlock(Point_3, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_3, Point_2, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[3][3]; StiffMatrixSpace.AddBlock(Point_3, Point_3, StiffMatrix_Node); Jacobian.AddBlock(Point_3, Point_3, StiffMatrix_Node); + + } + } + + if (config->GetUnsteady_Simulation() != STEADY) { + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + total_index = iPoint*nVar; + LinSysSol[total_index] = node[iPoint]->GetSolution(0); + LinSysAux[total_index] = 0.0; + } + + StiffMatrixSpace.MatrixVectorProduct(LinSysSol, LinSysAux); + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + total_index = iPoint*nVar; + Residual[0] = LinSysAux[total_index]; + LinSysRes.SubtractBlock(iPoint, Residual); + } + } + +} + +void CHeatSolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { } + +void CHeatSolver::BC_Isothermal_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned long iPoint, iVertex, total_index; + su2double Twall; + + /*--- Identify the boundary ---*/ + + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + + /*--- Retrieve the specified wall temperature ---*/ + + Twall = config->GetIsothermal_Temperature(Marker_Tag); + + /*--- Set the solution at the boundary nodes and zero the residual ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + Solution[0] = Twall; + + node[iPoint]->SetSolution(Solution); + node[iPoint]->SetSolution_Old(Solution); + + /*--- Unsteady solution, the equation is solved in terms of increments ---*/ + if (config->GetUnsteady_Simulation() != STEADY) Residual[0] = 0.0; + + LinSysRes.SetBlock(iPoint, Residual); + LinSysSol.SetBlock(iPoint, Residual); + + total_index = iPoint*nVar; + Jacobian.DeleteValsRowi(total_index); + + } + +} + + +void CHeatSolver::SetResidual_DualTime(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iRKStep, + unsigned short iMesh, unsigned short RunTime_EqSystem) { + + unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, Point_3 = 0; + su2double a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}, c[3] = {0.0,0.0,0.0}, d[3] = {0.0,0.0,0.0}, Area_Local = 0.0, Volume_Local = 0.0, Time_Num; + su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, *Coord_3= NULL; + unsigned short iDim, iVar; + su2double TimeJac = 0.0; + + /*--- Numerical time step (this system is uncoditional stable... a very big number can be used) ---*/ + Time_Num = config->GetDelta_UnstTimeND(); + + /*--- Loop through elements to compute contributions from the matrix + blocks involving time. These contributions are also added to the + Jacobian w/ the time step. Spatial source terms are also computed. ---*/ + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + /*--- Get node numbers and their coordinate vectors ---*/ + + Point_0 = geometry->elem[iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); + Point_1 = geometry->elem[iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); + Point_2 = geometry->elem[iElem]->GetNode(2); Coord_2 = geometry->node[Point_2]->GetCoord(); + + /*--- Compute area and volume ---*/ + + if (nDim == 2) { + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = Coord_0[iDim]-Coord_2[iDim]; + b[iDim] = Coord_1[iDim]-Coord_2[iDim]; + } + Area_Local = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); + } + else { + Point_3 = geometry->elem[iElem]->GetNode(3); + Coord_3 = geometry->node[Point_3]->GetCoord(); + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = Coord_0[iDim]-Coord_2[iDim]; + b[iDim] = Coord_1[iDim]-Coord_2[iDim]; + c[iDim] = Coord_3[iDim]-Coord_2[iDim]; + } + d[0] = a[1]*b[2]-a[2]*b[1]; d[1] = -(a[0]*b[2]-a[2]*b[0]); d[2] = a[0]*b[1]-a[1]*b[0]; + Volume_Local = fabs(c[0]*d[0] + c[1]*d[1] + c[2]*d[2])/6.0; + } + + /*--- Block contributions to the Jacobian (includes time step) ---*/ + + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) TimeJac = 1.0/Time_Num; + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) TimeJac = 3.0/(2.0*Time_Num); + + if (nDim == 2) { StiffMatrix_Node[0][0] = (2.0/12.0)*(Area_Local*TimeJac); } + else { StiffMatrix_Node[0][0] = (2.0/20.0)*(Volume_Local*TimeJac); } + + Jacobian.AddBlock(Point_0, Point_0, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_0, Point_0, StiffMatrix_Node); + Jacobian.AddBlock(Point_1, Point_1, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_1, Point_1, StiffMatrix_Node); + Jacobian.AddBlock(Point_2, Point_2, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_2, Point_2, StiffMatrix_Node); + if (nDim == 3) { Jacobian.AddBlock(Point_3, Point_3, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_2, Point_2, StiffMatrix_Node); } + + if (nDim == 2) { StiffMatrix_Node[0][0] = (1.0/12.0)*(Area_Local*TimeJac); } + else { StiffMatrix_Node[0][0] = (1.0/20.0)*(Volume_Local*TimeJac); } + + Jacobian.AddBlock(Point_0, Point_1, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_0, Point_1, StiffMatrix_Node); + Jacobian.AddBlock(Point_0, Point_2, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_0, Point_2, StiffMatrix_Node); + Jacobian.AddBlock(Point_1, Point_0, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_1, Point_0, StiffMatrix_Node); + Jacobian.AddBlock(Point_1, Point_2, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_1, Point_2, StiffMatrix_Node); + Jacobian.AddBlock(Point_2, Point_0, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_2, Point_0, StiffMatrix_Node); + Jacobian.AddBlock(Point_2, Point_1, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_2, Point_1, StiffMatrix_Node); + if (nDim == 3) { + Jacobian.AddBlock(Point_0, Point_3, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_0, Point_3, StiffMatrix_Node); + Jacobian.AddBlock(Point_1, Point_3, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_1, Point_3, StiffMatrix_Node); + Jacobian.AddBlock(Point_2, Point_3, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_2, Point_3, StiffMatrix_Node); + Jacobian.AddBlock(Point_3, Point_0, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_3, Point_0, StiffMatrix_Node); + Jacobian.AddBlock(Point_3, Point_1, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_3, Point_1, StiffMatrix_Node); + Jacobian.AddBlock(Point_3, Point_2, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_3, Point_2, StiffMatrix_Node); + } + + } + + unsigned long iPoint, total_index; + su2double *U_time_nM1, *U_time_n, *U_time_nP1; + + /*--- loop over points ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Solution at time n-1, n and n+1 ---*/ + + U_time_nM1 = node[iPoint]->GetSolution_time_n1(); + U_time_n = node[iPoint]->GetSolution_time_n(); + U_time_nP1 = node[iPoint]->GetSolution(); + + /*--- Compute residual ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + LinSysSol[total_index] = ( U_time_nP1[iVar] - U_time_n[iVar] ); + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + LinSysSol[total_index] = ( U_time_nP1[iVar] - (4.0/3.0)*U_time_n[iVar] + (1.0/3.0)*U_time_nM1[iVar] ); + } + } + + /*--- Contribution to the residual ---*/ + + StiffMatrixTime.MatrixVectorProduct(LinSysSol, LinSysAux); + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + total_index = iPoint*nVar; + Residual[0] = LinSysAux[total_index]; + LinSysRes.SubtractBlock(iPoint, Residual); + } + +} + +void CHeatSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { + + unsigned short iVar; + unsigned long iPoint, total_index; + + /*--- Build implicit system ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + LinSysSol[total_index] = 0.0; + } + + } + + /*--- Initialize residual and solution at the ghost points ---*/ + + for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar + iVar; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + } + } + + /*--- Solve or smooth the linear system ---*/ + + CSysSolve system; + system.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); + + /*--- Update solution (system written in terms of increments) ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + if (config->GetUnsteady_Simulation() == STEADY) node[iPoint]->SetSolution(iVar, LinSysSol[iPoint*nVar+iVar]); + else node[iPoint]->AddSolution(iVar, LinSysSol[iPoint*nVar+iVar]); + } + } + + /*--- MPI solution ---*/ + + Set_MPI_Solution(geometry, config); + + /*--- Compute the residual Ax-f ---*/ + + Jacobian.ComputeResidual(LinSysSol, LinSysRes, LinSysAux); + + /*--- Set maximum residual to zero ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + SetRes_RMS(iVar, 0.0); + SetRes_Max(iVar, 0.0, 0); + } + + /*--- Compute the residual ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + AddRes_RMS(iVar, LinSysAux[total_index]*LinSysAux[total_index]); + AddRes_Max(iVar, fabs(LinSysAux[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); + } + } + + /*--- Compute the root mean square residual ---*/ + + SetResidual_RMS(geometry, config); + +} diff --git a/SU2_CFD/src/solver_direct_mean.cpp b/SU2_CFD/src/solver_direct_mean.cpp index 53f9eba7221..123dcc7db7a 100644 --- a/SU2_CFD/src/solver_direct_mean.cpp +++ b/SU2_CFD/src/solver_direct_mean.cpp @@ -1,13717 +1,13717 @@ -/*! - * \file solution_direct_mean.cpp - * \brief Main subrotuines for solving direct problems (Euler, Navier-Stokes, etc.). - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/solver_structure.hpp" - -CEulerSolver::CEulerSolver(void) : CSolver() { - - /*--- Basic array initialization ---*/ - - CDrag_Inv = NULL; CLift_Inv = NULL; CSideForce_Inv = NULL; CEff_Inv = NULL; - CMx_Inv = NULL; CMy_Inv = NULL; CMz_Inv = NULL; - CFx_Inv = NULL; CFy_Inv = NULL; CFz_Inv = NULL; - - CPressure = NULL; CPressureTarget = NULL; HeatFlux = NULL; HeatFluxTarget = NULL; YPlus = NULL; - ForceInviscid = NULL; MomentInviscid = NULL; - - /*--- Surface based array initialization ---*/ - - Surface_CLift_Inv = NULL; Surface_CDrag_Inv = NULL; Surface_CSideForce_Inv = NULL; Surface_CEff_Inv = NULL; - Surface_CFx_Inv = NULL; Surface_CFy_Inv = NULL; Surface_CFz_Inv = NULL; - Surface_CMx_Inv = NULL; Surface_CMy_Inv = NULL; Surface_CMz_Inv = NULL; - - Surface_CLift = NULL; Surface_CDrag = NULL; Surface_CSideForce = NULL; Surface_CEff = NULL; - Surface_CFx = NULL; Surface_CFy = NULL; Surface_CFz = NULL; - Surface_CMx = NULL; Surface_CMy = NULL; Surface_CMz = NULL; - - /*--- Rotorcraft simulation array initialization ---*/ - - CMerit_Inv = NULL; CT_Inv = NULL; CQ_Inv = NULL; - - /*--- Supersonic simulation array initialization ---*/ - - CEquivArea_Inv = NULL; - CNearFieldOF_Inv = NULL; - - /*--- Engine simulation array initialization ---*/ - - Inflow_MassFlow = NULL; Inflow_Pressure = NULL; - Inflow_Mach = NULL; Inflow_Area = NULL; - Bleed_MassFlow = NULL; Bleed_Pressure = NULL; - Bleed_Temperature = NULL; Inflow_Area = NULL; - Exhaust_Pressure = NULL; Exhaust_Temperature = NULL; - Exhaust_MassFlow = NULL; Exhaust_Area = NULL; - - /*--- Numerical methods array initialization ---*/ - - iPoint_UndLapl = NULL; - jPoint_UndLapl = NULL; - LowMach_Precontioner = NULL; - Primitive = NULL; Primitive_i = NULL; Primitive_j = NULL; - CharacPrimVar = NULL; - - /*--- Fixed CL mode initialization (cauchy criteria) ---*/ - - Cauchy_Value = 0; - Cauchy_Func = 0; - Old_Func = 0; - New_Func = 0; - Cauchy_Counter = 0; - Cauchy_Serie = NULL; - -} - -CEulerSolver::CEulerSolver(CGeometry *geometry, CConfig *config, unsigned short iMesh) : CSolver() { - - unsigned long iPoint, index, counter_local = 0, counter_global = 0, iVertex; - unsigned short iVar, iDim, iMarker, nLineLets; - su2double StaticEnergy, Density, Velocity2, Pressure, Temperature, dull_val; - int Unst_RestartIter; - ifstream restart_file; - unsigned short iZone = config->GetiZone(); - unsigned short nZone = geometry->GetnZone(); - bool restart = (config->GetRestart() || config->GetRestart_Flow()); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - bool roe_turkel = (config->GetKind_Upwind_Flow() == TURKEL); - bool adjoint = config->GetAdjoint(); - string filename = config->GetSolution_FlowFileName(); - - unsigned short direct_diff = config->GetDirectDiff(); - unsigned short nMarkerTurboPerf = config->Get_nMarkerTurboPerf(); - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Array initialization ---*/ - - CDrag_Inv = NULL; CLift_Inv = NULL; CSideForce_Inv = NULL; CEff_Inv = NULL; - CMx_Inv = NULL; CMy_Inv = NULL; CMz_Inv = NULL; - CFx_Inv = NULL; CFy_Inv = NULL; CFz_Inv = NULL; - - Surface_CLift_Inv = NULL; Surface_CDrag_Inv = NULL; Surface_CSideForce_Inv = NULL; Surface_CEff_Inv = NULL; - Surface_CFx_Inv = NULL; Surface_CFy_Inv = NULL; Surface_CFz_Inv = NULL; - Surface_CMx_Inv = NULL; Surface_CMy_Inv = NULL; Surface_CMz_Inv = NULL; - - Surface_CLift = NULL; Surface_CDrag = NULL; Surface_CSideForce = NULL; Surface_CEff = NULL; - Surface_CFx = NULL; Surface_CFy = NULL; Surface_CFz = NULL; - Surface_CMx = NULL; Surface_CMy = NULL; Surface_CMz = NULL; - - ForceInviscid = NULL; MomentInviscid = NULL; - CPressure = NULL; CPressureTarget = NULL; HeatFlux = NULL; - HeatFluxTarget = NULL; YPlus = NULL; - - CMerit_Inv = NULL; CT_Inv = NULL; CQ_Inv = NULL; - - CEquivArea_Inv = NULL; CNearFieldOF_Inv = NULL; - - Inflow_MassFlow = NULL; Exhaust_MassFlow = NULL; Exhaust_Area = NULL; Exhaust_Pressure = NULL; - Inflow_Pressure = NULL; Inflow_Mach = NULL; Inflow_Area = NULL; Exhaust_Temperature = NULL; - Bleed_MassFlow = NULL; Bleed_Pressure = NULL; Bleed_Temperature = NULL; Bleed_Area = NULL; - - iPoint_UndLapl = NULL; jPoint_UndLapl = NULL; - LowMach_Precontioner = NULL; - Primitive = NULL; Primitive_i = NULL; Primitive_j = NULL; - Secondary = NULL; Secondary_i = NULL; Secondary_j = NULL; - CharacPrimVar = NULL; - Cauchy_Serie = NULL; - - /*--- Set the gamma value ---*/ - - Gamma = config->GetGamma(); - Gamma_Minus_One = Gamma - 1.0; - - /*--- Define geometry constants in the solver structure - Compressible flow, primitive variables (T, vx, vy, vz, P, rho, h, c, lamMu, EddyMu, ThCond, Cp) - Incompressible flow, primitive variables (P, vx, vy, vz, rho, beta, lamMu, EddyMu). - FreeSurface Incompressible flow, primitive variables (P, vx, vy, vz, rho, beta, lamMu, EddyMu, LevelSet, Dist). - ---*/ - - nDim = geometry->GetnDim(); - - if (incompressible) { nVar = nDim+1; nPrimVar = nDim+5; nPrimVarGrad = nDim+3; } - if (freesurface) { nVar = nDim+2; nPrimVar = nDim+7; nPrimVarGrad = nDim+6; } - if (compressible) { nVar = nDim+2; - nPrimVar = nDim+9; nPrimVarGrad = nDim+4; - nSecondaryVar = 2; nSecondaryVarGrad = 2; - } - - nMarker = config->GetnMarker_All(); - nPoint = geometry->GetnPoint(); - nPointDomain = geometry->GetnPointDomain(); - - /*--- Perform the non-dimensionalization for the flow equations using the - specified reference values. ---*/ - - SetNondimensionalization(geometry, config, iMesh); - - /*--- Allocate the node variables ---*/ - - node = new CVariable*[nPoint]; - - /*--- Define some auxiliary vectors related to the residual ---*/ - - Residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; - Residual_RMS = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_RMS[iVar] = 0.0; - Residual_Max = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_Max[iVar] = 0.0; - Residual_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_i[iVar] = 0.0; - Residual_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_j[iVar] = 0.0; - Res_Conv = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Conv[iVar] = 0.0; - Res_Visc = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Visc[iVar] = 0.0; - Res_Sour = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Sour[iVar] = 0.0; - - /*--- Define some structures for locating max residuals ---*/ - - Point_Max = new unsigned long[nVar]; for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; - Point_Max_Coord = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Point_Max_Coord[iVar] = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; - } - - /*--- Define some auxiliary vectors related to the solution ---*/ - - Solution = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; - Solution_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_i[iVar] = 0.0; - Solution_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_j[iVar] = 0.0; - - /*--- Define some auxiliary vectors related to the geometry ---*/ - - Vector = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = 0.0; - Vector_i = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_i[iDim] = 0.0; - Vector_j = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_j[iDim] = 0.0; - - /*--- Define some auxiliary vectors related to the primitive solution ---*/ - - Primitive = new su2double[nPrimVar]; for (iVar = 0; iVar < nPrimVar; iVar++) Primitive[iVar] = 0.0; - Primitive_i = new su2double[nPrimVar]; for (iVar = 0; iVar < nPrimVar; iVar++) Primitive_i[iVar] = 0.0; - Primitive_j = new su2double[nPrimVar]; for (iVar = 0; iVar < nPrimVar; iVar++) Primitive_j[iVar] = 0.0; - - /*--- Define some auxiliary vectors related to the Secondary solution ---*/ - - Secondary = new su2double[nSecondaryVar]; for (iVar = 0; iVar < nSecondaryVar; iVar++) Secondary[iVar] = 0.0; - Secondary_i = new su2double[nSecondaryVar]; for (iVar = 0; iVar < nSecondaryVar; iVar++) Secondary_i[iVar] = 0.0; - Secondary_j = new su2double[nSecondaryVar]; for (iVar = 0; iVar < nSecondaryVar; iVar++) Secondary_j[iVar] = 0.0; - - /*--- Define some auxiliary vectors related to the undivided lapalacian ---*/ - - if (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED) { - iPoint_UndLapl = new su2double [nPoint]; - jPoint_UndLapl = new su2double [nPoint]; - } - - /*--- Define some auxiliary vectors related to low-speed preconditioning ---*/ - - if (roe_turkel) { - LowMach_Precontioner = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar ++) - LowMach_Precontioner[iVar] = new su2double[nVar]; - } - - /*--- Initialize the solution and right hand side vectors for storing - the residuals and updating the solution (always needed even for - explicit schemes). ---*/ - - LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); - - /*--- Jacobians and vector structures for implicit computations ---*/ - - if (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT) { - - Jacobian_i = new su2double* [nVar]; - Jacobian_j = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Jacobian_i[iVar] = new su2double [nVar]; - Jacobian_j[iVar] = new su2double [nVar]; - } - - if (rank == MASTER_NODE) cout << "Initialize Jacobian structure (Euler). MG level: " << iMesh <<"." << endl; - Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); - - if ((config->GetKind_Linear_Solver_Prec() == LINELET) || - (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { - nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); - if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; - } - - } - - else { - if (rank == MASTER_NODE) cout << "Explicit scheme. No Jacobian structure (Euler). MG level: " << iMesh <<"." << endl; - } - - /*--- Define some auxiliary vectors for computing flow variable - gradients by least squares, S matrix := inv(R)*traspose(inv(R)), - c vector := transpose(WA)*(Wb) ---*/ - - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { - - Smatrix = new su2double* [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Smatrix[iDim] = new su2double [nDim]; - - cvector = new su2double* [nPrimVarGrad]; - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - cvector[iVar] = new su2double [nDim]; - - } - - /*--- Store the value of the characteristic primitive variables at the boundaries ---*/ - - CharacPrimVar = new su2double** [nMarker]; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - CharacPrimVar[iMarker] = new su2double* [geometry->nVertex[iMarker]]; - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - CharacPrimVar[iMarker][iVertex] = new su2double [nPrimVar]; - for (iVar = 0; iVar < nPrimVar; iVar++) { - CharacPrimVar[iMarker][iVertex][iVar] = 0.0; - } - } - } - - /*--- Force definition and coefficient arrays for all of the markers ---*/ - - CPressure = new su2double* [nMarker]; - CPressureTarget = new su2double* [nMarker]; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - CPressure[iMarker] = new su2double [geometry->nVertex[iMarker]]; - CPressureTarget[iMarker] = new su2double [geometry->nVertex[iMarker]]; - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - CPressure[iMarker][iVertex] = 0.0; - CPressureTarget[iMarker][iVertex] = 0.0; - } - } - - /*--- Non-dimensional coefficients ---*/ - - ForceInviscid = new su2double[nDim]; - MomentInviscid = new su2double[3]; - CDrag_Inv = new su2double[nMarker]; - CLift_Inv = new su2double[nMarker]; - CSideForce_Inv = new su2double[nMarker]; - CMx_Inv = new su2double[nMarker]; - CMy_Inv = new su2double[nMarker]; - CMz_Inv = new su2double[nMarker]; - CEff_Inv = new su2double[nMarker]; - CFx_Inv = new su2double[nMarker]; - CFy_Inv = new su2double[nMarker]; - CFz_Inv = new su2double[nMarker]; - - Surface_CLift_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CDrag_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CSideForce_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CEff_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CFx_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CFy_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CFz_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CMx_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CMy_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CMz_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CLift = new su2double[config->GetnMarker_Monitoring()]; - Surface_CDrag = new su2double[config->GetnMarker_Monitoring()]; - Surface_CSideForce = new su2double[config->GetnMarker_Monitoring()]; - Surface_CEff = new su2double[config->GetnMarker_Monitoring()]; - Surface_CFx = new su2double[config->GetnMarker_Monitoring()]; - Surface_CFy = new su2double[config->GetnMarker_Monitoring()]; - Surface_CFz = new su2double[config->GetnMarker_Monitoring()]; - Surface_CMx = new su2double[config->GetnMarker_Monitoring()]; - Surface_CMy = new su2double[config->GetnMarker_Monitoring()]; - Surface_CMz = new su2double[config->GetnMarker_Monitoring()]; - - /*--- Rotorcraft coefficients ---*/ - - CT_Inv = new su2double[nMarker]; - CQ_Inv = new su2double[nMarker]; - CMerit_Inv = new su2double[nMarker]; - - /*--- Supersonic coefficients ---*/ - - CEquivArea_Inv = new su2double[nMarker]; - CNearFieldOF_Inv = new su2double[nMarker]; - - /*--- Engine simulation ---*/ - - Inflow_MassFlow = new su2double[nMarker]; - Inflow_Pressure = new su2double[nMarker]; - Inflow_Mach = new su2double[nMarker]; - Inflow_Area = new su2double[nMarker]; - - Exhaust_MassFlow = new su2double[nMarker]; - Exhaust_Pressure = new su2double[nMarker]; - Exhaust_Temperature = new su2double[nMarker]; - Exhaust_Area = new su2double[nMarker]; - - Bleed_MassFlow = new su2double[nMarker]; - Bleed_Pressure = new su2double[nMarker]; - Bleed_Temperature = new su2double[nMarker]; - Bleed_Area = new su2double[nMarker]; - - /*--- Init total coefficients ---*/ - - Total_CDrag = 0.0; Total_CLift = 0.0; Total_CSideForce = 0.0; - Total_CMx = 0.0; Total_CMy = 0.0; Total_CMz = 0.0; - Total_CEff = 0.0; Total_CEquivArea = 0.0; Total_CNearFieldOF = 0.0; - Total_CFx = 0.0; Total_CFy = 0.0; Total_CFz = 0.0; - Total_CT = 0.0; Total_CQ = 0.0; Total_CMerit = 0.0; - Total_MaxHeat = 0.0; Total_Heat = 0.0; - Total_CpDiff = 0.0; Total_HeatFluxDiff = 0.0; - - /*--- Read farfield conditions ---*/ - - Density_Inf = config->GetDensity_FreeStreamND(); - Pressure_Inf = config->GetPressure_FreeStreamND(); - Velocity_Inf = config->GetVelocity_FreeStreamND(); - Energy_Inf = config->GetEnergy_FreeStreamND(); - Temperature_Inf = config->GetTemperature_FreeStreamND(); - Mach_Inf = config->GetMach(); - - /*--- Initialize the secondary values for direct derivative approxiations ---*/ - - switch(direct_diff){ - case NO_DERIVATIVE: - /*--- Default ---*/ - break; - case D_DENSITY: - SU2_TYPE::SetDerivative(Density_Inf, 1.0); - break; - case D_PRESSURE: - SU2_TYPE::SetDerivative(Pressure_Inf, 1.0); - break; - case D_TEMPERATURE: - SU2_TYPE::SetDerivative(Temperature_Inf, 1.0); - break; - case D_MACH: case D_AOA: - case D_SIDESLIP: case D_REYNOLDS: - case D_TURB2LAM: case D_DESIGN: - /*--- Already done in postprocessing of config ---*/ - break; - default: - break; - } - - - /*--- Initializate fan face pressure, fan face mach number, and mass flow rate ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - Inflow_MassFlow[iMarker] = 0.0; - Inflow_Mach[iMarker] = Mach_Inf; - Inflow_Pressure[iMarker] = Pressure_Inf; - Inflow_Area[iMarker] = 0.0; - - Exhaust_MassFlow[iMarker] = 0.0; - Exhaust_Temperature[iMarker] = Temperature_Inf; - Exhaust_Pressure[iMarker] = Pressure_Inf; - Exhaust_Area[iMarker] = 0.0; - - Bleed_MassFlow[iMarker] = 0.0; - Bleed_Temperature[iMarker] = Temperature_Inf; - Bleed_Pressure[iMarker] = Pressure_Inf; - Bleed_Area[iMarker] = 0.0; - } - - /*--- Initializate quantities for the mixing process ---*/ - - AveragedVelocity = new su2double* [nMarker]; - AveragedNormal = new su2double* [nMarker]; - AveragedGridVel = new su2double* [nMarker]; - AveragedFlux = new su2double* [nMarker]; - TotalFlux = new su2double* [nMarker]; - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - AveragedVelocity[iMarker] = new su2double [nDim]; - AveragedNormal[iMarker] = new su2double [nDim]; - AveragedGridVel[iMarker] = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) { - AveragedVelocity[iMarker][iDim] = 0.0; - AveragedNormal[iMarker][iDim] = 0.0; - AveragedGridVel [iMarker][iDim] = 0.0; - } - } - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - AveragedFlux[iMarker] = new su2double [nVar]; - TotalFlux[iMarker] = new su2double [nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - AveragedFlux[iMarker][iVar] = 0.0; - TotalFlux[iMarker][iVar] = 0.0; - } - } - - AveragedNormalVelocity = new su2double[nMarker]; - AveragedTangVelocity = new su2double[nMarker]; - ExtAveragedNormalVelocity = new su2double[nMarker]; - ExtAveragedTangVelocity = new su2double[nMarker]; - MassFlow= new su2double[nMarker]; - FlowAngle= new su2double[nMarker]; - AveragedEnthalpy = new su2double[nMarker]; - AveragedPressure = new su2double[nMarker]; - AveragedTotPressure = new su2double[nMarker]; - AveragedTotTemperature = new su2double[nMarker]; - ExtAveragedTotPressure = new su2double[nMarker]; - ExtAveragedTotTemperature = new su2double[nMarker]; - AveragedDensity = new su2double[nMarker]; - ExtAveragedPressure = new su2double[nMarker]; - ExtAveragedDensity = new su2double[nMarker]; - AveragedSoundSpeed= new su2double[nMarker]; - AveragedEntropy = new su2double[nMarker]; - AveragedTangGridVelocity = new su2double[nMarker]; - AveragedMach = new su2double[nMarker]; - AveragedNormalMach = new su2double[nMarker]; - AveragedTangMach = new su2double[nMarker]; - - - /*--- Initializate quantities for turboperformace ---*/ - - TotalStaticEfficiency = new su2double[nMarkerTurboPerf]; - TotalTotalEfficiency = new su2double[nMarkerTurboPerf]; - KineticEnergyLoss= new su2double[nMarkerTurboPerf]; - TotalPressureLoss= new su2double[nMarkerTurboPerf]; - MassFlowIn= new su2double[nMarkerTurboPerf]; - MassFlowOut= new su2double[nMarkerTurboPerf]; - FlowAngleIn= new su2double[nMarkerTurboPerf]; - FlowAngleOut= new su2double[nMarkerTurboPerf]; - EulerianWork= new su2double[nMarkerTurboPerf]; - TotalEnthalpyIn= new su2double[nMarkerTurboPerf]; - PressureRatio= new su2double[nMarkerTurboPerf]; - PressureOut= new su2double[nMarkerTurboPerf]; - EnthalpyOut= new su2double[nMarkerTurboPerf]; - MachIn= new su2double[nMarkerTurboPerf]; - MachOut= new su2double[nMarkerTurboPerf]; - NormalMachIn= new su2double[nMarkerTurboPerf]; - NormalMachOut= new su2double[nMarkerTurboPerf]; - VelocityOutIs= new su2double[nMarkerTurboPerf]; - - for (iMarker = 0; iMarker < nMarkerTurboPerf; iMarker++){ - TotalStaticEfficiency[iMarker]= 0.0; - TotalTotalEfficiency[iMarker]= 0.0; - KineticEnergyLoss[iMarker]= 0.0; - TotalPressureLoss[iMarker]= 0.0; - MassFlowIn[iMarker]= 0.0; - MassFlowOut[iMarker]= 0.0; - FlowAngleIn[iMarker]= 0.0; - FlowAngleOut[iMarker]= 0.0; - EulerianWork[iMarker]= 0.0; - TotalEnthalpyIn[iMarker]= 0.0; - PressureRatio[iMarker]= 0.0; - PressureOut[iMarker]= 0.0; - EnthalpyOut[iMarker]= 0.0; - MachIn[iMarker]= 0.0; - MachOut[iMarker]= 0.0; - NormalMachIn[iMarker]= 0.0; - NormalMachOut[iMarker]= 0.0; - VelocityOutIs[iMarker]= 0.0; - } - - - /*--- Initialize the cauchy critera array for fixed CL mode ---*/ - - if (config->GetFixed_CL_Mode()) - - Cauchy_Serie = new su2double [config->GetCauchy_Elems()+1]; - - /*--- Check for a restart and set up the variables at each node - appropriately. Coarse multigrid levels will be intitially set to - the farfield values bc the solver will immediately interpolate - the solution from the finest mesh to the coarser levels. ---*/ - - if (!restart || (iMesh != MESH_0)) { - - /*--- Restart the solution from the free-stream state ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) - node[iPoint] = new CEulerVariable(Density_Inf, Velocity_Inf, Energy_Inf, nDim, nVar, config); - - } else { - - /*--- Modify file name for an unsteady restart ---*/ - - if (dual_time) { - - if (adjoint) { Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_AdjointIter()) - 1; } - else if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_RestartIter())-1; - else - Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_RestartIter())-2; - - filename = config->GetUnsteady_FileName(filename, Unst_RestartIter); - } - if (nZone >1) - filename= config->GetRestart_FlowFileName(filename, iZone); - - /*--- Open the restart file, throw an error if this fails. ---*/ - - restart_file.open(filename.data(), ios::in); - if (restart_file.fail()) { - if (rank == MASTER_NODE) - cout << "There is no flow restart file!! " << filename.data() << "."<< endl; - exit(EXIT_FAILURE); - } - - /*--- In case this is a parallel simulation, we need to perform the - Global2Local index transformation first. ---*/ - - long *Global2Local = new long[geometry->GetGlobal_nPointDomain()]; - - /*--- First, set all indices to a negative value by default ---*/ - - for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) - Global2Local[iPoint] = -1; - - /*--- Now fill array with the transform values only for local points ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) - Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; - - /*--- Read all lines in the restart file ---*/ - - long iPoint_Local; - unsigned long iPoint_Global_Local = 0, iPoint_Global = 0; string text_line; - unsigned short rbuf_NotMatching = 0, sbuf_NotMatching = 0; - - /*--- The first line is the header ---*/ - - getline (restart_file, text_line); - - while (getline (restart_file, text_line)) { - istringstream point_line(text_line); - - /*--- Retrieve local index. If this node from the restart file lives - on a different processor, the value of iPoint_Local will be -1. - Otherwise, the local index for this node on the current processor - will be returned and used to instantiate the vars. ---*/ - - iPoint_Local = Global2Local[iPoint_Global]; - - /*--- Load the solution for this node. Note that the first entry - on the restart file line is the global index, followed by the - node coordinates, and then the conservative variables. ---*/ - - if (iPoint_Local >= 0) { - if (compressible) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3] >> Solution[4]; - } - if (incompressible) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; - } - if (freesurface) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3] >> Solution[4]; - } - node[iPoint_Local] = new CEulerVariable(Solution, nDim, nVar, config); - iPoint_Global_Local++; - } - iPoint_Global++; - } - - /*--- Detect a wrong solution file ---*/ - - if (iPoint_Global_Local < nPointDomain) { sbuf_NotMatching = 1; } - -#ifndef HAVE_MPI - rbuf_NotMatching = sbuf_NotMatching; -#else - SU2_MPI::Allreduce(&sbuf_NotMatching, &rbuf_NotMatching, 1, MPI_UNSIGNED_SHORT, MPI_SUM, MPI_COMM_WORLD); -#endif - - if (rbuf_NotMatching != 0) { - if (rank == MASTER_NODE) { - cout << endl << "The solution file " << filename.data() << " doesn't match with the mesh file!" << endl; - cout << "It could be empty lines at the end of the file." << endl << endl; - } -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Barrier(MPI_COMM_WORLD); - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - } - - /*--- Instantiate the variable class with an arbitrary solution - at any halo/periodic nodes. The initial solution can be arbitrary, - because a send/recv is performed immediately in the solver. ---*/ - - for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) - node[iPoint] = new CEulerVariable(Solution, nDim, nVar, config); - - /*--- Close the restart file ---*/ - - restart_file.close(); - - /*--- Free memory needed for the transformation ---*/ - - delete [] Global2Local; - - } - - /*--- Check that the initial solution is physical, report any non-physical nodes ---*/ - - if (compressible) { - - counter_local = 0; - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - - Density = node[iPoint]->GetSolution(0); - - Velocity2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Velocity2 += (node[iPoint]->GetSolution(iDim+1)/Density)*(node[iPoint]->GetSolution(iDim+1)/Density); - - StaticEnergy= node[iPoint]->GetSolution(nDim+1)/Density - 0.5*Velocity2; - - FluidModel->SetTDState_rhoe(Density, StaticEnergy); - Pressure= FluidModel->GetPressure(); - Temperature= FluidModel->GetTemperature(); - - /*--- Use the values at the infinity ---*/ - - if ((Pressure < 0.0) || (Density < 0.0) || (Temperature < 0.0)) { - Solution[0] = Density_Inf; - for (iDim = 0; iDim < nDim; iDim++) - Solution[iDim+1] = Velocity_Inf[iDim]*Density_Inf; - Solution[nDim+1] = Energy_Inf*Density_Inf; - node[iPoint]->SetSolution(Solution); - node[iPoint]->SetSolution_Old(Solution); - counter_local++; - } - - } - - /*--- Warning message about non-physical points ---*/ - - if (config->GetConsole_Output_Verb() == VERB_HIGH) { -#ifdef HAVE_MPI - SU2_MPI::Reduce(&counter_local, &counter_global, 1, MPI_UNSIGNED_LONG, MPI_SUM, MASTER_NODE, MPI_COMM_WORLD); -#else - counter_global = counter_local; -#endif - if ((rank == MASTER_NODE) && (counter_global != 0)) - cout << "Warning. The original solution contains "<< counter_global << " points that are not physical." << endl; - } - - } - - /*--- Define solver parameters needed for execution of destructor ---*/ - - if (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED ) space_centered = true; - else space_centered = false; - - if (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT) euler_implicit = true; - else euler_implicit = false; - - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) least_squares = true; - else least_squares = false; - - /*--- Perform the MPI communication of the solution ---*/ - - Set_MPI_Solution(geometry, config); - -} - -CEulerSolver::~CEulerSolver(void) { - unsigned short iVar, iMarker; - - /*--- Array deallocation ---*/ - if (CDrag_Inv != NULL) delete [] CDrag_Inv; - if (CLift_Inv != NULL) delete [] CLift_Inv; - if (CSideForce_Inv != NULL) delete [] CSideForce_Inv; - if (CMx_Inv != NULL) delete [] CMx_Inv; - if (CMy_Inv != NULL) delete [] CMy_Inv; - if (CMz_Inv != NULL) delete [] CMz_Inv; - if (CFx_Inv != NULL) delete [] CFx_Inv; - if (CFy_Inv != NULL) delete [] CFy_Inv; - if (CFz_Inv != NULL) delete [] CFz_Inv; - if (Surface_CLift_Inv != NULL) delete[] Surface_CLift_Inv; - if (Surface_CDrag_Inv != NULL) delete[] Surface_CDrag_Inv; - if (Surface_CSideForce_Inv != NULL) delete[] Surface_CSideForce_Inv; - if (Surface_CEff_Inv != NULL) delete[] Surface_CEff_Inv; - if (Surface_CFx_Inv != NULL) delete [] Surface_CFx_Inv; - if (Surface_CFy_Inv != NULL) delete [] Surface_CFy_Inv; - if (Surface_CFz_Inv != NULL) delete [] Surface_CFz_Inv; - if (Surface_CMx_Inv != NULL) delete [] Surface_CMx_Inv; - if (Surface_CMy_Inv != NULL) delete [] Surface_CMy_Inv; - if (Surface_CMz_Inv != NULL) delete [] Surface_CMz_Inv; - if (Surface_CLift != NULL) delete [] Surface_CLift; - if (Surface_CDrag != NULL) delete [] Surface_CDrag; - if (Surface_CSideForce != NULL) delete [] Surface_CSideForce; - if (Surface_CEff != NULL) delete [] Surface_CEff; - if (Surface_CFx != NULL) delete [] Surface_CFx; - if (Surface_CFy != NULL) delete [] Surface_CFy; - if (Surface_CFz != NULL) delete [] Surface_CFz; - if (Surface_CMx != NULL) delete [] Surface_CMx; - if (Surface_CMy != NULL) delete [] Surface_CMy; - if (Surface_CMz != NULL) delete [] Surface_CMz; - if (CEff_Inv != NULL) delete [] CEff_Inv; - if (CMerit_Inv != NULL) delete [] CMerit_Inv; - if (CT_Inv != NULL) delete [] CT_Inv; - if (CQ_Inv != NULL) delete [] CQ_Inv; - if (CEquivArea_Inv != NULL) delete [] CEquivArea_Inv; - if (CNearFieldOF_Inv != NULL) delete [] CNearFieldOF_Inv; - if (ForceInviscid != NULL) delete [] ForceInviscid; - if (MomentInviscid != NULL) delete [] MomentInviscid; - if (Inflow_MassFlow != NULL) delete [] Inflow_MassFlow; - if (Exhaust_MassFlow != NULL) delete [] Exhaust_MassFlow; - if (Exhaust_Area != NULL) delete [] Exhaust_Area; - if (Inflow_Pressure != NULL) delete [] Inflow_Pressure; - if (Inflow_Mach != NULL) delete [] Inflow_Mach; - if (Inflow_Area != NULL) delete [] Inflow_Area; - if (Bleed_Pressure != NULL) delete [] Bleed_Pressure; - if (Bleed_Temperature != NULL) delete [] Bleed_Temperature; - if (Exhaust_Pressure != NULL) delete [] Exhaust_Pressure; - if (Exhaust_Temperature != NULL) delete [] Exhaust_Temperature; - if (Bleed_Area != NULL) delete [] Bleed_Area; - if (iPoint_UndLapl != NULL) delete [] iPoint_UndLapl; - if (jPoint_UndLapl != NULL) delete [] jPoint_UndLapl; - if (Primitive != NULL) delete [] Primitive; - if (Primitive_i != NULL) delete [] Primitive_i; - if (Primitive_j != NULL) delete [] Primitive_j; - // if (Secondary != NULL) delete [] Secondary; - if (Secondary_i != NULL) delete [] Secondary_i; - if (Secondary_j != NULL) delete [] Secondary_j; - - if (LowMach_Precontioner != NULL) { - for (iVar = 0; iVar < nVar; iVar ++) - delete LowMach_Precontioner[iVar]; - delete [] LowMach_Precontioner; - } - - if (CPressure != NULL) { - for (iMarker = 0; iMarker < nMarker; iMarker++) - delete CPressure[iMarker]; - delete [] CPressure; - } - - if (CPressureTarget != NULL) { - for (iMarker = 0; iMarker < nMarker; iMarker++) - delete CPressureTarget[iMarker]; - delete [] CPressureTarget; - } - - // if (CharacPrimVar != NULL) { - // for (iMarker = 0; iMarker < nMarker; iMarker++) { - // for (iVertex = 0; iVertex < nVertex; iVertex++) { - // delete CharacPrimVar[iMarker][iVertex]; - // } - // } - // delete [] CharacPrimVar; - // } - - if (HeatFlux != NULL) { - for (iMarker = 0; iMarker < nMarker; iMarker++) { - delete HeatFlux[iMarker]; - } - delete [] HeatFlux; - } - - if (HeatFluxTarget != NULL) { - for (iMarker = 0; iMarker < nMarker; iMarker++) { - delete HeatFluxTarget[iMarker]; - } - delete [] HeatFluxTarget; - } - - if (YPlus != NULL) { - for (iMarker = 0; iMarker < nMarker; iMarker++) { - delete YPlus[iMarker]; - } - delete [] YPlus; - } - - if (Cauchy_Serie != NULL) - delete [] Cauchy_Serie; - -} - -void CEulerSolver::Set_MPI_Solution(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_U = new su2double [nBufferR_Vector]; - Buffer_Send_U = new su2double[nBufferS_Vector]; - - /*--- Copy the solution that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution(iVar); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); - -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_U; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = Buffer_Receive_U[iVar*nVertexR+iVertex]; - - /*--- Rotate the momentum components. ---*/ - if (nDim == 2) { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex]; - } - else { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex] + - rotMatrix[0][2]*Buffer_Receive_U[3*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex] + - rotMatrix[1][2]*Buffer_Receive_U[3*nVertexR+iVertex]; - Solution[3] = rotMatrix[2][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[2][1]*Buffer_Receive_U[2*nVertexR+iVertex] + - rotMatrix[2][2]*Buffer_Receive_U[3*nVertexR+iVertex]; - } - - /*--- Copy transformed conserved variables back into buffer. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetSolution(iVar, Solution[iVar]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_U; - - } - - } - -} - -void CEulerSolver::Set_MPI_Solution_Old(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, - *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_U = new su2double [nBufferR_Vector]; - Buffer_Send_U = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution_Old(iVar); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); - -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_U; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = Buffer_Receive_U[iVar*nVertexR+iVertex]; - - /*--- Rotate the momentum components. ---*/ - if (nDim == 2) { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex]; - } - else { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex] + - rotMatrix[0][2]*Buffer_Receive_U[3*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex] + - rotMatrix[1][2]*Buffer_Receive_U[3*nVertexR+iVertex]; - Solution[3] = rotMatrix[2][0]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[2][1]*Buffer_Receive_U[2*nVertexR+iVertex] + - rotMatrix[2][2]*Buffer_Receive_U[3*nVertexR+iVertex]; - } - - /*--- Copy transformed conserved variables back into buffer. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetSolution_Old(iVar, Solution[iVar]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_U; - - } - - } -} - -void CEulerSolver::Set_MPI_Undivided_Laplacian(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, - *Buffer_Receive_Undivided_Laplacian = NULL, *Buffer_Send_Undivided_Laplacian = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_Undivided_Laplacian = new su2double [nBufferR_Vector]; - Buffer_Send_Undivided_Laplacian = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_Undivided_Laplacian[iVar*nVertexS+iVertex] = node[iPoint]->GetUndivided_Laplacian(iVar); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Undivided_Laplacian, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_Undivided_Laplacian, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); - -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_Undivided_Laplacian[iVar*nVertexR+iVertex] = Buffer_Send_Undivided_Laplacian[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_Undivided_Laplacian; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = Buffer_Receive_Undivided_Laplacian[iVar*nVertexR+iVertex]; - - /*--- Rotate the momentum components. ---*/ - if (nDim == 2) { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex]; - } - else { - Solution[1] = rotMatrix[0][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex] + - rotMatrix[0][2]*Buffer_Receive_Undivided_Laplacian[3*nVertexR+iVertex]; - Solution[2] = rotMatrix[1][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex] + - rotMatrix[1][2]*Buffer_Receive_Undivided_Laplacian[3*nVertexR+iVertex]; - Solution[3] = rotMatrix[2][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + - rotMatrix[2][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex] + - rotMatrix[2][2]*Buffer_Receive_Undivided_Laplacian[3*nVertexR+iVertex]; - } - - /*--- Copy transformed conserved variables back into buffer. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetUndivided_Laplacian(iVar, Solution[iVar]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_Undivided_Laplacian; - - } - - } - -} - -void CEulerSolver::Set_MPI_MaxEigenvalue(CGeometry *geometry, CConfig *config) { - unsigned short iMarker, MarkerS, MarkerR, *Buffer_Receive_Neighbor = NULL, *Buffer_Send_Neighbor = NULL; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double *Buffer_Receive_Lambda = NULL, *Buffer_Send_Lambda = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS; nBufferR_Vector = nVertexR; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_Lambda = new su2double [nBufferR_Vector]; - Buffer_Send_Lambda = new su2double[nBufferS_Vector]; - Buffer_Receive_Neighbor = new unsigned short [nBufferR_Vector]; - Buffer_Send_Neighbor = new unsigned short[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - Buffer_Send_Lambda[iVertex] = node[iPoint]->GetLambda(); - Buffer_Send_Neighbor[iVertex] = geometry->node[iPoint]->GetnPoint(); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Lambda, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_Lambda, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); - SU2_MPI::Sendrecv(Buffer_Send_Neighbor, nBufferS_Vector, MPI_UNSIGNED_SHORT, send_to, 1, - Buffer_Receive_Neighbor, nBufferR_Vector, MPI_UNSIGNED_SHORT, receive_from, 1, MPI_COMM_WORLD, &status); - -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - Buffer_Receive_Lambda[iVertex] = Buffer_Send_Lambda[iVertex]; - Buffer_Receive_Neighbor[iVertex] = Buffer_Send_Neighbor[iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_Lambda; - delete [] Buffer_Send_Neighbor; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - node[iPoint]->SetLambda(Buffer_Receive_Lambda[iVertex]); - geometry->node[iPoint]->SetnNeighbor(Buffer_Receive_Neighbor[iVertex]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_Lambda; - delete [] Buffer_Receive_Neighbor; - - } - - } -} - -void CEulerSolver::Set_MPI_Dissipation_Switch(CGeometry *geometry, CConfig *config) { - unsigned short iMarker, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double *Buffer_Receive_Lambda = NULL, *Buffer_Send_Lambda = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS; nBufferR_Vector = nVertexR; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_Lambda = new su2double [nBufferR_Vector]; - Buffer_Send_Lambda = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - Buffer_Send_Lambda[iVertex] = node[iPoint]->GetSensor(); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Lambda, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_Lambda, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); - -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - Buffer_Receive_Lambda[iVertex] = Buffer_Send_Lambda[iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_Lambda; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - node[iPoint]->SetSensor(Buffer_Receive_Lambda[iVertex]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_Lambda; - - } - - } -} - -void CEulerSolver::Set_MPI_Solution_Gradient(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, - *Buffer_Receive_Gradient = NULL, *Buffer_Send_Gradient = NULL; - - su2double **Gradient = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - Gradient[iVar] = new su2double[nDim]; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar*nDim; nBufferR_Vector = nVertexR*nVar*nDim; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_Gradient = new su2double [nBufferR_Vector]; - Buffer_Send_Gradient = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Gradient[iDim*nVar*nVertexS+iVar*nVertexS+iVertex] = node[iPoint]->GetGradient(iVar, iDim); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Gradient, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_Gradient, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); - -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex] = Buffer_Send_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_Gradient; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Gradient[iVar][iDim] = Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; - - /*--- Need to rotate the gradients for all conserved variables. ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - if (nDim == 2) { - Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; - } - else { - Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][2] = rotMatrix[2][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; - } - } - - /*--- Store the received information ---*/ - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - node[iPoint]->SetGradient(iVar, iDim, Gradient[iVar][iDim]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_Gradient; - - } - - } - - for (iVar = 0; iVar < nVar; iVar++) - delete [] Gradient[iVar]; - delete [] Gradient; - -} - -void CEulerSolver::Set_MPI_Solution_Limiter(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, - *Buffer_Receive_Limit = NULL, *Buffer_Send_Limit = NULL; - - su2double *Limiter = new su2double [nVar]; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_Limit = new su2double [nBufferR_Vector]; - Buffer_Send_Limit = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_Limit[iVar*nVertexS+iVertex] = node[iPoint]->GetLimiter(iVar); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Limit, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_Limit, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); - -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_Limit[iVar*nVertexR+iVertex] = Buffer_Send_Limit[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_Limit; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - Limiter[iVar] = Buffer_Receive_Limit[iVar*nVertexR+iVertex]; - - /*--- Rotate the momentum components. ---*/ - if (nDim == 2) { - Limiter[1] = rotMatrix[0][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_Limit[2*nVertexR+iVertex]; - Limiter[2] = rotMatrix[1][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_Limit[2*nVertexR+iVertex]; - } - else { - Limiter[1] = rotMatrix[0][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + - rotMatrix[0][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; - Limiter[2] = rotMatrix[1][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + - rotMatrix[1][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; - Limiter[3] = rotMatrix[2][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[2][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + - rotMatrix[2][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; - } - - /*--- Copy transformed conserved variables back into buffer. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetLimiter(iVar, Limiter[iVar]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_Limit; - - } - - } - - delete [] Limiter; - -} - -void CEulerSolver::Set_MPI_Primitive_Gradient(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, - *Buffer_Receive_Gradient = NULL, *Buffer_Send_Gradient = NULL; - - su2double **Gradient = new su2double* [nPrimVarGrad]; - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - Gradient[iVar] = new su2double[nDim]; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nPrimVarGrad*nDim; nBufferR_Vector = nVertexR*nPrimVarGrad*nDim; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_Gradient = new su2double [nBufferR_Vector]; - Buffer_Send_Gradient = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Gradient[iDim*nPrimVarGrad*nVertexS+iVar*nVertexS+iVertex] = node[iPoint]->GetGradient_Primitive(iVar, iDim); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Gradient, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_Gradient, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); - -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Receive_Gradient[iDim*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] = Buffer_Send_Gradient[iDim*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_Gradient; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Gradient[iVar][iDim] = Buffer_Receive_Gradient[iDim*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex]; - - /*--- Need to rotate the gradients for all conserved variables. ---*/ - for (iVar = 0; iVar < nPrimVarGrad; iVar++) { - if (nDim == 2) { - Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex]; - } - else { - Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][2]*Buffer_Receive_Gradient[2*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][2]*Buffer_Receive_Gradient[2*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][2] = rotMatrix[2][0]*Buffer_Receive_Gradient[0*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][1]*Buffer_Receive_Gradient[1*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][2]*Buffer_Receive_Gradient[2*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex]; - } - } - - /*--- Store the received information ---*/ - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - node[iPoint]->SetGradient_Primitive(iVar, iDim, Gradient[iVar][iDim]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_Gradient; - - } - - } - - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - delete [] Gradient[iVar]; - delete [] Gradient; - -} - -void CEulerSolver::Set_MPI_Primitive_Limiter(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, - *Buffer_Receive_Limit = NULL, *Buffer_Send_Limit = NULL; - - su2double *Limiter = new su2double [nPrimVarGrad]; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nPrimVarGrad; nBufferR_Vector = nVertexR*nPrimVarGrad; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_Limit = new su2double [nBufferR_Vector]; - Buffer_Send_Limit = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - Buffer_Send_Limit[iVar*nVertexS+iVertex] = node[iPoint]->GetLimiter_Primitive(iVar); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Limit, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_Limit, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); - -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - Buffer_Receive_Limit[iVar*nVertexR+iVertex] = Buffer_Send_Limit[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_Limit; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - Limiter[iVar] = Buffer_Receive_Limit[iVar*nVertexR+iVertex]; - - /*--- Rotate the momentum components. ---*/ - if (nDim == 2) { - Limiter[1] = rotMatrix[0][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_Limit[2*nVertexR+iVertex]; - Limiter[2] = rotMatrix[1][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_Limit[2*nVertexR+iVertex]; - } - else { - Limiter[1] = rotMatrix[0][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + - rotMatrix[0][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; - Limiter[2] = rotMatrix[1][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + - rotMatrix[1][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; - Limiter[3] = rotMatrix[2][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + - rotMatrix[2][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + - rotMatrix[2][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; - } - - /*--- Copy transformed conserved variables back into buffer. ---*/ - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - node[iPoint]->SetLimiter_Primitive(iVar, Limiter[iVar]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_Limit; - - } - - } - - delete [] Limiter; - -} - -//void CEulerSolver::Set_MPI_Secondary_Gradient(CGeometry *geometry, CConfig *config) { -// unsigned short iVar, iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; -// unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; -// su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, -// *Buffer_Receive_Gradient = NULL, *Buffer_Send_Gradient = NULL; -// int send_to, receive_from; -// -// su2double **Gradient = new su2double* [nSecondaryVarGrad]; -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) -// Gradient[iVar] = new su2double[nDim]; -// -//#ifdef HAVE_MPI -// MPI_Status status; -//#endif -// -// for (iMarker = 0; iMarker < nMarker; iMarker++) { -// -// if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && -// (config->GetMarker_All_SendRecv(iMarker) > 0)) { -// -// MarkerS = iMarker; MarkerR = iMarker+1; -// -// send_to = config->GetMarker_All_SendRecv(MarkerS)-1; -// receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -// -// nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; -// nBufferS_Vector = nVertexS*nSecondaryVarGrad*nDim; nBufferR_Vector = nVertexR*nSecondaryVarGrad*nDim; -// -// /*--- Allocate Receive and send buffers ---*/ -// Buffer_Receive_Gradient = new su2double [nBufferR_Vector]; -// Buffer_Send_Gradient = new su2double[nBufferS_Vector]; -// -// /*--- Copy the solution old that should be sended ---*/ -// for (iVertex = 0; iVertex < nVertexS; iVertex++) { -// iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) -// for (iDim = 0; iDim < nDim; iDim++) -// Buffer_Send_Gradient[iDim*nSecondaryVarGrad*nVertexS+iVar*nVertexS+iVertex] = node[iPoint]->GetGradient_Secondary(iVar, iDim); -// } -// -//#ifdef HAVE_MPI -// -// /*--- Send/Receive information using Sendrecv ---*/ -// SU2_MPI::Sendrecv(Buffer_Send_Gradient, nBufferS_Vector, MPI_DOUBLE, send_to, 0, -// Buffer_Receive_Gradient, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); -// -//#else -// -// /*--- Receive information without MPI ---*/ -// for (iVertex = 0; iVertex < nVertexR; iVertex++) { -// iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) -// for (iDim = 0; iDim < nDim; iDim++) -// Buffer_Receive_Gradient[iDim*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] = Buffer_Send_Gradient[iDim*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex]; -// } -// -//#endif -// -// /*--- Deallocate send buffer ---*/ -// delete [] Buffer_Send_Gradient; -// -// /*--- Do the coordinate transformation ---*/ -// for (iVertex = 0; iVertex < nVertexR; iVertex++) { -// -// /*--- Find point and its type of transformation ---*/ -// iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); -// iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); -// -// /*--- Retrieve the supplied periodic information. ---*/ -// angles = config->GetPeriodicRotation(iPeriodic_Index); -// -// /*--- Store angles separately for clarity. ---*/ -// theta = angles[0]; phi = angles[1]; psi = angles[2]; -// cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); -// sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); -// -// /*--- Compute the rotation matrix. Note that the implicit -// ordering is rotation about the x-axis, y-axis, -// then z-axis. Note that this is the transpose of the matrix -// used during the preprocessing stage. ---*/ -// rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; -// rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; -// rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; -// -// /*--- Copy conserved variables before performing transformation. ---*/ -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) -// for (iDim = 0; iDim < nDim; iDim++) -// Gradient[iVar][iDim] = Buffer_Receive_Gradient[iDim*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex]; -// -// /*--- Need to rotate the gradients for all conserved variables. ---*/ -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { -// if (nDim == 2) { -// Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex]; -// Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex]; -// } -// else { -// Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][2]*Buffer_Receive_Gradient[2*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex]; -// Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][2]*Buffer_Receive_Gradient[2*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex]; -// Gradient[iVar][2] = rotMatrix[2][0]*Buffer_Receive_Gradient[0*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][1]*Buffer_Receive_Gradient[1*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][2]*Buffer_Receive_Gradient[2*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex]; -// } -// } -// -// /*--- Store the received information ---*/ -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) -// for (iDim = 0; iDim < nDim; iDim++) -// node[iPoint]->SetGradient_Secondary(iVar, iDim, Gradient[iVar][iDim]); -// -// } -// -// /*--- Deallocate receive buffer ---*/ -// delete [] Buffer_Receive_Gradient; -// -// } -// -// } -// -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) -// delete [] Gradient[iVar]; -// delete [] Gradient; -// -//} - -//void CEulerSolver::Set_MPI_Secondary_Limiter(CGeometry *geometry, CConfig *config) { -// unsigned short iVar, iMarker, MarkerS, MarkerR; -// unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; -// su2double *Buffer_Receive_Limit = NULL, *Buffer_Send_Limit = NULL; -// int send_to, receive_from; -// -// su2double *Limiter = new su2double [nSecondaryVarGrad]; -// -//#ifdef HAVE_MPI -// MPI_Status status; -//#endif -// -// for (iMarker = 0; iMarker < nMarker; iMarker++) { -// -// if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && -// (config->GetMarker_All_SendRecv(iMarker) > 0)) { -// -// MarkerS = iMarker; MarkerR = iMarker+1; -// -// send_to = config->GetMarker_All_SendRecv(MarkerS)-1; -// receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -// -// nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; -// nBufferS_Vector = nVertexS*nSecondaryVarGrad; nBufferR_Vector = nVertexR*nSecondaryVarGrad; -// -// /*--- Allocate Receive and send buffers ---*/ -// Buffer_Receive_Limit = new su2double [nBufferR_Vector]; -// Buffer_Send_Limit = new su2double[nBufferS_Vector]; -// -// /*--- Copy the solution old that should be sended ---*/ -// for (iVertex = 0; iVertex < nVertexS; iVertex++) { -// iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) -// Buffer_Send_Limit[iVar*nVertexS+iVertex] = node[iPoint]->GetLimiter_Secondary(iVar); -// } -// -//#ifdef HAVE_MPI -// -// /*--- Send/Receive information using Sendrecv ---*/ -// SU2_MPI::Sendrecv(Buffer_Send_Limit, nBufferS_Vector, MPI_DOUBLE, send_to, 0, -// Buffer_Receive_Limit, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); -// -//#else -// -// /*--- Receive information without MPI ---*/ -// for (iVertex = 0; iVertex < nVertexR; iVertex++) { -// iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) -// Buffer_Receive_Limit[iVar*nVertexR+iVertex] = Buffer_Send_Limit[iVar*nVertexR+iVertex]; -// } -// -//#endif -// -// /*--- Deallocate send buffer ---*/ -// delete [] Buffer_Send_Limit; -// -// /*--- Do the coordinate transformation ---*/ -// for (iVertex = 0; iVertex < nVertexR; iVertex++) { -// -// /*--- Find point and its type of transformation ---*/ -// iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); -// -// /*--- Copy conserved variables before performing transformation. ---*/ -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) -// Limiter[iVar] = Buffer_Receive_Limit[iVar*nVertexR+iVertex]; -// -// /*--- Copy transformed conserved variables back into buffer. ---*/ -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) -// node[iPoint]->SetLimiter_Secondary(iVar, Limiter[iVar]); -// -// } -// -// /*--- Deallocate receive buffer ---*/ -// delete [] Buffer_Receive_Limit; -// -// } -// -// } -// -// delete [] Limiter; -// -//} - -void CEulerSolver::SetNondimensionalization(CGeometry *geometry, CConfig *config, unsigned short iMesh) { - - su2double Temperature_FreeStream = 0.0, Mach2Vel_FreeStream = 0.0, ModVel_FreeStream = 0.0, - Energy_FreeStream = 0.0, ModVel_FreeStreamND = 0.0, Velocity_Reynolds = 0.0, - Omega_FreeStream = 0.0, Omega_FreeStreamND = 0.0, Viscosity_FreeStream = 0.0, - Density_FreeStream = 0.0, Pressure_FreeStream = 0.0, Tke_FreeStream = 0.0, - Length_Ref = 0.0, Density_Ref = 0.0, Pressure_Ref = 0.0, Velocity_Ref = 0.0, - Temperature_Ref = 0.0, Time_Ref = 0.0, Omega_Ref = 0.0, Force_Ref = 0.0, - Gas_Constant_Ref = 0.0, Viscosity_Ref = 0.0, Conductivity_Ref = 0.0, Energy_Ref= 0.0, - Froude = 0.0, Pressure_FreeStreamND = 0.0, Density_FreeStreamND = 0.0, - Temperature_FreeStreamND = 0.0, Gas_ConstantND = 0.0, - Velocity_FreeStreamND[3] = {0.0, 0.0, 0.0}, Viscosity_FreeStreamND = 0.0, - Tke_FreeStreamND = 0.0, Energy_FreeStreamND = 0.0, - Total_UnstTimeND = 0.0, Delta_UnstTimeND = 0.0, TgammaR = 0.0; - - unsigned short iDim; - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Local variables ---*/ - - su2double Alpha = config->GetAoA()*PI_NUMBER/180.0; - su2double Beta = config->GetAoS()*PI_NUMBER/180.0; - su2double Mach = config->GetMach(); - su2double Reynolds = config->GetReynolds(); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool unsteady = (config->GetUnsteady_Simulation() != NO); - bool viscous = config->GetViscous(); - bool grid_movement = config->GetGrid_Movement(); - bool gravity = config->GetGravityForce(); - bool turbulent = (config->GetKind_Solver() == RANS) || (config->GetKind_Solver() == DISC_ADJ_RANS); - bool tkeNeeded = ((turbulent) && (config->GetKind_Turb_Model() == SST)); - bool free_stream_temp = (config->GetKind_FreeStreamOption() == TEMPERATURE_FS); - bool standard_air = (config->GetKind_FluidModel() == STANDARD_AIR); - bool reynolds_init = (config->GetKind_InitOption() == REYNOLDS); - bool aeroelastic = config->GetAeroelastic_Simulation(); - - /*--- Set temperature via the flutter speed index ---*/ - if (aeroelastic) { - su2double vf = config->GetAeroelastic_Flutter_Speed_Index(); - su2double w_alpha = config->GetAeroelastic_Frequency_Pitch(); - su2double b = config->GetLength_Reynolds()/2.0; // airfoil semichord, Reynolds length is by defaul 1.0 - su2double mu = config->GetAeroelastic_Airfoil_Mass_Ratio(); - // The temperature times gamma times the gas constant. Depending on the FluidModel temp is calculated below. - TgammaR = ((vf*vf)*(b*b)*(w_alpha*w_alpha)*mu) / (Mach*Mach); - } - - /*--- Compressible non dimensionalization ---*/ - - if (compressible) { - - /*--- Compute the Free Stream velocity, using the Mach number ---*/ - - Pressure_FreeStream = config->GetPressure_FreeStream(); - Density_FreeStream = config->GetDensity_FreeStream(); - Temperature_FreeStream = config->GetTemperature_FreeStream(); - - switch (config->GetKind_FluidModel()) { - - case STANDARD_AIR: - - if (config->GetSystemMeasurements() == SI) config->SetGas_Constant(287.058); - else if (config->GetSystemMeasurements() == US) config->SetGas_Constant(1716.49); - - FluidModel = new CIdealGas(1.4, config->GetGas_Constant()); - if (free_stream_temp) { - if (aeroelastic) { - Temperature_FreeStream = TgammaR / (config->GetGas_Constant()*1.4); - config->SetTemperature_FreeStream(Temperature_FreeStream); - } - FluidModel->SetTDState_PT(Pressure_FreeStream, Temperature_FreeStream); - Density_FreeStream = FluidModel->GetDensity(); - config->SetDensity_FreeStream(Density_FreeStream); - } - else { - FluidModel->SetTDState_Prho(Pressure_FreeStream, Density_FreeStream ); - Temperature_FreeStream = FluidModel->GetTemperature(); - config->SetTemperature_FreeStream(Temperature_FreeStream); - } - break; - - case IDEAL_GAS: - - FluidModel = new CIdealGas(Gamma, config->GetGas_Constant()); - if (free_stream_temp) { - FluidModel->SetTDState_PT(Pressure_FreeStream, Temperature_FreeStream); - Density_FreeStream = FluidModel->GetDensity(); - config->SetDensity_FreeStream(Density_FreeStream); - } - else { - FluidModel->SetTDState_Prho(Pressure_FreeStream, Density_FreeStream ); - Temperature_FreeStream = FluidModel->GetTemperature(); - config->SetTemperature_FreeStream(Temperature_FreeStream); - } - break; - - case VW_GAS: - - FluidModel = new CVanDerWaalsGas(Gamma, config->GetGas_Constant(), - config->GetPressure_Critical(), config->GetTemperature_Critical()); - if (free_stream_temp) { - FluidModel->SetTDState_PT(Pressure_FreeStream, Temperature_FreeStream); - Density_FreeStream = FluidModel->GetDensity(); - config->SetDensity_FreeStream(Density_FreeStream); - } - else { - FluidModel->SetTDState_Prho(Pressure_FreeStream, Density_FreeStream ); - Temperature_FreeStream = FluidModel->GetTemperature(); - config->SetTemperature_FreeStream(Temperature_FreeStream); - } - break; - - case PR_GAS: - - FluidModel = new CPengRobinson(Gamma, config->GetGas_Constant(), config->GetPressure_Critical(), - config->GetTemperature_Critical(), config->GetAcentric_Factor()); - if (free_stream_temp) { - FluidModel->SetTDState_PT(Pressure_FreeStream, Temperature_FreeStream); - Density_FreeStream = FluidModel->GetDensity(); - config->SetDensity_FreeStream(Density_FreeStream); - } - else { - FluidModel->SetTDState_Prho(Pressure_FreeStream, Density_FreeStream ); - Temperature_FreeStream = FluidModel->GetTemperature(); - config->SetTemperature_FreeStream(Temperature_FreeStream); - } - break; - - } - - Mach2Vel_FreeStream = FluidModel->GetSoundSpeed(); - - /*--- Compute the Free Stream velocity, using the Mach number ---*/ - - if (nDim == 2) { - config->GetVelocity_FreeStream()[0] = cos(Alpha)*Mach*Mach2Vel_FreeStream; - config->GetVelocity_FreeStream()[1] = sin(Alpha)*Mach*Mach2Vel_FreeStream; - } - if (nDim == 3) { - config->GetVelocity_FreeStream()[0] = cos(Alpha)*cos(Beta)*Mach*Mach2Vel_FreeStream; - config->GetVelocity_FreeStream()[1] = sin(Beta)*Mach*Mach2Vel_FreeStream; - config->GetVelocity_FreeStream()[2] = sin(Alpha)*cos(Beta)*Mach*Mach2Vel_FreeStream; - } - - /*--- Compute the modulus of the free stream velocity ---*/ - - ModVel_FreeStream = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - ModVel_FreeStream += config->GetVelocity_FreeStream()[iDim]*config->GetVelocity_FreeStream()[iDim]; - ModVel_FreeStream = sqrt(ModVel_FreeStream); config->SetModVel_FreeStream(ModVel_FreeStream); - - /*--- Viscous initialization ---*/ - - if (viscous) { - - /*--- Reynolds based initialization ---*/ - - if (reynolds_init) { - - /*--- First, check if there is mesh motion. If yes, use the Mach - number relative to the body to initialize the flow. ---*/ - - if (grid_movement) Velocity_Reynolds = config->GetMach_Motion()*Mach2Vel_FreeStream; - else Velocity_Reynolds = ModVel_FreeStream; - - /*--- Change of measurement system, hard coded value working only with STANDAR AIR model ---*/ - - if (standard_air) { - if (config->GetSystemMeasurements() == SI) { - config->SetMu_RefND(1.716E-5); - config->SetMu_SND(110.4); - config->SetMu_Temperature_RefND(273.15); - } - if (config->GetSystemMeasurements() == US) { - config->SetMu_RefND(3.62E-7); - config->SetMu_SND(198.72); - config->SetMu_Temperature_RefND(518.7); - } - } - - /*--- For viscous flows, pressure will be computed from a density - that is found from the Reynolds number. The viscosity is computed - from the dimensional version of Sutherland's law ---*/ - - FluidModel->SetLaminarViscosityModel(config); - - Viscosity_FreeStream = FluidModel->GetLaminarViscosity(); - config->SetViscosity_FreeStream(Viscosity_FreeStream); - - Density_FreeStream = Reynolds*Viscosity_FreeStream/(Velocity_Reynolds*config->GetLength_Reynolds()); - config->SetDensity_FreeStream(Density_FreeStream); - FluidModel->SetTDState_rhoT(Density_FreeStream, Temperature_FreeStream); - Pressure_FreeStream = FluidModel->GetPressure(); - config->SetPressure_FreeStream(Pressure_FreeStream); - Energy_FreeStream = FluidModel->GetStaticEnergy() + 0.5*ModVel_FreeStream*ModVel_FreeStream; - - } - - /*--- Thermodynamics quantities based initialization ---*/ - - else { - - FluidModel->SetLaminarViscosityModel(config); - Viscosity_FreeStream = FluidModel->GetLaminarViscosity(); - config->SetViscosity_FreeStream(Viscosity_FreeStream); - Energy_FreeStream = FluidModel->GetStaticEnergy() + 0.5*ModVel_FreeStream*ModVel_FreeStream; - - } - - /*--- Turbulence kinetic energy ---*/ - - Tke_FreeStream = 3.0/2.0*(ModVel_FreeStream*ModVel_FreeStream*config->GetTurbulenceIntensity_FreeStream()*config->GetTurbulenceIntensity_FreeStream()); - - } - else { - - /*--- For inviscid flow, energy is calculated from the specified - FreeStream quantities using the proper gas law. ---*/ - - Energy_FreeStream = FluidModel->GetStaticEnergy() + 0.5*ModVel_FreeStream*ModVel_FreeStream; - - } - - /*-- Compute the freestream energy. ---*/ - - if (tkeNeeded) { Energy_FreeStream += Tke_FreeStream; }; config->SetEnergy_FreeStream(Energy_FreeStream); - - /*--- Compute non dimensional quantities. By definition, - Lref is one because we have converted the grid to meters. ---*/ - - if (config->GetRef_NonDim() == DIMENSIONAL) { - Pressure_Ref = 1.0; - Density_Ref = 1.0; - Temperature_Ref = 1.0; - } - else if (config->GetRef_NonDim() == FREESTREAM_PRESS_EQ_ONE) { - Pressure_Ref = Pressure_FreeStream; // Pressure_FreeStream = 1.0 - Density_Ref = Density_FreeStream; // Density_FreeStream = 1.0 - Temperature_Ref = Temperature_FreeStream; // Temperature_FreeStream = 1.0 - } - else if (config->GetRef_NonDim() == FREESTREAM_VEL_EQ_MACH) { - Pressure_Ref = Gamma*Pressure_FreeStream; // Pressure_FreeStream = 1.0/Gamma - Density_Ref = Density_FreeStream; // Density_FreeStream = 1.0 - Temperature_Ref = Temperature_FreeStream; // Temp_FreeStream = 1.0 - } - else if (config->GetRef_NonDim() == FREESTREAM_VEL_EQ_ONE) { - Pressure_Ref = Mach*Mach*Gamma*Pressure_FreeStream; // Pressure_FreeStream = 1.0/(Gamma*(M_inf)^2) - Density_Ref = Density_FreeStream; // Density_FreeStream = 1.0 - Temperature_Ref = Temperature_FreeStream; // Temp_FreeStream = 1.0 - } - config->SetPressure_Ref(Pressure_Ref); - config->SetDensity_Ref(Density_Ref); - config->SetTemperature_Ref(Temperature_Ref); - - Length_Ref = 1.0; config->SetLength_Ref(Length_Ref); - Velocity_Ref = sqrt(config->GetPressure_Ref()/config->GetDensity_Ref()); config->SetVelocity_Ref(Velocity_Ref); - Time_Ref = Length_Ref/Velocity_Ref; config->SetTime_Ref(Time_Ref); - Omega_Ref = Velocity_Ref/Length_Ref; config->SetOmega_Ref(Omega_Ref); - Force_Ref = Velocity_Ref*Velocity_Ref/Length_Ref; config->SetForce_Ref(Force_Ref); - Gas_Constant_Ref = Velocity_Ref*Velocity_Ref/config->GetTemperature_Ref(); config->SetGas_Constant_Ref(Gas_Constant_Ref); - Viscosity_Ref = config->GetDensity_Ref()*Velocity_Ref*Length_Ref; config->SetViscosity_Ref(Viscosity_Ref); - Conductivity_Ref = Viscosity_Ref*Gas_Constant_Ref; config->SetConductivity_Ref(Conductivity_Ref); - Froude = ModVel_FreeStream/sqrt(STANDART_GRAVITY*Length_Ref); config->SetFroude(Froude); - - } - - /*--- Incompressible non dimensionalization ---*/ - - else { - - /*--- Reference length = 1 (by default) - Reference density = liquid density or freestream - Reference viscosity = liquid viscosity or freestream - Reference velocity = liquid velocity or freestream - Reference pressure = Reference density * Reference velocity * Reference velocity - Reynolds number based on the liquid or reference viscosity ---*/ - - Pressure_FreeStream = 0.0; config->SetPressure_FreeStream(Pressure_FreeStream); - Density_FreeStream = config->GetDensity_FreeStream(); - ModVel_FreeStream = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - ModVel_FreeStream += config->GetVelocity_FreeStream()[iDim]*config->GetVelocity_FreeStream()[iDim]; - ModVel_FreeStream = sqrt(ModVel_FreeStream); config->SetModVel_FreeStream(ModVel_FreeStream); - - /*--- Additional reference values defined by Pref, Tref, Rho_ref. By definition, - Lref is one because we have converted the grid to meters.---*/ - - Length_Ref = config->GetLength_Reynolds(); config->SetLength_Ref(Length_Ref); - Density_Ref = Density_FreeStream; config->SetDensity_Ref(Density_Ref); - Velocity_Ref = ModVel_FreeStream; config->SetVelocity_Ref(Velocity_Ref); - Pressure_Ref = Density_Ref*(Velocity_Ref*Velocity_Ref); config->SetPressure_Ref(Pressure_Ref); - - if (viscous) { - Viscosity_FreeStream = config->GetViscosity_FreeStream(); - Reynolds = Density_Ref*Velocity_Ref*Length_Ref / Viscosity_FreeStream; config->SetReynolds(Reynolds); - Viscosity_Ref = Viscosity_FreeStream * Reynolds; config->SetViscosity_Ref(Viscosity_Ref); - } - - /*--- Compute Mach number ---*/ - - Mach = ModVel_FreeStream / sqrt(config->GetBulk_Modulus()/Density_FreeStream); config->SetMach(Mach); - - /*--- Compute Alpha angle ---*/ - - if (nDim == 2) Alpha = atan(config->GetVelocity_FreeStream()[1]/config->GetVelocity_FreeStream()[0])*180.0/PI_NUMBER; - else Alpha = atan(config->GetVelocity_FreeStream()[2]/config->GetVelocity_FreeStream()[0])*180.0/PI_NUMBER; - config->SetAoA(Alpha); - - /*--- Compute Beta angle ---*/ - - if (nDim == 2) Beta = 0.0; - else Beta = asin(config->GetVelocity_FreeStream()[1]/ModVel_FreeStream)*180.0/PI_NUMBER; - config->SetAoS(Beta); - - /*--- Compute Froude ---*/ - - Froude = ModVel_FreeStream/sqrt(STANDART_GRAVITY*Length_Ref); config->SetFroude(Froude); - Time_Ref = Length_Ref/Velocity_Ref; config->SetTime_Ref(Time_Ref); - - } - - /*--- Divide by reference values, to compute the non-dimensional free-stream values ---*/ - - Pressure_FreeStreamND = Pressure_FreeStream/config->GetPressure_Ref(); config->SetPressure_FreeStreamND(Pressure_FreeStreamND); - Density_FreeStreamND = Density_FreeStream/config->GetDensity_Ref(); config->SetDensity_FreeStreamND(Density_FreeStreamND); - - for (iDim = 0; iDim < nDim; iDim++) { - Velocity_FreeStreamND[iDim] = config->GetVelocity_FreeStream()[iDim]/Velocity_Ref; config->SetVelocity_FreeStreamND(Velocity_FreeStreamND[iDim], iDim); - } - - Temperature_FreeStreamND = Temperature_FreeStream/config->GetTemperature_Ref(); config->SetTemperature_FreeStreamND(Temperature_FreeStreamND); - - Gas_ConstantND = config->GetGas_Constant()/Gas_Constant_Ref; config->SetGas_ConstantND(Gas_ConstantND); - - - ModVel_FreeStreamND = 0.0; - for (iDim = 0; iDim < nDim; iDim++) ModVel_FreeStreamND += Velocity_FreeStreamND[iDim]*Velocity_FreeStreamND[iDim]; - ModVel_FreeStreamND = sqrt(ModVel_FreeStreamND); config->SetModVel_FreeStreamND(ModVel_FreeStreamND); - - Viscosity_FreeStreamND = Viscosity_FreeStream / Viscosity_Ref; config->SetViscosity_FreeStreamND(Viscosity_FreeStreamND); - - Tke_FreeStream = 3.0/2.0*(ModVel_FreeStream*ModVel_FreeStream*config->GetTurbulenceIntensity_FreeStream()*config->GetTurbulenceIntensity_FreeStream()); - config->SetTke_FreeStream(Tke_FreeStream); - - Tke_FreeStreamND = 3.0/2.0*(ModVel_FreeStreamND*ModVel_FreeStreamND*config->GetTurbulenceIntensity_FreeStream()*config->GetTurbulenceIntensity_FreeStream()); - config->SetTke_FreeStreamND(Tke_FreeStreamND); - - Omega_FreeStream = Density_FreeStream*Tke_FreeStream/(Viscosity_FreeStream*config->GetTurb2LamViscRatio_FreeStream()); - config->SetOmega_FreeStream(Omega_FreeStream); - - Omega_FreeStreamND = Density_FreeStreamND*Tke_FreeStreamND/(Viscosity_FreeStreamND*config->GetTurb2LamViscRatio_FreeStream()); - config->SetOmega_FreeStreamND(Omega_FreeStreamND); - - /*--- Initialize the dimensionless Fluid Model that will be used to solve the dimensionless problem ---*/ - - switch (config->GetKind_FluidModel()) { - - case STANDARD_AIR: - FluidModel = new CIdealGas(1.4, Gas_ConstantND); - FluidModel->SetEnergy_Prho(Pressure_FreeStreamND, Density_FreeStreamND); - break; - - case IDEAL_GAS: - FluidModel = new CIdealGas(Gamma, Gas_ConstantND); - FluidModel->SetEnergy_Prho(Pressure_FreeStreamND, Density_FreeStreamND); - break; - - case VW_GAS: - FluidModel = new CVanDerWaalsGas(Gamma, Gas_ConstantND, config->GetPressure_Critical() /config->GetPressure_Ref(), - config->GetTemperature_Critical()/config->GetTemperature_Ref()); - FluidModel->SetEnergy_Prho(Pressure_FreeStreamND, Density_FreeStreamND); - break; - - case PR_GAS: - FluidModel = new CPengRobinson(Gamma, Gas_ConstantND, config->GetPressure_Critical() /config->GetPressure_Ref(), - config->GetTemperature_Critical()/config->GetTemperature_Ref(), config->GetAcentric_Factor()); - FluidModel->SetEnergy_Prho(Pressure_FreeStreamND, Density_FreeStreamND); - break; - - } - - Energy_FreeStreamND = FluidModel->GetStaticEnergy() + 0.5*ModVel_FreeStreamND*ModVel_FreeStreamND; - - if (viscous) { - - /*--- Constant viscosity model ---*/ - config->SetMu_ConstantND(config->GetMu_ConstantND()/Viscosity_Ref); - - /*--- Sutherland's model ---*/ - - config->SetMu_RefND(config->GetMu_RefND()/Viscosity_Ref); - config->SetMu_SND(config->GetMu_SND()/config->GetTemperature_Ref()); - config->SetMu_Temperature_RefND(config->GetMu_Temperature_RefND()/config->GetTemperature_Ref()); - - /* constant thermal conductivity model */ - config->SetKt_ConstantND(config->GetKt_ConstantND()/Conductivity_Ref); - - FluidModel->SetLaminarViscosityModel(config); - FluidModel->SetThermalConductivityModel(config); - - } - - if (tkeNeeded) { Energy_FreeStreamND += Tke_FreeStreamND; }; config->SetEnergy_FreeStreamND(Energy_FreeStreamND); - - Energy_Ref = Energy_FreeStream/Energy_FreeStreamND; config->SetEnergy_Ref(Energy_Ref); - - Total_UnstTimeND = config->GetTotal_UnstTime() / Time_Ref; config->SetTotal_UnstTimeND(Total_UnstTimeND); - Delta_UnstTimeND = config->GetDelta_UnstTime() / Time_Ref; config->SetDelta_UnstTimeND(Delta_UnstTimeND); - - /*--- Write output to the console if this is the master node and first domain ---*/ - - if ((rank == MASTER_NODE) && (iMesh == MESH_0)) { - - cout.precision(6); - - if (compressible) { - if (viscous) { - cout << "Viscous flow: Computing pressure using the ideal gas law" << endl; - cout << "based on the free-stream temperature and a density computed" << endl; - cout << "from the Reynolds number." << endl; - } else { - cout << "Inviscid flow: Computing density based on free-stream" << endl; - cout << "temperature and pressure using the ideal gas law." << endl; - } - } - - if (grid_movement) cout << "Force coefficients computed using MACH_MOTION." << endl; - else cout << "Force coefficients computed using free-stream values." << endl; - - if (incompressible || freesurface) { - cout << "Viscous and Inviscid flow: rho_ref, and vel_ref" << endl; - cout << "are based on the free-stream values, p_ref = rho_ref*vel_ref^2." << endl; - cout << "The free-stream value of the pressure is 0." << endl; - cout << "Mach number: "<< config->GetMach() << ", computed using the Bulk modulus." << endl; - cout << "Angle of attack (deg): "<< config->GetAoA() << ", computed using the the free-stream velocity." << endl; - cout << "Side slip angle (deg): "<< config->GetAoS() << ", computed using the the free-stream velocity." << endl; - if (viscous) cout << "Reynolds number: " << config->GetReynolds() << ", computed using free-stream values."<< endl; - cout << "Only dimensional computation, the grid should be dimensional." << endl; - } - - cout <<"-- Input conditions:"<< endl; - - if (compressible) { - switch (config->GetKind_FluidModel()) { - - case STANDARD_AIR: - cout << "Fluid Model: STANDARD_AIR "<< endl; - cout << "Specific gas constant: " << config->GetGas_Constant(); - if (config->GetSystemMeasurements() == SI) cout << " N.m/kg.K." << endl; - else if (config->GetSystemMeasurements() == US) cout << " lbf.ft/slug.R." << endl; - cout << "Specific gas constant (non-dim): " << config->GetGas_ConstantND()<< endl; - cout << "Specific Heat Ratio: "<< Gamma << endl; - break; - - case IDEAL_GAS: - cout << "Fluid Model: IDEAL_GAS "<< endl; - cout << "Specific gas constant: " << config->GetGas_Constant() << " N.m/kg.K." << endl; - cout << "Specific gas constant (non-dim): " << config->GetGas_ConstantND()<< endl; - cout << "Specific Heat Ratio: "<< Gamma << endl; - break; - - case VW_GAS: - cout << "Fluid Model: Van der Waals "<< endl; - cout << "Specific gas constant: " << config->GetGas_Constant() << " N.m/kg.K." << endl; - cout << "Specific gas constant (non-dim): " << config->GetGas_ConstantND()<< endl; - cout << "Specific Heat Ratio: "<< Gamma << endl; - cout << "Critical Pressure: " << config->GetPressure_Critical() << " Pa." << endl; - cout << "Critical Temperature: " << config->GetTemperature_Critical() << " K." << endl; - cout << "Critical Pressure (non-dim): " << config->GetPressure_Critical() /config->GetPressure_Ref() << endl; - cout << "Critical Temperature (non-dim) : " << config->GetTemperature_Critical() /config->GetTemperature_Ref() << endl; - break; - - case PR_GAS: - cout << "Fluid Model: Peng-Robinson "<< endl; - cout << "Specific gas constant: " << config->GetGas_Constant() << " N.m/kg.K." << endl; - cout << "Specific gas constant (non-dim): " << config->GetGas_ConstantND()<< endl; - cout << "Specific Heat Ratio: "<< Gamma << endl; - cout << "Critical Pressure: " << config->GetPressure_Critical() << " Pa." << endl; - cout << "Critical Temperature: " << config->GetTemperature_Critical() << " K." << endl; - cout << "Critical Pressure (non-dim): " << config->GetPressure_Critical() /config->GetPressure_Ref() << endl; - cout << "Critical Temperature (non-dim) : " << config->GetTemperature_Critical() /config->GetTemperature_Ref() << endl; - break; - - } - if (viscous) { - switch (config->GetKind_ViscosityModel()) { - - case CONSTANT_VISCOSITY: - cout << "Viscosity Model: CONSTANT_VISCOSITY "<< endl; - cout << "Laminar Viscosity: " << config->GetMu_ConstantND()*Viscosity_Ref; - if (config->GetSystemMeasurements() == SI) cout << " N.s/m^2." << endl; - else if (config->GetSystemMeasurements() == US) cout << " lbf.s/ft^2." << endl; - cout << "Laminar Viscosity (non-dim): " << config->GetMu_ConstantND()<< endl; - break; - - case SUTHERLAND: - cout << "Viscosity Model: SUTHERLAND "<< endl; - cout << "Ref. Laminar Viscosity: " << config->GetMu_RefND()*Viscosity_Ref; - if (config->GetSystemMeasurements() == SI) cout << " N.s/m^2." << endl; - else if (config->GetSystemMeasurements() == US) cout << " lbf.s/ft^2." << endl; - cout << "Ref. Temperature: " << config->GetMu_Temperature_RefND()*config->GetTemperature_Ref(); - if (config->GetSystemMeasurements() == SI) cout << " K." << endl; - else if (config->GetSystemMeasurements() == US) cout << " R." << endl; - cout << "Sutherland Constant: "<< config->GetMu_SND()*config->GetTemperature_Ref(); - if (config->GetSystemMeasurements() == SI) cout << " K." << endl; - else if (config->GetSystemMeasurements() == US) cout << " R." << endl; - cout << "Laminar Viscosity (non-dim): " << config->GetMu_ConstantND()<< endl; - cout << "Ref. Temperature (non-dim): " << config->GetMu_Temperature_RefND()<< endl; - cout << "Sutherland constant (non-dim): "<< config->GetMu_SND()<< endl; - break; - - } - switch (config->GetKind_ConductivityModel()) { - - case CONSTANT_PRANDTL: - cout << "Conductivity Model: CONSTANT_PRANDTL "<< endl; - cout << "Prandtl: " << config->GetPrandtl_Lam()<< endl; - break; - - case CONSTANT_CONDUCTIVITY: - cout << "Conductivity Model: CONSTANT_CONDUCTIVITY "<< endl; - cout << "Molecular Conductivity: " << config->GetKt_ConstantND()*Conductivity_Ref<< " W/m^2.K." << endl; - cout << "Molecular Conductivity (non-dim): " << config->GetKt_ConstantND()<< endl; - break; - - } - } - } - - if (incompressible || freesurface) { - cout << "Bulk modulus: " << config->GetBulk_Modulus(); - if (config->GetSystemMeasurements() == SI) cout << " Pa." << endl; - else if (config->GetSystemMeasurements() == US) cout << " psf." << endl; - cout << "Artificial compressibility factor: " << config->GetArtComp_Factor(); - if (config->GetSystemMeasurements() == SI) cout << " Pa." << endl; - else if (config->GetSystemMeasurements() == US) cout << " psf." << endl; - } - - cout << "Free-stream static pressure: " << config->GetPressure_FreeStream(); - if (config->GetSystemMeasurements() == SI) cout << " Pa." << endl; - else if (config->GetSystemMeasurements() == US) cout << " psf." << endl; - - cout << "Free-stream total pressure: " << config->GetPressure_FreeStream() * pow( 1.0+Mach*Mach*0.5*(Gamma-1.0), Gamma/(Gamma-1.0) ); - if (config->GetSystemMeasurements() == SI) cout << " Pa." << endl; - else if (config->GetSystemMeasurements() == US) cout << " psf." << endl; - - if (compressible) { - cout << "Free-stream temperature: " << config->GetTemperature_FreeStream(); - if (config->GetSystemMeasurements() == SI) cout << " K." << endl; - else if (config->GetSystemMeasurements() == US) cout << " R." << endl; - } - - cout << "Free-stream density: " << config->GetDensity_FreeStream(); - if (config->GetSystemMeasurements() == SI) cout << " kg/m^3." << endl; - else if (config->GetSystemMeasurements() == US) cout << " slug/ft^3." << endl; - - if (nDim == 2) { - cout << "Free-stream velocity: (" << config->GetVelocity_FreeStream()[0] << ", "; - cout << config->GetVelocity_FreeStream()[1] << ")"; - } - if (nDim == 3) { - cout << "Free-stream velocity: (" << config->GetVelocity_FreeStream()[0] << ", "; - cout << config->GetVelocity_FreeStream()[1] << ", " << config->GetVelocity_FreeStream()[2] << ")"; - } - if (config->GetSystemMeasurements() == SI) cout << " m/s. "; - else if (config->GetSystemMeasurements() == US) cout << " ft/s. "; - - cout << "Magnitude: " << config->GetModVel_FreeStream(); - if (config->GetSystemMeasurements() == SI) cout << " m/s." << endl; - else if (config->GetSystemMeasurements() == US) cout << " ft/s." << endl; - - if (compressible) { - cout << "Free-stream total energy per unit mass: " << config->GetEnergy_FreeStream(); - if (config->GetSystemMeasurements() == SI) cout << " m^2/s^2." << endl; - else if (config->GetSystemMeasurements() == US) cout << " ft^2/s^2." << endl; - } - - if (viscous) { - cout << "Free-stream viscosity: " << config->GetViscosity_FreeStream(); - if (config->GetSystemMeasurements() == SI) cout << " N.s/m^2." << endl; - else if (config->GetSystemMeasurements() == US) cout << " lbf.s/ft^2." << endl; - if (turbulent) { - cout << "Free-stream turb. kinetic energy per unit mass: " << config->GetTke_FreeStream(); - if (config->GetSystemMeasurements() == SI) cout << " m^2/s^2." << endl; - else if (config->GetSystemMeasurements() == US) cout << " ft^2/s^2." << endl; - cout << "Free-stream specific dissipation: " << config->GetOmega_FreeStream(); - if (config->GetSystemMeasurements() == SI) cout << " 1/s." << endl; - else if (config->GetSystemMeasurements() == US) cout << " 1/s." << endl; - } - } - - if (unsteady) { cout << "Total time: " << config->GetTotal_UnstTime() << " s. Time step: " << config->GetDelta_UnstTime() << " s." << endl; } - - /*--- Print out reference values. ---*/ - - cout <<"-- Reference values:"<< endl; - - if (compressible) { - cout << "Reference specific gas constant: " << config->GetGas_Constant_Ref(); - if (config->GetSystemMeasurements() == SI) cout << " N.m/kg.K." << endl; - else if (config->GetSystemMeasurements() == US) cout << " lbf.ft/slug.R." << endl; - } - - cout << "Reference pressure: " << config->GetPressure_Ref(); - if (config->GetSystemMeasurements() == SI) cout << " Pa." << endl; - else if (config->GetSystemMeasurements() == US) cout << " psf." << endl; - - if (compressible) { - cout << "Reference temperature: " << config->GetTemperature_Ref(); - if (config->GetSystemMeasurements() == SI) cout << " K." << endl; - else if (config->GetSystemMeasurements() == US) cout << " R." << endl; - } - - cout << "Reference density: " << config->GetDensity_Ref(); - if (config->GetSystemMeasurements() == SI) cout << " kg/m^3." << endl; - else if (config->GetSystemMeasurements() == US) cout << " slug/ft^3." << endl; - - cout << "Reference velocity: " << config->GetVelocity_Ref(); - if (config->GetSystemMeasurements() == SI) cout << " m/s." << endl; - else if (config->GetSystemMeasurements() == US) cout << " ft/s." << endl; - - if (compressible) { - cout << "Reference energy per unit mass: " << config->GetEnergy_Ref(); - if (config->GetSystemMeasurements() == SI) cout << " m^2/s^2." << endl; - else if (config->GetSystemMeasurements() == US) cout << " ft^2/s^2." << endl; - } - - if (incompressible || freesurface) { - cout << "Reference length: " << config->GetLength_Ref(); - if (config->GetSystemMeasurements() == SI) cout << " m." << endl; - else if (config->GetSystemMeasurements() == US) cout << " in." << endl; - } - - if (viscous) { - cout << "Reference viscosity: " << config->GetViscosity_Ref(); - if (config->GetSystemMeasurements() == SI) cout << " N.s/m^2." << endl; - else if (config->GetSystemMeasurements() == US) cout << " lbf.s/ft^2." << endl; - if (compressible){ - cout << "Reference conductivity: " << config->GetConductivity_Ref(); - if (config->GetSystemMeasurements() == SI) cout << " W/m^2.K." << endl; - else if (config->GetSystemMeasurements() == US) cout << " lbf/ft.s.R." << endl; - } - } - - - if (unsteady) cout << "Reference time: " << config->GetTime_Ref() <<" s." << endl; - - /*--- Print out resulting non-dim values here. ---*/ - - cout << "-- Resulting non-dimensional state:" << endl; - cout << "Mach number (non-dim): " << config->GetMach() << endl; - if (viscous) { - cout << "Reynolds number (non-dim): " << config->GetReynolds() <<". Re length: " << config->GetLength_Reynolds(); - if (config->GetSystemMeasurements() == SI) cout << " m." << endl; - else if (config->GetSystemMeasurements() == US) cout << " ft." << endl; - } - if (gravity) { - cout << "Froude number (non-dim): " << Froude << endl; - cout << "Lenght of the baseline wave (non-dim): " << 2.0*PI_NUMBER*Froude*Froude << endl; - } - - if (compressible) { - cout << "Specific gas constant (non-dim): " << config->GetGas_ConstantND() << endl; - cout << "Free-stream temperature (non-dim): " << config->GetTemperature_FreeStreamND() << endl; - } - - cout << "Free-stream pressure (non-dim): " << config->GetPressure_FreeStreamND() << endl; - - cout << "Free-stream density (non-dim): " << config->GetDensity_FreeStreamND() << endl; - - if (nDim == 2) { - cout << "Free-stream velocity (non-dim): (" << config->GetVelocity_FreeStreamND()[0] << ", "; - cout << config->GetVelocity_FreeStreamND()[1] << "). "; - } else { - cout << "Free-stream velocity (non-dim): (" << config->GetVelocity_FreeStreamND()[0] << ", "; - cout << config->GetVelocity_FreeStreamND()[1] << ", " << config->GetVelocity_FreeStreamND()[2] << "). "; - } - cout << "Magnitude: " << config->GetModVel_FreeStreamND() << endl; - - if (compressible) - cout << "Free-stream total energy per unit mass (non-dim): " << config->GetEnergy_FreeStreamND() << endl; - - if (viscous) { - cout << "Free-stream viscosity (non-dim): " << config->GetViscosity_FreeStreamND() << endl; - if (turbulent) { - cout << "Free-stream turb. kinetic energy (non-dim): " << config->GetTke_FreeStreamND() << endl; - cout << "Free-stream specific dissipation (non-dim): " << config->GetOmega_FreeStreamND() << endl; - } - } - - if (unsteady) { - cout << "Total time (non-dim): " << config->GetTotal_UnstTimeND() << endl; - cout << "Time step (non-dim): " << config->GetDelta_UnstTimeND() << endl; - } - - cout << endl; - - } - -} - -void CEulerSolver::SetInitialCondition(CGeometry **geometry, CSolver ***solver_container, CConfig *config, unsigned long ExtIter) { - - unsigned long iPoint, Point_Fine; - unsigned short iMesh, iChildren, iVar, iDim; - su2double Density, Pressure, yFreeSurface, PressFreeSurface, Froude, yCoord, Velx, Vely, Velz, RhoVelx, RhoVely, RhoVelz, YCoord = 0.0, - ZCoord = 0.0, DensityInc, ViscosityInc, Heaviside, LevelSet, lambda, Area_Children, Area_Parent, LevelSet_Fine, epsilon, - *Solution_Fine, *Solution, PressRef, yCoordRef; - - unsigned short nDim = geometry[MESH_0]->GetnDim(); - bool restart = (config->GetRestart() || config->GetRestart_Flow()); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool rans = ((config->GetKind_Solver() == RANS) || - (config->GetKind_Solver() == ADJ_RANS) || - (config->GetKind_Solver() == DISC_ADJ_RANS)); - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - bool gravity = (config->GetGravityForce() == YES); - bool engine_intake = config->GetEngine_Intake(); - - - /*--- Set the location and value of the free-surface ---*/ - - if (freesurface) { - - for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { - - for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { - - /*--- Set initial boundary condition at iter 0 ---*/ - - if ((ExtIter == 0) && (!restart)) { - - /*--- Compute the level set value in all the MG levels (basic case, distance to - the Y/Z plane, and interpolate the solution to the coarse levels ---*/ - - if (iMesh == MESH_0) { - YCoord = geometry[iMesh]->node[iPoint]->GetCoord(1); - if (nDim == 2) LevelSet = YCoord - config->GetFreeSurface_Zero(); - else { - ZCoord = geometry[iMesh]->node[iPoint]->GetCoord(2); - LevelSet = ZCoord - config->GetFreeSurface_Zero(); - } - solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(nDim+1, LevelSet); - } - else { - Area_Parent = geometry[iMesh]->node[iPoint]->GetVolume(); - LevelSet = 0.0; - for (iChildren = 0; iChildren < geometry[iMesh]->node[iPoint]->GetnChildren_CV(); iChildren++) { - Point_Fine = geometry[iMesh]->node[iPoint]->GetChildren_CV(iChildren); - Area_Children = geometry[iMesh-1]->node[Point_Fine]->GetVolume(); - LevelSet_Fine = solver_container[iMesh-1][FLOW_SOL]->node[Point_Fine]->GetSolution(nDim+1); - LevelSet += LevelSet_Fine*Area_Children/Area_Parent; - } - solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(nDim+1, LevelSet); - } - - /*--- Compute the flow solution using the level set value. ---*/ - - epsilon = config->GetFreeSurface_Thickness(); - Heaviside = 0.0; - if (LevelSet < -epsilon) Heaviside = 1.0; - if (fabs(LevelSet) <= epsilon) Heaviside = 1.0 - (0.5*(1.0+(LevelSet/epsilon)+(1.0/PI_NUMBER)*sin(PI_NUMBER*LevelSet/epsilon))); - if (LevelSet > epsilon) Heaviside = 0.0; - - /*--- Set the value of the incompressible density for free surface flows (density ratio g/l) ---*/ - - lambda = config->GetRatioDensity(); - DensityInc = (lambda + (1.0 - lambda)*Heaviside)*config->GetDensity_FreeStreamND(); - solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetDensityInc(DensityInc); - - /*--- Set the value of the incompressible viscosity for free surface flows (viscosity ratio g/l) ---*/ - - lambda = config->GetRatioViscosity(); - ViscosityInc = (lambda + (1.0 - lambda)*Heaviside)*config->GetViscosity_FreeStreamND(); - solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetLaminarViscosityInc(ViscosityInc); - - /*--- Update solution with the new pressure ---*/ - - yFreeSurface = config->GetFreeSurface_Zero(); - PressFreeSurface = solver_container[iMesh][FLOW_SOL]->GetPressure_Inf(); - Density = solver_container[iMesh][FLOW_SOL]->node[iPoint]->GetDensityInc(); - Froude = config->GetFroude(); - yCoord = geometry[iMesh]->node[iPoint]->GetCoord(nDim-1); - Pressure = PressFreeSurface + Density*((yFreeSurface-yCoord)/(Froude*Froude)); - solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(0, Pressure); - - /*--- Update solution with the new velocity ---*/ - - Velx = solver_container[iMesh][FLOW_SOL]->GetVelocity_Inf(0); - Vely = solver_container[iMesh][FLOW_SOL]->GetVelocity_Inf(1); - RhoVelx = Velx * Density; RhoVely = Vely * Density; - solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(1, RhoVelx); - solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(2, RhoVely); - if (nDim == 3) { - Velz = solver_container[iMesh][FLOW_SOL]->GetVelocity_Inf(2); - RhoVelz = Velz * Density; - solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(3, RhoVelz); - } - - } - - } - - /*--- Set the MPI communication ---*/ - - solver_container[iMesh][FLOW_SOL]->Set_MPI_Solution(geometry[iMesh], config); - solver_container[iMesh][FLOW_SOL]->Set_MPI_Solution_Old(geometry[iMesh], config); - - } - - } - - /*--- Set the pressure value in simulations with gravity ---*/ - - - if (incompressible && gravity ) { - - - for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { - - for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { - - /*--- Set initial boundary condition at iter 0 ---*/ - - if ((ExtIter == 0) && (!restart)) { - - /*--- Update solution with the new pressure ---*/ - - PressRef = solver_container[iMesh][FLOW_SOL]->GetPressure_Inf(); - Density = solver_container[iMesh][FLOW_SOL]->GetDensity_Inf(); - yCoordRef = 0.0; - yCoord = geometry[iMesh]->node[iPoint]->GetCoord(nDim-1); - Pressure = PressRef + Density*((yCoordRef-yCoord)/(config->GetFroude()*config->GetFroude())); - solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(0, Pressure); - - } - - } - - /*--- Set the MPI communication ---*/ - - solver_container[iMesh][FLOW_SOL]->Set_MPI_Solution(geometry[iMesh], config); - solver_container[iMesh][FLOW_SOL]->Set_MPI_Solution_Old(geometry[iMesh], config); - - } - - } - - - /*--- Set subsonic initial condition for engine intakes ---*/ - - if (engine_intake) { - - /*--- Set initial boundary condition at iteration 0 ---*/ - - if ((ExtIter == 0) && (!restart)) { - - su2double Velocity_Box[3] = {0.0, 0.0, 0.0}, Velocity_BoxND[3] = {0.0, 0.0, 0.0}, Viscosity_Box, - Density_Box, Density_BoxND, Pressure_Box, Pressure_BoxND, ModVel_Box, ModVel_BoxND, Energy_BoxND, - T_ref = 0.0, S = 0.0, Mu_ref = 0.0, *Coord, MinCoordValues[3], - MaxCoordValues[3], *Subsonic_Engine_Box; - - su2double Mach = 0.40; - su2double Alpha = config->GetAoA()*PI_NUMBER/180.0; - su2double Beta = config->GetAoS()*PI_NUMBER/180.0; - - su2double Gamma_Minus_One = Gamma - 1.0; - su2double Gas_Constant = config->GetGas_Constant(); - - su2double Temperature_Box = config->GetTemperature_FreeStream(); - su2double Mach2Vel_Box = sqrt(Gamma*Gas_Constant*Temperature_Box); - - for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { - - for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { - - Velocity_Box[0] = cos(Alpha)*cos(Beta)*Mach*Mach2Vel_Box; - Velocity_Box[1] = sin(Beta)*Mach*Mach2Vel_Box; - Velocity_Box[2] = sin(Alpha)*cos(Beta)*Mach*Mach2Vel_Box; - - ModVel_Box = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - ModVel_Box += Velocity_Box[iDim]*Velocity_Box[iDim]; - } - ModVel_Box = sqrt(ModVel_Box); - - if (config->GetViscous()) { - if (config->GetSystemMeasurements() == SI) { T_ref = 273.15; S = 110.4; Mu_ref = 1.716E-5; } - if (config->GetSystemMeasurements() == US) { T_ref = 518.7; S = 198.72; Mu_ref = 3.62E-7; } - Viscosity_Box = Mu_ref*(pow(Temperature_Box/T_ref, 1.5) * (T_ref+S)/(Temperature_Box+S)); - Density_Box = config->GetReynolds()*Viscosity_Box/(ModVel_Box*config->GetLength_Reynolds()); - Pressure_Box = Density_Box*Gas_Constant*Temperature_Box; - } - else { - Pressure_Box = config->GetPressure_FreeStream(); - Density_Box = Pressure_Box/(Gas_Constant*Temperature_Box); - } - - Density_BoxND = Density_Box/config->GetDensity_Ref(); - Pressure_BoxND = Pressure_Box/config->GetPressure_Ref(); - - for (iDim = 0; iDim < nDim; iDim++) { - Velocity_BoxND[iDim] = Velocity_Box[iDim]/config->GetVelocity_Ref(); - } - - ModVel_BoxND = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - ModVel_BoxND += Velocity_BoxND[iDim]*Velocity_BoxND[iDim]; - } - ModVel_BoxND = sqrt(ModVel_BoxND); - - Energy_BoxND = Pressure_BoxND/(Density_BoxND*Gamma_Minus_One)+0.5*ModVel_BoxND*ModVel_BoxND; - - Coord = geometry[iMesh]->node[iPoint]->GetCoord(); - - Subsonic_Engine_Box = config->GetSubsonic_Engine_Box(); - - MinCoordValues[0] = Subsonic_Engine_Box[0]; MinCoordValues[1] = Subsonic_Engine_Box[1]; MinCoordValues[2] = Subsonic_Engine_Box[2]; - MaxCoordValues[0] = Subsonic_Engine_Box[3]; MaxCoordValues[1] = Subsonic_Engine_Box[4]; MaxCoordValues[2] = Subsonic_Engine_Box[5]; - - if (((Coord[0] >= MinCoordValues[0]) && (Coord[0] <= MaxCoordValues[0])) && - ((Coord[1] >= MinCoordValues[1]) && (Coord[1] <= MaxCoordValues[1])) && - ((Coord[2] >= MinCoordValues[2]) && (Coord[2] <= MaxCoordValues[2]))) { - - solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(0, Density_BoxND); - for (iDim = 0; iDim < nDim; iDim++) - solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(iDim+1, Density_BoxND*Velocity_BoxND[iDim]); - solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(nVar-1, Density_BoxND*Energy_BoxND); - - solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution_Old(0, Density_BoxND); - for (iDim = 0; iDim < nDim; iDim++) - solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution_Old(iDim+1, Density_BoxND*Velocity_BoxND[iDim]); - solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution_Old(nVar-1, Density_BoxND*Energy_BoxND); - - } - - } - - /*--- Set the MPI communication ---*/ - - solver_container[iMesh][FLOW_SOL]->Set_MPI_Solution(geometry[iMesh], config); - solver_container[iMesh][FLOW_SOL]->Set_MPI_Solution_Old(geometry[iMesh], config); - - } - - } - - } - - /*--- If restart solution, then interpolate the flow solution to - all the multigrid levels, this is important with the dual time strategy ---*/ - - if (restart && (ExtIter == 0)) { - - Solution = new su2double[nVar]; - for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++) { - for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { - Area_Parent = geometry[iMesh]->node[iPoint]->GetVolume(); - for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; - for (iChildren = 0; iChildren < geometry[iMesh]->node[iPoint]->GetnChildren_CV(); iChildren++) { - Point_Fine = geometry[iMesh]->node[iPoint]->GetChildren_CV(iChildren); - Area_Children = geometry[iMesh-1]->node[Point_Fine]->GetVolume(); - Solution_Fine = solver_container[iMesh-1][FLOW_SOL]->node[Point_Fine]->GetSolution(); - for (iVar = 0; iVar < nVar; iVar++) { - Solution[iVar] += Solution_Fine[iVar]*Area_Children/Area_Parent; - } - } - solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(Solution); - } - solver_container[iMesh][FLOW_SOL]->Set_MPI_Solution(geometry[iMesh], config); - } - delete [] Solution; - - /*--- Interpolate the turblence variable also, if needed ---*/ - - if (rans) { - - unsigned short nVar_Turb = solver_container[MESH_0][TURB_SOL]->GetnVar(); - Solution = new su2double[nVar_Turb]; - for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++) { - for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { - Area_Parent = geometry[iMesh]->node[iPoint]->GetVolume(); - for (iVar = 0; iVar < nVar_Turb; iVar++) Solution[iVar] = 0.0; - for (iChildren = 0; iChildren < geometry[iMesh]->node[iPoint]->GetnChildren_CV(); iChildren++) { - Point_Fine = geometry[iMesh]->node[iPoint]->GetChildren_CV(iChildren); - Area_Children = geometry[iMesh-1]->node[Point_Fine]->GetVolume(); - Solution_Fine = solver_container[iMesh-1][TURB_SOL]->node[Point_Fine]->GetSolution(); - for (iVar = 0; iVar < nVar_Turb; iVar++) { - Solution[iVar] += Solution_Fine[iVar]*Area_Children/Area_Parent; - } - } - solver_container[iMesh][TURB_SOL]->node[iPoint]->SetSolution(Solution); - } - solver_container[iMesh][TURB_SOL]->Set_MPI_Solution(geometry[iMesh], config); - solver_container[iMesh][TURB_SOL]->Postprocessing(geometry[iMesh], solver_container[iMesh], config, iMesh); - } - delete [] Solution; - } - - } - - /*--- The value of the solution for the first iteration of the dual time ---*/ - - if (dual_time && (ExtIter == 0 || (restart && (long)ExtIter == config->GetUnst_RestartIter()))) { - - /*--- Push back the initial condition to previous solution containers - for a 1st-order restart or when simply intitializing to freestream. ---*/ - - for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { - for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { - solver_container[iMesh][FLOW_SOL]->node[iPoint]->Set_Solution_time_n(); - solver_container[iMesh][FLOW_SOL]->node[iPoint]->Set_Solution_time_n1(); - if (rans) { - solver_container[iMesh][TURB_SOL]->node[iPoint]->Set_Solution_time_n(); - solver_container[iMesh][TURB_SOL]->node[iPoint]->Set_Solution_time_n1(); - } - } - } - - if ((restart && (long)ExtIter == config->GetUnst_RestartIter()) && - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { - - /*--- Load an additional restart file for a 2nd-order restart ---*/ - - solver_container[MESH_0][FLOW_SOL]->LoadRestart(geometry, solver_container, config, SU2_TYPE::Int(config->GetUnst_RestartIter()-1)); - - /*--- Load an additional restart file for the turbulence model ---*/ - if (rans) - solver_container[MESH_0][TURB_SOL]->LoadRestart(geometry, solver_container, config, SU2_TYPE::Int(config->GetUnst_RestartIter()-1)); - - /*--- Push back this new solution to time level N. ---*/ - - for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { - for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { - solver_container[iMesh][FLOW_SOL]->node[iPoint]->Set_Solution_time_n(); - if (rans) { - solver_container[iMesh][TURB_SOL]->node[iPoint]->Set_Solution_time_n(); - } - } - } - } - } -} - -void CEulerSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { - - unsigned long ErrorCounter = 0; - -#ifdef HAVE_MPI - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - unsigned long ExtIter = config->GetExtIter(); - bool adjoint = config->GetAdjoint(); - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool low_fidelity = (config->GetLowFidelitySim() && (iMesh == MESH_1)); - bool second_order = ((config->GetSpatialOrder_Flow() == SECOND_ORDER) || (config->GetSpatialOrder_Flow() == SECOND_ORDER_LIMITER) || (adjoint && config->GetKind_ConvNumScheme_AdjFlow() == ROE)); - bool limiter = ((config->GetSpatialOrder_Flow() == SECOND_ORDER_LIMITER) && (!low_fidelity) && (ExtIter <= config->GetLimiterIter())); - bool center = (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED) || (adjoint && config->GetKind_ConvNumScheme_AdjFlow() == SPACE_CENTERED); - bool center_jst = center && (config->GetKind_Centered_Flow() == JST); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool engine = ((config->GetnMarker_EngineInflow() != 0) || (config->GetnMarker_EngineBleed() != 0) || (config->GetnMarker_EngineExhaust() != 0)); - bool actuator_disk = ((config->GetnMarker_ActDisk_Inlet() != 0) || (config->GetnMarker_ActDisk_Outlet() != 0)); - bool fixed_cl = config->GetFixed_CL_Mode(); - - /*--- Compute the engine properties ---*/ - - if (engine) { GetEngine_Properties(geometry, config, iMesh, Output); } - - /*--- Compute the actuator disk properties ---*/ - - if (actuator_disk) { GetActuatorDisk_Properties(geometry, config, iMesh, Output); } - - /*--- Update the angle of attack at the far-field for fixed CL calculations. ---*/ - - if (fixed_cl) { SetFarfield_AoA(geometry, solver_container, config, iMesh, Output); } - - /*--- Compute distance function to zero level set (Set LevelSet and Distance primitive variables)---*/ - - if (freesurface) { SetFreeSurface_Distance(geometry, config); } - - /*--- Set the primitive variables ---*/ - - ErrorCounter = SetPrimitive_Variables(solver_container, config, Output); - - /*--- Upwind second order reconstruction ---*/ - - if ((second_order && !center) && ((iMesh == MESH_0) || low_fidelity) && !Output) { - - /*--- Gradient computation ---*/ - - if (config->GetKind_Gradient_Method() == GREEN_GAUSS) { - SetPrimitive_Gradient_GG(geometry, config); - // if (compressible && !ideal_gas) SetSecondary_Gradient_GG(geometry, config); - } - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { - SetPrimitive_Gradient_LS(geometry, config); - // if (compressible && !ideal_gas) SetSecondary_Gradient_LS(geometry, config); - } - - - /*--- Limiter computation ---*/ - - if ((limiter) && (iMesh == MESH_0) && !Output) { - SetPrimitive_Limiter(geometry, config); - // if (compressible && !ideal_gas) SetSecondary_Limiter(geometry, config); - } - - } - - /*--- Artificial dissipation ---*/ - - if (center && !Output) { - SetMax_Eigenvalue(geometry, config); - if ((center_jst) && ((iMesh == MESH_0) || low_fidelity)) { - SetDissipation_Switch(geometry, config); - SetUndivided_Laplacian(geometry, config); - } - } - - /*--- Initialize the Jacobian matrices ---*/ - - if (implicit && !config->GetDiscrete_Adjoint()) Jacobian.SetValZero(); - - /*--- Error message ---*/ - - if (config->GetConsole_Output_Verb() == VERB_HIGH) { -#ifdef HAVE_MPI - unsigned long MyErrorCounter = ErrorCounter; ErrorCounter = 0; - SU2_MPI::Allreduce(&MyErrorCounter, &ErrorCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#endif - if (iMesh == MESH_0) config->SetNonphysical_Points(ErrorCounter); - } - -} - -void CEulerSolver::Postprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, - unsigned short iMesh) { } - -unsigned long CEulerSolver::SetPrimitive_Variables(CSolver **solver_container, CConfig *config, bool Output) { - - unsigned long iPoint, ErrorCounter = 0; - bool RightSol = true; - - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - - for (iPoint = 0; iPoint < nPoint; iPoint ++) { - - /*--- Initialize the non-physical points vector ---*/ - - node[iPoint]->SetNon_Physical(false); - - /*--- Incompressible flow, primitive variables nDim+3, (P, vx, vy, vz, rho, beta), - FreeSurface Incompressible flow, primitive variables nDim+4, (P, vx, vy, vz, rho, beta, dist), - Compressible flow, primitive variables nDim+5, (T, vx, vy, vz, P, rho, h, c, lamMu, eddyMu, ThCond, Cp) ---*/ - - if (compressible) { - RightSol = node[iPoint]->SetPrimVar_Compressible(FluidModel); - node[iPoint]->SetSecondaryVar_Compressible(FluidModel); - } - - if (incompressible) { - RightSol = node[iPoint]->SetPrimVar_Incompressible(Density_Inf, config); - } - - - if (freesurface){ - RightSol = node[iPoint]->SetPrimVar_FreeSurface(config); - } - - if (!RightSol) { node[iPoint]->SetNon_Physical(true); ErrorCounter++; } - - /*--- Initialize the convective, source and viscous residual vector ---*/ - - if (!Output) LinSysRes.SetBlock_Zero(iPoint); - - } - - return ErrorCounter; -} -void CEulerSolver::SetTime_Step(CGeometry *geometry, CSolver **solver_container, CConfig *config, - unsigned short iMesh, unsigned long Iteration) { - - su2double *Normal, Area, Vol, Mean_SoundSpeed = 0.0, Mean_ProjVel = 0.0, Mean_BetaInc2, Lambda, Local_Delta_Time, Mean_DensityInc, Mean_LevelSet, - Global_Delta_Time = 1E6, Global_Delta_UnstTimeND, ProjVel, ProjVel_i, ProjVel_j, Delta = 0.0, a, b, c, e, f; - unsigned long iEdge, iVertex, iPoint, jPoint; - unsigned short iDim, iMarker; - - su2double epsilon = config->GetFreeSurface_Thickness(); - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool grid_movement = config->GetGrid_Movement(); - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - - Min_Delta_Time = 1.E6; Max_Delta_Time = 0.0; - - /*--- Set maximum inviscid eigenvalue to zero, and compute sound speed ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) - node[iPoint]->SetMax_Lambda_Inv(0.0); - - /*--- Loop interior edges ---*/ - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Point identification, Normal vector and area ---*/ - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - - Normal = geometry->edge[iEdge]->GetNormal(); - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); - - /*--- Mean Values ---*/ - - if (compressible) { - Mean_ProjVel = 0.5 * (node[iPoint]->GetProjVel(Normal) + node[jPoint]->GetProjVel(Normal)); - Mean_SoundSpeed = 0.5 * (node[iPoint]->GetSoundSpeed() + node[jPoint]->GetSoundSpeed()) * Area; - } - if (incompressible) { - Mean_ProjVel = 0.5 * (node[iPoint]->GetProjVel(Normal) + node[jPoint]->GetProjVel(Normal)); - Mean_BetaInc2 = 0.5 * (node[iPoint]->GetBetaInc2() + node[jPoint]->GetBetaInc2()); - Mean_DensityInc = 0.5 * (node[iPoint]->GetDensityInc() + node[jPoint]->GetDensityInc()); - Mean_SoundSpeed = sqrt(Mean_ProjVel*Mean_ProjVel + (Mean_BetaInc2/Mean_DensityInc)*Area*Area); - } - if (freesurface) { - Mean_ProjVel = 0.5 * (node[iPoint]->GetProjVel(Normal) + node[jPoint]->GetProjVel(Normal)); - Mean_BetaInc2 = 0.5 * (node[iPoint]->GetBetaInc2() + node[jPoint]->GetBetaInc2()); - Mean_DensityInc = 0.5 * (node[iPoint]->GetDensityInc() + node[jPoint]->GetDensityInc()); - Mean_LevelSet = 0.5 * (node[iPoint]->GetLevelSet() + node[jPoint]->GetLevelSet()); - - if (Mean_LevelSet < -epsilon) Delta = 0.0; - if (fabs(Mean_LevelSet) <= epsilon) Delta = 0.5*(1.0+cos(PI_NUMBER*Mean_LevelSet/epsilon))/epsilon; - if (Mean_LevelSet > epsilon) Delta = 0.0; - - a = Mean_BetaInc2/Mean_DensityInc, b = Mean_LevelSet/Mean_DensityInc; - c = (1.0 - config->GetRatioDensity())*Delta*config->GetDensity_FreeStreamND(); - e = (2.0*fabs(Mean_ProjVel) + b*c*fabs(Mean_ProjVel)), f = sqrt(4.0*a*Area*Area + e*e); - Mean_SoundSpeed = 0.5*f; - Mean_ProjVel = 0.5*e; - - } - - /*--- Adjustment for grid movement ---*/ - - if (grid_movement) { - su2double *GridVel_i = geometry->node[iPoint]->GetGridVel(); - su2double *GridVel_j = geometry->node[jPoint]->GetGridVel(); - ProjVel_i = 0.0; ProjVel_j = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - ProjVel_i += GridVel_i[iDim]*Normal[iDim]; - ProjVel_j += GridVel_j[iDim]*Normal[iDim]; - } - Mean_ProjVel -= 0.5 * (ProjVel_i + ProjVel_j); - } - - /*--- Inviscid contribution ---*/ - - Lambda = fabs(Mean_ProjVel) + Mean_SoundSpeed; - if (geometry->node[iPoint]->GetDomain()) node[iPoint]->AddMax_Lambda_Inv(Lambda); - if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddMax_Lambda_Inv(Lambda); - - } - - /*--- Loop boundary edges ---*/ - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - - /*--- Point identification, Normal vector and area ---*/ - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); - - /*--- Mean Values ---*/ - - if (compressible) { - Mean_ProjVel = node[iPoint]->GetProjVel(Normal); - Mean_SoundSpeed = node[iPoint]->GetSoundSpeed() * Area; - } - if (incompressible) { - Mean_ProjVel = node[iPoint]->GetProjVel(Normal); - Mean_BetaInc2 = node[iPoint]->GetBetaInc2(); - Mean_DensityInc = node[iPoint]->GetDensityInc(); - Mean_SoundSpeed = sqrt(Mean_ProjVel*Mean_ProjVel + (Mean_BetaInc2/Mean_DensityInc)*Area*Area); - } - if (freesurface) { - Mean_ProjVel = node[iPoint]->GetProjVel(Normal); - Mean_BetaInc2 = node[iPoint]->GetBetaInc2(); - Mean_DensityInc = node[iPoint]->GetDensityInc(); - Mean_LevelSet = node[iPoint]->GetLevelSet(); - - if (Mean_LevelSet < -epsilon) Delta = 0.0; - if (fabs(Mean_LevelSet) <= epsilon) Delta = 0.5*(1.0+cos(PI_NUMBER*Mean_LevelSet/epsilon))/epsilon; - if (Mean_LevelSet > epsilon) Delta = 0.0; - - a = Mean_BetaInc2/Mean_DensityInc; b = Mean_LevelSet/Mean_DensityInc; - c = (1.0 - config->GetRatioDensity())*Delta*config->GetDensity_FreeStreamND(); - e = (2.0*fabs(Mean_ProjVel) + b*c*fabs(Mean_ProjVel)); f = sqrt(4.0*a*Area*Area + e*e); - Mean_SoundSpeed = 0.5*f; - Mean_ProjVel = 0.5*e; - } - - /*--- Adjustment for grid movement ---*/ - - if (grid_movement) { - su2double *GridVel = geometry->node[iPoint]->GetGridVel(); - ProjVel = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - ProjVel += GridVel[iDim]*Normal[iDim]; - Mean_ProjVel -= ProjVel; - } - - /*--- Inviscid contribution ---*/ - Lambda = fabs(Mean_ProjVel) + Mean_SoundSpeed; - if (geometry->node[iPoint]->GetDomain()) { - node[iPoint]->AddMax_Lambda_Inv(Lambda); - } - - } - } - - /*--- Each element uses their own speed, steady state simulation ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - Vol = geometry->node[iPoint]->GetVolume(); - - if (Vol != 0.0) { - Local_Delta_Time = config->GetCFL(iMesh)*Vol / node[iPoint]->GetMax_Lambda_Inv(); - Global_Delta_Time = min(Global_Delta_Time, Local_Delta_Time); - Min_Delta_Time = min(Min_Delta_Time, Local_Delta_Time); - Max_Delta_Time = max(Max_Delta_Time, Local_Delta_Time); - if (Local_Delta_Time > config->GetMax_DeltaTime()) - Local_Delta_Time = config->GetMax_DeltaTime(); - node[iPoint]->SetDelta_Time(Local_Delta_Time); - } - else { - node[iPoint]->SetDelta_Time(0.0); - } - - } - - - /*--- Compute the max and the min dt (in parallel) ---*/ - if (config->GetConsole_Output_Verb() == VERB_HIGH) { -#ifdef HAVE_MPI - su2double rbuf_time, sbuf_time; - sbuf_time = Min_Delta_Time; - SU2_MPI::Reduce(&sbuf_time, &rbuf_time, 1, MPI_DOUBLE, MPI_MIN, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Bcast(&rbuf_time, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - Min_Delta_Time = rbuf_time; - - sbuf_time = Max_Delta_Time; - SU2_MPI::Reduce(&sbuf_time, &rbuf_time, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Bcast(&rbuf_time, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - Max_Delta_Time = rbuf_time; -#endif - } - - /*--- For exact time solution use the minimum delta time of the whole mesh ---*/ - - if (config->GetUnsteady_Simulation() == TIME_STEPPING) { -#ifdef HAVE_MPI - su2double rbuf_time, sbuf_time; - sbuf_time = Global_Delta_Time; - SU2_MPI::Reduce(&sbuf_time, &rbuf_time, 1, MPI_DOUBLE, MPI_MIN, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Bcast(&rbuf_time, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - Global_Delta_Time = rbuf_time; -#endif - for (iPoint = 0; iPoint < nPointDomain; iPoint++) - node[iPoint]->SetDelta_Time(Global_Delta_Time); - } - - /*--- Recompute the unsteady time step for the dual time strategy - if the unsteady CFL is diferent from 0 ---*/ - - if ((dual_time) && (Iteration == 0) && (config->GetUnst_CFL() != 0.0) && (iMesh == MESH_0)) { - Global_Delta_UnstTimeND = config->GetUnst_CFL()*Global_Delta_Time/config->GetCFL(iMesh); - -#ifdef HAVE_MPI - su2double rbuf_time, sbuf_time; - sbuf_time = Global_Delta_UnstTimeND; - SU2_MPI::Reduce(&sbuf_time, &rbuf_time, 1, MPI_DOUBLE, MPI_MIN, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Bcast(&rbuf_time, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - Global_Delta_UnstTimeND = rbuf_time; -#endif - config->SetDelta_UnstTimeND(Global_Delta_UnstTimeND); - } - - /*--- The pseudo local time (explicit integration) cannot be greater than the physical time ---*/ - - if (dual_time) - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - if (!implicit) { - Local_Delta_Time = min((2.0/3.0)*config->GetDelta_UnstTimeND(), node[iPoint]->GetDelta_Time()); - node[iPoint]->SetDelta_Time(Local_Delta_Time); - } - } - -} - -void CEulerSolver::Centered_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config, unsigned short iMesh, unsigned short iRKStep) { - - unsigned long iEdge, iPoint, jPoint; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool second_order = ((config->GetKind_Centered_Flow() == JST) && (iMesh == MESH_0)); - bool low_fidelity = (config->GetLowFidelitySim() && (iMesh == MESH_1)); - bool grid_movement = config->GetGrid_Movement(); - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Points in edge, set normal vectors, and number of neighbors ---*/ - - iPoint = geometry->edge[iEdge]->GetNode(0); jPoint = geometry->edge[iEdge]->GetNode(1); - numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); - numerics->SetNeighbor(geometry->node[iPoint]->GetnNeighbor(), geometry->node[jPoint]->GetnNeighbor()); - - /*--- Set primitive variables w/o reconstruction ---*/ - - numerics->SetPrimitive(node[iPoint]->GetPrimitive(), node[jPoint]->GetPrimitive()); - - /*--- Set the largest convective eigenvalue ---*/ - - numerics->SetLambda(node[iPoint]->GetLambda(), node[jPoint]->GetLambda()); - - /*--- Set undivided laplacian an pressure based sensor ---*/ - - if ((second_order || low_fidelity)) { - numerics->SetUndivided_Laplacian(node[iPoint]->GetUndivided_Laplacian(), node[jPoint]->GetUndivided_Laplacian()); - numerics->SetSensor(node[iPoint]->GetSensor(), node[jPoint]->GetSensor()); - } - - /*--- Grid movement ---*/ - - if (grid_movement) { - numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[jPoint]->GetGridVel()); - } - - /*--- Compute residuals, and Jacobians ---*/ - - numerics->ComputeResidual(Res_Conv, Jacobian_i, Jacobian_j, config); - - /*--- Update convective and artificial dissipation residuals ---*/ - - LinSysRes.AddBlock(iPoint, Res_Conv); - LinSysRes.SubtractBlock(jPoint, Res_Conv); - - /*--- Set implicit computation ---*/ - if (implicit) { - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - Jacobian.AddBlock(iPoint, jPoint, Jacobian_j); - Jacobian.SubtractBlock(jPoint, iPoint, Jacobian_i); - Jacobian.SubtractBlock(jPoint, jPoint, Jacobian_j); - } - } - -} - -void CEulerSolver::Upwind_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config, unsigned short iMesh) { - - su2double **Gradient_i, **Gradient_j, Project_Grad_i, Project_Grad_j, RoeVelocity[3] = {0.0,0.0,0.0}, R, sq_vel, RoeEnthalpy, - *V_i, *V_j, *S_i, *S_j, *Limiter_i = NULL, *Limiter_j = NULL, YDistance, GradHidrosPress, sqvel, Non_Physical = 1.0; - unsigned long iEdge, iPoint, jPoint, counter_local = 0, counter_global = 0; - unsigned short iDim, iVar; - bool neg_density_i = false, neg_density_j = false, neg_pressure_i = false, neg_pressure_j = false, neg_sound_speed = false; - - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool low_fidelity = (config->GetLowFidelitySim() && (iMesh == MESH_1)); - bool second_order = (((config->GetSpatialOrder_Flow() == SECOND_ORDER) || (config->GetSpatialOrder_Flow() == SECOND_ORDER_LIMITER)) && ((iMesh == MESH_0) || low_fidelity)); - bool limiter = ((config->GetSpatialOrder_Flow() == SECOND_ORDER_LIMITER) && !low_fidelity); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool grid_movement = config->GetGrid_Movement(); - bool roe_turkel = (config->GetKind_Upwind_Flow() == TURKEL); - bool ideal_gas = (config->GetKind_FluidModel() == STANDARD_AIR || config->GetKind_FluidModel() == IDEAL_GAS ); - - /*--- Loop over all the edges ---*/ - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Points in edge and normal vectors ---*/ - - iPoint = geometry->edge[iEdge]->GetNode(0); jPoint = geometry->edge[iEdge]->GetNode(1); - numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); - - /*--- Roe Turkel preconditioning ---*/ - - if (roe_turkel) { - sqvel = 0.0; - for (iDim = 0; iDim < nDim; iDim ++) - sqvel += config->GetVelocity_FreeStream()[iDim]*config->GetVelocity_FreeStream()[iDim]; - numerics->SetVelocity2_Inf(sqvel); - } - - /*--- Grid movement ---*/ - - if (grid_movement) - numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[jPoint]->GetGridVel()); - - /*--- Get primitive variables ---*/ - - V_i = node[iPoint]->GetPrimitive(); V_j = node[jPoint]->GetPrimitive(); - S_i = node[iPoint]->GetSecondary(); S_j = node[jPoint]->GetSecondary(); - - /*--- The zero order reconstruction includes the gradient - of the hydrostatic pressure constribution ---*/ - - if (freesurface) { - - YDistance = 0.5*(geometry->node[jPoint]->GetCoord(nDim-1)-geometry->node[iPoint]->GetCoord(nDim-1)); - GradHidrosPress = node[iPoint]->GetDensityInc()/(config->GetFroude()*config->GetFroude()); - Primitive_i[0] = V_i[0] - GradHidrosPress*YDistance; - GradHidrosPress = node[jPoint]->GetDensityInc()/(config->GetFroude()*config->GetFroude()); - Primitive_j[0] = V_j[0] + GradHidrosPress*YDistance; - - for (iVar = 1; iVar < nPrimVar; iVar++) { - Primitive_i[iVar] = V_i[iVar]+EPS; - Primitive_j[iVar] = V_j[iVar]+EPS; - } - - } - - /*--- High order reconstruction using MUSCL strategy ---*/ - - if (second_order) { - - for (iDim = 0; iDim < nDim; iDim++) { - Vector_i[iDim] = 0.5*(geometry->node[jPoint]->GetCoord(iDim) - geometry->node[iPoint]->GetCoord(iDim)); - Vector_j[iDim] = 0.5*(geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim)); - } - - Gradient_i = node[iPoint]->GetGradient_Primitive(); - Gradient_j = node[jPoint]->GetGradient_Primitive(); - if (limiter) { - Limiter_i = node[iPoint]->GetLimiter_Primitive(); - Limiter_j = node[jPoint]->GetLimiter_Primitive(); - } - - for (iVar = 0; iVar < nPrimVarGrad; iVar++) { - Project_Grad_i = 0.0; Project_Grad_j = 0.0; - Non_Physical = node[iPoint]->GetNon_Physical()*node[jPoint]->GetNon_Physical(); - for (iDim = 0; iDim < nDim; iDim++) { - Project_Grad_i += Vector_i[iDim]*Gradient_i[iVar][iDim]*Non_Physical; - Project_Grad_j += Vector_j[iDim]*Gradient_j[iVar][iDim]*Non_Physical; - } - if (limiter) { - Primitive_i[iVar] = V_i[iVar] + Limiter_i[iVar]*Project_Grad_i; - Primitive_j[iVar] = V_j[iVar] + Limiter_j[iVar]*Project_Grad_j; - } - else { - Primitive_i[iVar] = V_i[iVar] + Project_Grad_i; - Primitive_j[iVar] = V_j[iVar] + Project_Grad_j; - } - } - - /*--- Recompute the extrapolated quantities in a - thermodynamic consistent way ---*/ - - if (!ideal_gas) { ComputeConsExtrapolation(config); } - - /*--- Check for non-physical solutions after reconstruction. If found, - use the cell-average value of the solution. This results in a locally - first-order approximation, but this is typically only active - during the start-up of a calculation. If non-physical, use the - cell-averaged state. ---*/ - - if (compressible) { - - neg_pressure_i = (Primitive_i[nDim+1] < 0.0); neg_pressure_j = (Primitive_j[nDim+1] < 0.0); - neg_density_i = (Primitive_i[nDim+2] < 0.0); neg_density_j = (Primitive_j[nDim+2] < 0.0); - - R = sqrt(fabs(Primitive_j[nDim+2]/Primitive_i[nDim+2])); - sq_vel = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - RoeVelocity[iDim] = (R*Primitive_j[iDim+1]+Primitive_i[iDim+1])/(R+1); - sq_vel += RoeVelocity[iDim]*RoeVelocity[iDim]; - } - RoeEnthalpy = (R*Primitive_j[nDim+3]+Primitive_i[nDim+3])/(R+1); - neg_sound_speed = ((Gamma-1)*(RoeEnthalpy-0.5*sq_vel) < 0.0); - - } - - if (neg_sound_speed) { - for (iVar = 0; iVar < nPrimVar; iVar++) { - Primitive_i[iVar] = V_i[iVar]; - Primitive_j[iVar] = V_j[iVar]; } - if (compressible) { - Secondary_i[0] = S_i[0]; Secondary_i[1] = S_i[1]; - Secondary_j[0] = S_i[0]; Secondary_j[1] = S_i[1]; } - counter_local++; - } - - if (neg_density_i || neg_pressure_i) { - for (iVar = 0; iVar < nPrimVar; iVar++) Primitive_i[iVar] = V_i[iVar]; - if (compressible) { Secondary_i[0] = S_i[0]; Secondary_i[1] = S_i[1]; } - counter_local++; - } - - if (neg_density_j || neg_pressure_j) { - for (iVar = 0; iVar < nPrimVar; iVar++) Primitive_j[iVar] = V_j[iVar]; - if (compressible) { Secondary_j[0] = S_j[0]; Secondary_j[1] = S_j[1]; } - counter_local++; - } - - numerics->SetPrimitive(Primitive_i, Primitive_j); - numerics->SetSecondary(Secondary_i, Secondary_j); - - } - else { - - /*--- Set conservative variables without reconstruction ---*/ - - numerics->SetPrimitive(V_i, V_j); - numerics->SetSecondary(S_i, S_j); - - if (freesurface) { - numerics->SetPrimitive(Primitive_i, Primitive_j); - } - - } - - /*--- Compute the residual ---*/ - - numerics->ComputeResidual(Res_Conv, Jacobian_i, Jacobian_j, config); - - /*--- Update residual value ---*/ - - LinSysRes.AddBlock(iPoint, Res_Conv); - LinSysRes.SubtractBlock(jPoint, Res_Conv); - - /*--- Set implicit Jacobians ---*/ - - if (implicit) { - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - Jacobian.AddBlock(iPoint, jPoint, Jacobian_j); - Jacobian.SubtractBlock(jPoint, iPoint, Jacobian_i); - Jacobian.SubtractBlock(jPoint, jPoint, Jacobian_j); - } - - /*--- Roe Turkel preconditioning, set the value of beta ---*/ - - if (roe_turkel) { - node[iPoint]->SetPreconditioner_Beta(numerics->GetPrecond_Beta()); - node[jPoint]->SetPreconditioner_Beta(numerics->GetPrecond_Beta()); - } - - } - - /*--- Warning message about non-physical reconstructions ---*/ - - if (config->GetConsole_Output_Verb() == VERB_HIGH) { -#ifdef HAVE_MPI - SU2_MPI::Reduce(&counter_local, &counter_global, 1, MPI_UNSIGNED_LONG, MPI_SUM, MASTER_NODE, MPI_COMM_WORLD); -#else - counter_global = counter_local; -#endif - if (iMesh == MESH_0) config->SetNonphysical_Reconstr(counter_global); - } - -} - -void CEulerSolver::ComputeConsExtrapolation(CConfig *config) { - - unsigned short iDim; - - su2double density_i = Primitive_i[nDim+2]; - su2double pressure_i = Primitive_i[nDim+1]; - su2double velocity2_i = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - velocity2_i += Primitive_i[iDim+1]*Primitive_i[iDim+1]; - } - - FluidModel->SetTDState_Prho(pressure_i, density_i); - - Primitive_i[0]= FluidModel->GetTemperature(); - Primitive_i[nDim+3]= FluidModel->GetStaticEnergy() + Primitive_i[nDim+1]/Primitive_i[nDim+2] + 0.5*velocity2_i; - Primitive_i[nDim+4]= FluidModel->GetSoundSpeed(); - Secondary_i[0]=FluidModel->GetdPdrho_e(); - Secondary_i[1]=FluidModel->GetdPde_rho(); - - - su2double density_j = Primitive_j[nDim+2]; - su2double pressure_j = Primitive_j[nDim+1]; - su2double velocity2_j = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - velocity2_j += Primitive_j[iDim+1]*Primitive_j[iDim+1]; - } - - FluidModel->SetTDState_Prho(pressure_j, density_j); - - Primitive_j[0]= FluidModel->GetTemperature(); - Primitive_j[nDim+3]= FluidModel->GetStaticEnergy() + Primitive_j[nDim+1]/Primitive_j[nDim+2] + 0.5*velocity2_j; - Primitive_j[nDim+4]=FluidModel->GetSoundSpeed(); - Secondary_j[0]=FluidModel->GetdPdrho_e(); - Secondary_j[1]=FluidModel->GetdPde_rho(); - -} - -void CEulerSolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, - CConfig *config, unsigned short iMesh) { - - unsigned short iVar, jVar; - unsigned long iPoint; - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool rotating_frame = config->GetRotating_Frame(); - bool axisymmetric = config->GetAxisymmetric(); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool gravity = (config->GetGravityForce() == YES); - bool time_spectral = (config->GetUnsteady_Simulation() == TIME_SPECTRAL); - bool windgust = config->GetWind_Gust(); - - /*--- Initialize the source residual to zero ---*/ - for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; - - if (rotating_frame) { - - /*--- Loop over all points ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Load the conservative variables ---*/ - numerics->SetConservative(node[iPoint]->GetSolution(), - node[iPoint]->GetSolution()); - - /*--- Load the volume of the dual mesh cell ---*/ - numerics->SetVolume(geometry->node[iPoint]->GetVolume()); - - /*--- Compute the rotating frame source residual ---*/ - numerics->ComputeResidual(Residual, Jacobian_i, config); - - /*--- Add the source residual to the total ---*/ - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Add the implicit Jacobian contribution ---*/ - if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - } - } - - if (axisymmetric) { - - /*--- Zero out Jacobian structure ---*/ - if (implicit) { - for (iVar = 0; iVar < nVar; iVar ++) - for (unsigned short jVar = 0; jVar < nVar; jVar ++) - Jacobian_i[iVar][jVar] = 0.0; - } - - /*--- loop over points ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Set solution ---*/ - numerics->SetConservative(node[iPoint]->GetSolution(), node[iPoint]->GetSolution()); - - if (incompressible || freesurface) { - /*--- Set incompressible density ---*/ - numerics->SetDensityInc(node[iPoint]->GetDensityInc(), node[iPoint]->GetDensityInc()); - } - - /*--- Set control volume ---*/ - numerics->SetVolume(geometry->node[iPoint]->GetVolume()); - - /*--- Set y coordinate ---*/ - numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[iPoint]->GetCoord()); - - /*--- Compute Source term Residual ---*/ - numerics->ComputeResidual(Residual, Jacobian_i, config); - - /*--- Add Residual ---*/ - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Implicit part ---*/ - if (implicit) - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - } - } - - if (gravity) { - - /*--- loop over points ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Set solution ---*/ - numerics->SetConservative(node[iPoint]->GetSolution(), node[iPoint]->GetSolution()); - - /*--- Set incompressible density ---*/ - if (incompressible || freesurface) { - numerics->SetDensityInc(node[iPoint]->GetDensityInc(), node[iPoint]->GetDensityInc()); - } - - /*--- Set control volume ---*/ - numerics->SetVolume(geometry->node[iPoint]->GetVolume()); - - /*--- Compute Source term Residual ---*/ - numerics->ComputeResidual(Residual, config); - - /*--- Add Residual ---*/ - LinSysRes.AddBlock(iPoint, Residual); - - } - - } - - if (freesurface) { - - unsigned long iPoint; - su2double Vol, x_o, x_od, x, z, levelset, DampingFactor; - su2double factor = config->GetFreeSurface_Damping_Length(); - - x_o = config->GetFreeSurface_Outlet(); - x_od = x_o - factor*2.0*PI_NUMBER*config->GetFroude()*config->GetFroude(); - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - Vol = geometry->node[iPoint]->GetVolume(); - x = geometry->node[iPoint]->GetCoord()[0]; - z = geometry->node[iPoint]->GetCoord()[nDim-1]-config->GetFreeSurface_Zero(); - levelset = node[iPoint]->GetSolution(nDim+1); - - DampingFactor = 0.0; - if (x >= x_od) - DampingFactor = config->GetFreeSurface_Damping_Coeff()*pow((x-x_od)/(x_o-x_od), 2.0); - - for (iVar = 0; iVar < nVar; iVar++) { - Residual[iVar] = 0.0; - for (jVar = 0; jVar < nVar; jVar++) - Jacobian_i[iVar][jVar] = 0.0; - } - - Residual[nDim+1] = Vol*(levelset-z)*DampingFactor; - Jacobian_i[nDim+1][nDim+1] = Vol*DampingFactor; - - LinSysRes.AddBlock(iPoint, Residual); - if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - } - - } - - if (time_spectral) { - - su2double Volume, Source; - - /*--- loop over points ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Get control volume ---*/ - Volume = geometry->node[iPoint]->GetVolume(); - - /*--- Get stored time spectral source term ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - Source = node[iPoint]->GetTimeSpectral_Source(iVar); - Residual[iVar] = Source*Volume; - } - - /*--- Add Residual ---*/ - LinSysRes.AddBlock(iPoint, Residual); - - } - } - - if (windgust) { - - /*--- Loop over all points ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Load the wind gust ---*/ - numerics->SetWindGust(node[iPoint]->GetWindGust(), node[iPoint]->GetWindGust()); - - /*--- Load the wind gust derivatives ---*/ - numerics->SetWindGustDer(node[iPoint]->GetWindGustDer(), node[iPoint]->GetWindGustDer()); - - /*--- Load the primitive variables ---*/ - numerics->SetPrimitive(node[iPoint]->GetPrimitive(), node[iPoint]->GetPrimitive()); - - /*--- Load the volume of the dual mesh cell ---*/ - numerics->SetVolume(geometry->node[iPoint]->GetVolume()); - - /*--- Compute the rotating frame source residual ---*/ - numerics->ComputeResidual(Residual, Jacobian_i, config); - - /*--- Add the source residual to the total ---*/ - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Add the implicit Jacobian contribution ---*/ - if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - } - } - -} - -void CEulerSolver::Source_Template(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config, unsigned short iMesh) { - - /* This method should be used to call any new source terms for a particular problem*/ - /* This method calls the new child class in CNumerics, where the new source term should be implemented. */ - - /* Next we describe how to get access to some important quanties for this method */ - /* Access to all points in the current geometric mesh by saying: nPointDomain */ - /* Get the vector of conservative variables at some point iPoint = node[iPoint]->GetSolution() */ - /* Get the volume (or area in 2D) associated with iPoint = node[iPoint]->GetVolume() */ - /* Get the vector of geometric coordinates of point iPoint = node[iPoint]->GetCoord() */ - -} - -void CEulerSolver::SetMax_Eigenvalue(CGeometry *geometry, CConfig *config) { - - su2double *Normal, Area, Mean_SoundSpeed = 0.0, Mean_ProjVel = 0.0, Mean_BetaInc2, Lambda, Mean_DensityInc, - ProjVel, ProjVel_i, ProjVel_j, *GridVel, *GridVel_i, *GridVel_j; - unsigned long iEdge, iVertex, iPoint, jPoint; - unsigned short iDim, iMarker; - - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool grid_movement = config->GetGrid_Movement(); - - /*--- Set maximum inviscid eigenvalue to zero, and compute sound speed ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - node[iPoint]->SetLambda(0.0); - } - - /*--- Loop interior edges ---*/ - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Point identification, Normal vector and area ---*/ - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - - Normal = geometry->edge[iEdge]->GetNormal(); - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); - - /*--- Mean Values ---*/ - - if (compressible) { - Mean_ProjVel = 0.5 * (node[iPoint]->GetProjVel(Normal) + node[jPoint]->GetProjVel(Normal)); - Mean_SoundSpeed = 0.5 * (node[iPoint]->GetSoundSpeed() + node[jPoint]->GetSoundSpeed()) * Area; - } - if (incompressible || freesurface) { - Mean_ProjVel = 0.5 * (node[iPoint]->GetProjVel(Normal) + node[jPoint]->GetProjVel(Normal)); - Mean_BetaInc2 = 0.5 * (node[iPoint]->GetBetaInc2() + node[jPoint]->GetBetaInc2()); - Mean_DensityInc = 0.5 * (node[iPoint]->GetDensityInc() + node[jPoint]->GetDensityInc()); - Mean_SoundSpeed = sqrt(Mean_ProjVel*Mean_ProjVel + (Mean_BetaInc2/Mean_DensityInc)*Area*Area); - } - - /*--- Adjustment for grid movement ---*/ - - if (grid_movement) { - GridVel_i = geometry->node[iPoint]->GetGridVel(); - GridVel_j = geometry->node[jPoint]->GetGridVel(); - ProjVel_i = 0.0; ProjVel_j =0.0; - for (iDim = 0; iDim < nDim; iDim++) { - ProjVel_i += GridVel_i[iDim]*Normal[iDim]; - ProjVel_j += GridVel_j[iDim]*Normal[iDim]; - } - Mean_ProjVel -= 0.5 * (ProjVel_i + ProjVel_j); - } - - /*--- Inviscid contribution ---*/ - - Lambda = fabs(Mean_ProjVel) + Mean_SoundSpeed; - if (geometry->node[iPoint]->GetDomain()) node[iPoint]->AddLambda(Lambda); - if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddLambda(Lambda); - - } - - /*--- Loop boundary edges ---*/ - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - - /*--- Point identification, Normal vector and area ---*/ - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); - - /*--- Mean Values ---*/ - - if (compressible) { - Mean_ProjVel = node[iPoint]->GetProjVel(Normal); - Mean_SoundSpeed = node[iPoint]->GetSoundSpeed() * Area; - } - if (incompressible || freesurface) { - Mean_ProjVel = node[iPoint]->GetProjVel(Normal); - Mean_BetaInc2 = node[iPoint]->GetBetaInc2(); - Mean_DensityInc = node[iPoint]->GetDensityInc(); - Mean_SoundSpeed = sqrt(Mean_ProjVel*Mean_ProjVel + (Mean_BetaInc2/Mean_DensityInc)*Area*Area); - } - - /*--- Adjustment for grid movement ---*/ - - if (grid_movement) { - GridVel = geometry->node[iPoint]->GetGridVel(); - ProjVel = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - ProjVel += GridVel[iDim]*Normal[iDim]; - Mean_ProjVel -= ProjVel; - } - - /*--- Inviscid contribution ---*/ - - Lambda = fabs(Mean_ProjVel) + Mean_SoundSpeed; - if (geometry->node[iPoint]->GetDomain()) { - node[iPoint]->AddLambda(Lambda); - } - - } - } - - /*--- MPI parallelization ---*/ - - Set_MPI_MaxEigenvalue(geometry, config); - -} - -void CEulerSolver::SetUndivided_Laplacian(CGeometry *geometry, CConfig *config) { - - unsigned long iPoint, jPoint, iEdge; - su2double Pressure_i = 0, Pressure_j = 0, *Diff; - unsigned short iVar; - bool boundary_i, boundary_j; - - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - - Diff = new su2double[nVar]; - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) - node[iPoint]->SetUnd_LaplZero(); - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - - /*--- Solution differences ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Diff[iVar] = node[iPoint]->GetSolution(iVar) - node[jPoint]->GetSolution(iVar); - - /*--- Correction for compressible flows which use the enthalpy ---*/ - - if (compressible) { - Pressure_i = node[iPoint]->GetPressure(); - Pressure_j = node[jPoint]->GetPressure(); - Diff[nVar-1] = (node[iPoint]->GetSolution(nVar-1) + Pressure_i) - (node[jPoint]->GetSolution(nVar-1) + Pressure_j); - } - - boundary_i = geometry->node[iPoint]->GetPhysicalBoundary(); - boundary_j = geometry->node[jPoint]->GetPhysicalBoundary(); - - /*--- Both points inside the domain, or both in the boundary ---*/ - - if ((!boundary_i && !boundary_j) || (boundary_i && boundary_j)) { - if (geometry->node[iPoint]->GetDomain()) node[iPoint]->SubtractUnd_Lapl(Diff); - if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddUnd_Lapl(Diff); - } - - /*--- iPoint inside the domain, jPoint on the boundary ---*/ - - if (!boundary_i && boundary_j) - if (geometry->node[iPoint]->GetDomain()) node[iPoint]->SubtractUnd_Lapl(Diff); - - /*--- jPoint inside the domain, iPoint on the boundary ---*/ - - if (boundary_i && !boundary_j) - if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddUnd_Lapl(Diff); - - } - - /*--- MPI parallelization ---*/ - - Set_MPI_Undivided_Laplacian(geometry, config); - - delete [] Diff; - -} - -void CEulerSolver::SetDissipation_Switch(CGeometry *geometry, CConfig *config) { - - unsigned long iEdge, iPoint, jPoint; - su2double Pressure_i = 0.0, Pressure_j = 0.0; - bool boundary_i, boundary_j; - - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - - /*--- Reset variables to store the undivided pressure ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - iPoint_UndLapl[iPoint] = 0.0; - jPoint_UndLapl[iPoint] = 0.0; - } - - /*--- Evaluate the pressure sensor ---*/ - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - - /*--- Get the pressure, or density for incompressible solvers ---*/ - - if (compressible) { - Pressure_i = node[iPoint]->GetPressure(); - Pressure_j = node[jPoint]->GetPressure(); - } - if (incompressible || freesurface) { - Pressure_i = node[iPoint]->GetDensityInc(); - Pressure_j = node[jPoint]->GetDensityInc(); - } - - boundary_i = geometry->node[iPoint]->GetPhysicalBoundary(); - boundary_j = geometry->node[jPoint]->GetPhysicalBoundary(); - - /*--- Both points inside the domain, or both on the boundary ---*/ - - if ((!boundary_i && !boundary_j) || (boundary_i && boundary_j)) { - if (geometry->node[iPoint]->GetDomain()) { iPoint_UndLapl[iPoint] += (Pressure_j - Pressure_i); jPoint_UndLapl[iPoint] += (Pressure_i + Pressure_j); } - if (geometry->node[jPoint]->GetDomain()) { iPoint_UndLapl[jPoint] += (Pressure_i - Pressure_j); jPoint_UndLapl[jPoint] += (Pressure_i + Pressure_j); } - } - - /*--- iPoint inside the domain, jPoint on the boundary ---*/ - - if (!boundary_i && boundary_j) - if (geometry->node[iPoint]->GetDomain()) { iPoint_UndLapl[iPoint] += (Pressure_j - Pressure_i); jPoint_UndLapl[iPoint] += (Pressure_i + Pressure_j); } - - /*--- jPoint inside the domain, iPoint on the boundary ---*/ - - if (boundary_i && !boundary_j) - if (geometry->node[jPoint]->GetDomain()) { iPoint_UndLapl[jPoint] += (Pressure_i - Pressure_j); jPoint_UndLapl[jPoint] += (Pressure_i + Pressure_j); } - - } - - /*--- Set pressure switch for each point ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) - node[iPoint]->SetSensor(fabs(iPoint_UndLapl[iPoint]) / jPoint_UndLapl[iPoint]); - - /*--- MPI parallelization ---*/ - - Set_MPI_Dissipation_Switch(geometry, config); - -} - -void CEulerSolver::Inviscid_Forces(CGeometry *geometry, CConfig *config) { - - unsigned long iVertex, iPoint; - unsigned short iDim, iMarker, Boundary, Monitoring, iMarker_Monitoring; - su2double Pressure = 0.0, *Normal = NULL, MomentDist[3] = {0.0,0.0,0.0}, *Coord, Area, - factor, NFPressOF, RefVel2, RefTemp, RefDensity, RefPressure, Mach2Vel, Mach_Motion, - Force[3] = {0.0,0.0,0.0}; - string Marker_Tag, Monitoring_Tag; - -#ifdef HAVE_MPI - su2double MyAllBound_CDrag_Inv, MyAllBound_CLift_Inv, MyAllBound_CSideForce_Inv, MyAllBound_CMx_Inv, MyAllBound_CMy_Inv, MyAllBound_CMz_Inv, MyAllBound_CFx_Inv, MyAllBound_CFy_Inv, MyAllBound_CFz_Inv, MyAllBound_CT_Inv, MyAllBound_CQ_Inv, MyAllBound_CNearFieldOF_Inv, *MySurface_CLift_Inv = NULL, *MySurface_CDrag_Inv = NULL, *MySurface_CSideForce_Inv = NULL, *MySurface_CEff_Inv = NULL, *MySurface_CFx_Inv = NULL, *MySurface_CFy_Inv = NULL, *MySurface_CFz_Inv = NULL, *MySurface_CMx_Inv = NULL, *MySurface_CMy_Inv = NULL, *MySurface_CMz_Inv = NULL; -#endif - - su2double Alpha = config->GetAoA()*PI_NUMBER/180.0; - su2double Beta = config->GetAoS()*PI_NUMBER/180.0; - su2double RefAreaCoeff = config->GetRefAreaCoeff(); - su2double RefLengthMoment = config->GetRefLengthMoment(); - su2double Gas_Constant = config->GetGas_ConstantND(); - su2double *Origin = config->GetRefOriginMoment(0); - bool grid_movement = config->GetGrid_Movement(); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - - /*--- 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; - RefPressure = Pressure_Inf; - if (grid_movement) { - 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]; - } - - factor = 1.0 / (0.5*RefDensity*RefAreaCoeff*RefVel2); - - /*-- Variables initialization ---*/ - - Total_CDrag = 0.0; Total_CLift = 0.0; Total_CSideForce = 0.0; Total_CEff = 0.0; - Total_CMx = 0.0; Total_CMy = 0.0; Total_CMz = 0.0; - Total_CFx = 0.0; Total_CFy = 0.0; Total_CFz = 0.0; - Total_CT = 0.0; Total_CQ = 0.0; Total_CMerit = 0.0; - Total_CNearFieldOF = 0.0; Total_Heat = 0.0; Total_MaxHeat = 0.0; - - AllBound_CDrag_Inv = 0.0; AllBound_CLift_Inv = 0.0; AllBound_CSideForce_Inv = 0.0; - AllBound_CMx_Inv = 0.0; AllBound_CMy_Inv = 0.0; AllBound_CMz_Inv = 0.0; - AllBound_CFx_Inv = 0.0; AllBound_CFy_Inv = 0.0; AllBound_CFz_Inv = 0.0; - AllBound_CT_Inv = 0.0; AllBound_CQ_Inv = 0.0; AllBound_CMerit_Inv = 0.0; - AllBound_CNearFieldOF_Inv = 0.0; AllBound_CEff_Inv = 0.0; - - for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { - Surface_CLift_Inv[iMarker_Monitoring] = 0.0; Surface_CDrag_Inv[iMarker_Monitoring] = 0.0; - Surface_CSideForce_Inv[iMarker_Monitoring] = 0.0; Surface_CEff_Inv[iMarker_Monitoring] = 0.0; - Surface_CFx_Inv[iMarker_Monitoring] = 0.0; Surface_CFy_Inv[iMarker_Monitoring] = 0.0; - Surface_CFz_Inv[iMarker_Monitoring] = 0.0; Surface_CMx_Inv[iMarker_Monitoring] = 0.0; - Surface_CMy_Inv[iMarker_Monitoring] = 0.0; Surface_CMz_Inv[iMarker_Monitoring] = 0.0; - Surface_CLift[iMarker_Monitoring] = 0.0; Surface_CDrag[iMarker_Monitoring] = 0.0; - Surface_CSideForce[iMarker_Monitoring] = 0.0; Surface_CEff[iMarker_Monitoring] = 0.0; - Surface_CFx[iMarker_Monitoring] = 0.0; Surface_CFy[iMarker_Monitoring] = 0.0; - Surface_CFz[iMarker_Monitoring] = 0.0; Surface_CMx[iMarker_Monitoring] = 0.0; - Surface_CMy[iMarker_Monitoring] = 0.0; Surface_CMz[iMarker_Monitoring] = 0.0; - } - - /*--- Loop over the Euler and Navier-Stokes markers ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - Boundary = config->GetMarker_All_KindBC(iMarker); - Monitoring = config->GetMarker_All_Monitoring(iMarker); - - /*--- Obtain the origin for the moment computation for a particular marker ---*/ - - if (Monitoring == YES) { - for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { - Monitoring_Tag = config->GetMarker_Monitoring(iMarker_Monitoring); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); - if (Marker_Tag == Monitoring_Tag) - Origin = config->GetRefOriginMoment(iMarker_Monitoring); - } - } - - if ((Boundary == EULER_WALL) || (Boundary == HEAT_FLUX) || - (Boundary == ISOTHERMAL) || (Boundary == NEARFIELD_BOUNDARY)) { - - /*--- Forces initialization at each Marker ---*/ - - CDrag_Inv[iMarker] = 0.0; CLift_Inv[iMarker] = 0.0; CSideForce_Inv[iMarker] = 0.0; - CMx_Inv[iMarker] = 0.0; CMy_Inv[iMarker] = 0.0; CMz_Inv[iMarker] = 0.0; - CFx_Inv[iMarker] = 0.0; CFy_Inv[iMarker] = 0.0; CFz_Inv[iMarker] = 0.0; - CT_Inv[iMarker] = 0.0; CQ_Inv[iMarker] = 0.0; CMerit_Inv[iMarker] = 0.0; - CNearFieldOF_Inv[iMarker] = 0.0; CEff_Inv[iMarker] = 0.0; - - for (iDim = 0; iDim < nDim; iDim++) ForceInviscid[iDim] = 0.0; - MomentInviscid[0] = 0.0; MomentInviscid[1] = 0.0; MomentInviscid[2] = 0.0; - NFPressOF = 0.0; - - /*--- Loop over the vertices to compute the forces ---*/ - - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (compressible) Pressure = node[iPoint]->GetPressure(); - if (incompressible || freesurface) Pressure = node[iPoint]->GetPressureInc(); - - CPressure[iMarker][iVertex] = (Pressure - RefPressure)*factor*RefAreaCoeff; - - /*--- Note that the pressure coefficient is computed at the - halo cells (for visualization purposes), but not the forces ---*/ - - if ( (geometry->node[iPoint]->GetDomain()) && (Monitoring == YES) ) { - - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - Coord = geometry->node[iPoint]->GetCoord(); - - /*--- Quadratic objective function for the near-field. - This uses the infinity pressure regardless of Mach number. ---*/ - - NFPressOF += 0.5*(Pressure - Pressure_Inf)*(Pressure - Pressure_Inf)*Normal[nDim-1]; - - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); - for (iDim = 0; iDim < nDim; iDim++) { - MomentDist[iDim] = Coord[iDim] - Origin[iDim]; - } - - /*--- Force computation, note the minus sign due to the - orientation of the normal (outward) ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - Force[iDim] = -(Pressure - Pressure_Inf)*Normal[iDim]*factor; - ForceInviscid[iDim] += Force[iDim]; - } - - /*--- Moment with respect to the reference axis ---*/ - - if (nDim == 3) { - MomentInviscid[0] += (Force[2]*MomentDist[1]-Force[1]*MomentDist[2])/RefLengthMoment; - MomentInviscid[1] += (Force[0]*MomentDist[2]-Force[2]*MomentDist[0])/RefLengthMoment; - } - MomentInviscid[2] += (Force[1]*MomentDist[0]-Force[0]*MomentDist[1])/RefLengthMoment; - } - - } - - /*--- Project forces and store the non-dimensional coefficients ---*/ - - if (Monitoring == YES) { - - if (Boundary != NEARFIELD_BOUNDARY) { - if (nDim == 2) { - CDrag_Inv[iMarker] = ForceInviscid[0]*cos(Alpha) + ForceInviscid[1]*sin(Alpha); - CLift_Inv[iMarker] = -ForceInviscid[0]*sin(Alpha) + ForceInviscid[1]*cos(Alpha); - CEff_Inv[iMarker] = CLift_Inv[iMarker] / (CDrag_Inv[iMarker]+EPS); - CMz_Inv[iMarker] = MomentInviscid[2]; - CFx_Inv[iMarker] = ForceInviscid[0]; - CFy_Inv[iMarker] = ForceInviscid[1]; - CT_Inv[iMarker] = -CFx_Inv[iMarker]; - CQ_Inv[iMarker] = -CMz_Inv[iMarker]; - CMerit_Inv[iMarker] = CT_Inv[iMarker] / (CQ_Inv[iMarker] + EPS); - } - if (nDim == 3) { - CDrag_Inv[iMarker] = ForceInviscid[0]*cos(Alpha)*cos(Beta) + ForceInviscid[1]*sin(Beta) + ForceInviscid[2]*sin(Alpha)*cos(Beta); - CLift_Inv[iMarker] = -ForceInviscid[0]*sin(Alpha) + ForceInviscid[2]*cos(Alpha); - CSideForce_Inv[iMarker] = -ForceInviscid[0]*sin(Beta)*cos(Alpha) + ForceInviscid[1]*cos(Beta) - ForceInviscid[2]*sin(Beta)*sin(Alpha); - CEff_Inv[iMarker] = CLift_Inv[iMarker] / (CDrag_Inv[iMarker] + EPS); - CMx_Inv[iMarker] = MomentInviscid[0]; - CMy_Inv[iMarker] = MomentInviscid[1]; - CMz_Inv[iMarker] = MomentInviscid[2]; - CFx_Inv[iMarker] = ForceInviscid[0]; - CFy_Inv[iMarker] = ForceInviscid[1]; - CFz_Inv[iMarker] = ForceInviscid[2]; - CT_Inv[iMarker] = -CFz_Inv[iMarker]; - CQ_Inv[iMarker] = -CMz_Inv[iMarker]; - CMerit_Inv[iMarker] = CT_Inv[iMarker] / (CQ_Inv[iMarker] + EPS); - } - - AllBound_CDrag_Inv += CDrag_Inv[iMarker]; - AllBound_CLift_Inv += CLift_Inv[iMarker]; - AllBound_CSideForce_Inv += CSideForce_Inv[iMarker]; - AllBound_CEff_Inv = AllBound_CLift_Inv / (AllBound_CDrag_Inv + EPS); - AllBound_CMx_Inv += CMx_Inv[iMarker]; - AllBound_CMy_Inv += CMy_Inv[iMarker]; - AllBound_CMz_Inv += CMz_Inv[iMarker]; - AllBound_CFx_Inv += CFx_Inv[iMarker]; - AllBound_CFy_Inv += CFy_Inv[iMarker]; - AllBound_CFz_Inv += CFz_Inv[iMarker]; - AllBound_CT_Inv += CT_Inv[iMarker]; - AllBound_CQ_Inv += CQ_Inv[iMarker]; - AllBound_CMerit_Inv = AllBound_CT_Inv / (AllBound_CQ_Inv + EPS); - - /*--- Compute the coefficients per surface ---*/ - - for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { - Monitoring_Tag = config->GetMarker_Monitoring(iMarker_Monitoring); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); - if (Marker_Tag == Monitoring_Tag) { - Surface_CLift_Inv[iMarker_Monitoring] += CLift_Inv[iMarker]; - Surface_CDrag_Inv[iMarker_Monitoring] += CDrag_Inv[iMarker]; - Surface_CSideForce_Inv[iMarker_Monitoring] += CSideForce_Inv[iMarker]; - Surface_CEff_Inv[iMarker_Monitoring] = CLift_Inv[iMarker] / (CDrag_Inv[iMarker] + EPS); - Surface_CFx_Inv[iMarker_Monitoring] += CFx_Inv[iMarker]; - Surface_CFy_Inv[iMarker_Monitoring] += CFy_Inv[iMarker]; - Surface_CFz_Inv[iMarker_Monitoring] += CFz_Inv[iMarker]; - Surface_CMx_Inv[iMarker_Monitoring] += CMx_Inv[iMarker]; - Surface_CMy_Inv[iMarker_Monitoring] += CMy_Inv[iMarker]; - Surface_CMz_Inv[iMarker_Monitoring] += CMz_Inv[iMarker]; - } - } - - } - - /*--- At the Nearfield SU2 only cares about the pressure coeffient ---*/ - - else { - CNearFieldOF_Inv[iMarker] = NFPressOF; - AllBound_CNearFieldOF_Inv += CNearFieldOF_Inv[iMarker]; - } - - } - - - } - } - -#ifdef HAVE_MPI - - /*--- Add AllBound information using all the nodes ---*/ - - MyAllBound_CDrag_Inv = AllBound_CDrag_Inv; AllBound_CDrag_Inv = 0.0; - MyAllBound_CLift_Inv = AllBound_CLift_Inv; AllBound_CLift_Inv = 0.0; - MyAllBound_CSideForce_Inv = AllBound_CSideForce_Inv; AllBound_CSideForce_Inv = 0.0; - AllBound_CEff_Inv = 0.0; - MyAllBound_CMx_Inv = AllBound_CMx_Inv; AllBound_CMx_Inv = 0.0; - MyAllBound_CMy_Inv = AllBound_CMy_Inv; AllBound_CMy_Inv = 0.0; - MyAllBound_CMz_Inv = AllBound_CMz_Inv; AllBound_CMz_Inv = 0.0; - MyAllBound_CFx_Inv = AllBound_CFx_Inv; AllBound_CFx_Inv = 0.0; - MyAllBound_CFy_Inv = AllBound_CFy_Inv; AllBound_CFy_Inv = 0.0; - MyAllBound_CFz_Inv = AllBound_CFz_Inv; AllBound_CFz_Inv = 0.0; - MyAllBound_CT_Inv = AllBound_CT_Inv; AllBound_CT_Inv = 0.0; - MyAllBound_CQ_Inv = AllBound_CQ_Inv; AllBound_CQ_Inv = 0.0; - AllBound_CMerit_Inv = 0.0; - MyAllBound_CNearFieldOF_Inv = AllBound_CNearFieldOF_Inv; AllBound_CNearFieldOF_Inv = 0.0; - - SU2_MPI::Allreduce(&MyAllBound_CDrag_Inv, &AllBound_CDrag_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CLift_Inv, &AllBound_CLift_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CSideForce_Inv, &AllBound_CSideForce_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - AllBound_CEff_Inv = AllBound_CLift_Inv / (AllBound_CDrag_Inv + EPS); - SU2_MPI::Allreduce(&MyAllBound_CMx_Inv, &AllBound_CMx_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CMy_Inv, &AllBound_CMy_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CMz_Inv, &AllBound_CMz_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CFx_Inv, &AllBound_CFx_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CFy_Inv, &AllBound_CFy_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CFz_Inv, &AllBound_CFz_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CT_Inv, &AllBound_CT_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CQ_Inv, &AllBound_CQ_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - AllBound_CMerit_Inv = AllBound_CT_Inv / (AllBound_CQ_Inv + EPS); - SU2_MPI::Allreduce(&MyAllBound_CNearFieldOF_Inv, &AllBound_CNearFieldOF_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - - /*--- Add the forces on the surfaces using all the nodes ---*/ - - MySurface_CLift_Inv = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CDrag_Inv = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CSideForce_Inv = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CEff_Inv = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CFx_Inv = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CFy_Inv = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CFz_Inv = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CMx_Inv = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CMy_Inv = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CMz_Inv = new su2double[config->GetnMarker_Monitoring()]; - - for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { - MySurface_CLift_Inv[iMarker_Monitoring] = Surface_CLift_Inv[iMarker_Monitoring]; - MySurface_CDrag_Inv[iMarker_Monitoring] = Surface_CDrag_Inv[iMarker_Monitoring]; - MySurface_CSideForce_Inv[iMarker_Monitoring] = Surface_CSideForce_Inv[iMarker_Monitoring]; - MySurface_CEff_Inv[iMarker_Monitoring] = Surface_CEff_Inv[iMarker_Monitoring]; - MySurface_CFx_Inv[iMarker_Monitoring] = Surface_CFx_Inv[iMarker_Monitoring]; - MySurface_CFy_Inv[iMarker_Monitoring] = Surface_CFy_Inv[iMarker_Monitoring]; - MySurface_CFz_Inv[iMarker_Monitoring] = Surface_CFz_Inv[iMarker_Monitoring]; - MySurface_CMx_Inv[iMarker_Monitoring] = Surface_CMx_Inv[iMarker_Monitoring]; - MySurface_CMy_Inv[iMarker_Monitoring] = Surface_CMy_Inv[iMarker_Monitoring]; - MySurface_CMz_Inv[iMarker_Monitoring] = Surface_CMz_Inv[iMarker_Monitoring]; - - Surface_CLift_Inv[iMarker_Monitoring] = 0.0; - Surface_CDrag_Inv[iMarker_Monitoring] = 0.0; - Surface_CSideForce_Inv[iMarker_Monitoring] = 0.0; - Surface_CEff_Inv[iMarker_Monitoring] = 0.0; - Surface_CFx_Inv[iMarker_Monitoring] = 0.0; - Surface_CFy_Inv[iMarker_Monitoring] = 0.0; - Surface_CFz_Inv[iMarker_Monitoring] = 0.0; - Surface_CMx_Inv[iMarker_Monitoring] = 0.0; - Surface_CMy_Inv[iMarker_Monitoring] = 0.0; - Surface_CMz_Inv[iMarker_Monitoring] = 0.0; - } - - SU2_MPI::Allreduce(MySurface_CLift_Inv, Surface_CLift_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(MySurface_CDrag_Inv, Surface_CDrag_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(MySurface_CSideForce_Inv, Surface_CSideForce_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) - Surface_CEff_Inv[iMarker_Monitoring] = Surface_CLift_Inv[iMarker_Monitoring] / (Surface_CDrag_Inv[iMarker_Monitoring] + EPS); - SU2_MPI::Allreduce(MySurface_CFx_Inv, Surface_CFx_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(MySurface_CFy_Inv, Surface_CFy_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(MySurface_CFz_Inv, Surface_CFz_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(MySurface_CMx_Inv, Surface_CMx_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(MySurface_CMy_Inv, Surface_CMy_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(MySurface_CMz_Inv, Surface_CMz_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - - delete [] MySurface_CLift_Inv; delete [] MySurface_CDrag_Inv; delete [] MySurface_CSideForce_Inv; - delete [] MySurface_CEff_Inv; delete [] MySurface_CFx_Inv; delete [] MySurface_CFy_Inv; - delete [] MySurface_CFz_Inv; delete [] MySurface_CMx_Inv; delete [] MySurface_CMy_Inv; - delete [] MySurface_CMz_Inv; - -#endif - - /*--- Update the total coefficients (note that all the nodes have the same value) ---*/ - - Total_CDrag = AllBound_CDrag_Inv; - Total_CLift = AllBound_CLift_Inv; - Total_CSideForce = AllBound_CSideForce_Inv; - Total_CEff = Total_CLift / (Total_CDrag + EPS); - Total_CMx = AllBound_CMx_Inv; - Total_CMy = AllBound_CMy_Inv; - Total_CMz = AllBound_CMz_Inv; - Total_CFx = AllBound_CFx_Inv; - Total_CFy = AllBound_CFy_Inv; - Total_CFz = AllBound_CFz_Inv; - Total_CT = AllBound_CT_Inv; - Total_CQ = AllBound_CQ_Inv; - Total_CMerit = Total_CT / (Total_CQ + EPS); - Total_CNearFieldOF = AllBound_CNearFieldOF_Inv; - - /*--- Update the total coefficients per surface (note that all the nodes have the same value)---*/ - - for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { - Surface_CLift[iMarker_Monitoring] = Surface_CLift_Inv[iMarker_Monitoring]; - Surface_CDrag[iMarker_Monitoring] = Surface_CDrag_Inv[iMarker_Monitoring]; - Surface_CSideForce[iMarker_Monitoring] = Surface_CSideForce_Inv[iMarker_Monitoring]; - Surface_CEff[iMarker_Monitoring] = Surface_CLift_Inv[iMarker_Monitoring] / (Surface_CDrag_Inv[iMarker_Monitoring] + EPS); - Surface_CFx[iMarker_Monitoring] = Surface_CFx_Inv[iMarker_Monitoring]; - Surface_CFy[iMarker_Monitoring] = Surface_CFy_Inv[iMarker_Monitoring]; - Surface_CFz[iMarker_Monitoring] = Surface_CFz_Inv[iMarker_Monitoring]; - Surface_CMx[iMarker_Monitoring] = Surface_CMx_Inv[iMarker_Monitoring]; - Surface_CMy[iMarker_Monitoring] = Surface_CMy_Inv[iMarker_Monitoring]; - Surface_CMz[iMarker_Monitoring] = Surface_CMz_Inv[iMarker_Monitoring]; - } - -} - -void CEulerSolver::TurboPerformance(CSolver *solver, CConfig *config, unsigned short inMarker, unsigned short outMarker, unsigned short Kind_TurboPerf, unsigned short inMarkerTP ){ - - su2double avgVel2In, avgVel2Out,avgVelRel2In, avgVelRel2Out, avgGridVel2In, avgGridVel2Out, avgTotalEnthalpyIn= 0.0,avgTotalRothalpyIn, - avgTotalEnthalpyOut, avgTotalRothalpyOut, avgTotalEnthalpyOutIs, avgEnthalpyOut, avgEnthalpyOutIs, - avgPressureOut, avgTotalRelPressureIn, avgTotalRelPressureOut, avgEntropyIn, avgEntropyOut; - unsigned short iDim; - - - /*--- compute or retrieve inlet information ---*/ - avgVelRel2In= 0.0; - avgGridVel2In= 0.0; - avgVel2In= 0.0; - for (iDim = 0; iDim < nDim; iDim++){ - avgVelRel2In +=( AveragedVelocity[inMarker][iDim] - AveragedGridVel[inMarker][iDim])*( AveragedVelocity[inMarker][iDim] - AveragedGridVel[inMarker][iDim]); - avgGridVel2In += AveragedGridVel[inMarker][iDim]*AveragedGridVel[inMarker][iDim]; - avgVel2In += AveragedVelocity[inMarker][iDim]*AveragedVelocity[inMarker][iDim]; - } - - avgTotalRothalpyIn = AveragedEnthalpy[inMarker] + 0.5*avgVelRel2In - 0.5*avgGridVel2In; - avgTotalEnthalpyIn = AveragedEnthalpy[inMarker] + 0.5*avgVel2In; - avgEntropyIn = AveragedEntropy[inMarker]; - FluidModel->SetTDState_hs(avgTotalRothalpyIn, avgEntropyIn); - avgTotalRelPressureIn = FluidModel->GetPressure(); - - - - /*--- compute or retrieve outlet information ---*/ - avgVelRel2Out = 0.0; - avgGridVel2Out = 0.0; - avgVel2Out = 0.0; - for (iDim = 0; iDim < nDim; iDim++){ - avgVelRel2Out += (solver->GetAveragedVelocity(outMarker)[iDim]- solver->GetAveragedGridVelocity(outMarker)[iDim])*(solver->GetAveragedVelocity(outMarker)[iDim]- solver->GetAveragedGridVelocity(outMarker)[iDim]); - avgGridVel2Out += solver->GetAveragedGridVelocity(outMarker)[iDim]*solver->GetAveragedGridVelocity(outMarker)[iDim]; - avgVel2Out += solver->GetAveragedVelocity(outMarker)[iDim]*solver->GetAveragedVelocity(outMarker)[iDim]; - } - avgTotalRothalpyOut = solver->GetAveragedEnthalpy(outMarker) + 0.5*avgVelRel2Out - 0.5*avgGridVel2Out; - avgTotalEnthalpyOut = solver->GetAveragedEnthalpy(outMarker) + 0.5*avgVel2Out; - avgEntropyOut = solver->GetAveragedEntropy(outMarker); - avgEnthalpyOut = solver->GetAveragedEnthalpy(outMarker); - FluidModel->SetTDState_hs(avgTotalRothalpyOut, avgEntropyOut); - avgTotalRelPressureOut = FluidModel->GetPressure(); - avgPressureOut= solver->GetAveragedPressure(outMarker); - - /*--- compute outlet isoentropic conditions ---*/ - FluidModel->SetTDState_Ps(avgPressureOut, avgEntropyIn); - avgEnthalpyOutIs = FluidModel->GetStaticEnergy() + avgPressureOut/FluidModel->GetDensity(); - avgTotalEnthalpyOutIs = avgEnthalpyOutIs + 0.5*avgVel2Out; - - /*--- store turboperformance informations ---*/ - PressureOut[inMarkerTP] = avgPressureOut; - PressureRatio[inMarkerTP] = avgTotalRelPressureIn/avgPressureOut; - - switch(Kind_TurboPerf){ - case BLADE: - - TotalPressureLoss[inMarkerTP] = (avgTotalRelPressureIn - avgTotalRelPressureOut)/(avgTotalRelPressureOut - avgPressureOut) ; - KineticEnergyLoss[inMarkerTP] = (avgEnthalpyOut - avgEnthalpyOutIs)/(avgTotalRothalpyIn - avgEnthalpyOut + 0.5*avgGridVel2Out); - EulerianWork[inMarkerTP] = avgTotalEnthalpyIn - avgTotalEnthalpyOut; - TotalEnthalpyIn[inMarkerTP] = avgTotalRothalpyIn; - FlowAngleIn[inMarkerTP]= FlowAngle[inMarker]; - FlowAngleOut[inMarkerTP]= solver->GetFlowAngle(outMarker); - MassFlowIn[inMarkerTP]= MassFlow[inMarker]; - MassFlowOut[inMarkerTP]= solver->GetMassFlow(outMarker); - MachIn[inMarkerTP]= AveragedMach[inMarker]; - MachOut[inMarkerTP]= solver->GetAveragedMach(outMarker); - NormalMachIn[inMarkerTP]= AveragedNormalMach[inMarker]; - NormalMachOut[inMarkerTP]= solver->GetAveragedNormalMach(outMarker); - EnthalpyOut[inMarkerTP]= avgEnthalpyOut; - VelocityOutIs[inMarkerTP]=sqrt(2.0*(avgTotalRothalpyIn - avgEnthalpyOut + 0.5*avgGridVel2Out)); - break; - - case STAGE: case TURBINE: - - TotalTotalEfficiency[inMarkerTP] = (avgTotalEnthalpyIn - avgTotalEnthalpyOut)/(avgTotalEnthalpyIn - avgTotalEnthalpyOutIs); - TotalStaticEfficiency[inMarkerTP] = (avgTotalEnthalpyIn - avgTotalEnthalpyOut)/(avgTotalEnthalpyIn - avgEnthalpyOutIs); - TotalEnthalpyIn[inMarkerTP]= avgTotalEnthalpyIn; - EnthalpyOut[inMarkerTP] = avgTotalEnthalpyOut; - break; - - default: - cout << "Warning! Invalid TurboPerformance option!" << endl; - exit(EXIT_FAILURE); - break; - } - - - - - -} - -void CEulerSolver::ExplicitRK_Iteration(CGeometry *geometry, CSolver **solver_container, - CConfig *config, unsigned short iRKStep) { - su2double *Residual, *Res_TruncError, Vol, Delta, Res; - unsigned short iVar; - unsigned long iPoint; - - su2double RK_AlphaCoeff = config->Get_Alpha_RKStep(iRKStep); - bool adjoint = config->GetAdjoint(); - - for (iVar = 0; iVar < nVar; iVar++) { - SetRes_RMS(iVar, 0.0); - SetRes_Max(iVar, 0.0, 0); - } - - /*--- Update the solution ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - Vol = geometry->node[iPoint]->GetVolume(); - Delta = node[iPoint]->GetDelta_Time() / Vol; - - Res_TruncError = node[iPoint]->GetResTruncError(); - Residual = LinSysRes.GetBlock(iPoint); - - if (!adjoint) { - for (iVar = 0; iVar < nVar; iVar++) { - Res = Residual[iVar] + Res_TruncError[iVar]; - node[iPoint]->AddSolution(iVar, -Res*Delta*RK_AlphaCoeff); - AddRes_RMS(iVar, Res*Res); - AddRes_Max(iVar, fabs(Res), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); - } - } - - } - - /*--- MPI solution ---*/ - - Set_MPI_Solution(geometry, config); - - /*--- Compute the root mean square residual ---*/ - - SetResidual_RMS(geometry, config); - - -} - -void CEulerSolver::ExplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { - su2double *local_Residual, *local_Res_TruncError, Vol, Delta, Res; - unsigned short iVar; - unsigned long iPoint; - - bool adjoint = config->GetAdjoint(); - - for (iVar = 0; iVar < nVar; iVar++) { - SetRes_RMS(iVar, 0.0); - SetRes_Max(iVar, 0.0, 0); - } - - /*--- Update the solution ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - Vol = geometry->node[iPoint]->GetVolume(); - Delta = node[iPoint]->GetDelta_Time() / Vol; - - local_Res_TruncError = node[iPoint]->GetResTruncError(); - local_Residual = LinSysRes.GetBlock(iPoint); - - if (!adjoint) { - for (iVar = 0; iVar < nVar; iVar++) { - Res = local_Residual[iVar] + local_Res_TruncError[iVar]; - node[iPoint]->AddSolution(iVar, -Res*Delta); - AddRes_RMS(iVar, Res*Res); - AddRes_Max(iVar, fabs(Res), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); - } - } - - } - - /*--- MPI solution ---*/ - - Set_MPI_Solution(geometry, config); - - /*--- Compute the root mean square residual ---*/ - - SetResidual_RMS(geometry, config); - -} - -void CEulerSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { - - unsigned short iVar, jVar; - unsigned long iPoint, total_index, IterLinSol = 0; - su2double Delta, *local_Res_TruncError, Vol; - - bool adjoint = config->GetAdjoint(); - bool roe_turkel = config->GetKind_Upwind_Flow() == TURKEL; - - /*--- Set maximum residual to zero ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - SetRes_RMS(iVar, 0.0); - SetRes_Max(iVar, 0.0, 0); - } - - /*--- Build implicit system ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Read the residual ---*/ - - local_Res_TruncError = node[iPoint]->GetResTruncError(); - - /*--- Read the volume ---*/ - - Vol = geometry->node[iPoint]->GetVolume(); - - /*--- Modify matrix diagonal to assure diagonal dominance ---*/ - - - if (node[iPoint]->GetDelta_Time() != 0.0) { - Delta = Vol / node[iPoint]->GetDelta_Time(); - if (roe_turkel) { - SetPreconditioner(config, iPoint); - for (iVar = 0; iVar < nVar; iVar ++ ) - for (jVar = 0; jVar < nVar; jVar ++ ) - LowMach_Precontioner[iVar][jVar] = Delta*LowMach_Precontioner[iVar][jVar]; - Jacobian.AddBlock(iPoint, iPoint, LowMach_Precontioner); - } - else { - Jacobian.AddVal2Diag(iPoint, Delta); - } - } - else { - Jacobian.SetVal2Diag(iPoint, 1.0); - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar + iVar; - LinSysRes[total_index] = 0.0; - local_Res_TruncError[iVar] = 0.0; - } - } - - /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar + iVar; - LinSysRes[total_index] = - (LinSysRes[total_index] + local_Res_TruncError[iVar]); - LinSysSol[total_index] = 0.0; - AddRes_RMS(iVar, LinSysRes[total_index]*LinSysRes[total_index]); - AddRes_Max(iVar, fabs(LinSysRes[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); - } - } - - /*--- Initialize residual and solution at the ghost points ---*/ - - for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar + iVar; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - } - } - - /*--- Solve or smooth the linear system ---*/ - - CSysSolve system; - IterLinSol = system.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); - - /*--- The the number of iterations of the linear solver ---*/ - - SetIterLinSolver(IterLinSol); - - /*--- Update solution (system written in terms of increments) ---*/ - - if (!adjoint) { - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - node[iPoint]->AddSolution(iVar, config->GetRelaxation_Factor_Flow()*LinSysSol[iPoint*nVar+iVar]); - } - } - } - - /*--- MPI solution ---*/ - - Set_MPI_Solution(geometry, config); - - /*--- Compute the root mean square residual ---*/ - - SetResidual_RMS(geometry, config); - -} - -void CEulerSolver::SetPrimitive_Gradient_GG(CGeometry *geometry, CConfig *config) { - unsigned long iPoint, jPoint, iEdge, iVertex; - unsigned short iDim, iVar, iMarker; - su2double *PrimVar_Vertex, *PrimVar_i, *PrimVar_j, PrimVar_Average, - Partial_Gradient, Partial_Res, *Normal; - - /*--- Gradient primitive variables compressible (temp, vx, vy, vz, P, rho) - Gradient primitive variables incompressible (rho, vx, vy, vz, beta) ---*/ - PrimVar_Vertex = new su2double [nPrimVarGrad]; - PrimVar_i = new su2double [nPrimVarGrad]; - PrimVar_j = new su2double [nPrimVarGrad]; - - /*--- Set Gradient_Primitive to zero ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) - node[iPoint]->SetGradient_PrimitiveZero(nPrimVarGrad); - - /*--- Loop interior edges ---*/ - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - - for (iVar = 0; iVar < nPrimVarGrad; iVar++) { - PrimVar_i[iVar] = node[iPoint]->GetPrimitive(iVar); - PrimVar_j[iVar] = node[jPoint]->GetPrimitive(iVar); - } - - Normal = geometry->edge[iEdge]->GetNormal(); - for (iVar = 0; iVar < nPrimVarGrad; iVar++) { - PrimVar_Average = 0.5 * ( PrimVar_i[iVar] + PrimVar_j[iVar] ); - for (iDim = 0; iDim < nDim; iDim++) { - Partial_Res = PrimVar_Average*Normal[iDim]; - if (geometry->node[iPoint]->GetDomain()) - node[iPoint]->AddGradient_Primitive(iVar, iDim, Partial_Res); - if (geometry->node[jPoint]->GetDomain()) - node[jPoint]->SubtractGradient_Primitive(iVar, iDim, Partial_Res); - } - } - } - - /*--- Loop boundary edges ---*/ - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if (geometry->node[iPoint]->GetDomain()) { - - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - PrimVar_Vertex[iVar] = node[iPoint]->GetPrimitive(iVar); - - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - for (iDim = 0; iDim < nDim; iDim++) { - Partial_Res = PrimVar_Vertex[iVar]*Normal[iDim]; - node[iPoint]->SubtractGradient_Primitive(iVar, iDim, Partial_Res); - } - } - } - } - - /*--- Update gradient value ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - for (iVar = 0; iVar < nPrimVarGrad; iVar++) { - for (iDim = 0; iDim < nDim; iDim++) { - Partial_Gradient = node[iPoint]->GetGradient_Primitive(iVar, iDim) / (geometry->node[iPoint]->GetVolume()); - node[iPoint]->SetGradient_Primitive(iVar, iDim, Partial_Gradient); - } - } - } - - delete [] PrimVar_Vertex; - delete [] PrimVar_i; - delete [] PrimVar_j; - - Set_MPI_Primitive_Gradient(geometry, config); - -} - -void CEulerSolver::SetPrimitive_Gradient_LS(CGeometry *geometry, CConfig *config) { - - unsigned short iVar, iDim, jDim, iNeigh; - unsigned long iPoint, jPoint; - su2double *PrimVar_i, *PrimVar_j, *Coord_i, *Coord_j, r11, r12, r13, r22, r23, r23_a, - r23_b, r33, weight, product, z11, z12, z13, z22, z23, z33, detR2; - bool singular; - - /*--- Loop over points of the grid ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Set the value of the singular ---*/ - singular = false; - - /*--- Get coordinates ---*/ - - Coord_i = geometry->node[iPoint]->GetCoord(); - - /*--- Get primitives from CVariable ---*/ - - PrimVar_i = node[iPoint]->GetPrimitive(); - - /*--- Inizialization of variables ---*/ - - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - cvector[iVar][iDim] = 0.0; - - r11 = 0.0; r12 = 0.0; r13 = 0.0; r22 = 0.0; - r23 = 0.0; r23_a = 0.0; r23_b = 0.0; r33 = 0.0; - - for (iNeigh = 0; iNeigh < geometry->node[iPoint]->GetnPoint(); iNeigh++) { - jPoint = geometry->node[iPoint]->GetPoint(iNeigh); - Coord_j = geometry->node[jPoint]->GetCoord(); - - PrimVar_j = node[jPoint]->GetPrimitive(); - - weight = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - weight += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); - - /*--- Sumations for entries of upper triangular matrix R ---*/ - - if (weight != 0.0) { - - r11 += (Coord_j[0]-Coord_i[0])*(Coord_j[0]-Coord_i[0])/weight; - r12 += (Coord_j[0]-Coord_i[0])*(Coord_j[1]-Coord_i[1])/weight; - r22 += (Coord_j[1]-Coord_i[1])*(Coord_j[1]-Coord_i[1])/weight; - - if (nDim == 3) { - r13 += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; - r23_a += (Coord_j[1]-Coord_i[1])*(Coord_j[2]-Coord_i[2])/weight; - r23_b += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; - r33 += (Coord_j[2]-Coord_i[2])*(Coord_j[2]-Coord_i[2])/weight; - } - - /*--- Entries of c:= transpose(A)*b ---*/ - - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - cvector[iVar][iDim] += (Coord_j[iDim]-Coord_i[iDim])*(PrimVar_j[iVar]-PrimVar_i[iVar])/weight; - - } - - } - - /*--- Entries of upper triangular matrix R ---*/ - - if (r11 >= 0.0) r11 = sqrt(r11); else r11 = 0.0; - if (r11 != 0.0) r12 = r12/r11; else r12 = 0.0; - if (r22-r12*r12 >= 0.0) r22 = sqrt(r22-r12*r12); else r22 = 0.0; - - if (nDim == 3) { - if (r11 != 0.0) r13 = r13/r11; else r13 = 0.0; - if ((r22 != 0.0) && (r11*r22 != 0.0)) r23 = r23_a/r22 - r23_b*r12/(r11*r22); else r23 = 0.0; - if (r33-r23*r23-r13*r13 >= 0.0) r33 = sqrt(r33-r23*r23-r13*r13); else r33 = 0.0; - } - - /*--- Compute determinant ---*/ - - if (nDim == 2) detR2 = (r11*r22)*(r11*r22); - else detR2 = (r11*r22*r33)*(r11*r22*r33); - - /*--- Detect singular matrices ---*/ - - if (abs(detR2) <= EPS) { detR2 = 1.0; singular = true; } - - /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ - - if (singular) { - for (iDim = 0; iDim < nDim; iDim++) - for (jDim = 0; jDim < nDim; jDim++) - Smatrix[iDim][jDim] = 0.0; - } - else { - if (nDim == 2) { - Smatrix[0][0] = (r12*r12+r22*r22)/detR2; - Smatrix[0][1] = -r11*r12/detR2; - Smatrix[1][0] = Smatrix[0][1]; - Smatrix[1][1] = r11*r11/detR2; - } - else { - z11 = r22*r33; z12 = -r12*r33; z13 = r12*r23-r13*r22; - z22 = r11*r33; z23 = -r11*r23; z33 = r11*r22; - Smatrix[0][0] = (z11*z11+z12*z12+z13*z13)/detR2; - Smatrix[0][1] = (z12*z22+z13*z23)/detR2; - Smatrix[0][2] = (z13*z33)/detR2; - Smatrix[1][0] = Smatrix[0][1]; - Smatrix[1][1] = (z22*z22+z23*z23)/detR2; - Smatrix[1][2] = (z23*z33)/detR2; - Smatrix[2][0] = Smatrix[0][2]; - Smatrix[2][1] = Smatrix[1][2]; - Smatrix[2][2] = (z33*z33)/detR2; - } - } - - /*--- Computation of the gradient: S*c ---*/ - for (iVar = 0; iVar < nPrimVarGrad; iVar++) { - for (iDim = 0; iDim < nDim; iDim++) { - product = 0.0; - for (jDim = 0; jDim < nDim; jDim++) { - product += Smatrix[iDim][jDim]*cvector[iVar][jDim]; - } - - node[iPoint]->SetGradient_Primitive(iVar, iDim, product); - } - } - - } - - Set_MPI_Primitive_Gradient(geometry, config); - -} - -void CEulerSolver::SetPrimitive_Limiter(CGeometry *geometry, CConfig *config) { - - unsigned long iEdge, iPoint, jPoint; - unsigned short iVar, iDim; - su2double **Gradient_i, **Gradient_j, *Coord_i, *Coord_j, *Primitive_i, *Primitive_j, - dave, LimK, eps2, eps1, dm, dp, du, y, limiter; - - /*--- Initialize solution max and solution min and the limiter in the entire domain --*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - for (iVar = 0; iVar < nPrimVarGrad; iVar++) { - node[iPoint]->SetSolution_Max(iVar, -EPS); - node[iPoint]->SetSolution_Min(iVar, EPS); - node[iPoint]->SetLimiter_Primitive(iVar, 2.0); - } - } - - /*--- Establish bounds for Spekreijse monotonicity by finding max & min values of neighbor variables --*/ - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Point identification, Normal vector and area ---*/ - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - - /*--- Get the primitive variables ---*/ - - Primitive_i = node[iPoint]->GetPrimitive(); - Primitive_j = node[jPoint]->GetPrimitive(); - - /*--- Compute the maximum, and minimum values for nodes i & j ---*/ - - for (iVar = 0; iVar < nPrimVarGrad; iVar++) { - du = (Primitive_j[iVar] - Primitive_i[iVar]); - node[iPoint]->SetSolution_Min(iVar, min(node[iPoint]->GetSolution_Min(iVar), du)); - node[iPoint]->SetSolution_Max(iVar, max(node[iPoint]->GetSolution_Max(iVar), du)); - node[jPoint]->SetSolution_Min(iVar, min(node[jPoint]->GetSolution_Min(iVar), -du)); - node[jPoint]->SetSolution_Max(iVar, max(node[jPoint]->GetSolution_Max(iVar), -du)); - } - - } - - - /*--- Barth-Jespersen limiter with Venkatakrishnan modification ---*/ - - if (config->GetKind_SlopeLimit_Flow() == BARTH_JESPERSEN) { - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - Gradient_i = node[iPoint]->GetGradient_Primitive(); - Gradient_j = node[jPoint]->GetGradient_Primitive(); - Coord_i = geometry->node[iPoint]->GetCoord(); - Coord_j = geometry->node[jPoint]->GetCoord(); - - for (iVar = 0; iVar < nPrimVarGrad; iVar++) { - - /*--- Calculate the interface left gradient, delta- (dm) ---*/ - - dm = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - dm += 0.5*(Coord_j[iDim]-Coord_i[iDim])*Gradient_i[iVar][iDim]; - - if (dm == 0.0) { limiter = 2.0; } - else { - if ( dm > 0.0 ) dp = node[iPoint]->GetSolution_Max(iVar); - else dp = node[iPoint]->GetSolution_Min(iVar); - limiter = dp/dm; - } - - if (limiter < node[iPoint]->GetLimiter_Primitive(iVar)) - node[iPoint]->SetLimiter_Primitive(iVar, limiter); - - /*--- Calculate the interface right gradient, delta+ (dp) ---*/ - - dm = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - dm += 0.5*(Coord_i[iDim]-Coord_j[iDim])*Gradient_j[iVar][iDim]; - - if (dm == 0.0) { limiter = 2.0; } - else { - if ( dm > 0.0 ) dp = node[jPoint]->GetSolution_Max(iVar); - else dp = node[jPoint]->GetSolution_Min(iVar); - limiter = dp/dm; - } - - if (limiter < node[jPoint]->GetLimiter_Primitive(iVar)) - node[jPoint]->SetLimiter_Primitive(iVar, limiter); - - } - - } - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - for (iVar = 0; iVar < nPrimVarGrad; iVar++) { - y = node[iPoint]->GetLimiter_Primitive(iVar); - limiter = (y*y + 2.0*y) / (y*y + y + 2.0); - node[iPoint]->SetLimiter_Primitive(iVar, limiter); - } - } - - } - - /*--- Venkatakrishnan limiter ---*/ - - if (config->GetKind_SlopeLimit_Flow() == VENKATAKRISHNAN) { - - /*-- Get limiter parameters from the configuration file ---*/ - - dave = config->GetRefElemLength(); - LimK = config->GetLimiterCoeff(); - eps1 = LimK*dave; - eps2 = eps1*eps1*eps1; - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - Gradient_i = node[iPoint]->GetGradient_Primitive(); - Gradient_j = node[jPoint]->GetGradient_Primitive(); - Coord_i = geometry->node[iPoint]->GetCoord(); - Coord_j = geometry->node[jPoint]->GetCoord(); - - for (iVar = 0; iVar < nPrimVarGrad; iVar++) { - - /*--- Calculate the interface left gradient, delta- (dm) ---*/ - - dm = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - dm += 0.5*(Coord_j[iDim]-Coord_i[iDim])*Gradient_i[iVar][iDim]; - - /*--- Calculate the interface right gradient, delta+ (dp) ---*/ - - if ( dm > 0.0 ) dp = node[iPoint]->GetSolution_Max(iVar); - else dp = node[iPoint]->GetSolution_Min(iVar); - - limiter = ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); - - if (limiter < node[iPoint]->GetLimiter_Primitive(iVar)) - node[iPoint]->SetLimiter_Primitive(iVar, limiter); - - /*-- Repeat for point j on the edge ---*/ - - dm = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - dm += 0.5*(Coord_i[iDim]-Coord_j[iDim])*Gradient_j[iVar][iDim]; - - if ( dm > 0.0 ) dp = node[jPoint]->GetSolution_Max(iVar); - else dp = node[jPoint]->GetSolution_Min(iVar); - - limiter = ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); - - if (limiter < node[jPoint]->GetLimiter_Primitive(iVar)) - node[jPoint]->SetLimiter_Primitive(iVar, limiter); - } - - } - - } - - /*--- Limiter MPI ---*/ - - Set_MPI_Primitive_Limiter(geometry, config); - -} - -//void CEulerSolver::SetSecondary_Gradient_GG(CGeometry *geometry, CConfig *config) { -// unsigned long iPoint, jPoint, iEdge, iVertex; -// unsigned short iDim, iVar, iMarker; -// su2double *SecondaryVar_Vertex, *SecondaryVar_i, *SecondaryVar_j, SecondaryVar_Average, -// Partial_Gradient, Partial_Res, *Normal; -// -// /*--- Gradient Secondary variables compressible (temp, vx, vy, vz, P, rho) -// Gradient Secondary variables incompressible (rho, vx, vy, vz, beta) ---*/ -// SecondaryVar_Vertex = new su2double [nSecondaryVarGrad]; -// SecondaryVar_i = new su2double [nSecondaryVarGrad]; -// SecondaryVar_j = new su2double [nSecondaryVarGrad]; -// -// /*--- Set Gradient_Secondary to zero ---*/ -// for (iPoint = 0; iPoint < nPointDomain; iPoint++) -// node[iPoint]->SetGradient_SecondaryZero(nSecondaryVarGrad); -// -// /*--- Loop interior edges ---*/ -// for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { -// iPoint = geometry->edge[iEdge]->GetNode(0); -// jPoint = geometry->edge[iEdge]->GetNode(1); -// -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { -// SecondaryVar_i[iVar] = node[iPoint]->GetSecondary(iVar); -// SecondaryVar_j[iVar] = node[jPoint]->GetSecondary(iVar); -// } -// -// Normal = geometry->edge[iEdge]->GetNormal(); -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { -// SecondaryVar_Average = 0.5 * ( SecondaryVar_i[iVar] + SecondaryVar_j[iVar] ); -// for (iDim = 0; iDim < nDim; iDim++) { -// Partial_Res = SecondaryVar_Average*Normal[iDim]; -// if (geometry->node[iPoint]->GetDomain()) -// node[iPoint]->AddGradient_Secondary(iVar, iDim, Partial_Res); -// if (geometry->node[jPoint]->GetDomain()) -// node[jPoint]->SubtractGradient_Secondary(iVar, iDim, Partial_Res); -// } -// } -// } -// -// /*--- Loop boundary edges ---*/ -// for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { -// for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { -// iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); -// if (geometry->node[iPoint]->GetDomain()) { -// -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) -// SecondaryVar_Vertex[iVar] = node[iPoint]->GetSecondary(iVar); -// -// Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) -// for (iDim = 0; iDim < nDim; iDim++) { -// Partial_Res = SecondaryVar_Vertex[iVar]*Normal[iDim]; -// node[iPoint]->SubtractGradient_Secondary(iVar, iDim, Partial_Res); -// } -// } -// } -// } -// -// /*--- Update gradient value ---*/ -// for (iPoint = 0; iPoint < nPointDomain; iPoint++) { -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { -// for (iDim = 0; iDim < nDim; iDim++) { -// Partial_Gradient = node[iPoint]->GetGradient_Secondary(iVar, iDim) / (geometry->node[iPoint]->GetVolume()); -// node[iPoint]->SetGradient_Secondary(iVar, iDim, Partial_Gradient); -// } -// } -// } -// -// delete [] SecondaryVar_Vertex; -// delete [] SecondaryVar_i; -// delete [] SecondaryVar_j; -// -// Set_MPI_Secondary_Gradient(geometry, config); -// -//} - -//void CEulerSolver::SetSecondary_Gradient_LS(CGeometry *geometry, CConfig *config) { -// -// unsigned short iVar, iDim, jDim, iNeigh; -// unsigned long iPoint, jPoint; -// su2double *SecondaryVar_i, *SecondaryVar_j, *Coord_i, *Coord_j, r11, r12, r13, r22, r23, r23_a, -// r23_b, r33, weight, product, z11, z12, z13, z22, z23, z33, detR2; -// bool singular; -// -// /*--- Loop over points of the grid ---*/ -// -// for (iPoint = 0; iPoint < nPointDomain; iPoint++) { -// -// /*--- Set the value of the singular ---*/ -// singular = false; -// -// /*--- Get coordinates ---*/ -// -// Coord_i = geometry->node[iPoint]->GetCoord(); -// -// /*--- Get Secondarys from CVariable ---*/ -// -// SecondaryVar_i = node[iPoint]->GetSecondary(); -// -// /*--- Inizialization of variables ---*/ -// -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) -// for (iDim = 0; iDim < nDim; iDim++) -// cvector[iVar][iDim] = 0.0; -// -// r11 = 0.0; r12 = 0.0; r13 = 0.0; r22 = 0.0; -// r23 = 0.0; r23_a = 0.0; r23_b = 0.0; r33 = 0.0; detR2 = 0.0; -// -// for (iNeigh = 0; iNeigh < geometry->node[iPoint]->GetnPoint(); iNeigh++) { -// jPoint = geometry->node[iPoint]->GetPoint(iNeigh); -// Coord_j = geometry->node[jPoint]->GetCoord(); -// -// SecondaryVar_j = node[jPoint]->GetSecondary(); -// -// weight = 0.0; -// for (iDim = 0; iDim < nDim; iDim++) -// weight += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); -// -// /*--- Sumations for entries of upper triangular matrix R ---*/ -// -// if (weight != 0.0) { -// -// r11 += (Coord_j[0]-Coord_i[0])*(Coord_j[0]-Coord_i[0])/weight; -// r12 += (Coord_j[0]-Coord_i[0])*(Coord_j[1]-Coord_i[1])/weight; -// r22 += (Coord_j[1]-Coord_i[1])*(Coord_j[1]-Coord_i[1])/weight; -// -// if (nDim == 3) { -// r13 += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; -// r23_a += (Coord_j[1]-Coord_i[1])*(Coord_j[2]-Coord_i[2])/weight; -// r23_b += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; -// r33 += (Coord_j[2]-Coord_i[2])*(Coord_j[2]-Coord_i[2])/weight; -// } -// -// /*--- Entries of c:= transpose(A)*b ---*/ -// -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) -// for (iDim = 0; iDim < nDim; iDim++) -// cvector[iVar][iDim] += (Coord_j[iDim]-Coord_i[iDim])*(SecondaryVar_j[iVar]-SecondaryVar_i[iVar])/weight; -// -// } -// -// } -// -// /*--- Entries of upper triangular matrix R ---*/ -// -// if (r11 >= 0.0) r11 = sqrt(r11); else r11 = 0.0; -// if (r11 != 0.0) r12 = r12/r11; else r12 = 0.0; -// if (r22-r12*r12 >= 0.0) r22 = sqrt(r22-r12*r12); else r22 = 0.0; -// -// if (nDim == 3) { -// if (r11 != 0.0) r13 = r13/r11; else r13 = 0.0; -// if ((r22 != 0.0) && (r11*r22 != 0.0)) r23 = r23_a/r22 - r23_b*r12/(r11*r22); else r23 = 0.0; -// if (r33-r23*r23-r13*r13 >= 0.0) r33 = sqrt(r33-r23*r23-r13*r13); else r33 = 0.0; -// } -// -// /*--- Compute determinant ---*/ -// -// if (nDim == 2) detR2 = (r11*r22)*(r11*r22); -// else detR2 = (r11*r22*r33)*(r11*r22*r33); -// -// /*--- Detect singular matrices ---*/ -// -// if (abs(detR2) <= EPS) { detR2 = 1.0; singular = true; } -// -// /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ -// -// if (singular) { -// for (iDim = 0; iDim < nDim; iDim++) -// for (jDim = 0; jDim < nDim; jDim++) -// Smatrix[iDim][jDim] = 0.0; -// } -// else { -// if (nDim == 2) { -// Smatrix[0][0] = (r12*r12+r22*r22)/detR2; -// Smatrix[0][1] = -r11*r12/detR2; -// Smatrix[1][0] = Smatrix[0][1]; -// Smatrix[1][1] = r11*r11/detR2; -// } -// else { -// z11 = r22*r33; z12 = -r12*r33; z13 = r12*r23-r13*r22; -// z22 = r11*r33; z23 = -r11*r23; z33 = r11*r22; -// Smatrix[0][0] = (z11*z11+z12*z12+z13*z13)/detR2; -// Smatrix[0][1] = (z12*z22+z13*z23)/detR2; -// Smatrix[0][2] = (z13*z33)/detR2; -// Smatrix[1][0] = Smatrix[0][1]; -// Smatrix[1][1] = (z22*z22+z23*z23)/detR2; -// Smatrix[1][2] = (z23*z33)/detR2; -// Smatrix[2][0] = Smatrix[0][2]; -// Smatrix[2][1] = Smatrix[1][2]; -// Smatrix[2][2] = (z33*z33)/detR2; -// } -// } -// -// /*--- Computation of the gradient: S*c ---*/ -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { -// for (iDim = 0; iDim < nDim; iDim++) { -// product = 0.0; -// for (jDim = 0; jDim < nDim; jDim++) { -// product += Smatrix[iDim][jDim]*cvector[iVar][jDim]; -// } -// -// node[iPoint]->SetGradient_Secondary(iVar, iDim, product); -// } -// } -// -// } -// -// Set_MPI_Secondary_Gradient(geometry, config); -// -//} - -//void CEulerSolver::SetSecondary_Limiter(CGeometry *geometry, CConfig *config) { -// -// unsigned long iEdge, iPoint, jPoint; -// unsigned short iVar, iDim; -// su2double **Gradient_i, **Gradient_j, *Coord_i, *Coord_j, *Secondary_i, *Secondary_j, -// dave, LimK, eps2, dm, dp, du, limiter; -// -// /*--- Initialize solution max and solution min in the entire domain --*/ -// for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { -// node[iPoint]->SetSolution_Max(iVar, -EPS); -// node[iPoint]->SetSolution_Min(iVar, EPS); -// } -// } -// -// /*--- Establish bounds for Spekreijse monotonicity by finding max & min values of neighbor variables --*/ -// for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { -// -// /*--- Point identification, Normal vector and area ---*/ -// iPoint = geometry->edge[iEdge]->GetNode(0); -// jPoint = geometry->edge[iEdge]->GetNode(1); -// -// /*--- Get the conserved variables ---*/ -// Secondary_i = node[iPoint]->GetSecondary(); -// Secondary_j = node[jPoint]->GetSecondary(); -// -// /*--- Compute the maximum, and minimum values for nodes i & j ---*/ -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { -// du = (Secondary_j[iVar] - Secondary_i[iVar]); -// node[iPoint]->SetSolution_Min(iVar, min(node[iPoint]->GetSolution_Min(iVar), du)); -// node[iPoint]->SetSolution_Max(iVar, max(node[iPoint]->GetSolution_Max(iVar), du)); -// node[jPoint]->SetSolution_Min(iVar, min(node[jPoint]->GetSolution_Min(iVar), -du)); -// node[jPoint]->SetSolution_Max(iVar, max(node[jPoint]->GetSolution_Max(iVar), -du)); -// } -// } -// -// /*--- Initialize the limiter --*/ -// for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { -// node[iPoint]->SetLimiter_Secondary(iVar, 2.0); -// } -// } -// -// /*--- Venkatakrishnan limiter ---*/ -// -// if (config->GetKind_SlopeLimit() == VENKATAKRISHNAN) { -// -// /*-- Get limiter parameters from the configuration file ---*/ -// dave = config->GetRefElemLength(); -// LimK = config->GetLimiterCoeff(); -// eps2 = pow((LimK*dave), 3.0); -// -// for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { -// -// iPoint = geometry->edge[iEdge]->GetNode(0); -// jPoint = geometry->edge[iEdge]->GetNode(1); -// Gradient_i = node[iPoint]->GetGradient_Secondary(); -// Gradient_j = node[jPoint]->GetGradient_Secondary(); -// Coord_i = geometry->node[iPoint]->GetCoord(); -// Coord_j = geometry->node[jPoint]->GetCoord(); -// -// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { -// -// /*--- Calculate the interface left gradient, delta- (dm) ---*/ -// dm = 0.0; -// for (iDim = 0; iDim < nDim; iDim++) -// dm += 0.5*(Coord_j[iDim]-Coord_i[iDim])*Gradient_i[iVar][iDim]; -// -// /*--- Calculate the interface right gradient, delta+ (dp) ---*/ -// if ( dm > 0.0 ) dp = node[iPoint]->GetSolution_Max(iVar); -// else dp = node[iPoint]->GetSolution_Min(iVar); -// -// limiter = ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); -// -// if (limiter < node[iPoint]->GetLimiter_Secondary(iVar)) -// if (geometry->node[iPoint]->GetDomain()) node[iPoint]->SetLimiter_Secondary(iVar, limiter); -// -// /*-- Repeat for point j on the edge ---*/ -// dm = 0.0; -// for (iDim = 0; iDim < nDim; iDim++) -// dm += 0.5*(Coord_i[iDim]-Coord_j[iDim])*Gradient_j[iVar][iDim]; -// -// if ( dm > 0.0 ) dp = node[jPoint]->GetSolution_Max(iVar); -// else dp = node[jPoint]->GetSolution_Min(iVar); -// -// limiter = ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); -// -// if (limiter < node[jPoint]->GetLimiter_Secondary(iVar)) -// if (geometry->node[jPoint]->GetDomain()) node[jPoint]->SetLimiter_Secondary(iVar, limiter); -// } -// } -// } -// -// /*--- Limiter MPI ---*/ -// Set_MPI_Secondary_Limiter(geometry, config); -// -//} - -void CEulerSolver::SetPreconditioner(CConfig *config, unsigned long iPoint) { - unsigned short iDim, jDim, iVar, jVar; - su2double Beta, local_Mach, Beta2, rho, enthalpy, soundspeed, sq_vel; - su2double *U_i = NULL; - su2double Beta_min = config->GetminTurkelBeta(); - su2double Beta_max = config->GetmaxTurkelBeta(); - - - /*--- Variables to calculate the preconditioner parameter Beta ---*/ - local_Mach = sqrt(node[iPoint]->GetVelocity2())/node[iPoint]->GetSoundSpeed(); - Beta = max(Beta_min, min(local_Mach, Beta_max)); - Beta2 = Beta*Beta; - - U_i = node[iPoint]->GetSolution(); - - rho = U_i[0]; - enthalpy = node[iPoint]->GetEnthalpy(); - soundspeed = node[iPoint]->GetSoundSpeed(); - sq_vel = node[iPoint]->GetVelocity2(); - - /*---Calculating the inverse of the preconditioning matrix that multiplies the time derivative */ - LowMach_Precontioner[0][0] = 0.5*sq_vel; - LowMach_Precontioner[0][nVar-1] = 1.0; - for (iDim = 0; iDim < nDim; iDim ++) - LowMach_Precontioner[0][1+iDim] = -1.0*U_i[iDim+1]/rho; - - for (iDim = 0; iDim < nDim; iDim ++) { - LowMach_Precontioner[iDim+1][0] = 0.5*sq_vel*U_i[iDim+1]/rho; - LowMach_Precontioner[iDim+1][nVar-1] = U_i[iDim+1]/rho; - for (jDim = 0; jDim < nDim; jDim ++) { - LowMach_Precontioner[iDim+1][1+jDim] = -1.0*U_i[jDim+1]/rho*U_i[iDim+1]/rho; - } - } - - LowMach_Precontioner[nVar-1][0] = 0.5*sq_vel*enthalpy; - LowMach_Precontioner[nVar-1][nVar-1] = enthalpy; - for (iDim = 0; iDim < nDim; iDim ++) - LowMach_Precontioner[nVar-1][1+iDim] = -1.0*U_i[iDim+1]/rho*enthalpy; - - - for (iVar = 0; iVar < nVar; iVar ++ ) { - for (jVar = 0; jVar < nVar; jVar ++ ) { - LowMach_Precontioner[iVar][jVar] = (1.0/(Beta2+EPS) - 1.0) * (Gamma-1.0)/(soundspeed*soundspeed)*LowMach_Precontioner[iVar][jVar]; - if (iVar == jVar) - LowMach_Precontioner[iVar][iVar] += 1.0; - } - } - -} - -void CEulerSolver::GetEngine_Properties(CGeometry *geometry, CConfig *config, unsigned short iMesh, bool Output) { - - unsigned short iDim, iMarker, iMarker_EngineInflow, iMarker_EngineBleed, iMarker_EngineExhaust, iVar; - unsigned long iVertex, iPoint; - su2double Pressure, Temperature, Velocity[3], Velocity2, MassFlow, Density, Energy, Area, - Mach, SoundSpeed, Flow_Dir[3], alpha; - - su2double Gas_Constant = config->GetGas_ConstantND(); - unsigned short nMarker_EngineInflow = config->GetnMarker_EngineInflow(); - unsigned short nMarker_EngineBleed = config->GetnMarker_EngineBleed(); - unsigned short nMarker_EngineExhaust = config->GetnMarker_EngineExhaust(); - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Compute the numerical fan face Mach number, and the total area of the inflow ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - Inflow_MassFlow[iMarker] = 0.0; - Inflow_Mach[iMarker] = 0.0; - Inflow_Pressure[iMarker] = 0.0; - Inflow_Area[iMarker] = 0.0; - - Bleed_MassFlow[iMarker] = 0.0; - Bleed_Pressure[iMarker] = 0.0; - Bleed_Temperature[iMarker] = 0.0; - Bleed_Area[iMarker] = 0.0; - - Exhaust_MassFlow[iMarker] = 0.0; - Exhaust_Pressure[iMarker] = 0.0; - Exhaust_Temperature[iMarker] = 0.0; - Exhaust_Area[iMarker] = 0.0; - - if (config->GetMarker_All_KindBC(iMarker) == ENGINE_INFLOW) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - geometry->vertex[iMarker][iVertex]->GetNormal(Vector); - - Density = node[iPoint]->GetSolution(0); - Velocity2 = 0.0; Area = 0.0; MassFlow = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Area += Vector[iDim]*Vector[iDim]; - Velocity[iDim] = node[iPoint]->GetSolution(iDim+1)/Density; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - MassFlow -= Vector[iDim]*node[iPoint]->GetSolution(iDim+1); - } - - Area = sqrt (Area); - Energy = node[iPoint]->GetSolution(nVar-1)/Density; - Pressure = Gamma_Minus_One*Density*(Energy-0.5*Velocity2); - SoundSpeed = sqrt(Gamma*Pressure/Density); - Mach = sqrt(Velocity2)/SoundSpeed; - - /*--- Compute the Inflow_MassFlow, Inflow_Pressure, Inflow_Mach, and Inflow_Area ---*/ - - Inflow_MassFlow[iMarker] += MassFlow; - Inflow_Pressure[iMarker] += Pressure*Area; - Inflow_Mach[iMarker] += Mach*Area; - Inflow_Area[iMarker] += Area; - - } - } - - } - - if (config->GetMarker_All_KindBC(iMarker) == ENGINE_BLEED) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - geometry->vertex[iMarker][iVertex]->GetNormal(Vector); - - Density = node[iPoint]->GetSolution(0); - Velocity2 = 0.0; Area = 0.0; MassFlow = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Area += Vector[iDim]*Vector[iDim]; - Velocity[iDim] = node[iPoint]->GetSolution(iDim+1)/Density; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - MassFlow += Vector[iDim]*node[iPoint]->GetSolution(iDim+1); - } - - Area = sqrt (Area); - Energy = node[iPoint]->GetSolution(nVar-1)/Density; - Pressure = Gamma_Minus_One*Density*(Energy-0.5*Velocity2); - Temperature = Pressure / (Gas_Constant * Density); - - /*--- Compute the Bleed_MassFlow, Bleed_Pressure, Bleed_Temperature, and Bleed_Area ---*/ - - Bleed_MassFlow[iMarker] += MassFlow; - Bleed_Pressure[iMarker] += Pressure*Area; - Bleed_Temperature[iMarker] += Temperature*Area; - Bleed_Area[iMarker] += Area; - - } - } - - } - - if (config->GetMarker_All_KindBC(iMarker) == ENGINE_EXHAUST) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - geometry->vertex[iMarker][iVertex]->GetNormal(Vector); - - Density = node[iPoint]->GetSolution(0); - Velocity2 = 0.0; Area = 0.0; MassFlow = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Area += Vector[iDim]*Vector[iDim]; - Velocity[iDim] = node[iPoint]->GetSolution(iDim+1)/Density; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - MassFlow += Vector[iDim]*node[iPoint]->GetSolution(iDim+1); - } - - Area = sqrt (Area); - Energy = node[iPoint]->GetSolution(nVar-1)/Density; - Pressure = Gamma_Minus_One*Density*(Energy-0.5*Velocity2); - Temperature = Pressure / (Gas_Constant * Density); - - /*--- Compute the mass Exhaust_MassFlow ---*/ - - Exhaust_MassFlow[iMarker] += MassFlow; - Exhaust_Pressure[iMarker] += Pressure*Area; - Exhaust_Temperature[iMarker] += Temperature*Area; - Exhaust_Area[iMarker] += Area; - - } - } - - } - - } - - /*--- Copy to the appropriate structure ---*/ - - su2double *Inflow_MassFlow_Local = new su2double [nMarker_EngineInflow]; - su2double *Inflow_Mach_Local = new su2double [nMarker_EngineInflow]; - su2double *Inflow_Pressure_Local = new su2double [nMarker_EngineInflow]; - su2double *Inflow_Area_Local = new su2double [nMarker_EngineInflow]; - - su2double *Inflow_MassFlow_Total = new su2double [nMarker_EngineInflow]; - su2double *Inflow_Mach_Total = new su2double [nMarker_EngineInflow]; - su2double *Inflow_Pressure_Total = new su2double [nMarker_EngineInflow]; - su2double *Inflow_Area_Total = new su2double [nMarker_EngineInflow]; - - for (iMarker_EngineInflow = 0; iMarker_EngineInflow < nMarker_EngineInflow; iMarker_EngineInflow++) { - Inflow_MassFlow_Local[iMarker_EngineInflow] = 0.0; - Inflow_Mach_Local[iMarker_EngineInflow] = 0.0; - Inflow_Pressure_Local[iMarker_EngineInflow] = 0.0; - Inflow_Area_Local[iMarker_EngineInflow] = 0.0; - - Inflow_MassFlow_Total[iMarker_EngineInflow] = 0.0; - Inflow_Mach_Total[iMarker_EngineInflow] = 0.0; - Inflow_Pressure_Total[iMarker_EngineInflow] = 0.0; - Inflow_Area_Total[iMarker_EngineInflow] = 0.0; - } - - su2double *Bleed_MassFlow_Local = new su2double [nMarker_EngineBleed]; - su2double *Bleed_Temperature_Local = new su2double [nMarker_EngineBleed]; - su2double *Bleed_Pressure_Local = new su2double [nMarker_EngineBleed]; - su2double *Bleed_Area_Local = new su2double [nMarker_EngineBleed]; - - su2double *Bleed_MassFlow_Total = new su2double [nMarker_EngineBleed]; - su2double *Bleed_Temperature_Total = new su2double [nMarker_EngineBleed]; - su2double *Bleed_Pressure_Total = new su2double [nMarker_EngineBleed]; - su2double *Bleed_Area_Total = new su2double [nMarker_EngineBleed]; - - for (iMarker_EngineBleed = 0; iMarker_EngineBleed < nMarker_EngineBleed; iMarker_EngineBleed++) { - Bleed_MassFlow_Local[iMarker_EngineBleed] = 0.0; - Bleed_Temperature_Local[iMarker_EngineBleed] = 0.0; - Bleed_Pressure_Local[iMarker_EngineBleed] = 0.0; - Bleed_Area_Local[iMarker_EngineBleed] = 0.0; - - Bleed_MassFlow_Total[iMarker_EngineBleed] = 0.0; - Bleed_Temperature_Total[iMarker_EngineBleed] = 0.0; - Bleed_Pressure_Total[iMarker_EngineBleed] = 0.0; - Bleed_Area_Total[iMarker_EngineBleed] = 0.0; - } - - su2double *Exhaust_MassFlow_Local = new su2double [nMarker_EngineExhaust]; - su2double *Exhaust_Temperature_Local = new su2double [nMarker_EngineExhaust]; - su2double *Exhaust_Pressure_Local = new su2double [nMarker_EngineExhaust]; - su2double *Exhaust_Area_Local = new su2double [nMarker_EngineExhaust]; - - su2double *Exhaust_MassFlow_Total = new su2double [nMarker_EngineExhaust]; - su2double *Exhaust_Temperature_Total = new su2double [nMarker_EngineExhaust]; - su2double *Exhaust_Pressure_Total = new su2double [nMarker_EngineExhaust]; - su2double *Exhaust_Area_Total = new su2double [nMarker_EngineExhaust]; - - for (iMarker_EngineExhaust = 0; iMarker_EngineExhaust < nMarker_EngineExhaust; iMarker_EngineExhaust++) { - Exhaust_MassFlow_Local[iMarker_EngineExhaust] = 0.0; - Exhaust_Temperature_Local[iMarker_EngineExhaust] = 0.0; - Exhaust_Pressure_Local[iMarker_EngineExhaust] = 0.0; - Exhaust_Area_Local[iMarker_EngineExhaust] = 0.0; - - Exhaust_MassFlow_Total[iMarker_EngineExhaust] = 0.0; - Exhaust_Temperature_Total[iMarker_EngineExhaust] = 0.0; - Exhaust_Pressure_Total[iMarker_EngineExhaust] = 0.0; - Exhaust_Area_Total[iMarker_EngineExhaust] = 0.0; - } - - /*--- Compute the numerical fan face Mach number, mach number, temperature and the total area ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) == ENGINE_INFLOW) { - - for (iMarker_EngineInflow = 0; iMarker_EngineInflow < nMarker_EngineInflow; iMarker_EngineInflow++) { - - /*--- Add the Inflow_MassFlow, Inflow_Mach, Inflow_Pressure and Inflow_Area to the particular boundary ---*/ - - if (config->GetMarker_All_TagBound(iMarker) == config->GetMarker_EngineInflow(iMarker_EngineInflow)) { - Inflow_MassFlow_Local[iMarker_EngineInflow] += Inflow_MassFlow[iMarker]; - Inflow_Mach_Local[iMarker_EngineInflow] += Inflow_Mach[iMarker]; - Inflow_Pressure_Local[iMarker_EngineInflow] += Inflow_Pressure[iMarker]; - Inflow_Area_Local[iMarker_EngineInflow] += Inflow_Area[iMarker]; - } - - } - - } - - if (config->GetMarker_All_KindBC(iMarker) == ENGINE_BLEED) { - - for (iMarker_EngineBleed = 0; iMarker_EngineBleed < nMarker_EngineBleed; iMarker_EngineBleed++) { - - /*--- Add the Bleed_MassFlow, Bleed_Temperature, Bleed_Pressure and Bleed_Area to the particular boundary ---*/ - - if (config->GetMarker_All_TagBound(iMarker) == config->GetMarker_EngineBleed(iMarker_EngineBleed)) { - Bleed_MassFlow_Local[iMarker_EngineBleed] += Bleed_MassFlow[iMarker]; - Bleed_Temperature_Local[iMarker_EngineBleed] += Bleed_Temperature[iMarker]; - Bleed_Pressure_Local[iMarker_EngineBleed] += Bleed_Pressure[iMarker]; - Bleed_Area_Local[iMarker_EngineBleed] += Bleed_Area[iMarker]; - } - - } - - } - - if (config->GetMarker_All_KindBC(iMarker) == ENGINE_EXHAUST) { - - for (iMarker_EngineExhaust= 0; iMarker_EngineExhaust < nMarker_EngineExhaust; iMarker_EngineExhaust++) { - - /*--- Add the Exhaust_MassFlow, and Exhaust_Area to the particular boundary ---*/ - - if (config->GetMarker_All_TagBound(iMarker) == config->GetMarker_EngineExhaust(iMarker_EngineExhaust)) { - Exhaust_MassFlow_Local[iMarker_EngineExhaust] += Exhaust_MassFlow[iMarker]; - Exhaust_Temperature_Local[iMarker_EngineExhaust] += Exhaust_Temperature[iMarker]; - Exhaust_Pressure_Local[iMarker_EngineExhaust] += Exhaust_Pressure[iMarker]; - Exhaust_Area_Local[iMarker_EngineExhaust] += Exhaust_Area[iMarker]; - } - - } - - } - - } - -#ifdef HAVE_MPI - - SU2_MPI::Allreduce(Inflow_MassFlow_Local, Inflow_MassFlow_Total, nMarker_EngineInflow, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(Inflow_Mach_Local, Inflow_Mach_Total, nMarker_EngineInflow, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(Inflow_Pressure_Local, Inflow_Pressure_Total, nMarker_EngineInflow, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(Inflow_Area_Local, Inflow_Area_Total, nMarker_EngineInflow, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - - SU2_MPI::Allreduce(Bleed_MassFlow_Local, Bleed_MassFlow_Total, nMarker_EngineBleed, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(Bleed_Temperature_Local, Bleed_Temperature_Total, nMarker_EngineBleed, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(Bleed_Pressure_Local, Bleed_Pressure_Total, nMarker_EngineBleed, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(Bleed_Area_Local, Bleed_Area_Total, nMarker_EngineBleed, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - - SU2_MPI::Allreduce(Exhaust_MassFlow_Local, Exhaust_MassFlow_Total, nMarker_EngineExhaust, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(Exhaust_Temperature_Local, Exhaust_Temperature_Total, nMarker_EngineExhaust, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(Exhaust_Pressure_Local, Exhaust_Pressure_Total, nMarker_EngineExhaust, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(Exhaust_Area_Local, Exhaust_Area_Total, nMarker_EngineExhaust, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - -#else - - for (iMarker_EngineInflow = 0; iMarker_EngineInflow < nMarker_EngineInflow; iMarker_EngineInflow++) { - Inflow_MassFlow_Total[iMarker_EngineInflow] = Inflow_MassFlow_Local[iMarker_EngineInflow]; - Inflow_Mach_Total[iMarker_EngineInflow] = Inflow_Mach_Local[iMarker_EngineInflow]; - Inflow_Pressure_Total[iMarker_EngineInflow] = Inflow_Pressure_Local[iMarker_EngineInflow]; - Inflow_Area_Total[iMarker_EngineInflow] = Inflow_Area_Local[iMarker_EngineInflow]; - } - - for (iMarker_EngineBleed = 0; iMarker_EngineBleed < nMarker_EngineBleed; iMarker_EngineBleed++) { - Bleed_MassFlow_Total[iMarker_EngineBleed] = Bleed_MassFlow_Local[iMarker_EngineBleed]; - Bleed_Temperature_Total[iMarker_EngineBleed] = Bleed_Temperature_Local[iMarker_EngineBleed]; - Bleed_Pressure_Total[iMarker_EngineBleed] = Bleed_Pressure_Local[iMarker_EngineBleed]; - Bleed_Area_Total[iMarker_EngineBleed] = Bleed_Area_Local[iMarker_EngineBleed]; - } - - for (iMarker_EngineExhaust = 0; iMarker_EngineExhaust < nMarker_EngineExhaust; iMarker_EngineExhaust++) { - Exhaust_MassFlow_Total[iMarker_EngineExhaust] = Exhaust_MassFlow_Local[iMarker_EngineExhaust]; - Exhaust_Temperature_Total[iMarker_EngineExhaust] = Exhaust_Temperature_Local[iMarker_EngineExhaust]; - Exhaust_Pressure_Total[iMarker_EngineExhaust] = Exhaust_Pressure_Local[iMarker_EngineExhaust]; - Exhaust_Area_Total[iMarker_EngineExhaust] = Exhaust_Area_Local[iMarker_EngineExhaust]; - } - -#endif - - /*--- Compute the value of Inflow_Area_Total, and Inflow_Pressure_Total, and - set the value in the config structure for future use ---*/ - - for (iMarker_EngineInflow = 0; iMarker_EngineInflow < nMarker_EngineInflow; iMarker_EngineInflow++) { - if (Inflow_Area_Total[iMarker_EngineInflow] != 0.0) Inflow_Mach_Total[iMarker_EngineInflow] /= Inflow_Area_Total[iMarker_EngineInflow]; - else Inflow_Mach_Total[iMarker_EngineInflow] = 0.0; - if (Inflow_Area_Total[iMarker_EngineInflow] != 0.0) Inflow_Pressure_Total[iMarker_EngineInflow] /= Inflow_Area_Total[iMarker_EngineInflow]; - else Inflow_Pressure_Total[iMarker_EngineInflow] = 0.0; - - if (iMesh == MESH_0) { - config->SetInflow_Mach(iMarker_EngineInflow, Inflow_Mach_Total[iMarker_EngineInflow]); - config->SetInflow_Pressure(iMarker_EngineInflow, Inflow_Pressure_Total[iMarker_EngineInflow]); - } - - } - - /*--- Compute the value of Bleed_Area_Total, and Bleed_Pressure_Total, and - set the value in the config structure for future use ---*/ - - for (iMarker_EngineBleed = 0; iMarker_EngineBleed < nMarker_EngineBleed; iMarker_EngineBleed++) { - if (Bleed_Area_Total[iMarker_EngineBleed] != 0.0) Bleed_Temperature_Total[iMarker_EngineBleed] /= Bleed_Area_Total[iMarker_EngineBleed]; - else Bleed_Temperature_Total[iMarker_EngineBleed] = 0.0; - if (Bleed_Area_Total[iMarker_EngineBleed] != 0.0) Bleed_Pressure_Total[iMarker_EngineBleed] /= Bleed_Area_Total[iMarker_EngineBleed]; - else Bleed_Pressure_Total[iMarker_EngineBleed] = 0.0; - - if (iMesh == MESH_0) { - config->SetBleed_Temperature(iMarker_EngineBleed, Bleed_Temperature_Total[iMarker_EngineBleed]); - config->SetBleed_MassFlow(iMarker_EngineBleed, Bleed_MassFlow_Total[iMarker_EngineBleed]); - config->SetBleed_Pressure(iMarker_EngineBleed, Bleed_Pressure_Total[iMarker_EngineBleed]); - } - - } - - /*--- Compute the value of Exhaust_Area_Total, and Exhaust_Pressure_Total, and - set the value in the config structure for future use ---*/ - - for (iMarker_EngineExhaust = 0; iMarker_EngineExhaust < nMarker_EngineExhaust; iMarker_EngineExhaust++) { - if (Exhaust_Area_Total[iMarker_EngineExhaust] != 0.0) Exhaust_Temperature_Total[iMarker_EngineExhaust] /= Exhaust_Area_Total[iMarker_EngineExhaust]; - else Exhaust_Temperature_Total[iMarker_EngineExhaust] = 0.0; - if (Exhaust_Area_Total[iMarker_EngineExhaust] != 0.0) Exhaust_Pressure_Total[iMarker_EngineExhaust] /= Exhaust_Area_Total[iMarker_EngineExhaust]; - else Exhaust_Pressure_Total[iMarker_EngineExhaust] = 0.0; - - if (iMesh == MESH_0) { - config->SetExhaust_Temperature(iMarker_EngineExhaust, Exhaust_Temperature_Total[iMarker_EngineExhaust]); - config->SetExhaust_Pressure(iMarker_EngineExhaust, Exhaust_Pressure_Total[iMarker_EngineExhaust]); - } - - } - - bool write_heads = (((config->GetExtIter() % (config->GetWrt_Con_Freq()*40)) == 0)); - - if ((rank == MASTER_NODE) && (iMesh == MESH_0) && write_heads && Output) { - - cout.precision(4); - cout.setf(ios::fixed, ios::floatfield); - - cout << endl << "---------------------------- Engine properties --------------------------" << endl; - for (iMarker_EngineInflow = 0; iMarker_EngineInflow < nMarker_EngineInflow; iMarker_EngineInflow++) { - cout << "Engine inflow ("<< config->GetMarker_EngineInflow(iMarker_EngineInflow); - if (config->GetSystemMeasurements() == SI) cout << "): Mass flow (kg/s): "; - else if (config->GetSystemMeasurements() == US) cout << "): Mass flow (slug/s): "; - cout << Inflow_MassFlow_Total[iMarker_EngineInflow] * config->GetDensity_Ref() * config->GetVelocity_Ref() - << ", Mach: " << Inflow_Mach_Total[iMarker_EngineInflow]; - if (config->GetSystemMeasurements() == SI) cout << ", Area (m^2): "; - else if (config->GetSystemMeasurements() == US) cout << ", Area (ft^2): "; - cout << Inflow_Area_Total[iMarker_EngineInflow] <<"."<< endl; - } - - for (iMarker_EngineBleed = 0; iMarker_EngineBleed < nMarker_EngineBleed; iMarker_EngineBleed++) { - cout << "Engine bleed ("<< config->GetMarker_EngineBleed(iMarker_EngineBleed); - if (config->GetSystemMeasurements() == SI) cout << "): Mass flow (kg/s): "; - else if (config->GetSystemMeasurements() == US) cout << "): Mass flow (slug/s): "; - cout << Bleed_MassFlow_Total[iMarker_EngineBleed] * config->GetDensity_Ref() * config->GetVelocity_Ref(); - if (config->GetSystemMeasurements() == SI) cout << ", Temp (K): "; - else if (config->GetSystemMeasurements() == US) cout << ", Temp (R): "; - cout << Bleed_Temperature_Total[iMarker_EngineBleed] * config->GetTemperature_Ref(); - if (config->GetSystemMeasurements() == SI) cout << ", Area (m^2): "; - else if (config->GetSystemMeasurements() == US) cout << ", Area (ft^2): "; - cout << Bleed_Area_Total[iMarker_EngineBleed] <<"."<< endl; - } - - for (iMarker_EngineExhaust = 0; iMarker_EngineExhaust < nMarker_EngineExhaust; iMarker_EngineExhaust++) { - cout << "Engine exhaust ("<< config->GetMarker_EngineExhaust(iMarker_EngineExhaust); - if (config->GetSystemMeasurements() == SI) cout << "): Mass flow (kg/s): "; - else if (config->GetSystemMeasurements() == US) cout << "): Mass flow (slug/s): "; - cout << Exhaust_MassFlow_Total[iMarker_EngineExhaust] * config->GetDensity_Ref() * config->GetVelocity_Ref(); - if (config->GetSystemMeasurements() == SI) cout << ", Temp (K): "; - else if (config->GetSystemMeasurements() == US) cout << ", Temp (R): "; - cout << Exhaust_Temperature_Total[iMarker_EngineExhaust] * config->GetTemperature_Ref(); - if (config->GetSystemMeasurements() == SI) cout << ", Pressure (Pa): "; - else if (config->GetSystemMeasurements() == US) cout << ", Pressure (psf): "; - cout << Exhaust_Pressure_Total[iMarker_EngineExhaust] * config->GetPressure_Ref(); - if (config->GetSystemMeasurements() == SI) cout << ", Area (m^2): "; - else if (config->GetSystemMeasurements() == US) cout << ", Area (ft^2): "; - cout << Exhaust_Area_Total[iMarker_EngineExhaust] <<"."<< endl; - } - cout << "-------------------------------------------------------------------------" << endl; - - } - - /*--- Check the flow orientation in the engine ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == ENGINE_INFLOW) || - (config->GetMarker_All_KindBC(iMarker) == ENGINE_EXHAUST) || - (config->GetMarker_All_KindBC(iMarker) == ENGINE_BLEED)) { - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[iMarker][iVertex]->GetNormal(Vector); - - for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = -Vector[iDim]; - - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Area += Vector[iDim]*Vector[iDim]; - Area = sqrt (Area); - - /*--- Compute unitary vector ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - Vector[iDim] /= Area; - - /*--- The flow direction is defined by the local velocity on the surface ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - Flow_Dir[iDim] = node[iPoint]->GetSolution(iDim+1) / node[iPoint]->GetSolution(0); - - /*--- Dot product of normal and flow direction. ---*/ - - alpha = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - alpha += Vector[iDim]*Flow_Dir[iDim]; - - /*--- Flow in the wrong direction. ---*/ - - if (((config->GetMarker_All_KindBC(iMarker) == ENGINE_EXHAUST) || - (config->GetMarker_All_KindBC(iMarker) == ENGINE_BLEED)) && (alpha > 0.0)) { - - /*--- Copy the old solution ---*/ - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetSolution(iVar, node[iPoint]->GetSolution_Old(iVar)); - - } - - if ((config->GetMarker_All_KindBC(iMarker) == ENGINE_INFLOW) && (alpha < 0.0)) { - - /*--- Copy the old solution ---*/ - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetSolution(iVar, node[iPoint]->GetSolution_Old(iVar)); - - } - - } - - } - - } - - - delete [] Inflow_MassFlow_Local; - delete [] Inflow_Mach_Local; - delete [] Inflow_Pressure_Local; - delete [] Inflow_Area_Local; - - delete [] Inflow_MassFlow_Total; - delete [] Inflow_Mach_Total; - delete [] Inflow_Pressure_Total; - delete [] Inflow_Area_Total; - - delete [] Exhaust_MassFlow_Local; - delete [] Exhaust_Temperature_Local; - delete [] Exhaust_Pressure_Local; - delete [] Exhaust_Area_Local; - - delete [] Exhaust_MassFlow_Total; - delete [] Exhaust_Temperature_Total; - delete [] Exhaust_Pressure_Total; - delete [] Exhaust_Area_Total; - - delete [] Bleed_MassFlow_Local; - delete [] Bleed_Temperature_Local; - delete [] Bleed_Pressure_Local; - delete [] Bleed_Area_Local; - - delete [] Bleed_MassFlow_Total; - delete [] Bleed_Temperature_Total; - delete [] Bleed_Pressure_Total; - delete [] Bleed_Area_Total; - -} - -void CEulerSolver::GetActuatorDisk_Properties(CGeometry *geometry, CConfig *config, unsigned short iMesh, bool Output) { - - unsigned short iDim, iMarker; - unsigned long iVertex, iPoint; - su2double Pressure, Temperature, Velocity[3], Velocity2, MassFlow, Density, Energy, Area; - unsigned short iMarker_ActDiskInlet, iMarker_ActDiskOutlet; - - su2double Gas_Constant = config->GetGas_ConstantND(); - - unsigned short nMarker_ActDiskInlet = config->GetnMarker_ActDisk_Inlet(); - unsigned short nMarker_ActDiskOutlet = config->GetnMarker_ActDisk_Outlet(); - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - su2double *Inlet_MassFlow = new su2double [config->GetnMarker_All()]; - su2double *Inlet_Pressure = new su2double [config->GetnMarker_All()]; - su2double *Inlet_Temperature = new su2double [config->GetnMarker_All()]; - su2double *Inlet_Area = new su2double [config->GetnMarker_All()]; - - su2double *Outlet_MassFlow = new su2double [config->GetnMarker_All()]; - su2double *Outlet_Pressure = new su2double [config->GetnMarker_All()]; - su2double *Outlet_Temperature = new su2double [config->GetnMarker_All()]; - su2double *Outlet_Area = new su2double [config->GetnMarker_All()]; - - /*--- Compute the numerical fan face Mach number, and the total area of the inflow ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - Inlet_MassFlow[iMarker] = 0.0; - Inlet_Pressure[iMarker] = 0.0; - Inlet_Temperature[iMarker] = 0.0; - Inlet_Area[iMarker] = 0.0; - - Outlet_MassFlow[iMarker] = 0.0; - Outlet_Pressure[iMarker] = 0.0; - Outlet_Temperature[iMarker] = 0.0; - Outlet_Area[iMarker] = 0.0; - - if (config->GetMarker_All_KindBC(iMarker) == ACTDISK_INLET) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - geometry->vertex[iMarker][iVertex]->GetNormal(Vector); - - Density = node[iPoint]->GetSolution(0); - Velocity2 = 0.0; Area = 0.0; MassFlow = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Area += Vector[iDim]*Vector[iDim]; - Velocity[iDim] = node[iPoint]->GetSolution(iDim+1)/Density; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - MassFlow += Vector[iDim]*node[iPoint]->GetSolution(iDim+1); - } - - Area = sqrt (Area); - Energy = node[iPoint]->GetSolution(nVar-1)/Density; - Pressure = Gamma_Minus_One*Density*(Energy-0.5*Velocity2); - Temperature = Pressure / (Gas_Constant * Density); - - /*--- Compute the Inlet_MassFlow, Inlet_Pressure, Inlet_Temperature, and Inlet_Area ---*/ - - Inlet_MassFlow[iMarker] += MassFlow; - Inlet_Pressure[iMarker] += Pressure*Area; - Inlet_Temperature[iMarker] += Temperature*Area; - Inlet_Area[iMarker] += Area; - - } - } - - } - - if (config->GetMarker_All_KindBC(iMarker) == ACTDISK_OUTLET) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - geometry->vertex[iMarker][iVertex]->GetNormal(Vector); - - Density = node[iPoint]->GetSolution(0); - Velocity2 = 0.0; Area = 0.0; MassFlow = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Area += Vector[iDim]*Vector[iDim]; - Velocity[iDim] = node[iPoint]->GetSolution(iDim+1)/Density; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - MassFlow += Vector[iDim]*node[iPoint]->GetSolution(iDim+1); - } - - Area = sqrt (Area); - Energy = node[iPoint]->GetSolution(nVar-1)/Density; - Pressure = Gamma_Minus_One*Density*(Energy-0.5*Velocity2); - Temperature = Pressure / (Gas_Constant * Density); - - /*--- Compute the mass Outlet_MassFlow ---*/ - - Outlet_MassFlow[iMarker] += MassFlow; - Outlet_Pressure[iMarker] += Pressure*Area; - Outlet_Temperature[iMarker] += Temperature*Area; - Outlet_Area[iMarker] += Area; - - } - } - - } - - } - - /*--- Copy to the appropriate structure ---*/ - - su2double *Inlet_MassFlow_Local = new su2double [nMarker_ActDiskInlet]; - su2double *Inlet_Temperature_Local = new su2double [nMarker_ActDiskInlet]; - su2double *Inlet_Pressure_Local = new su2double [nMarker_ActDiskInlet]; - su2double *Inlet_Area_Local = new su2double [nMarker_ActDiskInlet]; - - su2double *Inlet_MassFlow_Total = new su2double [nMarker_ActDiskInlet]; - su2double *Inlet_Temperature_Total = new su2double [nMarker_ActDiskInlet]; - su2double *Inlet_Pressure_Total = new su2double [nMarker_ActDiskInlet]; - su2double *Inlet_Area_Total = new su2double [nMarker_ActDiskInlet]; - - for (iMarker_ActDiskInlet = 0; iMarker_ActDiskInlet < nMarker_ActDiskInlet; iMarker_ActDiskInlet++) { - Inlet_MassFlow_Local[iMarker_ActDiskInlet] = 0.0; - Inlet_Temperature_Local[iMarker_ActDiskInlet] = 0.0; - Inlet_Pressure_Local[iMarker_ActDiskInlet] = 0.0; - Inlet_Area_Local[iMarker_ActDiskInlet] = 0.0; - - Inlet_MassFlow_Total[iMarker_ActDiskInlet] = 0.0; - Inlet_Temperature_Total[iMarker_ActDiskInlet] = 0.0; - Inlet_Pressure_Total[iMarker_ActDiskInlet] = 0.0; - Inlet_Area_Total[iMarker_ActDiskInlet] = 0.0; - } - - su2double *Outlet_MassFlow_Local = new su2double [nMarker_ActDiskOutlet]; - su2double *Outlet_Temperature_Local = new su2double [nMarker_ActDiskOutlet]; - su2double *Outlet_Pressure_Local = new su2double [nMarker_ActDiskOutlet]; - su2double *Outlet_Area_Local = new su2double [nMarker_ActDiskOutlet]; - - su2double *Outlet_MassFlow_Total = new su2double [nMarker_ActDiskOutlet]; - su2double *Outlet_Temperature_Total = new su2double [nMarker_ActDiskOutlet]; - su2double *Outlet_Pressure_Total = new su2double [nMarker_ActDiskOutlet]; - su2double *Outlet_Area_Total = new su2double [nMarker_ActDiskOutlet]; - - for (iMarker_ActDiskOutlet = 0; iMarker_ActDiskOutlet < nMarker_ActDiskOutlet; iMarker_ActDiskOutlet++) { - Outlet_MassFlow_Local[iMarker_ActDiskOutlet] = 0.0; - Outlet_Temperature_Local[iMarker_ActDiskOutlet] = 0.0; - Outlet_Pressure_Local[iMarker_ActDiskOutlet] = 0.0; - Outlet_Area_Local[iMarker_ActDiskOutlet] = 0.0; - - Outlet_MassFlow_Total[iMarker_ActDiskOutlet] = 0.0; - Outlet_Temperature_Total[iMarker_ActDiskOutlet] = 0.0; - Outlet_Pressure_Total[iMarker_ActDiskOutlet] = 0.0; - Outlet_Area_Total[iMarker_ActDiskOutlet] = 0.0; - } - - /*--- Compute the numerical fan face Mach number, mach number, temperature and the total area ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) == ACTDISK_INLET) { - - for (iMarker_ActDiskInlet = 0; iMarker_ActDiskInlet < nMarker_ActDiskInlet; iMarker_ActDiskInlet++) { - - /*--- Add the Inlet_MassFlow, Inlet_Temperature, Inlet_Pressure and Inlet_Area to the particular boundary ---*/ - - if (config->GetMarker_All_TagBound(iMarker) == config->GetMarker_ActDisk_Inlet(iMarker_ActDiskInlet)) { - Inlet_MassFlow_Local[iMarker_ActDiskInlet] += Inlet_MassFlow[iMarker]; - Inlet_Temperature_Local[iMarker_ActDiskInlet] += Inlet_Temperature[iMarker]; - Inlet_Pressure_Local[iMarker_ActDiskInlet] += Inlet_Pressure[iMarker]; - Inlet_Area_Local[iMarker_ActDiskInlet] += Inlet_Area[iMarker]; - } - - } - - } - - if (config->GetMarker_All_KindBC(iMarker) == ACTDISK_OUTLET) { - - for (iMarker_ActDiskOutlet= 0; iMarker_ActDiskOutlet < nMarker_ActDiskOutlet; iMarker_ActDiskOutlet++) { - - /*--- Add the Outlet_MassFlow, and Outlet_Area to the particular boundary ---*/ - - if (config->GetMarker_All_TagBound(iMarker) == config->GetMarker_ActDisk_Outlet(iMarker_ActDiskOutlet)) { - Outlet_MassFlow_Local[iMarker_ActDiskOutlet] += Outlet_MassFlow[iMarker]; - Outlet_Temperature_Local[iMarker_ActDiskOutlet] += Outlet_Temperature[iMarker]; - Outlet_Pressure_Local[iMarker_ActDiskOutlet] += Outlet_Pressure[iMarker]; - Outlet_Area_Local[iMarker_ActDiskOutlet] += Outlet_Area[iMarker]; - } - - } - - } - - } - -#ifdef HAVE_MPI - - SU2_MPI::Allreduce(Inlet_MassFlow_Local, Inlet_MassFlow_Total, nMarker_ActDiskInlet, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(Inlet_Temperature_Local, Inlet_Temperature_Total, nMarker_ActDiskInlet, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(Inlet_Pressure_Local, Inlet_Pressure_Total, nMarker_ActDiskInlet, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(Inlet_Area_Local, Inlet_Area_Total, nMarker_ActDiskInlet, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - - SU2_MPI::Allreduce(Outlet_MassFlow_Local, Outlet_MassFlow_Total, nMarker_ActDiskOutlet, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(Outlet_Temperature_Local, Outlet_Temperature_Total, nMarker_ActDiskOutlet, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(Outlet_Pressure_Local, Outlet_Pressure_Total, nMarker_ActDiskOutlet, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(Outlet_Area_Local, Outlet_Area_Total, nMarker_ActDiskOutlet, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - -#else - - for (iMarker_ActDiskInlet = 0; iMarker_ActDiskInlet < nMarker_ActDiskInlet; iMarker_ActDiskInlet++) { - Inlet_MassFlow_Total[iMarker_ActDiskInlet] = Inlet_MassFlow_Local[iMarker_ActDiskInlet]; - Inlet_Temperature_Total[iMarker_ActDiskInlet] = Inlet_Temperature_Local[iMarker_ActDiskInlet]; - Inlet_Pressure_Total[iMarker_ActDiskInlet] = Inlet_Pressure_Local[iMarker_ActDiskInlet]; - Inlet_Area_Total[iMarker_ActDiskInlet] = Inlet_Area_Local[iMarker_ActDiskInlet]; - } - - for (iMarker_ActDiskOutlet = 0; iMarker_ActDiskOutlet < nMarker_ActDiskOutlet; iMarker_ActDiskOutlet++) { - Outlet_MassFlow_Total[iMarker_ActDiskOutlet] = Outlet_MassFlow_Local[iMarker_ActDiskOutlet]; - Outlet_Temperature_Total[iMarker_ActDiskOutlet] = Outlet_Temperature_Local[iMarker_ActDiskOutlet]; - Outlet_Pressure_Total[iMarker_ActDiskOutlet] = Outlet_Pressure_Local[iMarker_ActDiskOutlet]; - Outlet_Area_Total[iMarker_ActDiskOutlet] = Outlet_Area_Local[iMarker_ActDiskOutlet]; - } - -#endif - - /*--- Compute the value of Inlet_Area_Total, and Inlet_Pressure_Total, and - set the value in the config structure for future use ---*/ - - for (iMarker_ActDiskInlet = 0; iMarker_ActDiskInlet < nMarker_ActDiskInlet; iMarker_ActDiskInlet++) { - if (Inlet_Area_Total[iMarker_ActDiskInlet] != 0.0) Inlet_Temperature_Total[iMarker_ActDiskInlet] /= Inlet_Area_Total[iMarker_ActDiskInlet]; - else Inlet_Temperature_Total[iMarker_ActDiskInlet] = 0.0; - if (Inlet_Area_Total[iMarker_ActDiskInlet] != 0.0) Inlet_Pressure_Total[iMarker_ActDiskInlet] /= Inlet_Area_Total[iMarker_ActDiskInlet]; - else Inlet_Pressure_Total[iMarker_ActDiskInlet] = 0.0; - } - - /*--- Compute the value of Outlet_Area_Total, and Outlet_Pressure_Total, and - set the value in the config structure for future use ---*/ - - for (iMarker_ActDiskOutlet = 0; iMarker_ActDiskOutlet < nMarker_ActDiskOutlet; iMarker_ActDiskOutlet++) { - if (Outlet_Area_Total[iMarker_ActDiskOutlet] != 0.0) Outlet_Temperature_Total[iMarker_ActDiskOutlet] /= Outlet_Area_Total[iMarker_ActDiskOutlet]; - else Outlet_Temperature_Total[iMarker_ActDiskOutlet] = 0.0; - if (Outlet_Area_Total[iMarker_ActDiskOutlet] != 0.0) Outlet_Pressure_Total[iMarker_ActDiskOutlet] /= Outlet_Area_Total[iMarker_ActDiskOutlet]; - else Outlet_Pressure_Total[iMarker_ActDiskOutlet] = 0.0; - } - - bool write_heads = (((config->GetExtIter() % (config->GetWrt_Con_Freq()*40)) == 0)); - - if ((rank == MASTER_NODE) && (iMesh == MESH_0) && write_heads && Output) { - - cout.precision(4); - cout.setf(ios::fixed, ios::floatfield); - - cout << endl << "------------------------ Actuator Disk properties -----------------------" << endl; - - for (iMarker_ActDiskInlet = 0; iMarker_ActDiskInlet < nMarker_ActDiskInlet; iMarker_ActDiskInlet++) { - cout << "Actuator Disk Inlet ("<< config->GetMarker_ActDisk_Inlet(iMarker_ActDiskInlet); - if (config->GetSystemMeasurements() == SI) cout << "): Mass flow (kg/s): "; - else if (config->GetSystemMeasurements() == US) cout << "): Mass flow (slug/s): "; - cout << -Inlet_MassFlow_Total[iMarker_ActDiskInlet] * config->GetDensity_Ref() * config->GetVelocity_Ref(); - if (config->GetSystemMeasurements() == SI) cout << ", Temp (K): "; - else if (config->GetSystemMeasurements() == US) cout << ", Temp (R): "; - cout << Inlet_Temperature_Total[iMarker_ActDiskInlet] * config->GetTemperature_Ref(); - if (config->GetSystemMeasurements() == SI) cout << ", Pressure (Pa): "; - else if (config->GetSystemMeasurements() == US) cout << ", Pressure (psf): "; - cout << Inlet_Pressure_Total[iMarker_ActDiskInlet] * config->GetPressure_Ref(); - if (config->GetSystemMeasurements() == SI) cout << ", Area (m^2): "; - else if (config->GetSystemMeasurements() == US) cout << ", Area (ft^2): "; - cout << Inlet_Area_Total[iMarker_ActDiskInlet] <<"."<< endl; - } - - for (iMarker_ActDiskOutlet = 0; iMarker_ActDiskOutlet < nMarker_ActDiskOutlet; iMarker_ActDiskOutlet++) { - cout << "Actuator Disk Outlet ("<< config->GetMarker_ActDisk_Outlet(iMarker_ActDiskOutlet); - if (config->GetSystemMeasurements() == SI) cout << "): Mass flow (kg/s): "; - else if (config->GetSystemMeasurements() == US) cout << "): Mass flow (slug/s): "; - cout << Outlet_MassFlow_Total[iMarker_ActDiskOutlet] * config->GetDensity_Ref() * config->GetVelocity_Ref(); - if (config->GetSystemMeasurements() == SI) cout << ", Temp (K): "; - else if (config->GetSystemMeasurements() == US) cout << ", Temp (R): "; - cout << Outlet_Temperature_Total[iMarker_ActDiskOutlet] * config->GetTemperature_Ref(); - if (config->GetSystemMeasurements() == SI) cout << ", Pressure (Pa): "; - else if (config->GetSystemMeasurements() == US) cout << ", Pressure (psf): "; - cout << Outlet_Pressure_Total[iMarker_ActDiskOutlet] * config->GetPressure_Ref(); - if (config->GetSystemMeasurements() == SI) cout << ", Area (m^2): "; - else if (config->GetSystemMeasurements() == US) cout << ", Area (ft^2): "; - cout << Outlet_Area_Total[iMarker_ActDiskOutlet] <<"."<< endl; - } - cout << "-------------------------------------------------------------------------" << endl; - - } - - delete [] Outlet_MassFlow_Local; - delete [] Outlet_Temperature_Local; - delete [] Outlet_Pressure_Local; - delete [] Outlet_Area_Local; - - delete [] Outlet_MassFlow_Total; - delete [] Outlet_Temperature_Total; - delete [] Outlet_Pressure_Total; - delete [] Outlet_Area_Total; - - delete [] Inlet_MassFlow_Local; - delete [] Inlet_Temperature_Local; - delete [] Inlet_Pressure_Local; - delete [] Inlet_Area_Local; - - delete [] Inlet_MassFlow_Total; - delete [] Inlet_Temperature_Total; - delete [] Inlet_Pressure_Total; - delete [] Inlet_Area_Total; - - - delete [] Inlet_MassFlow; - delete [] Inlet_Pressure; - delete [] Inlet_Temperature; - delete [] Inlet_Area; - - delete [] Outlet_MassFlow; - delete [] Outlet_Pressure; - delete [] Outlet_Temperature; - delete [] Outlet_Area; - -} - -void CEulerSolver::SetFarfield_AoA(CGeometry *geometry, CSolver **solver_container, - CConfig *config, unsigned short iMesh, bool Output) { - - unsigned short iDim, iCounter; - bool Update_AoA = false; - su2double Target_CL, AoA_inc, AoA; - su2double DampingFactor = config->GetDamp_Fixed_CL(); - unsigned long Iter_Fixed_CL = config->GetIter_Fixed_CL(); - unsigned long ExtIter = config->GetExtIter(); - su2double Beta = config->GetAoS()*PI_NUMBER/180.0; - su2double Vel_Infty[3], Vel_Infty_Mag; - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Only the fine mesh level should check the convergence criteria ---*/ - - if (iMesh == MESH_0) { - - /*--- Initialize the update flag to false ---*/ - - Update_AoA = false; - - /*--- Reevaluate Angle of Attack at a fix number of iterations ---*/ - - if (ExtIter % Iter_Fixed_CL == 0) { Update_AoA = true; }; - - /*--- Store the update boolean for use on other mesh levels in the MG ---*/ - - config->SetUpdate_AoA(Update_AoA); - - } - - else { - Update_AoA = config->GetUpdate_AoA(); - } - - /*--- If we are within two digits of convergence in the CL coefficient, - compute an updated value for the AoA at the farfield. We are iterating - on the AoA in order to match the specified fixed lift coefficient. ---*/ - - if (Update_AoA) { - - /*--- Retrieve the specified target CL value. ---*/ - - Target_CL = config->GetTarget_CL(); - - /*--- Retrieve the old AoA. ---*/ - - AoA_old = config->GetAoA()*PI_NUMBER/180.0; - - /*--- Estimate the increment in AoA based on a 2*pi lift curve slope ---*/ - - AoA_inc = (1.0/(2.0*PI_NUMBER))*(Target_CL - Total_CLift); - - /*--- Compute a new value for AoA on the fine mesh only ---*/ - - if (iMesh == MESH_0) - AoA = (1.0 - DampingFactor)*AoA_old + DampingFactor * (AoA_old + AoA_inc); - else - AoA = config->GetAoA()*PI_NUMBER/180.0; - - /*--- 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 ---*/ - - 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); - - /*--- Compute the new freestream velocity with the updated AoA ---*/ - - if (nDim == 2) { - Vel_Infty[0] = cos(AoA)*Vel_Infty_Mag; - Vel_Infty[1] = sin(AoA)*Vel_Infty_Mag; - } - if (nDim == 3) { - Vel_Infty[0] = cos(AoA)*cos(Beta)*Vel_Infty_Mag; - Vel_Infty[1] = sin(Beta)*Vel_Infty_Mag; - Vel_Infty[2] = sin(AoA)*cos(Beta)*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 AoA in config ---*/ - if (iMesh == MESH_0) { - for (iDim = 0; iDim < nDim; iDim++) - config->SetVelocity_FreeStreamND(Vel_Infty[iDim], iDim); - config->SetAoA(AoA*180.0/PI_NUMBER); - } - - /*--- Reset the local cauchy criteria ---*/ - Cauchy_Value = 0.0; - Cauchy_Counter = 0; - for (iCounter = 0; iCounter < config->GetCauchy_Elems(); iCounter++) - Cauchy_Serie[iCounter] = 0.0; - } - - /*--- Output some information to the console with the headers ---*/ - - bool write_heads = (((config->GetExtIter() % (config->GetWrt_Con_Freq()*40)) == 0)); - if ((rank == MASTER_NODE) && (iMesh == MESH_0) && write_heads && Output) { - cout.precision(7); - cout.setf(ios::fixed, ios::floatfield); - cout << endl << "----------------------------- Fixed CL Mode -----------------------------" << endl; - cout << "Target CL: " << config->GetTarget_CL(); - cout << ", Current CL: " << Total_CLift; - cout << ", Current AoA: " << config->GetAoA() << " deg." << endl; - cout << "-------------------------------------------------------------------------" << endl; - } - - -} - -void CEulerSolver::BC_Euler_Wall(CGeometry *geometry, CSolver **solver_container, - CNumerics *numerics, CConfig *config, unsigned short val_marker) { - - unsigned short iDim, iVar, jVar, kVar, jDim; - unsigned long iPoint, iVertex; - su2double Density = 0.0, Pressure = 0.0, *Normal = NULL, *GridVel = NULL, Area, UnitNormal[3], *NormalArea, - ProjGridVel = 0.0, turb_ke; - su2double Density_b, StaticEnergy_b, Enthalpy_b, *Velocity_b, Kappa_b, Chi_b, Energy_b, VelMagnitude2_b, Pressure_b; - su2double Density_i, *Velocity_i, ProjVelocity_i = 0.0, Energy_i, VelMagnitude2_i; - su2double **Jacobian_b, **DubDu; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool grid_movement = config->GetGrid_Movement(); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool tkeNeeded = (((config->GetKind_Solver() == RANS )|| (config->GetKind_Solver() == DISC_ADJ_RANS)) && - (config->GetKind_Turb_Model() == SST)); - - Normal = new su2double[nDim]; - NormalArea = new su2double[nDim]; - Velocity_b = new su2double[nDim]; - Velocity_i = new su2double[nDim]; - Jacobian_b = new su2double*[nVar]; - DubDu = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Jacobian_b[iVar] = new su2double[nVar]; - DubDu[iVar] = new su2double[nVar]; - } - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Normal vector for this vertex (negative for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; - Area = sqrt (Area); - - for (iDim = 0; iDim < nDim; iDim++) { - NormalArea[iDim] = -Normal[iDim]; - UnitNormal[iDim] = -Normal[iDim]/Area; - } - - /*--- Compressible solver ---*/ - - if (compressible) { - - /*--- Get the state i ---*/ - - VelMagnitude2_i = 0.0; ProjVelocity_i = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity_i[iDim] = node[iPoint]->GetVelocity(iDim); - ProjVelocity_i += Velocity_i[iDim]*UnitNormal[iDim]; - VelMagnitude2_i += Velocity_i[iDim]*Velocity_i[iDim]; - } - Density_i = node[iPoint]->GetDensity(); - Energy_i = node[iPoint]->GetEnergy(); - - /*--- Compute the boundary state b ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - Velocity_b[iDim] = Velocity_i[iDim] - ProjVelocity_i * UnitNormal[iDim]; //Force the velocity to be tangential to the surface. - - if (grid_movement) { - GridVel = geometry->node[iPoint]->GetGridVel(); - ProjGridVel = 0.0; - for (iDim = 0; iDim < nDim; iDim++) ProjGridVel += GridVel[iDim]*UnitNormal[iDim]; - for (iDim = 0; iDim < nDim; iDim++) Velocity_b[iDim] += GridVel[iDim] - ProjGridVel * UnitNormal[iDim]; - } - - VelMagnitude2_b = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - VelMagnitude2_b += Velocity_b[iDim] * Velocity_b[iDim]; - - /*--- Compute the residual ---*/ - - turb_ke = 0.0; - if (tkeNeeded) turb_ke = solver_container[TURB_SOL]->node[iPoint]->GetSolution(0); - - Density_b = Density_i; - StaticEnergy_b = Energy_i - 0.5 * VelMagnitude2_i - turb_ke; - Energy_b = StaticEnergy_b + 0.5 * VelMagnitude2_b + turb_ke; - - FluidModel->SetTDState_rhoe(Density_b, StaticEnergy_b); - Kappa_b = FluidModel->GetdPde_rho() / Density_b; - Chi_b = FluidModel->GetdPdrho_e() - Kappa_b * StaticEnergy_b; - Pressure_b = FluidModel->GetPressure(); - Enthalpy_b = Energy_b + Pressure_b/Density_b; - - numerics->GetInviscidProjFlux(&Density_b, Velocity_b, &Pressure_b, &Enthalpy_b, NormalArea, Residual); - - /*--- Grid velocity correction to the energy term ---*/ - if (grid_movement) { - GridVel = geometry->node[iPoint]->GetGridVel(); - ProjGridVel = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - ProjGridVel += GridVel[iDim]*UnitNormal[iDim]; - Residual[nVar-1] += Pressure_b*ProjGridVel*Area; - } - - /*--- Add the Reynolds stress tensor contribution ---*/ - - if (tkeNeeded) { - for (iDim = 0; iDim < nDim; iDim++) - Residual[iDim+1] += (2.0/3.0)*Density_b*turb_ke*NormalArea[iDim]; - } - - } - - /*--- Incompressible solver ---*/ - - if (incompressible || freesurface) { - - /*--- Compute the residual ---*/ - - Pressure = node[iPoint]->GetPressureInc(); - Density = node[iPoint]->GetPressureInc(); - - Residual[0] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Residual[iDim+1] = Pressure*NormalArea[iDim]; - if (compressible || freesurface) { - Residual[nVar-1] = 0.0; - } - - /*--- Add the Reynolds stress tensor contribution ---*/ - - if (tkeNeeded) { - turb_ke = solver_container[TURB_SOL]->node[iPoint]->GetSolution(0); - for (iDim = 0; iDim < nDim; iDim++) - Residual[iDim+1] += (2.0/3.0)*Density*turb_ke*NormalArea[iDim]; - } - - /*--- Adjustment to energy equation due to grid motion ---*/ - - if (grid_movement) { - ProjGridVel = 0.0; - GridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - ProjGridVel += GridVel[iDim]*UnitNormal[iDim]; - Residual[nVar-1] = Pressure*ProjGridVel*Area; - } - - } - - /*--- Add value to the residual ---*/ - - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Form Jacobians for implicit computations ---*/ - - if (implicit) { - - /*--- Initialize Jacobian ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - for (jVar = 0; jVar < nVar; jVar++) - Jacobian_i[iVar][jVar] = 0.0; - } - - /*--- Compressible solver ---*/ - - if (compressible) { - - /*--- Compute DubDu ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - for (jVar = 0; jVar < nVar; jVar++) - DubDu[iVar][jVar]= 0.0; - DubDu[iVar][iVar]= 1.0; - } - - for (iDim = 0; iDim < nDim; iDim++) - for (jDim = 0; jDimGetInviscidProjJac(Velocity_b, &Enthalpy_b, &Chi_b, &Kappa_b, NormalArea, 1, Jacobian_b); - - // Check for grid movement, should be already considered since Jacobian b is computed from u_b - // if (grid_movement) { - // Jacobian_b[nVar-1][0] += 0.5*ProjGridVel*ProjGridVel; - // for (iDim = 0; iDim < nDim; iDim++) - // Jacobian_b[nVar-1][iDim+1] -= ProjGridVel * UnitNormal[iDim]; - // } - - /*--- Compute numerical flux Jacobian at node i ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - for (kVar = 0; kVar < nVar; kVar++) - Jacobian_i[iVar][jVar] += Jacobian_b[iVar][kVar] * DubDu[kVar][jVar]; - - /*--- Add the Jacobian to the sparse matrix ---*/ - - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - } - - /*--- Incompressible solver ---*/ - - if (incompressible || freesurface) { - for (iDim = 0; iDim < nDim; iDim++) - Jacobian_i[iDim+1][0] = -Normal[iDim]; - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - } - - } - } - } - - delete [] Normal; - delete [] NormalArea; - delete [] Velocity_b; - delete [] Velocity_i; - for (iVar = 0; iVar < nVar; iVar++) { - delete [] Jacobian_b[iVar]; - delete [] DubDu[iVar]; - } - delete [] Jacobian_b; - delete [] DubDu; - -} - -void CEulerSolver::BC_Far_Field(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, - CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned short iDim; - unsigned long iVertex, iPoint, Point_Normal; - - su2double *GridVel; - su2double Area, UnitNormal[3] = {0.0,0.0,0.0}; - su2double Density, Pressure, Energy, Velocity[3] = {0.0,0.0,0.0}; - su2double Density_Bound, Pressure_Bound, Vel_Bound[3] = {0.0,0.0,0.0}; - su2double Density_Infty, Pressure_Infty, Vel_Infty[3] = {0.0,0.0,0.0}; - su2double SoundSpeed, Entropy, Velocity2, Vn; - su2double SoundSpeed_Bound, Entropy_Bound, Vel2_Bound, Vn_Bound; - su2double SoundSpeed_Infty, Entropy_Infty, Vel2_Infty, Vn_Infty, Qn_Infty; - su2double RiemannPlus, RiemannMinus; - su2double *V_infty, *V_domain; - - su2double Gas_Constant = config->GetGas_ConstantND(); - - bool implicit = config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT; - bool grid_movement = config->GetGrid_Movement(); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool viscous = config->GetViscous(); - bool tkeNeeded = (((config->GetKind_Solver() == RANS ) || - (config->GetKind_Solver() == DISC_ADJ_RANS)) - && (config->GetKind_Turb_Model() == SST)); - - su2double *Normal = new su2double[nDim]; - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Allocate the value at the infinity ---*/ - V_infty = GetCharacPrimVar(val_marker, iVertex); - - /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Index of the closest interior node ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - /*--- Retrieve solution at the farfield boundary node ---*/ - V_domain = node[iPoint]->GetPrimitive(); - - /*--- Construct solution state at infinity (far-field) ---*/ - - if (compressible) { - - /*--- Construct solution state at infinity for compressible flow by - using Riemann invariants, and then impose a weak boundary condition - by computing the flux using this new state for U. See CFD texts by - Hirsch or Blazek for more detail. Adapted from an original - implementation in the Stanford University multi-block (SUmb) solver - in the routine bcFarfield.f90 written by Edwin van der Weide, - last modified 06-12-2005. First, compute the unit normal at the - boundary nodes. ---*/ - - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; - Area = sqrt(Area); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = Normal[iDim]/Area; - - /*--- Store primitive variables (density, velocities, velocity squared, - energy, pressure, and sound speed) at the boundary node, and set some - other quantities for clarity. Project the current flow velocity vector - at this boundary node into the local normal direction, i.e. compute - v_bound.n. ---*/ - - Density_Bound = V_domain[nDim+2]; - Vel2_Bound = 0.0; Vn_Bound = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Vel_Bound[iDim] = V_domain[iDim+1]; - Vel2_Bound += Vel_Bound[iDim]*Vel_Bound[iDim]; - Vn_Bound += Vel_Bound[iDim]*UnitNormal[iDim]; - } - Pressure_Bound = node[iPoint]->GetPressure(); - SoundSpeed_Bound = sqrt(Gamma*Pressure_Bound/Density_Bound); - Entropy_Bound = pow(Density_Bound, Gamma)/Pressure_Bound; - - /*--- Store the primitive variable state for the freestream. Project - the freestream velocity vector into the local normal direction, - i.e. compute v_infty.n. ---*/ - - Density_Infty = GetDensity_Inf(); - Vel2_Infty = 0.0; Vn_Infty = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Vel_Infty[iDim] = GetVelocity_Inf(iDim); - Vel2_Infty += Vel_Infty[iDim]*Vel_Infty[iDim]; - Vn_Infty += Vel_Infty[iDim]*UnitNormal[iDim]; - } - Pressure_Infty = GetPressure_Inf(); - SoundSpeed_Infty = sqrt(Gamma*Pressure_Infty/Density_Infty); - Entropy_Infty = pow(Density_Infty, Gamma)/Pressure_Infty; - - /*--- Adjust the normal freestream velocity for grid movement ---*/ - - Qn_Infty = Vn_Infty; - if (grid_movement) { - GridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - Qn_Infty -= GridVel[iDim]*UnitNormal[iDim]; - } - - /*--- Compute acoustic Riemann invariants: R = u.n +/- 2c/(gamma-1). - These correspond with the eigenvalues (u+c) and (u-c), respectively, - which represent the acoustic waves. Positive characteristics are - incoming, and a physical boundary condition is imposed (freestream - state). This occurs when either (u.n+c) > 0 or (u.n-c) > 0. Negative - characteristics are leaving the domain, and numerical boundary - conditions are required by extrapolating from the interior state - using the Riemann invariants. This occurs when (u.n+c) < 0 or - (u.n-c) < 0. Note that grid movement is taken into account when - checking the sign of the eigenvalue. ---*/ - - /*--- Check whether (u.n+c) is greater or less than zero ---*/ - - if (Qn_Infty > -SoundSpeed_Infty) { - /*--- Subsonic inflow or outflow ---*/ - RiemannPlus = Vn_Bound + 2.0*SoundSpeed_Bound/Gamma_Minus_One; - } else { - /*--- Supersonic inflow ---*/ - RiemannPlus = Vn_Infty + 2.0*SoundSpeed_Infty/Gamma_Minus_One; - } - - /*--- Check whether (u.n-c) is greater or less than zero ---*/ - - if (Qn_Infty > SoundSpeed_Infty) { - /*--- Supersonic outflow ---*/ - RiemannMinus = Vn_Bound - 2.0*SoundSpeed_Bound/Gamma_Minus_One; - } else { - /*--- Subsonic outflow ---*/ - RiemannMinus = Vn_Infty - 2.0*SoundSpeed_Infty/Gamma_Minus_One; - } - - /*--- Compute a new value for the local normal velocity and speed of - sound from the Riemann invariants. ---*/ - - Vn = 0.5 * (RiemannPlus + RiemannMinus); - SoundSpeed = 0.25 * (RiemannPlus - RiemannMinus)*Gamma_Minus_One; - - /*--- Construct the primitive variable state at the boundary for - computing the flux for the weak boundary condition. The values - that we choose to construct the solution (boundary or freestream) - depend on whether we are at an inflow or outflow. At an outflow, we - choose boundary information (at most one characteristic is incoming), - while at an inflow, we choose infinity values (at most one - characteristic is outgoing). ---*/ - - if (Qn_Infty > 0.0) { - /*--- Outflow conditions ---*/ - for (iDim = 0; iDim < nDim; iDim++) - Velocity[iDim] = Vel_Bound[iDim] + (Vn-Vn_Bound)*UnitNormal[iDim]; - Entropy = Entropy_Bound; - } else { - /*--- Inflow conditions ---*/ - for (iDim = 0; iDim < nDim; iDim++) - Velocity[iDim] = Vel_Infty[iDim] + (Vn-Vn_Infty)*UnitNormal[iDim]; - Entropy = Entropy_Infty; - } - - /*--- Recompute the primitive variables. ---*/ - - Density = pow(Entropy*SoundSpeed*SoundSpeed/Gamma,1.0/Gamma_Minus_One); - Velocity2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity2 += Velocity[iDim]*Velocity[iDim]; - } - Pressure = Density*SoundSpeed*SoundSpeed/Gamma; - Energy = Pressure/(Gamma_Minus_One*Density) + 0.5*Velocity2; - if (tkeNeeded) Energy += GetTke_Inf(); - - /*--- Store new primitive state for computing the flux. ---*/ - - V_infty[0] = Pressure/(Gas_Constant*Density); - for (iDim = 0; iDim < nDim; iDim++) - V_infty[iDim+1] = Velocity[iDim]; - V_infty[nDim+1] = Pressure; - V_infty[nDim+2] = Density; - V_infty[nDim+3] = Energy + Pressure/Density; - - } - if (incompressible) { - - /*--- All the values computed from the infinity ---*/ - - V_infty[0] = GetPressure_Inf(); - for (iDim = 0; iDim < nDim; iDim++) - V_infty[iDim+1] = GetVelocity_Inf(iDim); - V_infty[nDim+1] = GetDensity_Inf(); - V_infty[nDim+2] = config->GetArtComp_Factor(); - - } - if (freesurface) { - - /*--- All the values computed from the infinity ---*/ - - V_infty[0] = GetPressure_Inf(); - for (iDim = 0; iDim < nDim; iDim++) - V_infty[iDim+1] = GetVelocity_Inf(iDim); - V_infty[nDim+1] = GetDensity_Inf(); - V_infty[nDim+2] = config->GetArtComp_Factor(); - - } - - /*--- Set various quantities in the numerics class ---*/ - - conv_numerics->SetPrimitive(V_domain, V_infty); - - if (grid_movement) { - conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), - geometry->node[iPoint]->GetGridVel()); - } - - /*--- Compute the convective residual using an upwind scheme ---*/ - - conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Update residual value ---*/ - - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Convective Jacobian contribution for implicit integration ---*/ - - if (implicit) - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - /*--- Roe Turkel preconditioning, set the value of beta ---*/ - - if (config->GetKind_Upwind() == TURKEL) - node[iPoint]->SetPreconditioner_Beta(conv_numerics->GetPrecond_Beta()); - - /*--- Viscous residual contribution ---*/ - - if (viscous) { - - /*--- Set laminar and eddy viscosity at the infinity ---*/ - - if (compressible) { - V_infty[nDim+5] = node[iPoint]->GetLaminarViscosity(); - V_infty[nDim+6] = node[iPoint]->GetEddyViscosity(); - } - if (incompressible) { - V_infty[nDim+3] = node[iPoint]->GetLaminarViscosityInc(); - V_infty[nDim+4] = node[iPoint]->GetEddyViscosityInc(); - } - - /*--- Set the normal vector and the coordinates ---*/ - - visc_numerics->SetNormal(Normal); - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), - geometry->node[Point_Normal]->GetCoord()); - - /*--- Primitive variables, and gradient ---*/ - - visc_numerics->SetPrimitive(V_domain, V_infty); - visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), - node[iPoint]->GetGradient_Primitive()); - - /*--- Turbulent kinetic energy ---*/ - - if (config->GetKind_Turb_Model() == SST) - visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), - solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); - - /*--- Compute and update viscous residual ---*/ - - visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.SubtractBlock(iPoint, Residual); - - /*--- Viscous Jacobian contribution for implicit integration ---*/ - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - - } - } - - /*--- Free locally allocated memory ---*/ - delete [] Normal; - -} - -void CEulerSolver::BC_Riemann(CGeometry *geometry, CSolver **solver_container, - CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - unsigned short iDim, iVar, jVar, kVar; - unsigned long iVertex, iPoint, Point_Normal; - su2double P_Total, T_Total, P_static, T_static, Rho_static, *Mach, *Flow_Dir, Area, UnitNormal[3]; - su2double *Velocity_b, Velocity2_b, Enthalpy_b, Energy_b, StaticEnergy_b, Density_b, Kappa_b, Chi_b, Pressure_b, Temperature_b; - su2double *Velocity_e, Velocity2_e, VelMag_e, Enthalpy_e, Entropy_e, Energy_e = 0.0, StaticEnthalpy_e, StaticEnergy_e, Density_e = 0.0, Pressure_e; - su2double *Velocity_i, Velocity2_i, Enthalpy_i, Energy_i, StaticEnergy_i, Density_i, Kappa_i, Chi_i, Pressure_i, SoundSpeed_i; - su2double ProjVelocity_i; - su2double **P_Tensor, **invP_Tensor, *Lambda_i, **Jacobian_b, **DubDu, *dw, *u_e, *u_i, *u_b; - su2double *gridVel; - su2double *V_boundary, *V_domain, *S_boundary, *S_domain; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool grid_movement = config->GetGrid_Movement(); - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - bool viscous = config->GetViscous(); - bool gravity = (config->GetGravityForce()); - bool tkeNeeded = (((config->GetKind_Solver() == RANS )|| (config->GetKind_Solver() == DISC_ADJ_RANS)) && - (config->GetKind_Turb_Model() == SST)); - - su2double *Normal, *FlowDirMix, TangVelocity, NormalVelocity; - Normal = new su2double[nDim]; - su2double ext_flow_angle; - - Velocity_i = new su2double[nDim]; - Velocity_b = new su2double[nDim]; - Velocity_e = new su2double[nDim]; - FlowDirMix = new su2double[nDim]; - Lambda_i = new su2double[nVar]; - u_i = new su2double[nVar]; - u_e = new su2double[nVar]; - u_b = new su2double[nVar]; - dw = new su2double[nVar]; - - S_boundary = new su2double[8]; - - P_Tensor = new su2double*[nVar]; - invP_Tensor = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) - { - P_Tensor[iVar] = new su2double[nVar]; - invP_Tensor[iVar] = new su2double[nVar]; - } - - /*--- Loop over all the vertices on this boundary marker ---*/ - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - V_boundary= GetCharacPrimVar(val_marker, iVertex); - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Index of the closest interior node ---*/ - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; - Area = sqrt (Area); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = Normal[iDim]/Area; - - /*--- Retrieve solution at this boundary node ---*/ - V_domain = node[iPoint]->GetPrimitive(); - - /* --- Compute the internal state u_i --- */ - Velocity2_i = 0; - for (iDim=0; iDim < nDim; iDim++) - { - Velocity_i[iDim] = node[iPoint]->GetVelocity(iDim); - Velocity2_i += Velocity_i[iDim]*Velocity_i[iDim]; - } - - - Density_i = node[iPoint]->GetDensity(); - - Energy_i = node[iPoint]->GetEnergy(); - StaticEnergy_i = Energy_i - 0.5*Velocity2_i; - - FluidModel->SetTDState_rhoe(Density_i, StaticEnergy_i); - - Pressure_i = FluidModel->GetPressure(); - Enthalpy_i = Energy_i + Pressure_i/Density_i; - - SoundSpeed_i = FluidModel->GetSoundSpeed(); - - Kappa_i = FluidModel->GetdPde_rho() / Density_i; - Chi_i = FluidModel->GetdPdrho_e() - Kappa_i * StaticEnergy_i; - - ProjVelocity_i = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - ProjVelocity_i += Velocity_i[iDim]*UnitNormal[iDim]; - - /*--- Build the external state u_e from boundary data and internal node ---*/ - - switch(config->GetKind_Data_Riemann(Marker_Tag)) - { - //TODO(turbo), generilize for 3D case - //TODO(turbo), generilize for Inlet and Outlet in for backflow treatment - //TODO(turbo), implement not uniform inlet and radial equilibrium for the outlet - case TOTAL_CONDITIONS_PT: - - /*--- Retrieve the specified total conditions for this boundary. ---*/ - if (gravity) P_Total = config->GetRiemann_Var1(Marker_Tag) - geometry->node[iPoint]->GetCoord(nDim-1)*STANDART_GRAVITY;/// check in which case is true (only freesurface?) - else P_Total = config->GetRiemann_Var1(Marker_Tag); - T_Total = config->GetRiemann_Var2(Marker_Tag); - Flow_Dir = config->GetRiemann_FlowDir(Marker_Tag); - - /*--- Non-dim. the inputs if necessary. ---*/ - P_Total /= config->GetPressure_Ref(); - T_Total /= config->GetTemperature_Ref(); - - /* --- Computes the total state --- */ - FluidModel->SetTDState_PT(P_Total, T_Total); - Enthalpy_e = FluidModel->GetStaticEnergy()+ FluidModel->GetPressure()/FluidModel->GetDensity(); - Entropy_e = FluidModel->GetEntropy(); - - /* --- Compute the boundary state u_e --- */ - Velocity2_e = Velocity2_i; - if (nDim == 2){ - NormalVelocity= -sqrt(Velocity2_e)*Flow_Dir[0]; - TangVelocity= -sqrt(Velocity2_e)*Flow_Dir[1]; - Velocity_e[0]= UnitNormal[0]*NormalVelocity - UnitNormal[1]*TangVelocity; - Velocity_e[1]= UnitNormal[1]*NormalVelocity + UnitNormal[0]*TangVelocity; - }else{ - for (iDim = 0; iDim < nDim; iDim++) - Velocity_e[iDim] = sqrt(Velocity2_e)*Flow_Dir[iDim]; - } - StaticEnthalpy_e = Enthalpy_e - 0.5 * Velocity2_e; - FluidModel->SetTDState_hs(StaticEnthalpy_e, Entropy_e); - Density_e = FluidModel->GetDensity(); - StaticEnergy_e = FluidModel->GetStaticEnergy(); - Energy_e = StaticEnergy_e + 0.5 * Velocity2_e; - if (tkeNeeded) Energy_e += GetTke_Inf(); - break; - - case STATIC_SUPERSONIC_INFLOW_PT: - - /*--- Retrieve the specified total conditions for this boundary. ---*/ - if (gravity) P_static = config->GetRiemann_Var1(Marker_Tag) - geometry->node[iPoint]->GetCoord(nDim-1)*STANDART_GRAVITY;/// check in which case is true (only freesurface?) - else P_static = config->GetRiemann_Var1(Marker_Tag); - T_static = config->GetRiemann_Var2(Marker_Tag); - Mach = config->GetRiemann_FlowDir(Marker_Tag); - - /*--- Non-dim. the inputs if necessary. ---*/ - P_static /= config->GetPressure_Ref(); - T_static /= config->GetTemperature_Ref(); - - /* --- Computes the total state --- */ - FluidModel->SetTDState_PT(P_static, T_static); - - /* --- Compute the boundary state u_e --- */ - Velocity2_e = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity_e[iDim] = Mach[iDim]*FluidModel->GetSoundSpeed(); - Velocity2_e += Velocity_e[iDim]*Velocity_e[iDim]; - } - Density_e = FluidModel->GetDensity(); - StaticEnergy_e = FluidModel->GetStaticEnergy(); - Energy_e = StaticEnergy_e + 0.5 * Velocity2_e; - if (tkeNeeded) Energy_e += GetTke_Inf(); - break; - - case STATIC_SUPERSONIC_INFLOW_PD: - - /*--- Retrieve the specified total conditions for this boundary. ---*/ - - if (gravity) P_static = config->GetRiemann_Var1(Marker_Tag) - geometry->node[iPoint]->GetCoord(nDim-1)*STANDART_GRAVITY;/// check in which case is true (only freesurface?) - else P_static = config->GetRiemann_Var1(Marker_Tag); - Rho_static = config->GetRiemann_Var2(Marker_Tag); - Mach = config->GetRiemann_FlowDir(Marker_Tag); - - /*--- Non-dim. the inputs if necessary. ---*/ - P_static /= config->GetPressure_Ref(); - Rho_static /= config->GetDensity_Ref(); - - /* --- Computes the total state --- */ - FluidModel->SetTDState_Prho(P_static, Rho_static); - - /* --- Compute the boundary state u_e --- */ - Velocity2_e = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity_e[iDim] = Mach[iDim]*FluidModel->GetSoundSpeed(); - Velocity2_e += Velocity_e[iDim]*Velocity_e[iDim]; - } - Density_e = FluidModel->GetDensity(); - StaticEnergy_e = FluidModel->GetStaticEnergy(); - Energy_e = StaticEnergy_e + 0.5 * Velocity2_e; - if (tkeNeeded) Energy_e += GetTke_Inf(); - break; - - case MIXING_IN: - - /*--- Retrieve the specified total conditions for this boundary. ---*/ - P_Total = ExtAveragedTotPressure[val_marker]; - T_Total = ExtAveragedTotTemperature[val_marker]; - ext_flow_angle = atan(ExtAveragedTangVelocity[val_marker]/ExtAveragedNormalVelocity[val_marker]); - FlowDirMix[0] = cos(ext_flow_angle); - FlowDirMix[1] = sin(ext_flow_angle); - - /* --- Computes the total state --- */ - FluidModel->SetTDState_PT(P_Total, T_Total); - Enthalpy_e = FluidModel->GetStaticEnergy()+ FluidModel->GetPressure()/FluidModel->GetDensity(); - Entropy_e = FluidModel->GetEntropy(); - - /* --- Compute the boundary state u_e --- */ - Velocity2_e = Velocity2_i; - if (nDim == 2){ - NormalVelocity= -sqrt(Velocity2_e)*FlowDirMix[0]; - TangVelocity= -sqrt(Velocity2_e)*FlowDirMix[1]; - Velocity_e[0]= UnitNormal[0]*NormalVelocity - UnitNormal[1]*TangVelocity; - Velocity_e[1]= UnitNormal[1]*NormalVelocity + UnitNormal[0]*TangVelocity; - }else{ - for (iDim = 0; iDim < nDim; iDim++) - Velocity_e[iDim] = sqrt(Velocity2_e)*FlowDirMix[iDim]; - } - StaticEnthalpy_e = Enthalpy_e - 0.5 * Velocity2_e; - FluidModel->SetTDState_hs(StaticEnthalpy_e, Entropy_e); - Density_e = FluidModel->GetDensity(); - StaticEnergy_e = FluidModel->GetStaticEnergy(); - Energy_e = StaticEnergy_e + 0.5 * Velocity2_e; - if (tkeNeeded) Energy_e += GetTke_Inf(); - break; - - case DENSITY_VELOCITY: - - /*--- Retrieve the specified density and velocity magnitude ---*/ - Density_e = config->GetRiemann_Var1(Marker_Tag); - VelMag_e = config->GetRiemann_Var2(Marker_Tag); - Flow_Dir = config->GetRiemann_FlowDir(Marker_Tag); - - /*--- Non-dim. the inputs if necessary. ---*/ - Density_e /= config->GetDensity_Ref(); - VelMag_e /= config->GetVelocity_Ref(); - - for (iDim = 0; iDim < nDim; iDim++) - Velocity_e[iDim] = VelMag_e*Flow_Dir[iDim]; - Energy_e = Energy_i; - break; - - case MIXING_OUT: - - /*--- Retrieve the staic pressure for this boundary. ---*/ - Pressure_e = ExtAveragedPressure[val_marker]; - Density_e = Density_i; - - /* --- Compute the boundary state u_e --- */ - FluidModel->SetTDState_Prho(Pressure_e, Density_e); - Velocity2_e = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity_e[iDim] = Velocity_i[iDim]; - Velocity2_e += Velocity_e[iDim]*Velocity_e[iDim]; - } - Energy_e = FluidModel->GetStaticEnergy() + 0.5*Velocity2_e; - break; - - case STATIC_PRESSURE: - - /*--- Retrieve the staic pressure for this boundary. ---*/ - Pressure_e = config->GetRiemann_Var1(Marker_Tag); - Pressure_e /= config->GetPressure_Ref(); - Density_e = Density_i; - - /* --- Compute the boundary state u_e --- */ - FluidModel->SetTDState_Prho(Pressure_e, Density_e); - Velocity2_e = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity_e[iDim] = Velocity_i[iDim]; - Velocity2_e += Velocity_e[iDim]*Velocity_e[iDim]; - } - Energy_e = FluidModel->GetStaticEnergy() + 0.5*Velocity2_e; - break; - - default: - cout << "Warning! Invalid Riemann input!" << endl; - exit(EXIT_FAILURE); - break; - - } - - /*--- Compute P (matrix of right eigenvectors) ---*/ - conv_numerics->GetPMatrix(&Density_i, Velocity_i, &SoundSpeed_i, &Enthalpy_i, &Chi_i, &Kappa_i, UnitNormal, P_Tensor); - - /*--- Compute inverse P (matrix of left eigenvectors)---*/ - conv_numerics->GetPMatrix_inv(invP_Tensor, &Density_i, Velocity_i, &SoundSpeed_i, &Chi_i, &Kappa_i, UnitNormal); - - /*--- eigenvalues contribution due to grid motion ---*/ - if (grid_movement){ - gridVel = geometry->node[iPoint]->GetGridVel(); - - su2double ProjGridVel = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - ProjGridVel += gridVel[iDim]*UnitNormal[iDim]; - ProjVelocity_i -= ProjGridVel; - } - - /*--- Flow eigenvalues ---*/ - for (iDim = 0; iDim < nDim; iDim++) - Lambda_i[iDim] = ProjVelocity_i; - Lambda_i[nVar-2] = ProjVelocity_i + SoundSpeed_i; - Lambda_i[nVar-1] = ProjVelocity_i - SoundSpeed_i; - - /* --- Compute the boundary state u_e --- */ - u_e[0] = Density_e; - for (iDim = 0; iDim < nDim; iDim++) - u_e[iDim+1] = Velocity_e[iDim]*Density_e; - u_e[nVar-1] = Energy_e*Density_e; - - /* --- Compute the boundary state u_i --- */ - u_i[0] = Density_i; - for (iDim = 0; iDim < nDim; iDim++) - u_i[iDim+1] = Velocity_i[iDim]*Density_i; - u_i[nVar-1] = Energy_i*Density_i; - - /*--- Compute the characteristic jumps ---*/ - for (iVar = 0; iVar < nVar; iVar++) - { - dw[iVar] = 0; - for (jVar = 0; jVar < nVar; jVar++) - dw[iVar] += invP_Tensor[iVar][jVar] * (u_e[jVar] - u_i[jVar]); - - } - - /*--- Compute the boundary state u_b using characteristics ---*/ - for (iVar = 0; iVar < nVar; iVar++) - { - u_b[iVar] = u_i[iVar]; - - for (jVar = 0; jVar < nVar; jVar++) - { - if (Lambda_i[jVar] < 0) - { - u_b[iVar] += P_Tensor[iVar][jVar]*dw[jVar]; - - } - } - } - - - /*--- Compute the thermodynamic state in u_b ---*/ - Density_b = u_b[0]; - Velocity2_b = 0; - for (iDim = 0; iDim < nDim; iDim++) - { - Velocity_b[iDim] = u_b[iDim+1]/Density_b; - Velocity2_b += Velocity_b[iDim]*Velocity_b[iDim]; - } - Energy_b = u_b[nVar-1]/Density_b; - StaticEnergy_b = Energy_b - 0.5*Velocity2_b; - FluidModel->SetTDState_rhoe(Density_b, StaticEnergy_b); - Pressure_b = FluidModel->GetPressure(); - Temperature_b = FluidModel->GetTemperature(); - Enthalpy_b = Energy_b + Pressure_b/Density_b; - Kappa_b = FluidModel->GetdPde_rho() / Density_b; - Chi_b = FluidModel->GetdPdrho_e() - Kappa_b * StaticEnergy_b; - - /*--- Compute the residuals ---*/ - conv_numerics->GetInviscidProjFlux(&Density_b, Velocity_b, &Pressure_b, &Enthalpy_b, Normal, Residual); - - /*--- Residual contribution due to grid motion ---*/ - if (grid_movement) { - gridVel = geometry->node[iPoint]->GetGridVel(); - su2double projVelocity = 0.0; - - for (iDim = 0; iDim < nDim; iDim++) - projVelocity += gridVel[iDim]*Normal[iDim]; - for (iVar = 0; iVar < nVar; iVar++) - Residual[iVar] -= projVelocity *(u_b[iVar]); - } - - if (implicit) { - - Jacobian_b = new su2double*[nVar]; - DubDu = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) - { - Jacobian_b[iVar] = new su2double[nVar]; - DubDu[iVar] = new su2double[nVar]; - } - - /*--- Initialize DubDu to unit matrix---*/ - - for (iVar = 0; iVar < nVar; iVar++) - { - for (jVar = 0; jVar < nVar; jVar++) - DubDu[iVar][jVar]= 0; - - DubDu[iVar][iVar]= 1; - } - - /*--- Compute DubDu -= RNL---*/ - for (iVar=0; iVarGetInviscidProjJac(Velocity_b, &Enthalpy_b, &Chi_b, &Kappa_b, Normal, 1.0, Jacobian_b); - - /*--- Jacobian contribution due to grid motion ---*/ - if (grid_movement) - { - gridVel = geometry->node[iPoint]->GetGridVel(); - su2double projVelocity = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - projVelocity += gridVel[iDim]*Normal[iDim]; - for (iVar = 0; iVar < nVar; iVar++){ - Residual[iVar] -= projVelocity *(u_b[iVar]); - Jacobian_b[iVar][iVar] -= projVelocity; - } - - } - - /*--- initiate Jacobian_i to zero matrix ---*/ - for (iVar=0; iVarGetKind_Upwind() == TURKEL) - node[iPoint]->SetPreconditioner_Beta(conv_numerics->GetPrecond_Beta()); - - /*--- Viscous contribution ---*/ - if (viscous) { - - /*--- Primitive variables, using the derived quantities ---*/ - V_boundary[0] = Temperature_b; - for (iDim = 0; iDim < nDim; iDim++) - V_boundary[iDim+1] = Velocity_b[iDim]; - V_boundary[nDim+1] = Pressure_b; - V_boundary[nDim+2] = Density_b; - V_boundary[nDim+3] = Enthalpy_b; - - /*--- Set laminar and eddy viscosity at the infinity ---*/ - V_boundary[nDim+5] = FluidModel->GetLaminarViscosity(); - V_boundary[nDim+6] = node[iPoint]->GetEddyViscosity(); - V_boundary[nDim+7] = FluidModel->GetThermalConductivity(); - V_boundary[nDim+8] = FluidModel->GetCp(); - - /*--- Set the normal vector and the coordinates ---*/ - visc_numerics->SetNormal(Normal); - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - - /*--- Primitive variables, and gradient ---*/ - visc_numerics->SetPrimitive(V_domain, V_boundary); - visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); - - /*--- Secondary variables ---*/ - S_domain = node[iPoint]->GetSecondary(); - - /*--- Compute secondary thermodynamic properties (partial derivatives...) ---*/ - - S_boundary[0]= FluidModel->GetdPdrho_e(); - S_boundary[1]= FluidModel->GetdPde_rho(); - - S_boundary[2]= FluidModel->GetdTdrho_e(); - S_boundary[3]= FluidModel->GetdTde_rho(); - - /*--- Compute secondary thermo-physical properties (partial derivatives...) ---*/ - - S_boundary[4]= FluidModel->Getdmudrho_T(); - S_boundary[5]= FluidModel->GetdmudT_rho(); - - S_boundary[6]= FluidModel->Getdktdrho_T(); - S_boundary[7]= FluidModel->GetdktdT_rho(); - - visc_numerics->SetSecondary(S_domain, S_boundary); - - /*--- Turbulent kinetic energy ---*/ - if (config->GetKind_Turb_Model() == SST) - visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); - - /*--- Compute and update residual ---*/ - visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.SubtractBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - - } - } - - /*--- Free locally allocated memory ---*/ - delete [] Normal; - delete [] Velocity_e; - delete [] Velocity_b; - delete [] Velocity_i; - delete [] FlowDirMix; - - delete [] S_boundary; - delete [] Lambda_i; - delete [] u_i; - delete [] u_e; - delete [] u_b; - delete [] dw; - - - for (iVar = 0; iVar < nVar; iVar++) - { - delete [] P_Tensor[iVar]; - delete [] invP_Tensor[iVar]; - } - delete [] P_Tensor; - delete [] invP_Tensor; - -} - - -void CEulerSolver::Mixing_Process(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short val_Marker) { - - unsigned long iVertex, iPoint, nVert; - unsigned short iDim, iVar; - unsigned short mixing_process = config->GetKind_MixingProcess(); - su2double Pressure = 0.0, Density = 0.0, Enthalpy = 0.0, *Velocity = NULL, *Normal, *gridVel, - Area, TotalArea, TotalAreaPressure, TotalAreaDensity, *TotalAreaVelocity, UnitNormal[3]; - string Marker_Tag, Monitoring_Tag; - su2double val_init_pressure; - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool grid_movement = config->GetGrid_Movement(); - su2double TotalDensity, TotalPressure, *TotalVelocity, TotalNormal, avgVel2, avgTotalEnthaply; - - /*-- Variables declaration and allocation ---*/ - Velocity = new su2double[nDim]; - Normal = new su2double[nDim]; - TotalVelocity = new su2double[nDim]; - TotalAreaVelocity = new su2double[nDim]; - - for (iDim=0; iDimGetnVertex(val_Marker); iVertex++) { - - iPoint = geometry->vertex[val_Marker][iVertex]->GetNode(); - - /*--- Compute the integral fluxes for the boundaries ---*/ - if (compressible) { - Pressure = node[iPoint]->GetPressure(); - Density = node[iPoint]->GetDensity(); - Enthalpy = node[iPoint]->GetEnthalpy(); - } - else { - cout << "!!! Mixing process for incompressible and freesurface does not available yet !!! " << endl; - cout << "Press any key to exit..." << endl; - cin.get(); - exit(1); - } - - /*--- Note that the fluxes from halo cells are discarded ---*/ - if ( (geometry->node[iPoint]->GetDomain()) ) { - nVert++; - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - geometry->vertex[val_Marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); - su2double VelNormal = 0.0, VelSq = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - UnitNormal[iDim] = Normal[iDim]/Area; - Velocity[iDim] = node[iPoint]->GetPrimitive(iDim+1); - VelNormal += UnitNormal[iDim]*Velocity[iDim]; - VelSq += Velocity[iDim]*Velocity[iDim]; - } - - - /*--- Compute the integral fluxes for the boundary of interest ---*/ - - if ((mixing_process == AREA_AVERAGE) || (mixing_process == MIXEDOUT_AVERAGE)){ - - TotalFlux[val_Marker][0] += Area*(Density*VelNormal ); - for (iDim = 1; iDim < nDim+1; iDim++) - TotalFlux[val_Marker][iDim] += Area*(Density*VelNormal*Velocity[iDim -1] + Pressure*UnitNormal[iDim -1] ); - TotalFlux[val_Marker][nDim+1] += Area*(Density*VelNormal*Enthalpy ); - - TotalArea += Area; - TotalAreaPressure += Area*Pressure; - TotalAreaDensity += Area*Density; - for (iDim = 0; iDim < nDim; iDim++) - TotalAreaVelocity[iDim] += Area*Velocity[iDim]; - - }else{ - - TotalDensity += Density; - TotalPressure += Pressure; - for (iDim = 0; iDim < nDim; iDim++) - TotalVelocity[iDim] += Velocity[iDim]; - - - } - for (iDim = 0; iDim < nDim; iDim++) AveragedNormal[val_Marker][iDim] +=Normal[iDim]; - if (grid_movement){ - gridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - AveragedGridVel[val_Marker][iDim] +=gridVel[iDim]; - } - } - } - - /*--- Compute the averaged value for the boundary of interest ---*/ - for (iDim = 0; iDim < nDim; iDim++){ - AveragedNormal[val_Marker][iDim] /=nVert; - TotalNormal+= AveragedNormal[val_Marker][iDim]*AveragedNormal[val_Marker][iDim]; - } - for (iDim = 0; iDim < nDim; iDim++) AveragedNormal[val_Marker][iDim] /=sqrt(TotalNormal); - if (grid_movement){ - for (iDim = 0; iDim < nDim; iDim++) - AveragedGridVel[val_Marker][iDim] /=nVert; - } - - switch(mixing_process){ - - - case ALGEBRAIC_AVERAGE: - AveragedDensity[val_Marker] = TotalDensity / nVert; - AveragedPressure[val_Marker] = TotalPressure / nVert; - for (iDim = 0; iDim < nDim; iDim++) - AveragedVelocity[val_Marker][iDim] = TotalVelocity[iDim] / nVert; - break; - - case AREA_AVERAGE: - AveragedDensity[val_Marker] = TotalAreaDensity / TotalArea; - AveragedPressure[val_Marker] = TotalAreaPressure / TotalArea; - for (iDim = 0; iDim < nDim; iDim++) - AveragedVelocity[val_Marker][iDim] = TotalAreaVelocity[iDim] / TotalArea; - break; - - case MIXEDOUT_AVERAGE: - for (iVar = 0; iVarSetTDState_Prho(AveragedPressure[val_Marker], AveragedDensity[val_Marker]); - AveragedEnthalpy[val_Marker] = FluidModel->GetStaticEnergy() + AveragedPressure[val_Marker]/AveragedDensity[val_Marker]; - AveragedSoundSpeed[val_Marker] = FluidModel->GetSoundSpeed(); - AveragedEntropy[val_Marker] = FluidModel->GetEntropy(); - AveragedNormalVelocity[val_Marker]= AveragedNormal[val_Marker][0]*AveragedVelocity[val_Marker][0] + AveragedNormal[val_Marker][1]*AveragedVelocity[val_Marker][1]; - AveragedTangVelocity[val_Marker]= AveragedNormal[val_Marker][0]*AveragedVelocity[val_Marker][1] - AveragedNormal[val_Marker][1]*AveragedVelocity[val_Marker][0]; - MassFlow[val_Marker]= AveragedDensity[val_Marker]*AveragedNormalVelocity[val_Marker]*TotalArea; - FlowAngle[val_Marker]= atan(AveragedTangVelocity[val_Marker]/AveragedNormalVelocity[val_Marker]); - - /* --- compute total averaged quantities ---*/ - avgVel2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) avgVel2 += AveragedVelocity[val_Marker][iDim]*AveragedVelocity[val_Marker][iDim]; - - avgTotalEnthaply = AveragedEnthalpy[val_Marker] + 0.5*avgVel2; - FluidModel->SetTDState_hs(avgTotalEnthaply,AveragedEntropy[val_Marker]); - AveragedTotTemperature[val_Marker] = FluidModel->GetTemperature(); - AveragedTotPressure[val_Marker] = FluidModel->GetPressure(); - - if(grid_movement){ - AveragedTangGridVelocity[val_Marker] = AveragedNormal[val_Marker][0]*AveragedGridVel[val_Marker][1]-AveragedNormal[val_Marker][1]*AveragedGridVel[val_Marker][0]; - AveragedMach[val_Marker] = sqrt(AveragedNormalVelocity[val_Marker]*AveragedNormalVelocity[val_Marker] + (AveragedTangVelocity[val_Marker] - AveragedTangGridVelocity[val_Marker])*(AveragedTangVelocity[val_Marker] - AveragedTangGridVelocity[val_Marker])); - AveragedMach[val_Marker] /= AveragedSoundSpeed[val_Marker]; - AveragedTangMach[val_Marker] = (AveragedTangVelocity[val_Marker] - AveragedTangGridVelocity[val_Marker])/AveragedSoundSpeed[val_Marker]; - FlowAngle[val_Marker]= atan((AveragedTangVelocity[val_Marker] - AveragedTangGridVelocity[val_Marker])/AveragedNormalVelocity[val_Marker]); - - }else{ - AveragedMach[val_Marker] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - AveragedMach[val_Marker] += AveragedVelocity[val_Marker][iDim]*AveragedVelocity[val_Marker][iDim]; - } - AveragedMach[val_Marker] = sqrt(AveragedMach[val_Marker])/AveragedSoundSpeed[val_Marker]; - AveragedTangMach[val_Marker] = AveragedTangVelocity[val_Marker]/AveragedSoundSpeed[val_Marker]; - - } - - AveragedNormalMach[val_Marker] = AveragedNormalVelocity[val_Marker]/AveragedSoundSpeed[val_Marker]; - - - if ((AveragedDensity[val_Marker]!= AveragedDensity[val_Marker]) or (AveragedEnthalpy[val_Marker]!=AveragedEnthalpy[val_Marker])) - cout<<"nan in mixing process in boundary "<GetMarker_All_TagBound(val_Marker)<< endl; - - /*--- Free locally allocated memory ---*/ - delete [] Velocity; - delete [] Normal; - delete [] TotalVelocity; - delete [] TotalAreaVelocity; -} - -void CEulerSolver::MixedOut_Average (su2double val_init_pressure, su2double *val_Averaged_Flux, su2double *val_normal, - su2double *pressure_mix, su2double *density_mix) { - - unsigned short maxiter = 10; - unsigned short iter = 0; - su2double toll = 1.0e-07; - su2double resdl = 0.0; - - su2double *val_func = new su2double, *val_right_func = new su2double, *val_left_func = new su2double; - su2double deltaP, *p_mix = new su2double, *p_mix_right = new su2double, *p_mix_left = new su2double; - su2double epsilon = 1.0e-04; - su2double relax_factor = 1; - - *pressure_mix = val_init_pressure; - - /*--- Newton-Raphson's method with central difference formula ---*/ - - while ( iter <= maxiter ) { - deltaP = 2*epsilon*(*pressure_mix); - *p_mix_right = *pressure_mix+deltaP/2; - *p_mix_left = *pressure_mix-deltaP/2; - *p_mix = *pressure_mix; - MixedOut_Root_Function(p_mix_right,val_Averaged_Flux,val_normal,val_right_func,density_mix); - MixedOut_Root_Function(p_mix_left,val_Averaged_Flux,val_normal,val_left_func,density_mix); - MixedOut_Root_Function(p_mix,val_Averaged_Flux,val_normal,val_func,density_mix); - su2double der_func = (*val_right_func-*val_left_func) / deltaP; - deltaP = -*val_func/der_func; - resdl = deltaP/val_init_pressure; - *pressure_mix += relax_factor*(deltaP); - - iter += 1; - if ( abs(resdl) <= toll ) { - break; - } - - } - - MixedOut_Root_Function(pressure_mix,val_Averaged_Flux,val_normal,val_func,density_mix); - - /*--- Free locally allocated memory ---*/ - delete val_func; - delete val_right_func; - delete val_left_func; - delete p_mix; - delete p_mix_right; - delete p_mix_left; - -} - -void CEulerSolver::MixedOut_Root_Function(su2double *pressure, su2double *val_Averaged_Flux, su2double *val_normal, su2double *valfunc, su2double *density) { - - su2double velnormal, velsq; - - su2double *vel; - vel = new su2double[nDim]; - - - *valfunc = 0.0; - *density = 0.0; - - velnormal = 0.0; - velsq = 0.0; - - for (unsigned short iDim = 0; iDim < nDim; iDim++) { - vel[iDim] = (val_Averaged_Flux[iDim+1] - (*pressure)*val_normal[iDim]) / val_Averaged_Flux[0]; - velnormal += val_normal[iDim]*vel[iDim]; - velsq += vel[iDim]*vel[iDim]; - } - *density = val_Averaged_Flux[0] / velnormal; - if (*density <= 0) cout << " desnity in mixedout routine negative : " << endl; - FluidModel->SetTDState_Prho(*pressure, *density); - su2double enthalpy = FluidModel->GetStaticEnergy() + (*pressure)/(*density); - *valfunc = val_Averaged_Flux[nDim+1]/val_Averaged_Flux[0] - enthalpy - velsq/2; - if (*valfunc!=*valfunc) cout << " mixedout root func gives nan: " << endl; - - - /*--- Free locally allocated memory ---*/ - delete [] vel; - -} - -void CEulerSolver::Boundary_Fourier(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short val_Marker, vector >& c4k,signed long& nboundaryvertex) { - /* Implementation of Fuorier Transformations for non-regfelcting BC will come soon */ -} - -void CEulerSolver::Boundary_Fourier(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short val_Marker, vector >& c2k,vector >& c3k,signed long& nboundaryvertex) { - /* Implementation of Fuorier Transformations for non-regfelcting BC will come soon */ -} - -void CEulerSolver::BC_NonReflecting(CGeometry *geometry, CSolver **solver_container, - CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - unsigned short iDim, iVar, jVar, kVar; - unsigned long iVertex, iPoint, Point_Normal; - su2double Area, UnitNormal[3]; - - su2double *Velocity_b, Velocity2_b, Enthalpy_b, Energy_b, StaticEnergy_b, Density_b, Kappa_b, Chi_b, Pressure_b, Temperature_b; - su2double *Velocity_i, Velocity2_i, Enthalpy_i, Energy_i, StaticEnergy_i, Density_i, Kappa_i, Chi_i, Pressure_i, SoundSpeed_i; - su2double Pressure_e; - su2double ProjVelocity_i; - su2double **P_Tensor, **invP_Tensor, *Lambda_i, **Jacobian_b, **DubDu, *dw, *u_b; - su2double *gridVel; - su2double *V_boundary, *V_domain, *S_boundary, *S_domain; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool grid_movement = config->GetGrid_Movement(); - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - bool viscous = config->GetViscous(); - su2double *Normal; - - Normal = new su2double[nDim]; - - Velocity_i = new su2double[nDim]; - Velocity_b = new su2double[nDim]; - - - Lambda_i = new su2double[nVar]; - - u_b = new su2double[nVar]; - dw = new su2double[nVar]; - - S_boundary = new su2double[8]; - - P_Tensor = new su2double*[nVar]; - invP_Tensor = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) - { - P_Tensor[iVar] = new su2double[nVar]; - invP_Tensor[iVar] = new su2double[nVar]; - } - - /*--- new declarations ---*/ - std::vector > c4k ;// std::complex c3k[nVertex-OddEven]=0; - std::vector > c2k ;// std::complex c3k[nVertex-OddEven]=0; - std::vector > c3k ;// std::complex c3k[nVertex-OddEven]=0; - - su2double deltaDensity, deltaPressure, AvgMach, deltaTangVelocity, deltaNormalVelocity, cc,rhoc,c1j,c2j,c3j,c4j, - avg_c1, avg_c2, avg_c3, avg_c4,TangVelocity, NormalVelocity, GilesBeta, c4js, dc4js, *delta_c, **R_Matrix, *deltaprim; - - - delta_c = new su2double[nVar]; - deltaprim = new su2double[nVar]; - R_Matrix= new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) - { - R_Matrix[iVar] = new su2double[nVar]; - } - - - Mixing_Process(geometry, solver_container, config, val_marker); - - cc = AveragedSoundSpeed[val_marker]*AveragedSoundSpeed[val_marker]; - rhoc = AveragedSoundSpeed[val_marker]*AveragedDensity[val_marker]; - AvgMach = AveragedMach[val_marker]; - - conv_numerics->GetRMatrix(AveragedSoundSpeed[val_marker], AveragedDensity[val_marker], AveragedNormal[val_marker], R_Matrix); - - // Boundary_Fourier(geometry, solver_container, config, val_marker, c4k, nboundaryvertex); - // Boundary_Fourier(geometry, solver_container, config, val_marker, c2k,c3k,nboundaryvertex); - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - V_boundary= GetCharacPrimVar(val_marker, iVertex); - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Index of the closest interior node ---*/ - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; - Area = sqrt (Area); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = Normal[iDim]/Area; - - /*--- Retrieve solution at this boundary node ---*/ - V_domain = node[iPoint]->GetPrimitive(); - - /*--- Compute the internal state u_i ---*/ - Velocity2_i = 0; - for (iDim = 0; iDim < nDim; iDim++) - { - Velocity_i[iDim] = node[iPoint]->GetVelocity(iDim); - Velocity2_i += Velocity_i[iDim]*Velocity_i[iDim]; - } - - - Density_i = node[iPoint]->GetDensity(); - - Energy_i = node[iPoint]->GetEnergy(); - StaticEnergy_i = Energy_i - 0.5*Velocity2_i; - - FluidModel->SetTDState_rhoe(Density_i, StaticEnergy_i); - - Pressure_i = FluidModel->GetPressure(); - Enthalpy_i = Energy_i + Pressure_i/Density_i; - - SoundSpeed_i = FluidModel->GetSoundSpeed(); - - Kappa_i = FluidModel->GetdPde_rho() / Density_i; - Chi_i = FluidModel->GetdPdrho_e() - Kappa_i * StaticEnergy_i; - - ProjVelocity_i = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - ProjVelocity_i += Velocity_i[iDim]*UnitNormal[iDim]; - - - switch(config->GetKind_Data_NRBC(Marker_Tag)) - { - - //TODO(turbo), generilize for 3D case - //TODO(turbo), generilize for Inlet and Outlet in for backflow treatment - //TODO(turbo), implement not uniform inlet and radial equilibrium for the outlet - - case MIXING_IN: - - /* --- Compute jump of primitive variable --- */ - deltaDensity = ExtAveragedDensity[val_marker] - AveragedDensity[val_marker]; - deltaPressure = ExtAveragedPressure[val_marker] - AveragedPressure[val_marker]; - NormalVelocity= UnitNormal[0]*Velocity_i[0] + UnitNormal[1]*Velocity_i[1]; - deltaTangVelocity= ExtAveragedTangVelocity[val_marker]+AveragedTangVelocity[val_marker]; - deltaNormalVelocity= ExtAveragedNormalVelocity[val_marker]+AveragedNormalVelocity[val_marker]; - - /* --- Compute characteristic jumps --- */ - avg_c1= -cc*deltaDensity +deltaPressure; - avg_c2= (rhoc*deltaTangVelocity); - avg_c3= (rhoc*deltaNormalVelocity +deltaPressure); - c4j= -rhoc*(-NormalVelocity +AveragedNormalVelocity[val_marker]) +(Pressure_i - AveragedPressure[val_marker]); - - /* --- Impose Inlet BC --- */ - delta_c[0] = avg_c1; - delta_c[1] = avg_c2; - delta_c[2] = avg_c3; - delta_c[3] = c4j; - break; - - case MIXING_OUT: - - /* --- Compute jump of primitive variable --- */ - deltaDensity = Density_i - AveragedDensity[val_marker]; - deltaPressure = Pressure_i - AveragedPressure[val_marker]; - TangVelocity= UnitNormal[0]*Velocity_i[1] - UnitNormal[1]*Velocity_i[0]; - NormalVelocity= UnitNormal[0]*Velocity_i[0] + UnitNormal[1]*Velocity_i[1]; - deltaTangVelocity= TangVelocity - AveragedTangVelocity[val_marker]; - deltaNormalVelocity= NormalVelocity - AveragedNormalVelocity[val_marker]; - - /* --- Compute characteristic jumps --- */ - c1j= -cc*deltaDensity +deltaPressure; - c2j= rhoc*deltaTangVelocity; - c3j= rhoc*deltaNormalVelocity + deltaPressure; - avg_c4 = rhoc*(AveragedNormalVelocity[val_marker]+ExtAveragedNormalVelocity[val_marker]) -(AveragedPressure[val_marker]-ExtAveragedPressure[val_marker]); - - /* --- implementation of supersonic NRBC ---*/ - if (AvgMach > 1.001){ - if (AveragedTangVelocity[val_marker] >= 0.0){ - GilesBeta= -sqrt(pow(AvgMach,2)-1.0); - }else{ - GilesBeta= sqrt(pow(AvgMach,2)-1.0); - } - c4js= (2.0 * AveragedNormalMach[val_marker])/(GilesBeta - AveragedTangMach[val_marker])*c2j - (GilesBeta+AveragedTangMach[val_marker])/(GilesBeta-AveragedTangMach[val_marker])*c3j; - dc4js = c4js; - }else{ - dc4js = 0.0; - } - - /* --- Impose Outlet BC --- */ - delta_c[0] = c1j; - delta_c[1] = c2j; - delta_c[2] = c3j; - delta_c[3] = avg_c4 + dc4js; - break; - - case STATIC_PRESSURE: - - Pressure_e = config->GetNRBC_Var1(Marker_Tag); - Pressure_e /= config->GetPressure_Ref(); - - /* --- Compute jump of primitive variable --- */ - deltaDensity = Density_i - AveragedDensity[val_marker]; - deltaPressure = Pressure_i - AveragedPressure[val_marker]; - TangVelocity= UnitNormal[0]*Velocity_i[1] - UnitNormal[1]*Velocity_i[0]; - NormalVelocity= UnitNormal[0]*Velocity_i[0] + UnitNormal[1]*Velocity_i[1]; - deltaTangVelocity= TangVelocity - AveragedTangVelocity[val_marker]; - deltaNormalVelocity= NormalVelocity - AveragedNormalVelocity[val_marker]; - - /* --- Compute characteristic jumps --- */ - c1j= -cc*deltaDensity +deltaPressure; - c2j= rhoc*deltaTangVelocity; - c3j=rhoc*deltaNormalVelocity + deltaPressure; - c4j=-rhoc*deltaNormalVelocity + deltaPressure; - avg_c4 = -2.0*(AveragedPressure[val_marker]-Pressure_e); - - /* --- implementation of supersonic NRBC ---*/ - if (AvgMach > 1.001){ - if (AveragedTangVelocity[val_marker] >= 0.0){ - GilesBeta= -sqrt(pow(AvgMach,2)-1.0); - }else{ - GilesBeta= sqrt(pow(AvgMach,2)-1.0); - } - c4js= (2.0 * AveragedNormalMach[val_marker])/(GilesBeta - AveragedTangMach[val_marker])*c2j - (GilesBeta+AveragedTangMach[val_marker])/(GilesBeta-AveragedTangMach[val_marker])*c3j; - dc4js = c4js; - }else{ - dc4js = 0.0; - } - - /* --- Impose Outlet BC --- */ - delta_c[0] = c1j; - delta_c[1] = c2j; - delta_c[2] = c3j; - delta_c[3] = avg_c4 + dc4js; - break; - - default: - cout << "Warning! Invalid NRBC input!" << endl; - exit(EXIT_FAILURE); - break; - - } - - /*--- Compute primitive jump from characteristic variables ---*/ - for (iVar = 0; iVar < nVar; iVar++) - { - deltaprim[iVar]=0; - for (jVar = 0; jVar < nVar; jVar++) - { - deltaprim[iVar] += R_Matrix[iVar][jVar]*delta_c[jVar]; - } - } - - /*--- Compute P (matrix of right eigenvectors) ---*/ - conv_numerics->GetPMatrix(&Density_i, Velocity_i, &SoundSpeed_i, &Enthalpy_i, &Chi_i, &Kappa_i, UnitNormal, P_Tensor); - - /*--- Compute inverse P (matrix of left eigenvectors)---*/ - conv_numerics->GetPMatrix_inv(invP_Tensor, &Density_i, Velocity_i, &SoundSpeed_i, &Chi_i, &Kappa_i, UnitNormal); - - /*--- eigenvalues contribution due to grid motion ---*/ - if (grid_movement){ - gridVel = geometry->node[iPoint]->GetGridVel(); - su2double ProjGridVel = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - ProjGridVel += gridVel[iDim]*UnitNormal[iDim]; - ProjVelocity_i -= ProjGridVel; - } - - /*--- Flow eigenvalues ---*/ - for (iDim = 0; iDim < nDim; iDim++) - Lambda_i[iDim] = ProjVelocity_i; - Lambda_i[nVar-2] = ProjVelocity_i + SoundSpeed_i; - Lambda_i[nVar-1] = ProjVelocity_i - SoundSpeed_i; - - //TODO(turbo), provide the under relaxation factor sigma from cfg file - su2double sigma; - sigma = 1.0; - - /*--- retrieve boundary variables ---*/ - Density_b = AveragedDensity[val_marker] + sigma*deltaprim[0]; - Pressure_b = AveragedPressure[val_marker] + sigma*deltaprim[3]; - switch(config->GetKind_Data_NRBC(Marker_Tag)){ - case MIXING_IN: - NormalVelocity = AveragedNormalVelocity[val_marker] - sigma*deltaprim[1]; - TangVelocity = AveragedTangVelocity[val_marker] - sigma*deltaprim[2]; - break; - case MIXING_OUT: case STATIC_PRESSURE: - NormalVelocity = AveragedNormalVelocity[val_marker] + sigma*deltaprim[1]; - TangVelocity = AveragedTangVelocity[val_marker] + sigma*deltaprim[2]; - break; - default: - cout << "Warning! Invalid NRBC input!" << endl; - exit(EXIT_FAILURE); - break; - } - - Velocity_b[0] = NormalVelocity*UnitNormal[0] - TangVelocity*UnitNormal[1]; - Velocity_b[1] = NormalVelocity*UnitNormal[1] + TangVelocity*UnitNormal[0]; - Velocity2_b = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity2_b+= Velocity_b[iDim]*Velocity_b[iDim]; - } - - FluidModel->SetTDState_Prho(Pressure_b, Density_b); - Energy_b = FluidModel->GetStaticEnergy() + 0.5*Velocity2_b; - StaticEnergy_b = FluidModel->GetStaticEnergy(); - Temperature_b= FluidModel->GetTemperature(); - Enthalpy_b = Energy_b + Pressure_b/Density_b; - Kappa_b = FluidModel->GetdPde_rho() / Density_b; - Chi_b = FluidModel->GetdPdrho_e() - Kappa_b * StaticEnergy_b; - - /*--- Compute the thermodynamic state in u_b ---*/ - u_b[0]=Density_b; - u_b[1]=Density_b*Velocity_b[0]; - u_b[2]=Density_b*Velocity_b[1]; - u_b[3]=Energy_b*Density_b; - - /*--- Compute the residuals ---*/ - conv_numerics->GetInviscidProjFlux(&Density_b, Velocity_b, &Pressure_b, &Enthalpy_b, Normal, Residual); - - /*--- Residual contribution due to grid motion ---*/ - if (grid_movement) { - gridVel = geometry->node[iPoint]->GetGridVel(); - su2double projVelocity = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - projVelocity += gridVel[iDim]*Normal[iDim]; - for (iVar = 0; iVar < nVar; iVar++) - Residual[iVar] -= projVelocity *(u_b[iVar]); - } - - if (implicit) { - /*--- Residual contribution due to grid motion ---*/ - Jacobian_b = new su2double*[nVar]; - DubDu = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) - { - Jacobian_b[iVar] = new su2double[nVar]; - DubDu[iVar] = new su2double[nVar]; - } - - /*--- Initialize DubDu to unit matrix---*/ - for (iVar = 0; iVar < nVar; iVar++) - { - for (jVar = 0; jVar < nVar; jVar++) - DubDu[iVar][jVar]= 0; - - DubDu[iVar][iVar]= 1; - } - - /*--- Compute DubDu -= RNL---*/ - for (iVar=0; iVarGetInviscidProjJac(Velocity_b, &Enthalpy_b, &Chi_b, &Kappa_b, Normal, 1.0, Jacobian_b); - - /*--- Jacobian contribution due to grid motion ---*/ - if (grid_movement) - { - su2double projVelocity = 0.0; - gridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - projVelocity += gridVel[iDim]*Normal[iDim]; - for (iVar = 0; iVar < nVar; iVar++){ - Residual[iVar] -= projVelocity *(u_b[iVar]); - Jacobian_b[iVar][iVar] -= projVelocity; - } - - } - - /*--- initiate Jacobian_i to zero matrix ---*/ - for (iVar=0; iVarGetKind_Upwind() == TURKEL) - node[iPoint]->SetPreconditioner_Beta(conv_numerics->GetPrecond_Beta()); - - /*--- Viscous contribution ---*/ - if (viscous) { - - /*--- Primitive variables, using the derived quantities ---*/ - V_boundary[0] = Temperature_b; - for (iDim = 0; iDim < nDim; iDim++) - V_boundary[iDim+1] = Velocity_b[iDim]; - V_boundary[nDim+1] = Pressure_b; - V_boundary[nDim+2] = Density_b; - V_boundary[nDim+3] = Enthalpy_b; - - /*--- Set laminar and eddy viscosity at the infinity ---*/ - V_boundary[nDim+5] = FluidModel->GetLaminarViscosity(); - V_boundary[nDim+6] = node[iPoint]->GetEddyViscosity(); - V_boundary[nDim+7] = FluidModel->GetThermalConductivity(); - V_boundary[nDim+8] = FluidModel->GetCp(); - - /*--- Set the normal vector and the coordinates ---*/ - visc_numerics->SetNormal(Normal); - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - - /*--- Primitive variables, and gradient ---*/ - visc_numerics->SetPrimitive(V_domain, V_boundary); - visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); - - /*--- Secondary variables ---*/ - S_domain = node[iPoint]->GetSecondary(); - - /*--- Compute secondary thermodynamic properties (partial derivatives...) ---*/ - - S_boundary[0]= FluidModel->GetdPdrho_e(); - S_boundary[1]= FluidModel->GetdPde_rho(); - - S_boundary[2]= FluidModel->GetdTdrho_e(); - S_boundary[3]= FluidModel->GetdTde_rho(); - - /*--- Compute secondary thermo-physical properties (partial derivatives...) ---*/ - - S_boundary[4]= FluidModel->Getdmudrho_T(); - S_boundary[5]= FluidModel->GetdmudT_rho(); - - S_boundary[6]= FluidModel->Getdktdrho_T(); - S_boundary[7]= FluidModel->GetdktdT_rho(); - - visc_numerics->SetSecondary(S_domain, S_boundary); - - /*--- Turbulent kinetic energy ---*/ - if (config->GetKind_Turb_Model() == SST) - visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); - - /*--- Compute and update residual ---*/ - visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.SubtractBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - - } - } - - /*--- Free locally allocated memory ---*/ - delete [] Normal; - - delete [] Velocity_b; - delete [] Velocity_i; - - delete [] S_boundary; - delete [] Lambda_i; - delete [] u_b; - delete [] dw; - - - for (iVar = 0; iVar < nVar; iVar++) - { - delete [] P_Tensor[iVar]; - delete [] invP_Tensor[iVar]; - } - delete [] P_Tensor; - delete [] invP_Tensor; - - - delete [] delta_c; - delete [] deltaprim; - for (iVar = 0; iVar < nVar; iVar++) - { - delete [] R_Matrix[iVar]; - } - delete [] R_Matrix; - - -} - -void CEulerSolver::BC_Inlet(CGeometry *geometry, CSolver **solver_container, - CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - unsigned short iDim; - unsigned long iVertex, iPoint, Point_Normal; - su2double P_Total, T_Total, Velocity[3], Velocity2, H_Total, Temperature, Riemann, - Pressure, Density, Energy, *Flow_Dir, Mach2, SoundSpeed2, SoundSpeed_Total2, Vel_Mag, - alpha, aa, bb, cc, dd, Area, UnitNormal[3]; - su2double *V_inlet, *V_domain; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool grid_movement = config->GetGrid_Movement(); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - su2double Two_Gamma_M1 = 2.0/Gamma_Minus_One; - su2double Gas_Constant = config->GetGas_ConstantND(); - unsigned short Kind_Inlet = config->GetKind_Inlet(); - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - bool viscous = config->GetViscous(); - bool gravity = (config->GetGravityForce()); - bool tkeNeeded = (((config->GetKind_Solver() == RANS )|| (config->GetKind_Solver() == DISC_ADJ_RANS)) && - (config->GetKind_Turb_Model() == SST)); - su2double *Normal = new su2double[nDim]; - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - /*--- Allocate the value at the inlet ---*/ - - V_inlet = GetCharacPrimVar(val_marker, iVertex); - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Index of the closest interior node ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; - Area = sqrt (Area); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = Normal[iDim]/Area; - - /*--- Retrieve solution at this boundary node ---*/ - - V_domain = node[iPoint]->GetPrimitive(); - - /*--- Build the fictitious intlet state based on characteristics ---*/ - - if (compressible) { - - /*--- Subsonic inflow: there is one outgoing characteristic (u-c), - therefore we can specify all but one state variable at the inlet. - The outgoing Riemann invariant provides the final piece of info. - Adapted from an original implementation in the Stanford University - multi-block (SUmb) solver in the routine bcSubsonicInflow.f90 - written by Edwin van der Weide, last modified 04-20-2009. ---*/ - - switch (Kind_Inlet) { - - /*--- Total properties have been specified at the inlet. ---*/ - - case TOTAL_CONDITIONS: - - /*--- Retrieve the specified total conditions for this inlet. ---*/ - - if (gravity) P_Total = config->GetInlet_Ptotal(Marker_Tag) - geometry->node[iPoint]->GetCoord(nDim-1)*STANDART_GRAVITY; - else P_Total = config->GetInlet_Ptotal(Marker_Tag); - T_Total = config->GetInlet_Ttotal(Marker_Tag); - Flow_Dir = config->GetInlet_FlowDir(Marker_Tag); - - /*--- Non-dim. the inputs if necessary. ---*/ - - P_Total /= config->GetPressure_Ref(); - T_Total /= config->GetTemperature_Ref(); - - /*--- Store primitives and set some variables for clarity. ---*/ - - Density = V_domain[nDim+2]; - Velocity2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity[iDim] = V_domain[iDim+1]; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - } - Energy = V_domain[nDim+3] - V_domain[nDim+1]/V_domain[nDim+2]; - Pressure = V_domain[nDim+1]; - H_Total = (Gamma*Gas_Constant/Gamma_Minus_One)*T_Total; - SoundSpeed2 = Gamma*Pressure/Density; - - /*--- Compute the acoustic Riemann invariant that is extrapolated - from the domain interior. ---*/ - - Riemann = 2.0*sqrt(SoundSpeed2)/Gamma_Minus_One; - for (iDim = 0; iDim < nDim; iDim++) - Riemann += Velocity[iDim]*UnitNormal[iDim]; - - /*--- Total speed of sound ---*/ - - SoundSpeed_Total2 = Gamma_Minus_One*(H_Total - (Energy + Pressure/Density)+0.5*Velocity2) + SoundSpeed2; - - /*--- Dot product of normal and flow direction. This should - be negative due to outward facing boundary normal convention. ---*/ - - alpha = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - alpha += UnitNormal[iDim]*Flow_Dir[iDim]; - - /*--- Coefficients in the quadratic equation for the velocity ---*/ - - aa = 1.0 + 0.5*Gamma_Minus_One*alpha*alpha; - bb = -1.0*Gamma_Minus_One*alpha*Riemann; - cc = 0.5*Gamma_Minus_One*Riemann*Riemann - -2.0*SoundSpeed_Total2/Gamma_Minus_One; - - /*--- Solve quadratic equation for velocity magnitude. Value must - be positive, so the choice of root is clear. ---*/ - - dd = bb*bb - 4.0*aa*cc; - dd = sqrt(max(0.0, dd)); - Vel_Mag = (-bb + dd)/(2.0*aa); - Vel_Mag = max(0.0, Vel_Mag); - Velocity2 = Vel_Mag*Vel_Mag; - - /*--- Compute speed of sound from total speed of sound eqn. ---*/ - - SoundSpeed2 = SoundSpeed_Total2 - 0.5*Gamma_Minus_One*Velocity2; - - /*--- Mach squared (cut between 0-1), use to adapt velocity ---*/ - - Mach2 = Velocity2/SoundSpeed2; - Mach2 = min(1.0, Mach2); - Velocity2 = Mach2*SoundSpeed2; - Vel_Mag = sqrt(Velocity2); - SoundSpeed2 = SoundSpeed_Total2 - 0.5*Gamma_Minus_One*Velocity2; - - /*--- Compute new velocity vector at the inlet ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - Velocity[iDim] = Vel_Mag*Flow_Dir[iDim]; - - /*--- Static temperature from the speed of sound relation ---*/ - - Temperature = SoundSpeed2/(Gamma*Gas_Constant); - - /*--- Static pressure using isentropic relation at a point ---*/ - - Pressure = P_Total*pow((Temperature/T_Total), Gamma/Gamma_Minus_One); - - /*--- Density at the inlet from the gas law ---*/ - - Density = Pressure/(Gas_Constant*Temperature); - - /*--- Using pressure, density, & velocity, compute the energy ---*/ - - Energy = Pressure/(Density*Gamma_Minus_One) + 0.5*Velocity2; - if (tkeNeeded) Energy += GetTke_Inf(); - - /*--- Primitive variables, using the derived quantities ---*/ - - V_inlet[0] = Temperature; - for (iDim = 0; iDim < nDim; iDim++) - V_inlet[iDim+1] = Velocity[iDim]; - V_inlet[nDim+1] = Pressure; - V_inlet[nDim+2] = Density; - V_inlet[nDim+3] = Energy + Pressure/Density; - - break; - - /*--- Mass flow has been specified at the inlet. ---*/ - - case MASS_FLOW: - - /*--- Retrieve the specified mass flow for the inlet. ---*/ - - Density = config->GetInlet_Ttotal(Marker_Tag); - Vel_Mag = config->GetInlet_Ptotal(Marker_Tag); - Flow_Dir = config->GetInlet_FlowDir(Marker_Tag); - - /*--- Non-dim. the inputs if necessary. ---*/ - - Density /= config->GetDensity_Ref(); - Vel_Mag /= config->GetVelocity_Ref(); - - /*--- Get primitives from current inlet state. ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - Velocity[iDim] = node[iPoint]->GetVelocity(iDim); - Pressure = node[iPoint]->GetPressure(); - SoundSpeed2 = Gamma*Pressure/V_domain[nDim+2]; - - /*--- Compute the acoustic Riemann invariant that is extrapolated - from the domain interior. ---*/ - - Riemann = Two_Gamma_M1*sqrt(SoundSpeed2); - for (iDim = 0; iDim < nDim; iDim++) - Riemann += Velocity[iDim]*UnitNormal[iDim]; - - /*--- Speed of sound squared for fictitious inlet state ---*/ - - SoundSpeed2 = Riemann; - for (iDim = 0; iDim < nDim; iDim++) - SoundSpeed2 -= Vel_Mag*Flow_Dir[iDim]*UnitNormal[iDim]; - - SoundSpeed2 = max(0.0,0.5*Gamma_Minus_One*SoundSpeed2); - SoundSpeed2 = SoundSpeed2*SoundSpeed2; - - /*--- Pressure for the fictitious inlet state ---*/ - - Pressure = SoundSpeed2*Density/Gamma; - - /*--- Energy for the fictitious inlet state ---*/ - - Energy = Pressure/(Density*Gamma_Minus_One) + 0.5*Vel_Mag*Vel_Mag; - if (tkeNeeded) Energy += GetTke_Inf(); - - /*--- Primitive variables, using the derived quantities ---*/ - - V_inlet[0] = Pressure / ( Gas_Constant * Density); - for (iDim = 0; iDim < nDim; iDim++) - V_inlet[iDim+1] = Vel_Mag*Flow_Dir[iDim]; - V_inlet[nDim+1] = Pressure; - V_inlet[nDim+2] = Density; - V_inlet[nDim+3] = Energy + Pressure/Density; - - break; - } - } - if (incompressible) { - - /*--- Retrieve the specified velocity for the inlet. ---*/ - - Vel_Mag = config->GetInlet_Ptotal(Marker_Tag)/config->GetVelocity_Ref(); - Flow_Dir = config->GetInlet_FlowDir(Marker_Tag); - - /*--- Store the velocity in the primitive variable vector ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - V_inlet[iDim+1] = Vel_Mag*Flow_Dir[iDim]; - - /*--- Neumann condition for pressure ---*/ - - V_inlet[0] = node[iPoint]->GetPressureInc(); - - /*--- Constant value of density ---*/ - - V_inlet[nDim+1] = GetDensity_Inf(); - - /*--- Beta coefficient from the config file ---*/ - - V_inlet[nDim+2] = config->GetArtComp_Factor(); - - } - if (freesurface) { - - /*--- Neumann condition for pressure, density, level set, and distance ---*/ - - V_inlet[0] = node[iPoint]->GetPressureInc(); - V_inlet[nDim+1] = node[iPoint]->GetDensityInc(); - V_inlet[nDim+5] = node[iPoint]->GetLevelSet(); - V_inlet[nDim+6] = node[iPoint]->GetDistance(); - - /*--- The velocity is computed from the infinity values ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - V_inlet[iDim+1] = GetVelocity_Inf(iDim); - } - - /*--- The y/z velocity is interpolated due to the - free surface effect on the pressure ---*/ - - V_inlet[nDim] = node[iPoint]->GetPrimitive(nDim); - - /*--- Neumann condition for artifical compresibility factor ---*/ - - V_inlet[nDim+2] = config->GetArtComp_Factor(); - - } - - /*--- Set various quantities in the solver class ---*/ - - conv_numerics->SetPrimitive(V_domain, V_inlet); - - if (grid_movement) - conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[iPoint]->GetGridVel()); - - /*--- Compute the residual using an upwind scheme ---*/ - - conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Update residual value ---*/ - - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - - if (implicit) - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - /*--- Roe Turkel preconditioning, set the value of beta ---*/ - - if (config->GetKind_Upwind() == TURKEL) - node[iPoint]->SetPreconditioner_Beta(conv_numerics->GetPrecond_Beta()); - - /*--- Viscous contribution ---*/ - - if (viscous) { - - /*--- Set laminar and eddy viscosity at the infinity ---*/ - - if (compressible) { - V_inlet[nDim+5] = node[iPoint]->GetLaminarViscosity(); - V_inlet[nDim+6] = node[iPoint]->GetEddyViscosity(); - } - if (incompressible || freesurface) { - V_inlet[nDim+3] = node[iPoint]->GetLaminarViscosityInc(); - V_inlet[nDim+4] = node[iPoint]->GetEddyViscosityInc(); - } - - /*--- Set the normal vector and the coordinates ---*/ - - visc_numerics->SetNormal(Normal); - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - - /*--- Primitive variables, and gradient ---*/ - - visc_numerics->SetPrimitive(V_domain, V_inlet); - visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); - - /*--- Turbulent kinetic energy ---*/ - - if (config->GetKind_Turb_Model() == SST) - visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); - - /*--- Compute and update residual ---*/ - - visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.SubtractBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - - } - } - - /*--- Free locally allocated memory ---*/ - - delete [] Normal; - -} - -void CEulerSolver::BC_Outlet(CGeometry *geometry, CSolver **solver_container, - CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - unsigned short iVar, iDim; - unsigned long iVertex, iPoint, Point_Normal; - su2double LevelSet, Density_Outlet = 0.0, Pressure, P_Exit, Velocity[3], - Velocity2, Entropy, Density, Energy, Riemann, Vn, SoundSpeed, Mach_Exit, Vn_Exit, - Area, UnitNormal[3], Height, yCoordRef, yCoord; - su2double *V_outlet, *V_domain; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - su2double Gas_Constant = config->GetGas_ConstantND(); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool grid_movement = config->GetGrid_Movement(); - su2double FreeSurface_Zero = config->GetFreeSurface_Zero(); - su2double epsilon = config->GetFreeSurface_Thickness(); - su2double RatioDensity = config->GetRatioDensity(); - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - bool viscous = config->GetViscous(); - bool gravity = (config->GetGravityForce()); - su2double PressFreeSurface = GetPressure_Inf(); - su2double Froude = config->GetFroude(); - bool tkeNeeded = (((config->GetKind_Solver() == RANS )|| (config->GetKind_Solver() == DISC_ADJ_RANS)) && - (config->GetKind_Turb_Model() == SST)); - su2double *Normal = new su2double[nDim]; - - /*--- Loop over all the vertices on this boundary marker ---*/ - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - /*--- Allocate the value at the outlet ---*/ - V_outlet = GetCharacPrimVar(val_marker, iVertex); - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Index of the closest interior node ---*/ - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; - Area = sqrt (Area); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = Normal[iDim]/Area; - - /*--- Current solution at this boundary node ---*/ - V_domain = node[iPoint]->GetPrimitive(); - - /*--- Build the fictitious intlet state based on characteristics ---*/ - if (compressible) { - - /*--- Retrieve the specified back pressure for this outlet. ---*/ - if (gravity) P_Exit = config->GetOutlet_Pressure(Marker_Tag) - geometry->node[iPoint]->GetCoord(nDim-1)*STANDART_GRAVITY; - else P_Exit = config->GetOutlet_Pressure(Marker_Tag); - - /*--- Non-dim. the inputs if necessary. ---*/ - P_Exit = P_Exit/config->GetPressure_Ref(); - - /*--- Check whether the flow is supersonic at the exit. The type - of boundary update depends on this. ---*/ - Density = V_domain[nDim+2]; - Velocity2 = 0.0; Vn = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity[iDim] = V_domain[iDim+1]; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - Vn += Velocity[iDim]*UnitNormal[iDim]; - } - Pressure = V_domain[nDim+1]; - SoundSpeed = sqrt(Gamma*Pressure/Density); - Mach_Exit = sqrt(Velocity2)/SoundSpeed; - - if (Mach_Exit >= 1.0) { - - /*--- Supersonic exit flow: there are no incoming characteristics, - so no boundary condition is necessary. Set outlet state to current - state so that upwinding handles the direction of propagation. ---*/ - for (iVar = 0; iVar < nPrimVar; iVar++) V_outlet[iVar] = V_domain[iVar]; - - } else { - - /*--- Subsonic exit flow: there is one incoming characteristic, - therefore one variable can be specified (back pressure) and is used - to update the conservative variables. Compute the entropy and the - acoustic Riemann variable. These invariants, as well as the - tangential velocity components, are extrapolated. Adapted from an - original implementation in the Stanford University multi-block - (SUmb) solver in the routine bcSubsonicOutflow.f90 by Edwin van - der Weide, last modified 09-10-2007. ---*/ - - Entropy = Pressure*pow(1.0/Density, Gamma); - Riemann = Vn + 2.0*SoundSpeed/Gamma_Minus_One; - - /*--- Compute the new fictious state at the outlet ---*/ - Density = pow(P_Exit/Entropy,1.0/Gamma); - Pressure = P_Exit; - SoundSpeed = sqrt(Gamma*P_Exit/Density); - Vn_Exit = Riemann - 2.0*SoundSpeed/Gamma_Minus_One; - Velocity2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity[iDim] = Velocity[iDim] + (Vn_Exit-Vn)*UnitNormal[iDim]; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - } - Energy = P_Exit/(Density*Gamma_Minus_One) + 0.5*Velocity2; - if (tkeNeeded) Energy += GetTke_Inf(); - - /*--- Conservative variables, using the derived quantities ---*/ - V_outlet[0] = Pressure / ( Gas_Constant * Density); - for (iDim = 0; iDim < nDim; iDim++) - V_outlet[iDim+1] = Velocity[iDim]; - V_outlet[nDim+1] = Pressure; - V_outlet[nDim+2] = Density; - V_outlet[nDim+3] = Energy + Pressure/Density; - - } - } - if (incompressible) { - - /*--- The pressure is computed from the infinity values ---*/ - if (gravity) { - yCoordRef = 0.0; - yCoord = geometry->node[iPoint]->GetCoord(nDim-1); - V_outlet[0] = GetPressure_Inf() + GetDensity_Inf()*((yCoordRef-yCoord)/(config->GetFroude()*config->GetFroude())); - } - else { - V_outlet[0] = GetPressure_Inf(); - } - - /*--- Neumann condition for the velocity ---*/ - for (iDim = 0; iDim < nDim; iDim++) { - V_outlet[iDim+1] = node[Point_Normal]->GetPrimitive(iDim+1); - } - - /*--- Constant value of density ---*/ - V_outlet[nDim+1] = GetDensity_Inf(); - - /*--- Beta coefficient from the config file ---*/ - V_outlet[nDim+2] = config->GetArtComp_Factor(); - - } - if (freesurface) { - - /*--- Imposed pressure, density, level set and distance ---*/ - Height = geometry->node[iPoint]->GetCoord(nDim-1); - LevelSet = Height - FreeSurface_Zero; - if (LevelSet < -epsilon) Density_Outlet = config->GetDensity_FreeStreamND(); - if (LevelSet > epsilon) Density_Outlet = RatioDensity*config->GetDensity_FreeStreamND(); - V_outlet[0] = PressFreeSurface + Density_Outlet*((FreeSurface_Zero-Height)/(Froude*Froude)); - V_outlet[nDim+1] = Density_Outlet; - V_outlet[nDim+5] = LevelSet; - V_outlet[nDim+6] = LevelSet; - - /*--- Neumann condition in the interface for the pressure, density and level set and distance ---*/ - if (fabs(LevelSet) <= epsilon) { - V_outlet[0] = node[Point_Normal]->GetPressureInc(); - V_outlet[nDim+1] = node[Point_Normal]->GetDensityInc(); - V_outlet[nDim+5] = node[Point_Normal]->GetLevelSet(); - V_outlet[nDim+6] = node[Point_Normal]->GetDistance(); - } - - /*--- Neumann condition for the velocity ---*/ - for (iDim = 0; iDim < nDim; iDim++) { - V_outlet[iDim+1] = node[Point_Normal]->GetPrimitive(iDim+1); - } - - /*--- Neumann condition for artifical compresibility factor ---*/ - V_outlet[nDim+2] = config->GetArtComp_Factor(); - - } - - /*--- Set various quantities in the solver class ---*/ - conv_numerics->SetPrimitive(V_domain, V_outlet); - - if (grid_movement) - conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[iPoint]->GetGridVel()); - - /*--- Compute the residual using an upwind scheme ---*/ - conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Update residual value ---*/ - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - if (implicit) { - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - } - - /*--- Roe Turkel preconditioning, set the value of beta ---*/ - if (config->GetKind_Upwind() == TURKEL) - node[iPoint]->SetPreconditioner_Beta(conv_numerics->GetPrecond_Beta()); - - /*--- Viscous contribution ---*/ - if (viscous) { - - /*--- Set laminar and eddy viscosity at the infinity ---*/ - if (compressible) { - V_outlet[nDim+5] = node[iPoint]->GetLaminarViscosity(); - V_outlet[nDim+6] = node[iPoint]->GetEddyViscosity(); - } - if (incompressible || freesurface) { - V_outlet[nDim+3] = node[iPoint]->GetLaminarViscosityInc(); - V_outlet[nDim+4] = node[iPoint]->GetEddyViscosityInc(); - } - - /*--- Set the normal vector and the coordinates ---*/ - visc_numerics->SetNormal(Normal); - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - - /*--- Primitive variables, and gradient ---*/ - visc_numerics->SetPrimitive(V_domain, V_outlet); - visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); - - /*--- Turbulent kinetic energy ---*/ - if (config->GetKind_Turb_Model() == SST) - visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); - - /*--- Compute and update residual ---*/ - visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.SubtractBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - - } - } - - /*--- Free locally allocated memory ---*/ - delete [] Normal; - -} - -void CEulerSolver::BC_Supersonic_Inlet(CGeometry *geometry, CSolver **solver_container, - CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - unsigned short iDim; - unsigned long iVertex, iPoint, Point_Normal; - su2double *V_inlet, *V_domain; - - su2double Density, Pressure, Temperature, Energy, *Velocity, Velocity2; - su2double Gas_Constant = config->GetGas_ConstantND(); - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool grid_movement = config->GetGrid_Movement(); - bool viscous = config->GetViscous(); - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - bool tkeNeeded = (((config->GetKind_Solver() == RANS )|| (config->GetKind_Solver() == DISC_ADJ_RANS)) && - (config->GetKind_Turb_Model() == SST)); - su2double *Normal = new su2double[nDim]; - - /*--- Supersonic inlet flow: there are no outgoing characteristics, - so all flow variables can be imposed at the inlet. - First, retrieve the specified values for the primitive variables. ---*/ - - Temperature = config->GetInlet_Temperature(Marker_Tag); - Pressure = config->GetInlet_Pressure(Marker_Tag); - Velocity = config->GetInlet_Velocity(Marker_Tag); - - /*--- Density at the inlet from the gas law ---*/ - - Density = Pressure/(Gas_Constant*Temperature); - - /*--- Non-dim. the inputs if necessary. ---*/ - - Temperature = Temperature/config->GetTemperature_Ref(); - Pressure = Pressure/config->GetPressure_Ref(); - Density = Density/config->GetDensity_Ref(); - for (iDim = 0; iDim < nDim; iDim++) - Velocity[iDim] = Velocity[iDim]/config->GetVelocity_Ref(); - - /*--- Compute the energy from the specified state ---*/ - - Velocity2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Velocity2 += Velocity[iDim]*Velocity[iDim]; - Energy = Pressure/(Density*Gamma_Minus_One)+0.5*Velocity2; - if (tkeNeeded) Energy += GetTke_Inf(); - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - /*--- Allocate the value at the outlet ---*/ - - V_inlet = GetCharacPrimVar(val_marker, iVertex); - - /*--- Primitive variables, using the derived quantities ---*/ - - V_inlet[0] = Temperature; - for (iDim = 0; iDim < nDim; iDim++) - V_inlet[iDim+1] = Velocity[iDim]; - V_inlet[nDim+1] = Pressure; - V_inlet[nDim+2] = Density; - V_inlet[nDim+3] = Energy + Pressure/Density; - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Index of the closest interior node ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Current solution at this boundary node ---*/ - - V_domain = node[iPoint]->GetPrimitive(); - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - - /*--- Set various quantities in the solver class ---*/ - - conv_numerics->SetNormal(Normal); - conv_numerics->SetPrimitive(V_domain, V_inlet); - - if (grid_movement) - conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), - geometry->node[iPoint]->GetGridVel()); - - /*--- Compute the residual using an upwind scheme ---*/ - - conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - - if (implicit) - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - /*--- Viscous contribution ---*/ - - if (viscous) { - - /*--- Set laminar and eddy viscosity at the infinity ---*/ - - V_inlet[nDim+5] = node[iPoint]->GetLaminarViscosity(); - V_inlet[nDim+6] = node[iPoint]->GetEddyViscosity(); - - /*--- Set the normal vector and the coordinates ---*/ - - visc_numerics->SetNormal(Normal); - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - - /*--- Primitive variables, and gradient ---*/ - - visc_numerics->SetPrimitive(V_domain, V_inlet); - visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); - - /*--- Turbulent kinetic energy ---*/ - - if (config->GetKind_Turb_Model() == SST) - visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); - - /*--- Compute and update residual ---*/ - - visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.SubtractBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - } - - } - } - - /*--- Free locally allocated memory ---*/ - - delete [] Normal; - -} - -void CEulerSolver::BC_Supersonic_Outlet(CGeometry *geometry, CSolver **solver_container, - CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - unsigned short iDim; - unsigned long iVertex, iPoint, Point_Normal; - su2double *V_outlet, *V_domain; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool grid_movement = config->GetGrid_Movement(); - bool viscous = config->GetViscous(); - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - - su2double *Normal = new su2double[nDim]; - - /*--- Supersonic outlet flow: there are no ingoing characteristics, - so all flow variables can should be interpolated from the domain. ---*/ - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Index of the closest interior node ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Current solution at this boundary node ---*/ - - V_domain = node[iPoint]->GetPrimitive(); - - /*--- Allocate the value at the outlet ---*/ - - V_outlet = GetCharacPrimVar(val_marker, iVertex); - - /*--- Primitive variables, using the derived quantities ---*/ - - V_outlet[0] = V_domain[0]; - for (iDim = 0; iDim < nDim; iDim++) - V_outlet[iDim+1] = V_domain[iDim+1]; - V_outlet[nDim+1] = V_domain[nDim+1]; - V_outlet[nDim+2] = V_domain[nDim+2]; - V_outlet[nDim+3] = V_domain[nDim+3]; - - /*--- Current solution at this boundary node ---*/ - - V_domain = node[iPoint]->GetPrimitive(); - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - - /*--- Set various quantities in the solver class ---*/ - - conv_numerics->SetNormal(Normal); - conv_numerics->SetPrimitive(V_domain, V_outlet); - - if (grid_movement) - conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), - geometry->node[iPoint]->GetGridVel()); - - /*--- Compute the residual using an upwind scheme ---*/ - - conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - - if (implicit) - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - /*--- Viscous contribution ---*/ - - if (viscous) { - - /*--- Set laminar and eddy viscosity at the infinity ---*/ - - V_outlet[nDim+5] = node[iPoint]->GetLaminarViscosity(); - V_outlet[nDim+6] = node[iPoint]->GetEddyViscosity(); - - /*--- Set the normal vector and the coordinates ---*/ - - visc_numerics->SetNormal(Normal); - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - - /*--- Primitive variables, and gradient ---*/ - - visc_numerics->SetPrimitive(V_domain, V_outlet); - visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); - - /*--- Turbulent kinetic energy ---*/ - - if (config->GetKind_Turb_Model() == SST) - visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); - - /*--- Compute and update residual ---*/ - - visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.SubtractBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - } - - } - } - - /*--- Free locally allocated memory ---*/ - - delete [] Normal; - -} - -void CEulerSolver::BC_Engine_Inflow(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned short iDim; - unsigned long iVertex, iPoint, Point_Normal; - su2double Pressure, Inflow_Pressure, Velocity[3], Velocity2, Entropy, Target_Inflow_Mach = 0.0, Density, Energy, - Riemann, Area, UnitNormal[3], Vn, SoundSpeed, Vn_Exit, Inflow_Pressure_inc, Inflow_Pressure_old, Inflow_Mach_old; - su2double *V_inflow, *V_domain; - - su2double DampingFactor = config->GetDamp_Engine_Inflow(); - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool viscous = config->GetViscous(); - su2double Gas_Constant = config->GetGas_ConstantND(); - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - bool tkeNeeded = (((config->GetKind_Solver() == RANS )|| (config->GetKind_Solver() == DISC_ADJ_RANS)) && - (config->GetKind_Turb_Model() == SST)); - su2double Baseline_Press = 0.75 * config->GetPressure_FreeStreamND(); - - su2double *Normal = new su2double[nDim]; - - /*--- Retrieve the specified target fan face mach in the nacelle. ---*/ - - Target_Inflow_Mach = config->GetInflow_Mach_Target(Marker_Tag); - - /*--- Retrieve the old fan face pressure and mach number in the nacelle (this has been computed in a preprocessing). ---*/ - - Inflow_Pressure_old = config->GetInflow_Pressure(Marker_Tag); // Note that has been computed by the code (non-dimensional). - Inflow_Mach_old = config->GetInflow_Mach(Marker_Tag); - - /*--- Compute the pressure increment (note that increasing pressure decreases flow speed) ---*/ - - Inflow_Pressure_inc = - (1.0 - (Inflow_Mach_old/Target_Inflow_Mach)) * Baseline_Press; - - /*--- Estimate the new fan face pressure ---*/ - - Inflow_Pressure = (1.0 - DampingFactor)*Inflow_Pressure_old + DampingFactor * (Inflow_Pressure_old + Inflow_Pressure_inc); - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - /*--- Allocate the value at the outlet ---*/ - - V_inflow = GetCharacPrimVar(val_marker, iVertex); - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Index of the closest interior node ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Area += Normal[iDim]*Normal[iDim]; - Area = sqrt (Area); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = Normal[iDim]/Area; - - /*--- Current solution at this boundary node ---*/ - - V_domain = node[iPoint]->GetPrimitive(); - - /*--- Subsonic nacelle inflow: there is one incoming characteristic, - therefore one variable can be specified (back pressure) and is used - to update the conservative variables. - - Compute the entropy and the acoustic variable. These - riemann invariants, as well as the tangential velocity components, - are extrapolated. ---*/ - - Density = V_domain[nDim+2]; - Velocity2 = 0.0; Vn = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity[iDim] = V_domain[iDim+1]; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - Vn += Velocity[iDim]*UnitNormal[iDim]; - } - Pressure = V_domain[nDim+1]; - SoundSpeed = sqrt(Gamma*Pressure/Density); - Entropy = Pressure*pow(1.0/Density, Gamma); - Riemann = Vn + 2.0*SoundSpeed/Gamma_Minus_One; - - /*--- Compute the new fictious state at the outlet ---*/ - - Density = pow(Inflow_Pressure/Entropy,1.0/Gamma); - Pressure = Inflow_Pressure; - SoundSpeed = sqrt(Gamma*Inflow_Pressure/Density); - Vn_Exit = Riemann - 2.0*SoundSpeed/Gamma_Minus_One; - Velocity2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity[iDim] = Velocity[iDim] + (Vn_Exit-Vn)*UnitNormal[iDim]; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - } - - Energy = Inflow_Pressure/(Density*Gamma_Minus_One) + 0.5*Velocity2; - if (tkeNeeded) Energy += GetTke_Inf(); - - /*--- Conservative variables, using the derived quantities ---*/ - - V_inflow[0] = Pressure / ( Gas_Constant * Density); - for (iDim = 0; iDim < nDim; iDim++) - V_inflow[iDim+1] = Velocity[iDim]; - V_inflow[nDim+1] = Pressure; - V_inflow[nDim+2] = Density; - V_inflow[nDim+3] = Energy + Pressure/Density; - - /*--- Set various quantities in the solver class ---*/ - - conv_numerics->SetNormal(Normal); - conv_numerics->SetPrimitive(V_domain, V_inflow); - - /*--- Compute the residual using an upwind scheme ---*/ - - conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - - if (implicit) - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - /*--- Viscous contribution ---*/ - - if (viscous) { - - /*--- Set laminar and eddy viscosity at the infinity ---*/ - - V_inflow[nDim+5] = node[iPoint]->GetLaminarViscosity(); - V_inflow[nDim+6] = node[iPoint]->GetEddyViscosity(); - - /*--- Set the normal vector and the coordinates ---*/ - - visc_numerics->SetNormal(Normal); - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - - /*--- Primitive variables, and gradient ---*/ - - visc_numerics->SetPrimitive(V_domain, V_inflow); - visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); - - /*--- Turbulent kinetic energy ---*/ - - if (config->GetKind_Turb_Model() == SST) - visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); - - /*--- Compute and update residual ---*/ - - visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.SubtractBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - - } - } - - delete [] Normal; - -} - -void CEulerSolver::BC_Engine_Exhaust(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned short iDim; - unsigned long iVertex, iPoint, Point_Normal; - su2double Exhaust_Pressure, Exhaust_Temperature, Velocity[3], Velocity2, H_Exhaust, Temperature, Riemann, Area, UnitNormal[3], Pressure, Density, Energy, Mach2, SoundSpeed2, SoundSpeed_Exhaust2, Vel_Mag, alpha, aa, bb, cc, dd, Flow_Dir[3]; - su2double *V_exhaust, *V_domain; - su2double Gas_Constant = config->GetGas_ConstantND(); - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool viscous = config->GetViscous(); - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - bool tkeNeeded = (((config->GetKind_Solver() == RANS )|| (config->GetKind_Solver() == DISC_ADJ_RANS)) && - (config->GetKind_Turb_Model() == SST)); - // su2double Target_Exhaust_Pressure, Exhaust_Pressure_old, Exhaust_Pressure_inc; - // su2double DampingFactor = config->GetDamp_Engine_Exhaust(); - // su2double Baseline_Press = 0.75 * config->GetPressure_FreeStreamND(); - - su2double *Normal = new su2double[nDim]; - - /*--- Retrieve the specified exhaust pressure in the engine (non-dimensional). ---*/ - - // Target_Exhaust_Pressure = config->GetExhaust_Pressure_Target(Marker_Tag) / config->GetPressure_Ref(); - - /*--- Retrieve the old exhaust pressure in the engine exhaust (this has been computed in a preprocessing). ---*/ - - // Exhaust_Pressure_old = config->GetExhaust_Pressure(Marker_Tag); - - /*--- Compute the Pressure increment ---*/ - - // Exhaust_Pressure_inc = (1.0 - (Exhaust_Pressure_old/Target_Exhaust_Pressure)) * Baseline_Press; - - /*--- Estimate the new exhaust pressure ---*/ - - // Exhaust_Pressure = (1.0 - DampingFactor) * Exhaust_Pressure_old + DampingFactor * (Exhaust_Pressure_old + Exhaust_Pressure_inc); - - /*--- The temperature is given (no iteration is required) ---*/ - - Exhaust_Temperature = config->GetExhaust_Temperature_Target(Marker_Tag); - Exhaust_Temperature /= config->GetTemperature_Ref(); - - /*--- The pressure is given (no iteration is required) ---*/ - /*--- CHECK: the above iterative process is overwritten on the next line. ---*/ - - Exhaust_Pressure = config->GetExhaust_Pressure_Target(Marker_Tag); - Exhaust_Pressure /= config->GetPressure_Ref(); - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - /*--- Allocate the value at the exhaust ---*/ - - V_exhaust = GetCharacPrimVar(val_marker, iVertex); - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Index of the closest interior node ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Area += Normal[iDim]*Normal[iDim]; - Area = sqrt (Area); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = Normal[iDim]/Area; - - /*--- Current solution at this boundary node ---*/ - - V_domain = node[iPoint]->GetPrimitive(); - - /*--- Subsonic inflow: there is one outgoing characteristic (u-c), - therefore we can specify all but one state variable at the inlet. - The outgoing Riemann invariant provides the final piece of info. ---*/ - - /*--- Store primitives and set some variables for clarity. ---*/ - - Density = V_domain[nDim+2]; - Velocity2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity[iDim] = V_domain[iDim+1]; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - } - Energy = V_domain[nDim+3] - V_domain[nDim+1]/V_domain[nDim+2]; - Pressure = V_domain[nDim+1]; - H_Exhaust = (Gamma*Gas_Constant/Gamma_Minus_One)*Exhaust_Temperature; - SoundSpeed2 = Gamma*Pressure/Density; - - /*--- Compute the acoustic Riemann invariant that is extrapolated - from the domain interior. ---*/ - - Riemann = 2.0*sqrt(SoundSpeed2)/Gamma_Minus_One; - for (iDim = 0; iDim < nDim; iDim++) - Riemann += Velocity[iDim]*UnitNormal[iDim]; - - /*--- Total speed of sound ---*/ - - SoundSpeed_Exhaust2 = Gamma_Minus_One*(H_Exhaust - (Energy + Pressure/Density)+0.5*Velocity2) + SoundSpeed2; - - /*--- The flow direction is defined by the surface normal ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - Flow_Dir[iDim] = -UnitNormal[iDim]; - - /*--- Dot product of normal and flow direction. This should - be negative due to outward facing boundary normal convention. ---*/ - - alpha = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - alpha += UnitNormal[iDim]*Flow_Dir[iDim]; - - /*--- Coefficients in the quadratic equation for the velocity ---*/ - - aa = 1.0 + 0.5*Gamma_Minus_One*alpha*alpha; - bb = -1.0*Gamma_Minus_One*alpha*Riemann; - cc = 0.5*Gamma_Minus_One*Riemann*Riemann - 2.0*SoundSpeed_Exhaust2/Gamma_Minus_One; - - /*--- Solve quadratic equation for velocity magnitude. Value must - be positive, so the choice of root is clear. ---*/ - - dd = bb*bb - 4.0*aa*cc; - dd = sqrt(max(0.0, dd)); - Vel_Mag = (-bb + dd)/(2.0*aa); - - if (Vel_Mag >= 0.0) { - - Velocity2 = Vel_Mag*Vel_Mag; - - /*--- Compute speed of sound from total speed of sound eqn. ---*/ - - SoundSpeed2 = SoundSpeed_Exhaust2 - 0.5*Gamma_Minus_One*Velocity2; - Mach2 = Velocity2/SoundSpeed2; - Velocity2 = Mach2*SoundSpeed2; - Vel_Mag = sqrt(Velocity2); - SoundSpeed2 = SoundSpeed_Exhaust2 - 0.5*Gamma_Minus_One*Velocity2; - - /*--- Compute new velocity vector at the inlet ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - Velocity[iDim] = Vel_Mag*Flow_Dir[iDim]; - - /*--- Static temperature from the speed of sound relation ---*/ - - Temperature = SoundSpeed2/(Gamma*Gas_Constant); - - /*--- Static pressure using isentropic relation at a point ---*/ - - Pressure = Exhaust_Pressure*pow((Temperature/Exhaust_Temperature), Gamma/Gamma_Minus_One); - - /*--- Density at the exhaust from the gas law ---*/ - - Density = Pressure/(Gas_Constant*Temperature); - - /*--- Using pressure, density, & velocity, compute the energy ---*/ - - Energy = Pressure/(Density*Gamma_Minus_One) + 0.5*Velocity2; - if (tkeNeeded) Energy += GetTke_Inf(); - - /*--- Primitive variables, using the derived quantities ---*/ - - V_exhaust[0] = Temperature; - for (iDim = 0; iDim < nDim; iDim++) - V_exhaust[iDim+1] = Velocity[iDim]; - V_exhaust[nDim+1] = Pressure; - V_exhaust[nDim+2] = Density; - V_exhaust[nDim+3] = Energy + Pressure/Density; - - } - - /*--- The flow goes in the wrong direction ---*/ - - else { - - V_exhaust[0] = V_domain[0]; - for (iDim = 0; iDim < nDim; iDim++) - V_exhaust[iDim+1] = V_domain[iDim+1]; - V_exhaust[nDim+1] = V_domain[nDim+1]; - V_exhaust[nDim+2] = V_domain[nDim+2]; - V_exhaust[nDim+3] = V_domain[nDim+3]; - - } - - /*--- Set various quantities in the solver class ---*/ - - conv_numerics->SetNormal(Normal); - conv_numerics->SetPrimitive(V_domain, V_exhaust); - - /*--- Compute the residual using an upwind scheme ---*/ - - conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - - if (implicit) - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - /*--- Viscous contribution ---*/ - - if (viscous) { - - /*--- Set laminar and eddy viscosity at the infinity ---*/ - - V_exhaust[nDim+5] = node[iPoint]->GetLaminarViscosity(); - V_exhaust[nDim+6] = node[iPoint]->GetEddyViscosity(); - - /*--- Set the normal vector and the coordinates ---*/ - - visc_numerics->SetNormal(Normal); - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - - /*--- Primitive variables, and gradient ---*/ - - visc_numerics->SetPrimitive(V_domain, V_exhaust); - visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); - - /*--- Turbulent kinetic energy ---*/ - - if (config->GetKind_Turb_Model() == SST) - visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); - - /*--- Compute and update residual ---*/ - - visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.SubtractBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - - } - } - - delete [] Normal; - -} - -void CEulerSolver::BC_Engine_Bleed(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned short iDim; - unsigned long iVertex, iPoint, Point_Normal; - su2double Bleed_Pressure, Target_Bleed_MassFlow, Bleed_Pressure_old, Bleed_MassFlow_old, Bleed_Pressure_inc, Bleed_Temperature, Velocity[3], Velocity2, H_Bleed, Temperature, Riemann, Area, UnitNormal[3], Pressure, Density, Energy, Mach2, SoundSpeed2, SoundSpeed_Bleed2, Vel_Mag, alpha, aa, bb, cc, dd, Flow_Dir[3]; - su2double *V_bleed, *V_domain; - su2double Gas_Constant = config->GetGas_ConstantND(); - - su2double DampingFactor = config->GetDamp_Engine_Bleed(); - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool viscous = config->GetViscous(); - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - bool tkeNeeded = (((config->GetKind_Solver() == RANS )|| (config->GetKind_Solver() == DISC_ADJ_RANS)) && - (config->GetKind_Turb_Model() == SST)); - su2double Baseline_Press = 0.25 * config->GetPressure_FreeStreamND(); - - su2double *Normal = new su2double[nDim]; - - /*--- Retrieve the specified target bleed mass flow in the engine (non-dimensional). ---*/ - - Target_Bleed_MassFlow = config->GetBleed_MassFlow_Target(Marker_Tag) / (config->GetDensity_Ref() * config->GetVelocity_Ref()); - - /*--- Retrieve the old Bleed pressure and mass flow rate number in the engine bleed (this has been computed in a preprocessing). ---*/ - - Bleed_Pressure_old = config->GetBleed_Pressure(Marker_Tag); - Bleed_MassFlow_old = config->GetBleed_MassFlow(Marker_Tag); - - /*--- Compute the Pressure increment (note that increasing pressure also increases mass flow rate) ---*/ - - Bleed_Pressure_inc = (1.0 - (Bleed_MassFlow_old/Target_Bleed_MassFlow)) * Baseline_Press; - - /*--- Estimate the new bleed pressure ---*/ - - Bleed_Pressure = (1.0 - DampingFactor)*Bleed_Pressure_old + DampingFactor * (Bleed_Pressure_old + Bleed_Pressure_inc); - - /*--- The temperature is given (no iteration is required) ---*/ - - Bleed_Temperature = config->GetBleed_Temperature_Target(Marker_Tag); - Bleed_Temperature /= config->GetTemperature_Ref(); - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - /*--- Allocate the value at the exhaust ---*/ - - V_bleed = GetCharacPrimVar(val_marker, iVertex); - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Index of the closest interior node ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Area += Normal[iDim]*Normal[iDim]; - Area = sqrt (Area); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = Normal[iDim]/Area; - - /*--- Current solution at this boundary node ---*/ - - V_domain = node[iPoint]->GetPrimitive(); - - /*--- Subsonic inflow: there is one outgoing characteristic (u-c), - therefore we can specify all but one state variable at the inlet. - The outgoing Riemann invariant provides the final piece of info. ---*/ - - /*--- Store primitives and set some variables for clarity. ---*/ - - Density = V_domain[nDim+2]; - Velocity2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Velocity[iDim] = V_domain[iDim+1]; - Velocity2 += Velocity[iDim]*Velocity[iDim]; - } - Energy = V_domain[nDim+3] - V_domain[nDim+1]/V_domain[nDim+2]; - Pressure = V_domain[nDim+1]; - H_Bleed = (Gamma*Gas_Constant/Gamma_Minus_One)*Bleed_Temperature; - SoundSpeed2 = Gamma*Pressure/Density; - - /*--- Compute the acoustic Riemann invariant that is extrapolated - from the domain interior. ---*/ - - Riemann = 2.0*sqrt(SoundSpeed2)/Gamma_Minus_One; - for (iDim = 0; iDim < nDim; iDim++) - Riemann += Velocity[iDim]*UnitNormal[iDim]; - - /*--- Total speed of sound ---*/ - - SoundSpeed_Bleed2 = Gamma_Minus_One*(H_Bleed - (Energy + Pressure/Density)+0.5*Velocity2) + SoundSpeed2; - - /*--- The flow direction is defined by the surface normal ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - Flow_Dir[iDim] = -UnitNormal[iDim]; - - /*--- Dot product of normal and flow direction. This should - be negative due to outward facing boundary normal convention. ---*/ - - alpha = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - alpha += UnitNormal[iDim]*Flow_Dir[iDim]; - - /*--- Coefficients in the quadratic equation for the velocity ---*/ - - aa = 1.0 + 0.5*Gamma_Minus_One*alpha*alpha; - bb = -1.0*Gamma_Minus_One*alpha*Riemann; - cc = 0.5*Gamma_Minus_One*Riemann*Riemann - 2.0*SoundSpeed_Bleed2/Gamma_Minus_One; - - /*--- Solve quadratic equation for velocity magnitude. Value must - be positive, so the choice of root is clear. ---*/ - - dd = bb*bb - 4.0*aa*cc; - dd = sqrt(max(0.0, dd)); - Vel_Mag = (-bb + dd)/(2.0*aa); - - if (Vel_Mag >= 0.0) { - - Velocity2 = Vel_Mag*Vel_Mag; - - /*--- Compute speed of sound from total speed of sound eqn. ---*/ - - SoundSpeed2 = SoundSpeed_Bleed2 - 0.5*Gamma_Minus_One*Velocity2; - - /*--- Mach squared (cut between 0-1), use to adapt velocity ---*/ - - Mach2 = Velocity2/SoundSpeed2; - Mach2 = min(1.0, Mach2); - Velocity2 = Mach2*SoundSpeed2; - Vel_Mag = sqrt(Velocity2); - SoundSpeed2 = SoundSpeed_Bleed2 - 0.5*Gamma_Minus_One*Velocity2; - - /*--- Compute new velocity vector at the inlet ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - Velocity[iDim] = Vel_Mag*Flow_Dir[iDim]; - - /*--- Static temperature from the speed of sound relation ---*/ - - Temperature = SoundSpeed2/(Gamma*Gas_Constant); - - /*--- Static pressure using isentropic relation at a point ---*/ - - Pressure = Bleed_Pressure*pow((Temperature/Bleed_Temperature), Gamma/Gamma_Minus_One); - - /*--- Density at the inlet from the gas law ---*/ - - Density = Pressure/(Gas_Constant*Temperature); - - /*--- Using pressure, density, & velocity, compute the energy ---*/ - - Energy = Pressure/(Density*Gamma_Minus_One) + 0.5*Velocity2; - if (tkeNeeded) Energy += GetTke_Inf(); - - /*--- Primitive variables, using the derived quantities ---*/ - - V_bleed[0] = Temperature; - for (iDim = 0; iDim < nDim; iDim++) - V_bleed[iDim+1] = Velocity[iDim]; - V_bleed[nDim+1] = Pressure; - V_bleed[nDim+2] = Density; - V_bleed[nDim+3] = Energy + Pressure/Density; - - } - - /*--- The flow goes in the wrong direction ---*/ - - else { - - V_bleed[0] = V_domain[0]; - for (iDim = 0; iDim < nDim; iDim++) - V_bleed[iDim+1] = V_domain[iDim+1]; - V_bleed[nDim+1] = V_domain[nDim+1]; - V_bleed[nDim+2] = V_domain[nDim+2]; - V_bleed[nDim+3] = V_domain[nDim+3]; - - } - - /*--- Set various quantities in the solver class ---*/ - - conv_numerics->SetNormal(Normal); - conv_numerics->SetPrimitive(V_domain, V_bleed); - - /*--- Compute the residual using an upwind scheme ---*/ - - conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - - if (implicit) - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - /*--- Viscous contribution ---*/ - - if (viscous) { - - /*--- Set laminar and eddy viscosity at the infinity ---*/ - - V_bleed[nDim+5] = node[iPoint]->GetLaminarViscosity(); - V_bleed[nDim+6] = node[iPoint]->GetEddyViscosity(); - - /*--- Set the normal vector and the coordinates ---*/ - - visc_numerics->SetNormal(Normal); - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - - /*--- Primitive variables, and gradient ---*/ - - visc_numerics->SetPrimitive(V_domain, V_bleed); - visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); - - /*--- Turbulent kinetic energy ---*/ - - if (config->GetKind_Turb_Model() == SST) - visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); - - /*--- Compute and update residual ---*/ - - visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.SubtractBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - - if (implicit) - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - - } - } - - delete [] Normal; - -} - -void CEulerSolver::BC_Sym_Plane(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, - CConfig *config, unsigned short val_marker) { - - /*--- Call the Euler residual ---*/ - - BC_Euler_Wall(geometry, solver_container, conv_numerics, config, val_marker); - -} - -void CEulerSolver::BC_Interface_Boundary(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config) { - - unsigned long iVertex, iPoint, jPoint; - unsigned short iDim, iVar, iMarker; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - - su2double *Normal = new su2double[nDim]; - su2double *PrimVar_i = new su2double[nPrimVar]; - su2double *PrimVar_j = new su2double[nPrimVar]; - -#ifndef HAVE_MPI - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Find the associate pair to the original node ---*/ - - jPoint = geometry->vertex[iMarker][iVertex]->GetDonorPoint(); - - if (iPoint != jPoint) { - - /*--- Store the solution for both points ---*/ - - for (iVar = 0; iVar < nPrimVar; iVar++) { - PrimVar_i[iVar] = node[iPoint]->GetPrimitive(iVar); - PrimVar_j[iVar] = node[jPoint]->GetPrimitive(iVar); - } - - /*--- Set primitive variables ---*/ - - numerics->SetPrimitive(PrimVar_i, PrimVar_j); - - /*--- Set the normal vector ---*/ - - geometry->vertex[iMarker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - numerics->SetNormal(Normal); - - /*--- Compute the convective residual using an upwind scheme ---*/ - - numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Add Residuals and Jacobians ---*/ - - LinSysRes.AddBlock(iPoint, Residual); - if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - } - - } - } - } - } - -#else - - int rank, jProcessor; - MPI_Status status; - //MPI_Status send_stat[1], recv_stat[1]; - //MPI_Request send_req[1], recv_req[1]; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - bool compute; - su2double *Buffer_Send_V = new su2double [nPrimVar]; - su2double *Buffer_Receive_V = new su2double [nPrimVar]; - - /*--- Do the send process, by the moment we are sending each - node individually, this must be changed ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Find the associate pair to the original node ---*/ - - jPoint = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; - jProcessor = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; - - if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; - else compute = true; - - /*--- We only send the information that belong to other boundary, -1 processor - means that the boundary condition is not applied ---*/ - - if (compute) { - - if (jProcessor != rank) { - - /*--- Copy the primitive variable ---*/ - - for (iVar = 0; iVar < nPrimVar; iVar++) - Buffer_Send_V[iVar] = node[iPoint]->GetPrimitive(iVar); - - SU2_MPI::Bsend(Buffer_Send_V, nPrimVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD); - - // SU2_MPI::Isend(Buffer_Send_V, nPrimVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD, &send_req[0]); - - // /*--- Wait for this set of non-blocking comm. to complete ---*/ - // - // SU2_MPI::Waitall(1, send_req, send_stat); - - } - - } - - } - } - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Find the associate pair to the original node ---*/ - - jPoint = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; - jProcessor = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; - - if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; - else compute = true; - - if (compute) { - - /*--- We only receive the information that belong to other boundary ---*/ - - if (jProcessor != rank) { - - SU2_MPI::Recv(Buffer_Receive_V, nPrimVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &status); - - // SU2_MPI::Irecv(Buffer_Receive_V, nPrimVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &recv_req[0]); - - /*--- Wait for the this set of non-blocking recv's to complete ---*/ - - // SU2_MPI::Waitall(1, recv_req, recv_stat); - - } - else { - for (iVar = 0; iVar < nPrimVar; iVar++) - Buffer_Receive_V[iVar] = node[jPoint]->GetPrimitive(iVar); - } - - /*--- Store the solution for both points ---*/ - - for (iVar = 0; iVar < nPrimVar; iVar++) { - PrimVar_i[iVar] = node[iPoint]->GetPrimitive(iVar); - PrimVar_j[iVar] = Buffer_Receive_V[iVar]; - } - - /*--- Set Conservative Variables ---*/ - - numerics->SetPrimitive(PrimVar_i, PrimVar_j); - - /*--- Set Normal ---*/ - - geometry->vertex[iMarker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - numerics->SetNormal(Normal); - - /*--- Compute the convective residual using an upwind scheme ---*/ - - numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Add Residuals and Jacobians ---*/ - - LinSysRes.AddBlock(iPoint, Residual); - if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - } - - } - } - } - } - - MPI_Barrier(MPI_COMM_WORLD); - - delete[] Buffer_Send_V; - delete[] Buffer_Receive_V; - -#endif - - /*--- Free locally allocated memory ---*/ - - delete [] Normal; - delete [] PrimVar_i; - delete [] PrimVar_j; - -} - -void CEulerSolver::BC_NearField_Boundary(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config) { - - unsigned long iVertex, iPoint, jPoint; - unsigned short iDim, iVar, iMarker; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - - su2double *Normal = new su2double[nDim]; - su2double *PrimVar_i = new su2double[nPrimVar]; - su2double *PrimVar_j = new su2double[nPrimVar]; - -#ifndef HAVE_MPI - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Find the associate pair to the original node ---*/ - - jPoint = geometry->vertex[iMarker][iVertex]->GetDonorPoint(); - - if (iPoint != jPoint) { - - /*--- Store the solution for both points ---*/ - - for (iVar = 0; iVar < nPrimVar; iVar++) { - PrimVar_i[iVar] = node[iPoint]->GetPrimitive(iVar); - PrimVar_j[iVar] = node[jPoint]->GetPrimitive(iVar); - } - - /*--- Set primitive variables ---*/ - - numerics->SetPrimitive(PrimVar_i, PrimVar_j); - - /*--- Set the normal vector ---*/ - - geometry->vertex[iMarker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - numerics->SetNormal(Normal); - - /*--- Compute the convective residual using an upwind scheme ---*/ - - numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Add Residuals and Jacobians ---*/ - - LinSysRes.AddBlock(iPoint, Residual); - if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - } - - } - } - } - } - -#else - - int rank, jProcessor; - MPI_Status status; - //MPI_Status send_stat[1], recv_stat[1]; - //MPI_Request send_req[1], recv_req[1]; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - bool compute; - su2double *Buffer_Send_V = new su2double [nPrimVar]; - su2double *Buffer_Receive_V = new su2double [nPrimVar]; - - /*--- Do the send process, by the moment we are sending each - node individually, this must be changed ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Find the associate pair to the original node ---*/ - - jPoint = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; - jProcessor = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; - - if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; - else compute = true; - - /*--- We only send the information that belong to other boundary, -1 processor - means that the boundary condition is not applied ---*/ - - if (compute) { - - if (jProcessor != rank) { - - /*--- Copy the primitive variable ---*/ - - for (iVar = 0; iVar < nPrimVar; iVar++) - Buffer_Send_V[iVar] = node[iPoint]->GetPrimitive(iVar); - - SU2_MPI::Bsend(Buffer_Send_V, nPrimVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD); - - // SU2_MPI::Isend(Buffer_Send_V, nPrimVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD, &send_req[0]); - - // /*--- Wait for this set of non-blocking comm. to complete ---*/ - // - // SU2_MPI::Waitall(1, send_req, send_stat); - - } - - } - - } - } - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Find the associate pair to the original node ---*/ - - jPoint = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; - jProcessor = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; - - if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; - else compute = true; - - if (compute) { - - /*--- We only receive the information that belong to other boundary ---*/ - - if (jProcessor != rank) { - - SU2_MPI::Recv(Buffer_Receive_V, nPrimVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &status); - - // SU2_MPI::Irecv(Buffer_Receive_V, nPrimVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &recv_req[0]); - - /*--- Wait for the this set of non-blocking recv's to complete ---*/ - - // SU2_MPI::Waitall(1, recv_req, recv_stat); - - } - else { - for (iVar = 0; iVar < nPrimVar; iVar++) - Buffer_Receive_V[iVar] = node[jPoint]->GetPrimitive(iVar); - } - - /*--- Store the solution for both points ---*/ - - for (iVar = 0; iVar < nPrimVar; iVar++) { - PrimVar_i[iVar] = node[iPoint]->GetPrimitive(iVar); - PrimVar_j[iVar] = Buffer_Receive_V[iVar]; - } - - /*--- Set Conservative Variables ---*/ - - numerics->SetPrimitive(PrimVar_i, PrimVar_j); - - /*--- Set Normal ---*/ - - geometry->vertex[iMarker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - numerics->SetNormal(Normal); - - /*--- Compute the convective residual using an upwind scheme ---*/ - - numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Add Residuals and Jacobians ---*/ - - LinSysRes.AddBlock(iPoint, Residual); - if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - } - - } - } - } - } - - MPI_Barrier(MPI_COMM_WORLD); - - delete[] Buffer_Send_V; - delete[] Buffer_Receive_V; - -#endif - - /*--- Free locally allocated memory ---*/ - - delete [] Normal; - delete [] PrimVar_i; - delete [] PrimVar_j; - -} - -void CEulerSolver::BC_ActDisk_Boundary(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config) { - - unsigned long iVertex, iPoint, jPoint, Pin = 0, Pout = 0, jProcessor; - unsigned short iDim, iVar, iMarker; - int iProcessor; - su2double *Coord, radius, DeltaP_avg, DeltaP_tip, DeltaT_avg, DeltaT_tip, - Radial[3] = {0.0,0.0,0.0}, Tangent[3] = {0.0,0.0,0.0}, Normal[3] = {0.0,0.0,0.0}, - UnitRadial[3] = {0.0,0.0,0.0}, UnitTangent[3] = {0.0,0.0,0.0}, UnitNormal[3] = {0.0,0.0,0.0}; - su2double H_in_ghost, P_in_ghost, Vel_Swirl_out_ghost, T_in_ghost, Rho_in_ghost, sos_in_ghost, Area, Vel_in_ghost; - su2double H_out_ghost, P_out_ghost, T_out_ghost, Rho_out_ghost, sos_out_ghost, Vel_Normal_in, Rho_in, Vel_Normal_out_ghost, Vel_out_ghost; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - unsigned short nMarker_ActDisk_Inlet = config->GetnMarker_ActDisk_Inlet(); - // su2double DampingFactor = 0.75; - - if (nMarker_ActDisk_Inlet != 0) { - - su2double *PrimVar_out = new su2double[nPrimVar]; - su2double *PrimVar_in = new su2double[nPrimVar]; - su2double *MeanPrimVar = new su2double[nPrimVar]; - su2double *PrimVar_out_ghost = new su2double[nPrimVar]; - su2double *PrimVar_in_ghost = new su2double[nPrimVar]; - su2double *ActDisk_Jump = new su2double[nPrimVar]; - su2double *Buffer_Send_V = new su2double [nPrimVar]; - su2double *Buffer_Receive_V = new su2double [nPrimVar]; - -#ifndef HAVE_MPI - iProcessor = MASTER_NODE; -#else - MPI_Status status; - //MPI_Status send_stat[1], recv_stat[1]; - //MPI_Request send_req[1], recv_req[1]; - MPI_Comm_rank(MPI_COMM_WORLD, &iProcessor); -#endif - - /*--- Identify the points that should be sended in a MPI implementation. - Do the send process, by the moment we are sending each node individually, this must be changed---*/ - -#ifdef HAVE_MPI - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == ACTDISK_INLET) || - (config->GetMarker_All_KindBC(iMarker) == ACTDISK_OUTLET)) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Find the associate pair to the original node ---*/ - - jPoint = geometry->vertex[iMarker][iVertex]->GetDonorPoint(); - jProcessor = geometry->vertex[iMarker][iVertex]->GetDonorProcessor(); - - /*--- We only send the information that belong to other boundary, using jPoint as the ID for the message ---*/ - - if ((int)jProcessor != iProcessor) { - - /*--- Copy the primitive variables ---*/ - - for (iVar = 0; iVar < nPrimVar; iVar++) - Buffer_Send_V[iVar] = node[iPoint]->GetPrimitive(iVar); - - SU2_MPI::Bsend(Buffer_Send_V, nPrimVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD); - - // SU2_MPI::Isend(Buffer_Send_V, nPrimVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD, &send_req[0]); - // SU2_MPI::Waitall(1, send_req, send_stat); - - } - - } - } - } - } - -#endif - - /*--- Evaluate the fluxes, the donor solution has been sended using MPI ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == ACTDISK_INLET) || - (config->GetMarker_All_KindBC(iMarker) == ACTDISK_OUTLET)) { - - unsigned short boundary = config->GetMarker_All_KindBC(iMarker); - su2double *Origin = config->GetActDisk_Origin(config->GetMarker_All_TagBound(iMarker)); - su2double R_root = config->GetActDisk_RootRadius(config->GetMarker_All_TagBound(iMarker)); - su2double R_tip = config->GetActDisk_TipRadius(config->GetMarker_All_TagBound(iMarker)); - su2double Target_Press_Jump = config->GetActDisk_PressJump(config->GetMarker_All_TagBound(iMarker))/ config->GetPressure_Ref(); - su2double Target_Temp_Jump = config->GetActDisk_TempJump(config->GetMarker_All_TagBound(iMarker))/ config->GetTemperature_Ref(); - su2double Omega = config->GetActDisk_Omega(config->GetMarker_All_TagBound(iMarker))*(PI_NUMBER/30.0); - unsigned short Distribution = config->GetActDisk_Distribution(config->GetMarker_All_TagBound(iMarker)); - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Find the associate pair to the original node ---*/ - - jPoint = geometry->vertex[iMarker][iVertex]->GetDonorPoint(); - jProcessor = geometry->vertex[iMarker][iVertex]->GetDonorProcessor(); - - /*--- Receive the information, using jPoint as the ID for the message ---*/ - - if ((int)jProcessor != iProcessor) { -#ifdef HAVE_MPI - - SU2_MPI::Recv(Buffer_Receive_V, nPrimVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &status); - - // SU2_MPI::Irecv(Buffer_Receive_V, nPrimVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &recv_req[0]); - // SU2_MPI::Waitall(1, send_req, send_stat); - -#endif - } - else { - - /*--- The point is in the same processor... no MPI required ---*/ - - for (iVar = 0; iVar < nPrimVar; iVar++) - Buffer_Receive_V[iVar] = node[jPoint]->GetPrimitive(iVar); - - } - - /*--- Identify the inner and the outer point (based on the normal direction) ---*/ - - if (boundary == ACTDISK_INLET) { - - Pin = iPoint; - - for (iVar = 0; iVar < nPrimVar; iVar++) { - PrimVar_out[iVar] = Buffer_Receive_V[iVar]; - PrimVar_in[iVar] = node[Pin]->GetPrimitive(iVar); - } - - } - if (boundary == ACTDISK_OUTLET) { - - Pout = iPoint; - - for (iVar = 0; iVar < nPrimVar; iVar++) { - PrimVar_out[iVar] = node[Pout]->GetPrimitive(iVar); - PrimVar_in[iVar] = Buffer_Receive_V[iVar]; - } - - } - - /*--- Set the jump in the actuator disk ---*/ - - for (iVar = 0; iVar < nPrimVar; iVar++) { - ActDisk_Jump[iVar] = 0.0; - } - - /*--- Compute the distance to the center of the rotor ---*/ - - Coord = geometry->node[iPoint]->GetCoord(); - radius = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - radius += (Coord[iDim]-Origin[iDim])*(Coord[iDim]-Origin[iDim]); - radius = sqrt(radius); - - /*--- Compute the pressure jump ---*/ - - // su2double Press_Jump = fabs(PrimVar_in[nDim+1]-PrimVar_in[nDim+1]); - // su2double Press_inc = (1.0 - (Press_Jump/Target_Press_Jump)) * 0.01 * config->GetPressure_FreeStreamND(); - // DeltaP_avg = (1.0 - DampingFactor)*Press_Jump + DampingFactor * (Press_Jump + Press_inc); - - DeltaP_avg = Target_Press_Jump; - if (Distribution == 1) { - DeltaP_tip = (3.0/2.0)*DeltaP_avg*R_tip*(R_tip*R_tip-R_root*R_root)/(R_tip*R_tip*R_tip-R_root*R_root*R_root); - ActDisk_Jump[nDim+1] = DeltaP_tip*radius/R_tip; - } - else - ActDisk_Jump[nDim+1] = DeltaP_avg; - - /*--- Compute the temperature jump ---*/ - - // su2double Temp_Jump = fabs(PrimVar_in[0]-PrimVar_in[0]); - // su2double Temp_inc = (1.0 - (Temp_Jump/Target_Temp_Jump)) * 0.01 * config->GetTemperature_FreeStreamND(); - // DeltaT_avg = (1.0 - DampingFactor)*Temp_Jump + DampingFactor * (Temp_Jump + Temp_inc); - - DeltaT_avg = Target_Temp_Jump; - if (Distribution == 1) { - DeltaT_tip = (3.0/2.0)*DeltaT_avg*R_tip*(R_tip*R_tip-R_root*R_root)/(R_tip*R_tip*R_tip-R_root*R_root*R_root); - ActDisk_Jump[0] = DeltaT_tip*radius/R_tip; - } - else - ActDisk_Jump[0] = DeltaT_avg; - - /*--- Inner point ---*/ - - if (boundary == ACTDISK_INLET) { - - for (iVar = 0; iVar < nPrimVar; iVar++) - PrimVar_in_ghost[iVar] = PrimVar_out[iVar] - ActDisk_Jump[iVar]; - - /*--- Check that this is a meaningful state ---*/ - - P_in_ghost = PrimVar_in_ghost[nDim+1]; - T_in_ghost = PrimVar_in_ghost[0]; - - FluidModel->SetTDState_PT(P_in_ghost, T_in_ghost); - Rho_in_ghost = FluidModel->GetDensity(); - sos_in_ghost = FluidModel->GetSoundSpeed(); - - /*--- Find unit normal to the actuator disk ---*/ - - geometry->vertex[iMarker][iVertex]->GetNormal(Normal); - - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); - for (iDim = 0; iDim < nDim; iDim++) { UnitNormal[iDim] = -Normal[iDim]/Area; } - - /*--- Impose only normal velocity on the disk inflow ---*/ - - Vel_in_ghost = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Vel_in_ghost += PrimVar_in[iDim+1]*UnitNormal[iDim]; - } - - /*--- COmpute the enthalpy ---*/ - - H_in_ghost = FluidModel->GetStaticEnergy() + 0.5*Vel_in_ghost*Vel_in_ghost + P_in_ghost/Rho_in_ghost; - - PrimVar_in_ghost[0] = T_in_ghost; - PrimVar_in_ghost[1] = Vel_in_ghost*UnitNormal[0]; - PrimVar_in_ghost[2] = Vel_in_ghost*UnitNormal[1]; - PrimVar_in_ghost[3] = Vel_in_ghost*UnitNormal[2]; - PrimVar_in_ghost[nDim+1]= P_in_ghost; - PrimVar_in_ghost[nDim+2]= Rho_in_ghost; - PrimVar_in_ghost[nDim+3]= H_in_ghost; - PrimVar_in_ghost[nDim+4]= sos_in_ghost; - - numerics->SetPrimitive(PrimVar_in, PrimVar_in_ghost); - - } - - /*--- Outer point ---*/ - - if (boundary == ACTDISK_OUTLET) { - - for (iVar = 0; iVar < nPrimVar; iVar++) - PrimVar_out_ghost[iVar] = PrimVar_in[iVar] + ActDisk_Jump[iVar]; - - /*--- Check that this is a meaningful state ---*/ - - P_out_ghost = PrimVar_out_ghost[nDim+1]; - T_out_ghost = PrimVar_out_ghost[0]; - - FluidModel->SetTDState_PT(P_out_ghost, T_out_ghost); - Rho_out_ghost = FluidModel->GetDensity(); - sos_out_ghost = FluidModel->GetSoundSpeed(); - - /*--- Find unit normal to the actuator disk ---*/ - - geometry->vertex[iMarker][iVertex]->GetNormal(Normal); - - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); - for (iDim = 0; iDim < nDim; iDim++) { UnitNormal[iDim] = Normal[iDim]/Area; } - - /*--- Find unit radial to the actuator disk ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - Radial[iDim] = Coord[iDim]-Origin[iDim]; - - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Radial[iDim]*Radial[iDim]; Area = sqrt(Area); - for (iDim = 0; iDim < nDim; iDim++) { UnitRadial[iDim] = Radial[iDim]/Area; } - - /*--- Find unit tangent to the actuator disk ---*/ - - Tangent[0] = UnitNormal[1]*UnitRadial[2] - UnitNormal[2]*UnitRadial[1]; - Tangent[1] = UnitNormal[2]*UnitRadial[0] - UnitNormal[0]*UnitRadial[2]; - Tangent[2] = UnitNormal[0]*UnitRadial[1] - UnitNormal[1]*UnitRadial[0]; - - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Tangent[iDim]*Tangent[iDim]; Area = sqrt(Area); - for (iDim = 0; iDim < nDim; iDim++) { UnitTangent[iDim] = Tangent[iDim]/Area; } - - /*--- Normal velocity to the disk and density at the inlet---*/ - - Vel_Normal_in = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Vel_Normal_in += PrimVar_in[iDim+1]*UnitNormal[iDim]; - } - - Rho_in = PrimVar_in[nDim+2]; - - /*--- Conservation of mass to evaluate velocity at the outlet ---*/ - - Vel_out_ghost = (Rho_in*Vel_Normal_in)/Rho_out_ghost; - - /*--- Compute the swirl velocity (check the formula) ---*/ - - if (Omega != 0.0) - Vel_Swirl_out_ghost = Omega*radius*(1.0-(1.0-sqrt(2.0*ActDisk_Jump[nDim+1]/(Rho_in*pow(Omega*radius, 2.0))))); - else - Vel_Swirl_out_ghost = 0.0; - - /*--- Compute normal component of the velocity ---*/ - - Vel_Normal_out_ghost = sqrt(Vel_out_ghost*Vel_out_ghost-Vel_Swirl_out_ghost*Vel_Swirl_out_ghost); - - /*--- Compute total entalphy ---*/ - - H_out_ghost = FluidModel->GetStaticEnergy() + 0.5*(Vel_Normal_out_ghost+Vel_Swirl_out_ghost)*(Vel_Normal_out_ghost+Vel_Swirl_out_ghost) + P_out_ghost/Rho_out_ghost; - - PrimVar_out_ghost[0] = T_out_ghost; - PrimVar_out_ghost[1] = Vel_Normal_out_ghost*UnitNormal[0] + Vel_Swirl_out_ghost*UnitTangent[0]; - PrimVar_out_ghost[2] = Vel_Normal_out_ghost*UnitNormal[1] + Vel_Swirl_out_ghost*UnitTangent[1]; - PrimVar_out_ghost[3] = Vel_Normal_out_ghost*UnitNormal[2] + Vel_Swirl_out_ghost*UnitTangent[2]; - PrimVar_out_ghost[nDim+1]= P_out_ghost; - PrimVar_out_ghost[nDim+2]= Rho_out_ghost; - PrimVar_out_ghost[nDim+3]= H_out_ghost; - PrimVar_out_ghost[nDim+4]= sos_out_ghost; - - numerics->SetPrimitive(PrimVar_out, PrimVar_out_ghost); - - } - - /*--- Set the normal vector ---*/ - - geometry->vertex[iMarker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - numerics->SetNormal(Normal); - - /*--- Compute the convective residual using an upwind scheme ---*/ - - numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Add Residuals and Jacobians ---*/ - - LinSysRes.AddBlock(iPoint, Residual); - if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - } - - } - - } - - } - - /*--- We are using non-blocking communications ---*/ - -#ifdef HAVE_MPI - - MPI_Barrier(MPI_COMM_WORLD); - -#endif - - /*--- Free locally allocated memory ---*/ - - delete [] PrimVar_out; - delete [] PrimVar_in; - delete [] MeanPrimVar; - delete [] PrimVar_out_ghost; - delete [] PrimVar_in_ghost; - delete [] ActDisk_Jump; - delete[] Buffer_Send_V; - delete[] Buffer_Receive_V; - - } - -} - -void CEulerSolver::BC_Dirichlet(CGeometry *geometry, CSolver **solver_container, - CConfig *config, unsigned short val_marker) { } - -void CEulerSolver::BC_Custom(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, unsigned short val_marker) { } - -void CEulerSolver::SetResidual_DualTime(CGeometry *geometry, CSolver **solver_container, CConfig *config, - unsigned short iRKStep, unsigned short iMesh, unsigned short RunTime_EqSystem) { - - /*--- Local variables ---*/ - - unsigned short iVar, jVar, iMarker, iDim; - unsigned long iPoint, jPoint, iEdge, iVertex; - - su2double *U_time_nM1, *U_time_n, *U_time_nP1; - su2double Volume_nM1, Volume_nP1, TimeStep; - su2double *Normal = NULL, *GridVel_i = NULL, *GridVel_j = NULL, Residual_GCL; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool FlowEq = (RunTime_EqSystem == RUNTIME_FLOW_SYS); - bool AdjEq = (RunTime_EqSystem == RUNTIME_ADJFLOW_SYS); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool grid_movement = config->GetGrid_Movement(); - - /*--- Store the physical time step ---*/ - - TimeStep = config->GetDelta_UnstTimeND(); - - /*--- Compute the dual time-stepping source term for static meshes ---*/ - - if (!grid_movement) { - - /*--- Loop over all nodes (excluding halos) ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Retrieve the solution at time levels n-1, n, and n+1. Note that - we are currently iterating on U^n+1 and that U^n & U^n-1 are fixed, - previous solutions that are stored in memory. ---*/ - - U_time_nM1 = node[iPoint]->GetSolution_time_n1(); - U_time_n = node[iPoint]->GetSolution_time_n(); - U_time_nP1 = node[iPoint]->GetSolution(); - - /*--- CV volume at time n+1. As we are on a static mesh, the volume - of the CV will remained fixed for all time steps. ---*/ - - Volume_nP1 = geometry->node[iPoint]->GetVolume(); - - /*--- Compute the dual time-stepping source term based on the chosen - time discretization scheme (1st- or 2nd-order).---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Residual[iVar] = (U_time_nP1[iVar] - U_time_n[iVar])*Volume_nP1 / TimeStep; - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - Residual[iVar] = ( 3.0*U_time_nP1[iVar] - 4.0*U_time_n[iVar] - +1.0*U_time_nM1[iVar])*Volume_nP1 / (2.0*TimeStep); - } - if ((incompressible || freesurface) && (FlowEq || AdjEq)) Residual[0] = 0.0; - - /*--- Store the residual and compute the Jacobian contribution due - to the dual time source term. ---*/ - - LinSysRes.AddBlock(iPoint, Residual); - if (implicit) { - for (iVar = 0; iVar < nVar; iVar++) { - for (jVar = 0; jVar < nVar; jVar++) Jacobian_i[iVar][jVar] = 0.0; - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Jacobian_i[iVar][iVar] = Volume_nP1 / TimeStep; - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - Jacobian_i[iVar][iVar] = (Volume_nP1*3.0)/(2.0*TimeStep); - } - if ((incompressible || freesurface) && (FlowEq || AdjEq)) Jacobian_i[0][0] = 0.0; - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - } - } - - } - - else { - - /*--- For unsteady flows on dynamic meshes (rigidly transforming or - dynamically deforming), the Geometric Conservation Law (GCL) should be - satisfied in conjunction with the ALE formulation of the governing - equations. The GCL prevents accuracy issues caused by grid motion, i.e. - a uniform free-stream should be preserved through a moving grid. First, - we will loop over the edges and boundaries to compute the GCL component - of the dual time source term that depends on grid velocities. ---*/ - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Get indices for nodes i & j plus the face normal ---*/ - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - Normal = geometry->edge[iEdge]->GetNormal(); - - /*--- Grid velocities stored at nodes i & j ---*/ - - GridVel_i = geometry->node[iPoint]->GetGridVel(); - GridVel_j = geometry->node[jPoint]->GetGridVel(); - - /*--- Compute the GCL term by averaging the grid velocities at the - edge mid-point and dotting with the face normal. ---*/ - - Residual_GCL = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Residual_GCL += 0.5*(GridVel_i[iDim]+GridVel_j[iDim])*Normal[iDim]; - - /*--- Compute the GCL component of the source term for node i ---*/ - - U_time_n = node[iPoint]->GetSolution_time_n(); - for (iVar = 0; iVar < nVar; iVar++) - Residual[iVar] = U_time_n[iVar]*Residual_GCL; - if ((incompressible || freesurface) && (FlowEq || AdjEq)) Residual[0] = 0.0; - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Compute the GCL component of the source term for node j ---*/ - - U_time_n = node[jPoint]->GetSolution_time_n(); - for (iVar = 0; iVar < nVar; iVar++) - Residual[iVar] = U_time_n[iVar]*Residual_GCL; - if ((incompressible || freesurface) && (FlowEq || AdjEq)) Residual[0] = 0.0; - LinSysRes.SubtractBlock(jPoint, Residual); - - } - - /*--- Loop over the boundary edges ---*/ - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - - /*--- Get the index for node i plus the boundary face normal ---*/ - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - - /*--- Grid velocities stored at boundary node i ---*/ - - GridVel_i = geometry->node[iPoint]->GetGridVel(); - - /*--- Compute the GCL term by dotting the grid velocity with the face - normal. The normal is negated to match the boundary convention. ---*/ - - Residual_GCL = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Residual_GCL -= 0.5*(GridVel_i[iDim]+GridVel_i[iDim])*Normal[iDim]; - - /*--- Compute the GCL component of the source term for node i ---*/ - - U_time_n = node[iPoint]->GetSolution_time_n(); - for (iVar = 0; iVar < nVar; iVar++) - Residual[iVar] = U_time_n[iVar]*Residual_GCL; - if ((incompressible || freesurface) && (FlowEq || AdjEq)) Residual[0] = 0.0; - LinSysRes.AddBlock(iPoint, Residual); - - } - } - - /*--- Loop over all nodes (excluding halos) to compute the remainder - of the dual time-stepping source term. ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Retrieve the solution at time levels n-1, n, and n+1. Note that - we are currently iterating on U^n+1 and that U^n & U^n-1 are fixed, - previous solutions that are stored in memory. ---*/ - - U_time_nM1 = node[iPoint]->GetSolution_time_n1(); - U_time_n = node[iPoint]->GetSolution_time_n(); - U_time_nP1 = node[iPoint]->GetSolution(); - - /*--- CV volume at time n-1 and n+1. In the case of dynamically deforming - grids, the volumes will change. On rigidly transforming grids, the - volumes will remain constant. ---*/ - - Volume_nM1 = geometry->node[iPoint]->GetVolume_nM1(); - Volume_nP1 = geometry->node[iPoint]->GetVolume(); - - /*--- Compute the dual time-stepping source residual. Due to the - introduction of the GCL term above, the remainder of the source residual - due to the time discretization has a new form.---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Residual[iVar] = (U_time_nP1[iVar] - U_time_n[iVar])*(Volume_nP1/TimeStep); - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - Residual[iVar] = (U_time_nP1[iVar] - U_time_n[iVar])*(3.0*Volume_nP1/(2.0*TimeStep)) - + (U_time_nM1[iVar] - U_time_n[iVar])*(Volume_nM1/(2.0*TimeStep)); - } - if ((incompressible || freesurface) && (FlowEq || AdjEq)) Residual[0] = 0.0; - - /*--- Store the residual and compute the Jacobian contribution due - to the dual time source term. ---*/ - - LinSysRes.AddBlock(iPoint, Residual); - if (implicit) { - for (iVar = 0; iVar < nVar; iVar++) { - for (jVar = 0; jVar < nVar; jVar++) Jacobian_i[iVar][jVar] = 0.0; - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Jacobian_i[iVar][iVar] = Volume_nP1/TimeStep; - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - Jacobian_i[iVar][iVar] = (3.0*Volume_nP1)/(2.0*TimeStep); - } - if ((incompressible || freesurface) && (FlowEq || AdjEq)) Jacobian_i[0][0] = 0.0; - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - } - } - } - -} - -void CEulerSolver::SetFlow_Displacement(CGeometry **flow_geometry, CVolumetricMovement *flow_grid_movement, - CConfig *flow_config, CConfig *fea_config, CGeometry **fea_geometry, CSolver ***fea_solution) { - unsigned short iMarker, iDim; - unsigned long iVertex, iPoint; - su2double *Coord, VarCoord[3]; - - //#ifndef HAVE_MPI - unsigned long iPoint_Donor; - su2double *CoordDonor, *DisplacementDonor; - - for (iMarker = 0; iMarker < flow_config->GetnMarker_All(); iMarker++) { - - if (flow_config->GetMarker_All_FSIinterface(iMarker) != 0) { - - for(iVertex = 0; iVertex < flow_geometry[MESH_0]->nVertex[iMarker]; iVertex++) { - - iPoint = flow_geometry[MESH_0]->vertex[iMarker][iVertex]->GetNode(); - - iPoint_Donor = flow_geometry[MESH_0]->vertex[iMarker][iVertex]->GetDonorPoint(); - - Coord = flow_geometry[MESH_0]->node[iPoint]->GetCoord(); - - CoordDonor = fea_geometry[MESH_0]->node[iPoint_Donor]->GetCoord(); - - /*--- The displacements come from the predicted solution ---*/ - DisplacementDonor = fea_solution[MESH_0][FEA_SOL]->node[iPoint_Donor]->GetSolution_Pred(); - - for (iDim = 0; iDim < nDim; iDim++) - - VarCoord[iDim] = (CoordDonor[iDim]+DisplacementDonor[iDim])-Coord[iDim]; - - flow_geometry[MESH_0]->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - } - } - } - flow_grid_movement->SetVolume_Deformation(flow_geometry[MESH_0], flow_config, true); - - - //#else - // - // int rank = MPI::COMM_WORLD.Get_rank(), jProcessor; - // su2double *Buffer_Send_Coord = new su2double [nDim]; - // su2double *Buffer_Receive_Coord = new su2double [nDim]; - // unsigned long jPoint; - // - // /*--- Do the send process, by the moment we are sending each - // node individually, this must be changed ---*/ - // for (iMarker = 0; iMarker < fea_config->GetnMarker_All(); iMarker++) { - // if (fea_config->GetMarker_All_KindBC(iMarker) == LOAD_BOUNDARY) { - // for (iVertex = 0; iVertex < fea_geometry[MESH_0]->nVertex[iMarker]; iVertex++) { - // iPoint = fea_geometry[MESH_0]->vertex[iMarker][iVertex]->GetNode(); - // - // if (fea_geometry[MESH_0]->node[iPoint]->GetDomain()) { - // - // /*--- Find the associate pair to the original node (index and processor) ---*/ - // jPoint = fea_geometry[MESH_0]->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; - // jProcessor = fea_geometry[MESH_0]->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; - // - // /*--- We only send the pressure that belong to other boundary ---*/ - // if (jProcessor != rank) { - // for (iDim = 0; iDim < nDim; iDim++) - // Buffer_Send_Coord[iDim] = fea_geometry[MESH_0]->node[iPoint]->GetCoord(iDim); - // - // MPI::COMM_WORLD.Bsend(Buffer_Send_Coord, nDim, MPI::DOUBLE, jProcessor, iPoint); - // } - // - // } - // } - // } - // } - // - // /*--- Now the loop is over the fea points ---*/ - // for (iMarker = 0; iMarker < flow_config->GetnMarker_All(); iMarker++) { - // if ((flow_config->GetMarker_All_KindBC(iMarker) == EULER_WALL) && - // (flow_config->GetMarker_All_Moving(iMarker) == YES)) { - // for (iVertex = 0; iVertex < flow_geometry[MESH_0]->nVertex[iMarker]; iVertex++) { - // iPoint = flow_geometry[MESH_0]->vertex[iMarker][iVertex]->GetNode(); - // if (flow_geometry[MESH_0]->node[iPoint]->GetDomain()) { - // - // /*--- Find the associate pair to the original node ---*/ - // jPoint = flow_geometry[MESH_0]->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; - // jProcessor = flow_geometry[MESH_0]->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; - // - // /*--- We only receive the information that belong to other boundary ---*/ - // if (jProcessor != rank) - // MPI::COMM_WORLD.Recv(Buffer_Receive_Coord, nDim, MPI::DOUBLE, jProcessor, jPoint); - // else { - // for (iDim = 0; iDim < nDim; iDim++) - // Buffer_Send_Coord[iDim] = fea_geometry[MESH_0]->node[jPoint]->GetCoord(iDim); - // } - // - // /*--- Store the solution for both points ---*/ - // Coord = flow_geometry[MESH_0]->node[iPoint]->GetCoord(); - // - // for (iDim = 0; iDim < nDim; iDim++) - // VarCoord[iDim] = Buffer_Send_Coord[iDim]-Coord[iDim]; - // - // flow_geometry[MESH_0]->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - // - // - // } - // } - // } - // } - // delete[] Buffer_Send_Coord; - // delete[] Buffer_Receive_Coord; - // - //#endif - // -} - -void CEulerSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig *config, int val_iter) { - - /*--- Restart the solution from file information ---*/ - unsigned short iDim, iVar, iMesh, iMeshFine; - unsigned long iPoint, index, iChildren, Point_Fine; - unsigned short turb_model = config->GetKind_Turb_Model(); - su2double Area_Children, Area_Parent, *Coord, *Solution_Fine, dull_val; - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool grid_movement = config->GetGrid_Movement(); - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - string UnstExt, text_line; - ifstream restart_file; - - string restart_filename = config->GetSolution_FlowFileName(); - - Coord = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Coord[iDim] = 0.0; - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Modify file name for an unsteady restart ---*/ - - if (dual_time) - restart_filename = config->GetUnsteady_FileName(restart_filename, val_iter); - - /*--- Open the restart file, and throw an error if this fails. ---*/ - - restart_file.open(restart_filename.data(), ios::in); - if (restart_file.fail()) { - if (rank == MASTER_NODE) - cout << "There is no flow restart file!! " << restart_filename.data() << "."<< endl; - exit(EXIT_FAILURE); - } - - /*--- In case this is a parallel simulation, we need to perform the - Global2Local index transformation first. ---*/ - - long *Global2Local = NULL; - Global2Local = new long[geometry[MESH_0]->GetGlobal_nPointDomain()]; - /*--- First, set all indices to a negative value by default ---*/ - for (iPoint = 0; iPoint < geometry[MESH_0]->GetGlobal_nPointDomain(); iPoint++) { - Global2Local[iPoint] = -1; - } - - /*--- Now fill array with the transform values only for local points ---*/ - - for (iPoint = 0; iPoint < geometry[MESH_0]->GetnPointDomain(); iPoint++) { - Global2Local[geometry[MESH_0]->node[iPoint]->GetGlobalIndex()] = iPoint; - } - - /*--- Read all lines in the restart file ---*/ - - long iPoint_Local = 0; unsigned long iPoint_Global = 0; - - /*--- The first line is the header ---*/ - - getline (restart_file, text_line); - - while (getline (restart_file, text_line)) { - istringstream point_line(text_line); - - /*--- Retrieve local index. If this node from the restart file lives - on a different processor, the value of iPoint_Local will be -1, as - initialized above. Otherwise, the local index for this node on the - current processor will be returned and used to instantiate the vars. ---*/ - - iPoint_Local = Global2Local[iPoint_Global]; - if (iPoint_Local >= 0) { - - if (compressible) { - if (nDim == 2) point_line >> index >> Coord[0] >> Coord[1] >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; - if (nDim == 3) point_line >> index >> Coord[0] >> Coord[1] >> Coord[2] >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3] >> Solution[4]; - } - if (incompressible) { - if (nDim == 2) point_line >> index >> Coord[0] >> Coord[1] >> Solution[0] >> Solution[1] >> Solution[2]; - if (nDim == 3) point_line >> index >> Coord[0] >> Coord[1] >> Coord[2] >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; - } - if (freesurface) { - if (nDim == 2) point_line >> index >> Coord[0] >> Coord[1] >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; - if (nDim == 3) point_line >> index >> Coord[0] >> Coord[1] >> Coord[2] >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3] >> Solution[4]; - } - - node[iPoint_Local]->SetSolution(Solution); - - /*--- For dynamic meshes, read in and store the - grid coordinates and grid velocities for each node. ---*/ - - if (grid_movement) { - - /*--- First, remove any variables for the turbulence model that - appear in the restart file before the grid velocities. ---*/ - - if (turb_model == SA || turb_model == SA_NEG) { - point_line >> dull_val; - } else if (turb_model == SST) { - point_line >> dull_val >> dull_val; - } - - /*--- Read in the next 2 or 3 variables which are the grid velocities ---*/ - - su2double GridVel[3] = {0.0,0.0,0.0}; - if (nDim == 2) point_line >> GridVel[0] >> GridVel[1]; - else point_line >> GridVel[0] >> GridVel[1] >> GridVel[2]; - - for (iDim = 0; iDim < nDim; iDim++) { - geometry[MESH_0]->node[iPoint_Local]->SetCoord(iDim, Coord[iDim]); - geometry[MESH_0]->node[iPoint_Local]->SetGridVel(iDim, GridVel[iDim]); - } - - } - - } - iPoint_Global++; - } - - /*--- Close the restart file ---*/ - - restart_file.close(); - - /*--- Free memory needed for the transformation ---*/ - - delete [] Global2Local; - - /*--- MPI solution ---*/ - - solver[MESH_0][FLOW_SOL]->Set_MPI_Solution(geometry[MESH_0], config); - - /*--- Interpolate the solution down to the coarse multigrid levels ---*/ - - for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++) { - for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { - Area_Parent = geometry[iMesh]->node[iPoint]->GetVolume(); - for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; - for (iChildren = 0; iChildren < geometry[iMesh]->node[iPoint]->GetnChildren_CV(); iChildren++) { - Point_Fine = geometry[iMesh]->node[iPoint]->GetChildren_CV(iChildren); - Area_Children = geometry[iMesh-1]->node[Point_Fine]->GetVolume(); - Solution_Fine = solver[iMesh-1][FLOW_SOL]->node[Point_Fine]->GetSolution(); - for (iVar = 0; iVar < nVar; iVar++) { - Solution[iVar] += Solution_Fine[iVar]*Area_Children/Area_Parent; - } - } - solver[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(Solution); - } - solver[iMesh][FLOW_SOL]->Set_MPI_Solution(geometry[iMesh], config); - } - - /*--- Update the geometry for flows on dynamic meshes ---*/ - - if (grid_movement) { - - /*--- Communicate the new coordinates and grid velocities at the halos ---*/ - - geometry[MESH_0]->Set_MPI_Coord(config); - geometry[MESH_0]->Set_MPI_GridVel(config); - - /*--- Recompute the edges and dual mesh control volumes in the - domain and on the boundaries. ---*/ - - geometry[MESH_0]->SetCoord_CG(); - geometry[MESH_0]->SetControlVolume(config, UPDATE); - geometry[MESH_0]->SetBoundControlVolume(config, UPDATE); - - /*--- 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]); - geometry[iMesh]->SetRestricted_GridVelocity(geometry[iMeshFine], config); - } - } - - delete [] Coord; - -} - -void CEulerSolver::SetFreeSurface_Distance(CGeometry *geometry, CConfig *config) { - su2double *coord = NULL, dist2, *iCoord = NULL, *jCoord = NULL, LevelSet_i, LevelSet_j, - **Coord_LevelSet = NULL, *xCoord = NULL, *yCoord = NULL, *zCoord = NULL, auxCoordx, auxCoordy, - auxCoordz, FreeSurface, volume, LevelSetDiff_Squared, LevelSetDiff, dist, Min_dist; - unsigned short iDim; - unsigned long iPoint, jPoint, iVertex, jVertex, nVertex_LevelSet, iEdge; - ifstream index_file; - ofstream LevelSet_file; - string text_line; - int rank = MASTER_NODE; - char cstr[200], buffer[50]; - - unsigned short nDim = geometry->GetnDim(); - unsigned long iExtIter = config->GetExtIter(); - -#ifndef HAVE_MPI - - /*--- Identification of the 0 level set points and coordinates ---*/ - nVertex_LevelSet = 0; - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - iPoint = geometry->edge[iEdge]->GetNode(0); LevelSet_i = node[iPoint]->GetSolution(nDim+1); - jPoint = geometry->edge[iEdge]->GetNode(1); LevelSet_j = node[jPoint]->GetSolution(nDim+1); - if (LevelSet_i*LevelSet_j < 0.0) nVertex_LevelSet ++; - } - - /*--- Allocate vector of boundary coordinates ---*/ - Coord_LevelSet = new su2double* [nVertex_LevelSet]; - for (iVertex = 0; iVertex < nVertex_LevelSet; iVertex++) - Coord_LevelSet[iVertex] = new su2double [nDim]; - - /*--- Get coordinates of the points of the surface ---*/ - nVertex_LevelSet = 0; - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - iPoint = geometry->edge[iEdge]->GetNode(0); LevelSet_i = node[iPoint]->GetSolution(nDim+1); iCoord = geometry->node[iPoint]->GetCoord(); - jPoint = geometry->edge[iEdge]->GetNode(1); LevelSet_j = node[jPoint]->GetSolution(nDim+1); jCoord = geometry->node[jPoint]->GetCoord(); - if (LevelSet_i*LevelSet_j < 0.0) { - for (iDim = 0; iDim < nDim; iDim++) - Coord_LevelSet[nVertex_LevelSet][iDim] = iCoord[iDim]-LevelSet_i*(jCoord[iDim]-iCoord[iDim])/(LevelSet_j-LevelSet_i); - nVertex_LevelSet++; - } - } - -#else - - int nProcessor, iProcessor; - unsigned long *Buffer_Send_nVertex = NULL, *Buffer_Receive_nVertex = NULL, - nLocalVertex_LevelSet = 0, nGlobalVertex_LevelSet = 0, MaxLocalVertex_LevelSet = 0, nBuffer; - su2double *Buffer_Send_Coord = NULL, *Buffer_Receive_Coord = NULL; - - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - Buffer_Send_nVertex = new unsigned long [1]; - Buffer_Receive_nVertex = new unsigned long [nProcessor]; - - nLocalVertex_LevelSet = 0; - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - iPoint = geometry->edge[iEdge]->GetNode(0); LevelSet_i = node[iPoint]->GetSolution(nDim+1); - jPoint = geometry->edge[iEdge]->GetNode(1); LevelSet_j = node[jPoint]->GetSolution(nDim+1); - if (LevelSet_i*LevelSet_j < 0.0) nLocalVertex_LevelSet ++; - } - - Buffer_Send_nVertex[0] = nLocalVertex_LevelSet; - - SU2_MPI::Allreduce(&nLocalVertex_LevelSet, &nGlobalVertex_LevelSet, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalVertex_LevelSet, &MaxLocalVertex_LevelSet, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - - nBuffer = MaxLocalVertex_LevelSet*nDim; - Buffer_Send_Coord = new su2double [nBuffer]; - Buffer_Receive_Coord = new su2double [nProcessor*nBuffer]; - - for (iVertex = 0; iVertex < MaxLocalVertex_LevelSet; iVertex++) - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; - - nLocalVertex_LevelSet = 0; - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - iPoint = geometry->edge[iEdge]->GetNode(0); LevelSet_i = node[iPoint]->GetSolution(nDim+1); iCoord = geometry->node[iPoint]->GetCoord(); - jPoint = geometry->edge[iEdge]->GetNode(1); LevelSet_j = node[jPoint]->GetSolution(nDim+1); jCoord = geometry->node[jPoint]->GetCoord(); - - if (LevelSet_i*LevelSet_j < 0.0) { - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[nLocalVertex_LevelSet*nDim+iDim] = iCoord[iDim]-LevelSet_i*(jCoord[iDim]-iCoord[iDim])/(LevelSet_j-LevelSet_i); - nLocalVertex_LevelSet++; - } - } - - SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer, MPI_DOUBLE, MPI_COMM_WORLD); - - /*--- Identification of the 0 level set points and coordinates ---*/ - nVertex_LevelSet = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) - nVertex_LevelSet += Buffer_Receive_nVertex[iProcessor]; - - /*--- Allocate vector of boundary coordinates ---*/ - Coord_LevelSet = new su2double* [nVertex_LevelSet]; - for (iVertex = 0; iVertex < nVertex_LevelSet; iVertex++) - Coord_LevelSet[iVertex] = new su2double [nDim]; - - /*--- Set the value of the coordinates at the level set zero ---*/ - nVertex_LevelSet = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) - for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { - for (iDim = 0; iDim < nDim; iDim++) - Coord_LevelSet[nVertex_LevelSet][iDim] = Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_LevelSet+iVertex)*nDim+iDim]; - nVertex_LevelSet++; - } - - delete [] Buffer_Send_Coord; - delete [] Buffer_Receive_Coord; - delete [] Buffer_Send_nVertex; - delete [] Buffer_Receive_nVertex; - -#endif - - /*--- Get coordinates of the points and compute distances to the surface ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint++) { - coord = geometry->node[iPoint]->GetCoord(); - - /*--- Compute the min distance ---*/ - Min_dist = 1E20; - for (iVertex = 0; iVertex < nVertex_LevelSet; iVertex++) { - - dist2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - dist2 += (coord[iDim] - Coord_LevelSet[iVertex][iDim])*(coord[iDim]-Coord_LevelSet[iVertex][iDim]); - dist = sqrt(dist2); - if (dist < Min_dist) { Min_dist = dist; } - - } - - /*--- Compute the sign using the current solution ---*/ - su2double NumberSign = 1.0; - if (node[iPoint]->GetSolution(0) != 0.0) - NumberSign = node[iPoint]->GetSolution(nDim+1)/fabs(node[iPoint]->GetSolution(nDim+1)); - - /*--- Store the value of the Level Set and the Distance (primitive variables) ---*/ - node[iPoint]->SetPrimitive(nDim+5, node[iPoint]->GetSolution(nDim+1)); - node[iPoint]->SetPrimitive(nDim+6, Min_dist*NumberSign); - - } - - if (config->GetIntIter() == 0) { - - /*--- Order the arrays (x Coordinate, y Coordinate, z Coordiante) ---*/ - for (iVertex = 0; iVertex < nVertex_LevelSet; iVertex++) { - for (jVertex = 0; jVertex < nVertex_LevelSet - 1 - iVertex; jVertex++) { - if (Coord_LevelSet[jVertex][0] > Coord_LevelSet[jVertex+1][0]) { - auxCoordx = Coord_LevelSet[jVertex][0]; Coord_LevelSet[jVertex][0] = Coord_LevelSet[jVertex+1][0]; Coord_LevelSet[jVertex+1][0] = auxCoordx; - auxCoordy = Coord_LevelSet[jVertex][1]; Coord_LevelSet[jVertex][1] = Coord_LevelSet[jVertex+1][1]; Coord_LevelSet[jVertex+1][1] = auxCoordy; - if (nDim == 3) { auxCoordz = Coord_LevelSet[jVertex][2]; Coord_LevelSet[jVertex][2] = Coord_LevelSet[jVertex+1][2]; Coord_LevelSet[jVertex+1][2] = auxCoordz; } - } - } - } - - /*--- Get coordinates of the points and compute distances to the surface ---*/ - FreeSurface = 0.0; - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - coord = geometry->node[iPoint]->GetCoord(); - volume = geometry->node[iPoint]->GetVolume(); - LevelSetDiff = (node[iPoint]->GetSolution(nDim+1) - coord[nDim-1]); - LevelSetDiff_Squared = LevelSetDiff*LevelSetDiff; - FreeSurface += 0.5*LevelSetDiff_Squared*volume; - - node[iPoint]->SetDiffLevelSet(LevelSetDiff); - - } - - if ((rank == MASTER_NODE) && (iExtIter % config->GetWrt_Sol_Freq_DualTime() == 0)) { - - /*--- Write the Level Set distribution, the target level set---*/ - LevelSet_file.precision(15); - - /*--- Write file name with extension ---*/ - strcpy (cstr, "LevelSet"); - if (config->GetUnsteady_Simulation()) { - if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(iExtIter)); - if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(iExtIter)); - } - else { - SPRINTF (buffer, ".dat"); - } - - strcat(cstr, buffer); - - LevelSet_file.open(cstr, ios::out); - LevelSet_file << "TITLE = \"SU2 Free surface simulation\"" << endl; - if (nDim == 2) LevelSet_file << "VARIABLES = \"x coord\",\"y coord\"" << endl; - if (nDim == 3) LevelSet_file << "VARIABLES = \"x coord\",\"y coord\",\"z coord\"" << endl; - LevelSet_file << "ZONE T= \"Free Surface\"" << endl; - - for (iVertex = 0; iVertex < nVertex_LevelSet; iVertex++) { - if (nDim == 2) LevelSet_file << scientific << Coord_LevelSet[iVertex][0] << ", " << Coord_LevelSet[iVertex][1] << endl; - if (nDim == 3) LevelSet_file << scientific << Coord_LevelSet[iVertex][0] << ", " << Coord_LevelSet[iVertex][1] << ", " << Coord_LevelSet[iVertex][2] << endl; - } - LevelSet_file.close(); - - } - - /*--- Store the value of the free surface coefficient ---*/ - SetTotal_CFreeSurface(FreeSurface); - - delete [] xCoord; - delete [] yCoord; - if (nDim == 3) delete [] zCoord; - - } - - /*--- Deallocate vector of boundary coordinates ---*/ - for (iVertex = 0; iVertex < nVertex_LevelSet; iVertex++) - delete Coord_LevelSet[iVertex]; - delete [] Coord_LevelSet; - -} - -CNSSolver::CNSSolver(void) : CEulerSolver() { - - /*--- Basic array initialization ---*/ - - CDrag_Visc = NULL; CLift_Visc = NULL; CSideForce_Visc = NULL; CEff_Visc = NULL; - CMx_Visc = NULL; CMy_Visc = NULL; CMz_Visc = NULL; - CFx_Visc = NULL; CFy_Visc = NULL; CFz_Visc = NULL; - - ForceViscous = NULL; MomentViscous = NULL; CSkinFriction = NULL; - - /*--- Surface based array initialization ---*/ - - Surface_CLift_Visc = NULL; Surface_CDrag_Visc = NULL; Surface_CSideForce_Visc = NULL; Surface_CEff_Visc = NULL; - Surface_CFx_Visc = NULL; Surface_CFy_Visc = NULL; Surface_CFz_Visc = NULL; - Surface_CMx_Visc = NULL; Surface_CMy_Visc = NULL; Surface_CMz_Visc = NULL; - - /*--- Rotorcraft simulation array initialization ---*/ - - CMerit_Visc = NULL; CT_Visc = NULL; CQ_Visc = NULL; - -} - -CNSSolver::CNSSolver(CGeometry *geometry, CConfig *config, unsigned short iMesh) : CEulerSolver() { - - unsigned long iPoint, index, counter_local = 0, counter_global = 0, iVertex; - unsigned short iVar, iDim, iMarker, nLineLets; - su2double Density, Velocity2, Pressure, Temperature, dull_val, StaticEnergy; - int Unst_RestartIter; - ifstream restart_file; - unsigned short iZone = config->GetiZone(); - unsigned short nZone = geometry->GetnZone(); - bool restart = (config->GetRestart() || config->GetRestart_Flow()); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - bool roe_turkel = (config->GetKind_Upwind_Flow() == TURKEL); - bool adjoint = config->GetAdjoint(); - string filename = config->GetSolution_FlowFileName(); - - unsigned short direct_diff = config->GetDirectDiff(); - unsigned short nMarkerTurboPerf = config->Get_nMarkerTurboPerf(); - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Array initialization ---*/ - - CDrag_Visc = NULL; CLift_Visc = NULL; CSideForce_Visc = NULL; CEff_Visc = NULL; - CMx_Visc = NULL; CMy_Visc = NULL; CMz_Visc = NULL; - CFx_Visc = NULL; CFy_Visc = NULL; CFz_Visc = NULL; - - Surface_CLift_Visc = NULL; Surface_CDrag_Visc = NULL; Surface_CSideForce_Visc = NULL; Surface_CEff_Visc = NULL; - Surface_CFx_Visc = NULL; Surface_CFy_Visc = NULL; Surface_CFz_Visc = NULL; - Surface_CMx_Visc = NULL; Surface_CMy_Visc = NULL; Surface_CMz_Visc = NULL; - - CMerit_Visc = NULL; CT_Visc = NULL; CQ_Visc = NULL; - MaxHeatFlux_Visc = NULL; ForceViscous = NULL; MomentViscous = NULL; - CSkinFriction = NULL; Cauchy_Serie = NULL; Heat_Visc = NULL; - - /*--- Set the gamma value ---*/ - - Gamma = config->GetGamma(); - Gamma_Minus_One = Gamma - 1.0; - - /*--- Define geometry constants in the solver structure - Compressible flow, primitive variables (T, vx, vy, vz, P, rho, h, c, lamMu, EddyMu, ThCond, Cp) - Incompressible flow, primitive variables (P, vx, vy, vz, rho, beta, lamMu, EddyMu), - FreeSurface Incompressible flow, primitive variables (P, vx, vy, vz, rho, beta, lamMu, EddyMu, LevelSet, Dist), - ---*/ - - nDim = geometry->GetnDim(); - - if (incompressible) { nVar = nDim+1; nPrimVar = nDim+5; nPrimVarGrad = nDim+3; } - if (freesurface) { nVar = nDim+2; nPrimVar = nDim+7; nPrimVarGrad = nDim+6; } - if (compressible) { nVar = nDim+2; - nPrimVar = nDim+9; nPrimVarGrad = nDim+4; - nSecondaryVar = 8; nSecondaryVarGrad = 2; - } - - nMarker = config->GetnMarker_All(); - nPoint = geometry->GetnPoint(); - nPointDomain = geometry->GetnPointDomain(); - - /*--- Perform the non-dimensionalization for the flow equations using the - specified reference values. ---*/ - - SetNondimensionalization(geometry, config, iMesh); - - /*--- Allocate the node variables ---*/ - node = new CVariable*[nPoint]; - - /*--- Define some auxiliar vector related with the residual ---*/ - - Residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; - Residual_RMS = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_RMS[iVar] = 0.0; - Residual_Max = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_Max[iVar] = 0.0; - Residual_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_i[iVar] = 0.0; - Residual_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_j[iVar] = 0.0; - Res_Conv = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Conv[iVar] = 0.0; - Res_Visc = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Visc[iVar] = 0.0; - Res_Sour = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Sour[iVar] = 0.0; - - /*--- Define some structures for locating max residuals ---*/ - - Point_Max = new unsigned long[nVar]; for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; - Point_Max_Coord = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Point_Max_Coord[iVar] = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; - } - - /*--- Define some auxiliary vectors related to the solution ---*/ - - Solution = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; - Solution_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_i[iVar] = 0.0; - Solution_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_j[iVar] = 0.0; - - /*--- Define some auxiliary vectors related to the geometry ---*/ - - Vector = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = 0.0; - Vector_i = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_i[iDim] = 0.0; - Vector_j = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_j[iDim] = 0.0; - - /*--- Define some auxiliary vectors related to the primitive solution ---*/ - - Primitive = new su2double[nPrimVar]; for (iVar = 0; iVar < nPrimVar; iVar++) Primitive[iVar] = 0.0; - Primitive_i = new su2double[nPrimVar]; for (iVar = 0; iVar < nPrimVar; iVar++) Primitive_i[iVar] = 0.0; - Primitive_j = new su2double[nPrimVar]; for (iVar = 0; iVar < nPrimVar; iVar++) Primitive_j[iVar] = 0.0; - - /*--- Define some auxiliary vectors related to the Secondary solution ---*/ - - if (compressible){ - Secondary = new su2double[nSecondaryVar]; for (iVar = 0; iVar < nSecondaryVar; iVar++) Secondary[iVar] = 0.0; - Secondary_i = new su2double[nSecondaryVar]; for (iVar = 0; iVar < nSecondaryVar; iVar++) Secondary_i[iVar] = 0.0; - Secondary_j = new su2double[nSecondaryVar]; for (iVar = 0; iVar < nSecondaryVar; iVar++) Secondary_j[iVar] = 0.0; - } - - /*--- Define some auxiliar vector related with the undivided lapalacian computation ---*/ - - if (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED) { - iPoint_UndLapl = new su2double [nPoint]; - jPoint_UndLapl = new su2double [nPoint]; - } - - /*--- Define some auxiliary vectors related to low-speed preconditioning ---*/ - - if (roe_turkel) { - LowMach_Precontioner = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar ++) - LowMach_Precontioner[iVar] = new su2double[nVar]; - } - - /*--- Initialize the solution and right hand side vectors for storing - the residuals and updating the solution (always needed even for - explicit schemes). ---*/ - - LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); - - /*--- Jacobians and vector structures for implicit computations ---*/ - - if (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT) { - - Jacobian_i = new su2double* [nVar]; - Jacobian_j = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Jacobian_i[iVar] = new su2double [nVar]; - Jacobian_j[iVar] = new su2double [nVar]; - } - - if (rank == MASTER_NODE) cout << "Initialize Jacobian structure (Navier-Stokes). MG level: " << iMesh <<"." << endl; - Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); - - if ((config->GetKind_Linear_Solver_Prec() == LINELET) || - (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { - nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); - if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; - } - - } - - else { - if (rank == MASTER_NODE) - cout << "Explicit scheme. No Jacobian structure (Navier-Stokes). MG level: " << iMesh <<"." << endl; - } - - /*--- Define some auxiliary vectors for computing flow variable - gradients by least squares, S matrix := inv(R)*traspose(inv(R)), - c vector := transpose(WA)*(Wb) ---*/ - - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { - - Smatrix = new su2double* [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Smatrix[iDim] = new su2double [nDim]; - - cvector = new su2double* [nPrimVarGrad]; - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - cvector[iVar] = new su2double [nDim]; - } - - /*--- Store the value of the characteristic primitive variables at the boundaries ---*/ - - CharacPrimVar = new su2double** [nMarker]; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - CharacPrimVar[iMarker] = new su2double* [geometry->nVertex[iMarker]]; - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - CharacPrimVar[iMarker][iVertex] = new su2double [nPrimVar]; - for (iVar = 0; iVar < nPrimVar; iVar++) { - CharacPrimVar[iMarker][iVertex][iVar] = 0.0; - } - } - } - - /*--- Inviscid force definition and coefficient in all the markers ---*/ - - CPressure = new su2double* [nMarker]; - CPressureTarget = new su2double* [nMarker]; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - CPressure[iMarker] = new su2double [geometry->nVertex[iMarker]]; - CPressureTarget[iMarker] = new su2double [geometry->nVertex[iMarker]]; - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - CPressure[iMarker][iVertex] = 0.0; - CPressureTarget[iMarker][iVertex] = 0.0; - } - } - - /*--- Heat flux in all the markers ---*/ - - HeatFlux = new su2double* [nMarker]; - HeatFluxTarget = new su2double* [nMarker]; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - HeatFlux[iMarker] = new su2double [geometry->nVertex[iMarker]]; - HeatFluxTarget[iMarker] = new su2double [geometry->nVertex[iMarker]]; - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - HeatFlux[iMarker][iVertex] = 0.0; - HeatFluxTarget[iMarker][iVertex] = 0.0; - } - } - - /*--- Y plus in all the markers ---*/ - - YPlus = new su2double* [nMarker]; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - YPlus[iMarker] = new su2double [geometry->nVertex[iMarker]]; - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - YPlus[iMarker][iVertex] = 0.0; - } - } - - /*--- Skin friction in all the markers ---*/ - - CSkinFriction = new su2double* [nMarker]; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - CSkinFriction[iMarker] = new su2double [geometry->nVertex[iMarker]]; - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - CSkinFriction[iMarker][iVertex] = 0.0; - } - } - - /*--- Non dimensional coefficients ---*/ - - ForceInviscid = new su2double[3]; - MomentInviscid = new su2double[3]; - CDrag_Inv = new su2double[nMarker]; - CLift_Inv = new su2double[nMarker]; - CSideForce_Inv = new su2double[nMarker]; - CMx_Inv = new su2double[nMarker]; - CMy_Inv = new su2double[nMarker]; - CMz_Inv = new su2double[nMarker]; - CEff_Inv = new su2double[nMarker]; - CFx_Inv = new su2double[nMarker]; - CFy_Inv = new su2double[nMarker]; - CFz_Inv = new su2double[nMarker]; - - ForceViscous = new su2double[3]; - MomentViscous = new su2double[3]; - CDrag_Visc = new su2double[nMarker]; - CLift_Visc = new su2double[nMarker]; - CSideForce_Visc = new su2double[nMarker]; - CMx_Visc = new su2double[nMarker]; - CMy_Visc = new su2double[nMarker]; - CMz_Visc = new su2double[nMarker]; - CEff_Visc = new su2double[nMarker]; - CFx_Visc = new su2double[nMarker]; - CFy_Visc = new su2double[nMarker]; - CFz_Visc = new su2double[nMarker]; - - Surface_CLift_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CDrag_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CSideForce_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CEff_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CFx_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CFy_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CFz_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CMx_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CMy_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CMz_Inv = new su2double[config->GetnMarker_Monitoring()]; - Surface_CLift = new su2double[config->GetnMarker_Monitoring()]; - Surface_CDrag = new su2double[config->GetnMarker_Monitoring()]; - Surface_CSideForce = new su2double[config->GetnMarker_Monitoring()]; - Surface_CEff = new su2double[config->GetnMarker_Monitoring()]; - Surface_CFx = new su2double[config->GetnMarker_Monitoring()]; - Surface_CFy = new su2double[config->GetnMarker_Monitoring()]; - Surface_CFz = new su2double[config->GetnMarker_Monitoring()]; - Surface_CMx = new su2double[config->GetnMarker_Monitoring()]; - Surface_CMy = new su2double[config->GetnMarker_Monitoring()]; - Surface_CMz = new su2double[config->GetnMarker_Monitoring()]; - - Surface_CLift_Visc = new su2double[config->GetnMarker_Monitoring()]; - Surface_CDrag_Visc = new su2double[config->GetnMarker_Monitoring()]; - Surface_CSideForce_Visc = new su2double[config->GetnMarker_Monitoring()]; - Surface_CEff_Visc = new su2double[config->GetnMarker_Monitoring()]; - Surface_CFx_Visc = new su2double[config->GetnMarker_Monitoring()]; - Surface_CFy_Visc = new su2double[config->GetnMarker_Monitoring()]; - Surface_CFz_Visc = new su2double[config->GetnMarker_Monitoring()]; - Surface_CMx_Visc = new su2double[config->GetnMarker_Monitoring()]; - Surface_CMy_Visc = new su2double[config->GetnMarker_Monitoring()]; - Surface_CMz_Visc = new su2double[config->GetnMarker_Monitoring()]; - - /*--- Rotational coefficients ---*/ - - CMerit_Inv = new su2double[nMarker]; - CT_Inv = new su2double[nMarker]; - CQ_Inv = new su2double[nMarker]; - - CMerit_Visc = new su2double[nMarker]; - CT_Visc = new su2double[nMarker]; - CQ_Visc = new su2double[nMarker]; - - /*--- Heat based coefficients ---*/ - - Heat_Visc = new su2double[nMarker]; - MaxHeatFlux_Visc = new su2double[nMarker]; - - /*--- Supersonic coefficients ---*/ - - CEquivArea_Inv = new su2double[nMarker]; - CNearFieldOF_Inv = new su2double[nMarker]; - - /*--- Engine simulation ---*/ - - Inflow_MassFlow = new su2double[nMarker]; - Inflow_Pressure = new su2double[nMarker]; - Inflow_Mach = new su2double[nMarker]; - Inflow_Area = new su2double[nMarker]; - - Exhaust_MassFlow = new su2double[nMarker]; - Exhaust_Pressure = new su2double[nMarker]; - Exhaust_Temperature = new su2double[nMarker]; - Exhaust_Area = new su2double[nMarker]; - - Bleed_MassFlow = new su2double[nMarker]; - Bleed_Pressure = new su2double[nMarker]; - Bleed_Temperature = new su2double[nMarker]; - Bleed_Area = new su2double[nMarker]; - - /*--- Init total coefficients ---*/ - - Total_CDrag = 0.0; Total_CLift = 0.0; Total_CSideForce = 0.0; - Total_CMx = 0.0; Total_CMy = 0.0; Total_CMz = 0.0; - Total_CEff = 0.0; Total_CEquivArea = 0.0; Total_CNearFieldOF = 0.0; - Total_CFx = 0.0; Total_CFy = 0.0; Total_CFz = 0.0; - Total_CT = 0.0; Total_CQ = 0.0; Total_CMerit = 0.0; - Total_MaxHeat = 0.0; Total_Heat = 0.0; - Total_CpDiff = 0.0; Total_HeatFluxDiff = 0.0; - - /*--- Read farfield conditions from config ---*/ - - Density_Inf = config->GetDensity_FreeStreamND(); - Pressure_Inf = config->GetPressure_FreeStreamND(); - Velocity_Inf = config->GetVelocity_FreeStreamND(); - Energy_Inf = config->GetEnergy_FreeStreamND(); - Temperature_Inf = config->GetTemperature_FreeStreamND(); - Viscosity_Inf = config->GetViscosity_FreeStreamND(); - Mach_Inf = config->GetMach(); - Prandtl_Lam = config->GetPrandtl_Lam(); - Prandtl_Turb = config->GetPrandtl_Turb(); - Tke_Inf = config->GetTke_FreeStreamND(); - - /*--- Initialize the secondary values for direct derivative approxiations ---*/ - - switch(direct_diff){ - case NO_DERIVATIVE: - break; - case D_DENSITY: - SU2_TYPE::SetDerivative(Density_Inf, 1.0); - break; - case D_PRESSURE: - SU2_TYPE::SetDerivative(Pressure_Inf, 1.0); - break; - case D_TEMPERATURE: - SU2_TYPE::SetDerivative(Temperature_Inf, 1.0); - break; - case D_VISCOSITY: - SU2_TYPE::SetDerivative(Viscosity_Inf, 1.0); - break; - case D_MACH: case D_AOA: - case D_SIDESLIP: case D_REYNOLDS: - case D_TURB2LAM: case D_DESIGN: - /*--- Already done in postprocessing of config ---*/ - break; - default: - break; - } - - /*--- Initializate fan face pressure, fan face mach number, and mass flow rate ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - Inflow_MassFlow[iMarker] = 0.0; - Inflow_Mach[iMarker] = Mach_Inf; - Inflow_Pressure[iMarker] = Pressure_Inf; - Inflow_Area[iMarker] = 0.0; - - Exhaust_MassFlow[iMarker] = 0.0; - Exhaust_Temperature[iMarker] = Temperature_Inf; - Exhaust_Pressure[iMarker] = Pressure_Inf; - Exhaust_Area[iMarker] = 0.0; - - Bleed_MassFlow[iMarker] = 0.0; - Bleed_Temperature[iMarker] = Temperature_Inf; - Bleed_Pressure[iMarker] = Pressure_Inf; - Bleed_Area[iMarker] = 0.0; - } - - /*--- Initializate quantities for the mixing process*/ - - AveragedVelocity = new su2double* [nMarker]; - AveragedNormal = new su2double* [nMarker]; - AveragedGridVel = new su2double* [nMarker]; - AveragedFlux = new su2double* [nMarker]; - TotalFlux = new su2double* [nMarker]; - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - AveragedVelocity[iMarker] = new su2double [nDim]; - AveragedNormal[iMarker] = new su2double [nDim]; - AveragedGridVel[iMarker] = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) { - AveragedVelocity[iMarker][iDim] = 0.0; - AveragedNormal[iMarker][iDim] = 0.0; - AveragedGridVel[iMarker][iDim] = 0.0; - } - } - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - AveragedFlux[iMarker] = new su2double [nVar]; - TotalFlux[iMarker] = new su2double [nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - AveragedFlux[iMarker][iVar] = 0.0; - TotalFlux[iMarker][iVar] = 0.0; - } - } - - AveragedNormalVelocity = new su2double[nMarker]; - AveragedTangVelocity = new su2double[nMarker]; - ExtAveragedNormalVelocity = new su2double[nMarker]; - ExtAveragedTangVelocity = new su2double[nMarker]; - MassFlow= new su2double[nMarker]; - FlowAngle= new su2double[nMarker]; - AveragedEnthalpy = new su2double[nMarker]; - AveragedPressure = new su2double[nMarker]; - AveragedTotPressure = new su2double[nMarker]; - AveragedTotTemperature = new su2double[nMarker]; - ExtAveragedTotPressure = new su2double[nMarker]; - ExtAveragedTotTemperature = new su2double[nMarker]; - ExtAveragedPressure = new su2double[nMarker]; - AveragedDensity = new su2double[nMarker]; - ExtAveragedDensity = new su2double[nMarker]; - AveragedSoundSpeed= new su2double[nMarker]; - AveragedEntropy = new su2double[nMarker]; - AveragedTangGridVelocity = new su2double[nMarker]; - AveragedMach = new su2double[nMarker]; - AveragedNormalMach = new su2double[nMarker]; - AveragedTangMach = new su2double[nMarker]; - - - /*--- Initializate quantities for turboperformace ---*/ - - TotalStaticEfficiency = new su2double[nMarkerTurboPerf]; - TotalTotalEfficiency = new su2double[nMarkerTurboPerf]; - KineticEnergyLoss= new su2double[nMarkerTurboPerf]; - TotalPressureLoss= new su2double[nMarkerTurboPerf]; - MassFlowIn= new su2double[nMarkerTurboPerf]; - MassFlowOut= new su2double[nMarkerTurboPerf]; - FlowAngleIn= new su2double[nMarkerTurboPerf]; - FlowAngleOut= new su2double[nMarkerTurboPerf]; - EulerianWork= new su2double[nMarkerTurboPerf]; - TotalEnthalpyIn= new su2double[nMarkerTurboPerf]; - PressureRatio= new su2double[nMarkerTurboPerf]; - PressureOut= new su2double[nMarkerTurboPerf]; - EnthalpyOut= new su2double[nMarkerTurboPerf]; - MachIn= new su2double[nMarkerTurboPerf]; - MachOut= new su2double[nMarkerTurboPerf]; - NormalMachIn= new su2double[nMarkerTurboPerf]; - NormalMachOut= new su2double[nMarkerTurboPerf]; - VelocityOutIs= new su2double[nMarkerTurboPerf]; - - for (iMarker = 0; iMarker < nMarkerTurboPerf; iMarker++){ - TotalStaticEfficiency[iMarker]= 0.0; - TotalTotalEfficiency[iMarker]= 0.0; - KineticEnergyLoss[iMarker]= 0.0; - TotalPressureLoss[iMarker]= 0.0; - MassFlowIn[iMarker]= 0.0; - MassFlowOut[iMarker]= 0.0; - FlowAngleIn[iMarker]= 0.0; - FlowAngleOut[iMarker]= 0.0; - EulerianWork[iMarker]= 0.0; - TotalEnthalpyIn[iMarker]= 0.0; - PressureRatio[iMarker]= 0.0; - PressureOut[iMarker]= 0.0; - EnthalpyOut[iMarker]= 0.0; - MachIn[iMarker]= 0.0; - MachOut[iMarker]= 0.0; - NormalMachIn[iMarker]= 0.0; - NormalMachOut[iMarker]= 0.0; - VelocityOutIs[iMarker]= 0.0; - } - - - /*--- Initialize the cauchy critera array for fixed CL mode ---*/ - - if (config->GetFixed_CL_Mode()) - - Cauchy_Serie = new su2double [config->GetCauchy_Elems()+1]; - - /*--- Check for a restart and set up the variables at each node - appropriately. Coarse multigrid levels will be intitially set to - the farfield values bc the solver will immediately interpolate - the solution from the finest mesh to the coarser levels. ---*/ - - if (!restart || (iMesh != MESH_0)) { - - /*--- Restart the solution from the free-stream state ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) - node[iPoint] = new CNSVariable(Density_Inf, Velocity_Inf, Energy_Inf, nDim, nVar, config); - - } - - else { - - /*--- Modify file name for an unsteady restart ---*/ - - if (dual_time) { - - if (adjoint) { - Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_AdjointIter()) - 1; - } else if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_RestartIter())-1; - else - Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_RestartIter())-2; - - filename = config->GetUnsteady_FileName(filename, Unst_RestartIter); - - } - - if (nZone >1) - filename= config->GetRestart_FlowFileName(filename, iZone); - - /*--- Open the restart file, throw an error if this fails. ---*/ - - restart_file.open(filename.data(), ios::in); - if (restart_file.fail()) { - if (rank == MASTER_NODE) - cout << "There is no flow restart file!! " << filename.data() << "."<< endl; - exit(EXIT_FAILURE); - } - - /*--- In case this is a parallel simulation, we need to perform the - Global2Local index transformation first. ---*/ - - long *Global2Local = new long[geometry->GetGlobal_nPointDomain()]; - - /*--- First, set all indices to a negative value by default ---*/ - - for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) - Global2Local[iPoint] = -1; - - /*--- Now fill array with the transform values only for local points ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) - Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; - - /*--- Read all lines in the restart file ---*/ - - long iPoint_Local; - unsigned long iPoint_Global_Local = 0, iPoint_Global = 0; string text_line; - unsigned short rbuf_NotMatching = 0, sbuf_NotMatching = 0; - - /*--- The first line is the header ---*/ - - getline (restart_file, text_line); - - while (getline (restart_file, text_line)) { - istringstream point_line(text_line); - - /*--- Retrieve local index. If this node from the restart file lives - on a different processor, the value of iPoint_Local will be -1. - Otherwise, the local index for this node on the current processor - will be returned and used to instantiate the vars. ---*/ - - if (iPoint_Global >= geometry->GetGlobal_nPointDomain()) { sbuf_NotMatching = 1; break; } - - iPoint_Local = Global2Local[iPoint_Global]; - - /*--- Load the solution for this node. Note that the first entry - on the restart file line is the global index, followed by the - node coordinates, and then the conservative variables. ---*/ - - if (iPoint_Local >= 0) { - if (compressible) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3] >> Solution[4]; - } - if (incompressible) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; - } - if (freesurface) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3] >> Solution[4]; - } - node[iPoint_Local] = new CNSVariable(Solution, nDim, nVar, config); - iPoint_Global_Local++; - } - iPoint_Global++; - } - - /*--- Detect a wrong solution file ---*/ - - if (iPoint_Global_Local < nPointDomain) { sbuf_NotMatching = 1; } - -#ifndef HAVE_MPI - rbuf_NotMatching = sbuf_NotMatching; -#else - SU2_MPI::Allreduce(&sbuf_NotMatching, &rbuf_NotMatching, 1, MPI_UNSIGNED_SHORT, MPI_SUM, MPI_COMM_WORLD); -#endif - - if (rbuf_NotMatching != 0) { - if (rank == MASTER_NODE) { - cout << endl << "The solution file " << filename.data() << " doesn't match with the mesh file!" << endl; - cout << "It could be empty lines at the end of the file." << endl << endl; - } -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Barrier(MPI_COMM_WORLD); - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - } - - /*--- Instantiate the variable class with an arbitrary solution - at any halo/periodic nodes. The initial solution can be arbitrary, - because a send/recv is performed immediately in the solver. ---*/ - - for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) - node[iPoint] = new CNSVariable(Solution, nDim, nVar, config); - - /*--- Close the restart file ---*/ - - restart_file.close(); - - /*--- Free memory needed for the transformation ---*/ - - delete [] Global2Local; - - } - - /*--- Check that the initial solution is physical, report any non-physical nodes ---*/ - - if (compressible) { - - counter_local = 0; - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - - Density = node[iPoint]->GetSolution(0); - - Velocity2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Velocity2 += (node[iPoint]->GetSolution(iDim+1)/Density)*(node[iPoint]->GetSolution(iDim+1)/Density); - - StaticEnergy= node[iPoint]->GetSolution(nDim+1)/Density - 0.5*Velocity2; - - FluidModel->SetTDState_rhoe(Density, StaticEnergy); - Pressure= FluidModel->GetPressure(); - Temperature= FluidModel->GetTemperature(); - - /*--- Use the values at the infinity ---*/ - - if ((Pressure < 0.0) || (Density < 0.0) || (Temperature < 0.0)) { - Solution[0] = Density_Inf; - for (iDim = 0; iDim < nDim; iDim++) - Solution[iDim+1] = Velocity_Inf[iDim]*Density_Inf; - Solution[nDim+1] = Energy_Inf*Density_Inf; - node[iPoint]->SetSolution(Solution); - node[iPoint]->SetSolution_Old(Solution); - counter_local++; - } - - } - - /*--- Warning message about non-physical points ---*/ - - if (config->GetConsole_Output_Verb() == VERB_HIGH) { -#ifdef HAVE_MPI - SU2_MPI::Reduce(&counter_local, &counter_global, 1, MPI_UNSIGNED_LONG, MPI_SUM, MASTER_NODE, MPI_COMM_WORLD); -#else - counter_global = counter_local; -#endif - if ((rank == MASTER_NODE) && (counter_global != 0)) - cout << "Warning. The original solution contains "<< counter_global << " points that are not physical." << endl; - } - - } - - /*--- For incompressible solver set the initial values for the density and viscosity, - unless a freesurface problem, this must be constant during the computation ---*/ - - if (incompressible || freesurface) { - for (iPoint = 0; iPoint < nPoint; iPoint++) { - node[iPoint]->SetDensityInc(Density_Inf); - node[iPoint]->SetLaminarViscosityInc(Viscosity_Inf); - } - } - - /*--- Define solver parameters needed for execution of destructor ---*/ - - if (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED) space_centered = true; - else space_centered = false; - - if (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT) euler_implicit = true; - else euler_implicit = false; - - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) least_squares = true; - else least_squares = false; - - /*--- Perform the MPI communication of the solution ---*/ - - Set_MPI_Solution(geometry, config); - -} - -CNSSolver::~CNSSolver(void) { - unsigned short iMarker; - - if (CDrag_Visc != NULL) delete [] CDrag_Visc; - if (CLift_Visc != NULL) delete [] CLift_Visc; - if (CSideForce_Visc != NULL) delete [] CSideForce_Visc; - if (CMx_Visc != NULL) delete [] CMx_Visc; - if (CMy_Visc != NULL) delete [] CMy_Visc; - if (CMz_Visc != NULL) delete [] CMz_Visc; - if (CFx_Visc != NULL) delete [] CFx_Visc; - if (CFy_Visc != NULL) delete [] CFy_Visc; - if (CFz_Visc != NULL) delete [] CFz_Visc; - if (CEff_Visc != NULL) delete [] CEff_Visc; - if (CMerit_Visc != NULL) delete [] CMerit_Visc; - if (CT_Visc != NULL) delete [] CT_Visc; - if (CQ_Visc != NULL) delete [] CQ_Visc; - if (Heat_Visc != NULL) delete [] Heat_Visc; - if (MaxHeatFlux_Visc != NULL) delete [] MaxHeatFlux_Visc; - if (ForceViscous != NULL) delete [] ForceViscous; - if (MomentViscous != NULL) delete [] MomentViscous; - - - if (Surface_CLift_Visc != NULL) delete [] Surface_CLift_Visc; - if (Surface_CDrag_Visc != NULL) delete [] Surface_CDrag_Visc; - if (Surface_CSideForce_Visc != NULL) delete [] Surface_CSideForce_Visc; - if (Surface_CEff_Visc != NULL) delete [] Surface_CEff_Visc; - if (Surface_CFx_Visc != NULL) delete [] Surface_CFx_Visc; - if (Surface_CFy_Visc != NULL) delete [] Surface_CFy_Visc; - if (Surface_CFz_Visc != NULL) delete [] Surface_CFz_Visc; - if (Surface_CMx_Visc != NULL) delete [] Surface_CMx_Visc; - if (Surface_CMy_Visc != NULL) delete [] Surface_CMy_Visc; - if (Surface_CMz_Visc != NULL) delete [] Surface_CMz_Visc; - - if (Cauchy_Serie != NULL) delete [] Cauchy_Serie; - - if (CSkinFriction != NULL) { - for (iMarker = 0; iMarker < nMarker; iMarker++) { - delete CSkinFriction[iMarker]; - } - delete [] CSkinFriction; - } - -} - -void CNSSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { - - unsigned long iPoint, ErrorCounter = 0; - su2double StrainMag = 0.0, Omega = 0.0, *Vorticity; - -#ifdef HAVE_MPI - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - unsigned long ExtIter = config->GetExtIter(); - bool adjoint = config->GetAdjoint(); - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool center = (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED) || (adjoint && config->GetKind_ConvNumScheme_AdjFlow() == SPACE_CENTERED); - bool center_jst = center && config->GetKind_Centered_Flow() == JST; - bool limiter_flow = ((config->GetSpatialOrder_Flow() == SECOND_ORDER_LIMITER) && (ExtIter <= config->GetLimiterIter())); - bool limiter_turb = ((config->GetSpatialOrder_Turb() == SECOND_ORDER_LIMITER) && (ExtIter <= config->GetLimiterIter())); - bool limiter_adjflow = ((config->GetSpatialOrder_AdjFlow() == SECOND_ORDER_LIMITER) && (ExtIter <= config->GetLimiterIter())); - bool limiter_visc = config->GetViscous_Limiter_Flow(); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool fixed_cl = config->GetFixed_CL_Mode(); - bool engine = ((config->GetnMarker_EngineInflow() != 0) || (config->GetnMarker_EngineBleed() != 0) || (config->GetnMarker_EngineExhaust() != 0)); - bool actuator_disk = ((config->GetnMarker_ActDisk_Inlet() != 0) || (config->GetnMarker_ActDisk_Outlet() != 0)); - - /*--- Compute the engine properties ---*/ - - if (engine) { GetEngine_Properties(geometry, config, iMesh, Output); } - - /*--- Compute the actuator disk properties ---*/ - - if (actuator_disk) { GetActuatorDisk_Properties(geometry, config, iMesh, Output); } - - /*--- Update the angle of attack at the far-field for fixed CL calculations. ---*/ - - if (fixed_cl) { SetFarfield_AoA(geometry, solver_container, config, iMesh, Output); } - - /*--- Compute distance function to zero level set ---*/ - - if (freesurface) { SetFreeSurface_Distance(geometry, config); } - - /*--- Set the primitive variables ---*/ - - ErrorCounter = SetPrimitive_Variables(solver_container, config, Output); - - /*--- Artificial dissipation ---*/ - - if (center && !Output) { - SetMax_Eigenvalue(geometry, config); - if ((center_jst) && (iMesh == MESH_0)) { - SetDissipation_Switch(geometry, config); - SetUndivided_Laplacian(geometry, config); - } - } - - /*--- Compute gradient of the primitive variables ---*/ - - if (config->GetKind_Gradient_Method() == GREEN_GAUSS) { - SetPrimitive_Gradient_GG(geometry, config); - // if (compressible && !ideal_gas) SetSecondary_Gradient_GG(geometry, config); - } - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { - SetPrimitive_Gradient_LS(geometry, config); - // if (compressible && !ideal_gas) SetSecondary_Gradient_LS(geometry, config); - } - - /*--- Compute the limiter in case we need it in the turbulence model - or to limit the viscous terms (check this logic with JST and 2nd order turbulence model) ---*/ - - if ((iMesh == MESH_0) && (limiter_flow || limiter_turb || limiter_adjflow || limiter_visc) && !Output) { SetPrimitive_Limiter(geometry, config); - // if (compressible && !ideal_gas) SetSecondary_Limiter(geometry, config); - } - - /*--- Evaluate the vorticity and strain rate magnitude ---*/ - - StrainMag_Max = 0.0, Omega_Max = 0.0; - for (iPoint = 0; iPoint < nPoint; iPoint++) { - - solver_container[FLOW_SOL]->node[iPoint]->SetVorticity(limiter_visc); - solver_container[FLOW_SOL]->node[iPoint]->SetStrainMag(limiter_visc); - - StrainMag = solver_container[FLOW_SOL]->node[iPoint]->GetStrainMag(); - Vorticity = solver_container[FLOW_SOL]->node[iPoint]->GetVorticity(); - Omega = sqrt(Vorticity[0]*Vorticity[0]+ Vorticity[1]*Vorticity[1]+ Vorticity[2]*Vorticity[2]); - - StrainMag_Max = max(StrainMag_Max, StrainMag); - Omega_Max = max(Omega_Max, Omega); - - } - - /*--- Initialize the Jacobian matrices ---*/ - - if (implicit && !config->GetDiscrete_Adjoint()) Jacobian.SetValZero(); - - /*--- Error message ---*/ - - if (config->GetConsole_Output_Verb() == VERB_HIGH) { - -#ifdef HAVE_MPI - unsigned long MyErrorCounter = ErrorCounter; ErrorCounter = 0; - su2double MyOmega_Max = Omega_Max; Omega_Max = 0.0; - su2double MyStrainMag_Max = StrainMag_Max; StrainMag_Max = 0.0; - - SU2_MPI::Allreduce(&MyErrorCounter, &ErrorCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyStrainMag_Max, &StrainMag_Max, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyOmega_Max, &Omega_Max, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); -#endif - - if (iMesh == MESH_0) { - config->SetNonphysical_Points(ErrorCounter); - solver_container[FLOW_SOL]->SetStrainMag_Max(StrainMag_Max); - solver_container[FLOW_SOL]->SetOmega_Max(Omega_Max); - } - - } - -} - -unsigned long CNSSolver::SetPrimitive_Variables(CSolver **solver_container, CConfig *config, bool Output) { - - unsigned long iPoint, ErrorCounter = 0; - su2double eddy_visc = 0.0, turb_ke = 0.0; - unsigned short turb_model = config->GetKind_Turb_Model(); - bool RightSol = true; - - bool tkeNeeded = (turb_model == SST); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - - for (iPoint = 0; iPoint < nPoint; iPoint ++) { - - /*--- Retrieve the value of the kinetic energy (if need it) ---*/ - - if (turb_model != NONE) { - eddy_visc = solver_container[TURB_SOL]->node[iPoint]->GetmuT(); - if (tkeNeeded) turb_ke = solver_container[TURB_SOL]->node[iPoint]->GetSolution(0); - } - - /*--- Initialize the non-physical points vector ---*/ - - node[iPoint]->SetNon_Physical(false); - - /*--- Incompressible flow, primitive variables nDim+3, (P, vx, vy, vz, rho, beta), - FreeSurface Incompressible flow, primitive variables nDim+4, (P, vx, vy, vz, rho, beta, dist), - Compressible flow, primitive variables nDim+5, (T, vx, vy, vz, P, rho, h, c, lamMu, eddyMu, ThCond, Cp) ---*/ - - if (compressible) { - RightSol = node[iPoint]->SetPrimVar_Compressible(eddy_visc, turb_ke, FluidModel); - node[iPoint]->SetSecondaryVar_Compressible(FluidModel); - } - - if (incompressible){ - RightSol = node[iPoint]->SetPrimVar_Incompressible(Density_Inf, Viscosity_Inf, eddy_visc, turb_ke, config); - } - - if (freesurface){ - RightSol = node[iPoint]->SetPrimVar_FreeSurface(eddy_visc, turb_ke, config); - } - - if (!RightSol) { node[iPoint]->SetNon_Physical(true); ErrorCounter++; } - - /*--- Initialize the convective, source and viscous residual vector ---*/ - - if (!Output) LinSysRes.SetBlock_Zero(iPoint); - - } - - return ErrorCounter; -} - -void CNSSolver::SetTime_Step(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned long Iteration) { - - su2double Mean_BetaInc2, *Normal, Area, Vol, Mean_SoundSpeed = 0.0, Mean_ProjVel = 0.0, Lambda, Local_Delta_Time, Local_Delta_Time_Visc, Mean_DensityInc, - Global_Delta_Time = 1E6, Mean_LaminarVisc = 0.0, Mean_EddyVisc = 0.0, Mean_Density = 0.0, Lambda_1, Lambda_2, K_v = 0.25, Global_Delta_UnstTimeND; - unsigned long iEdge, iVertex, iPoint = 0, jPoint = 0; - unsigned short iDim, iMarker; - su2double ProjVel, ProjVel_i, ProjVel_j; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool grid_movement = config->GetGrid_Movement(); - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - - Min_Delta_Time = 1.E6; Max_Delta_Time = 0.0; - - /*--- Set maximum inviscid eigenvalue to zero, and compute sound speed and viscosity ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - node[iPoint]->SetMax_Lambda_Inv(0.0); - node[iPoint]->SetMax_Lambda_Visc(0.0); - } - - /*--- Loop interior edges ---*/ - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Point identification, Normal vector and area ---*/ - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - - Normal = geometry->edge[iEdge]->GetNormal(); - Area = 0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); - - /*--- Mean Values ---*/ - - if (compressible) { - Mean_ProjVel = 0.5 * (node[iPoint]->GetProjVel(Normal) + node[jPoint]->GetProjVel(Normal)); - Mean_SoundSpeed = 0.5 * (node[iPoint]->GetSoundSpeed() + node[jPoint]->GetSoundSpeed()) * Area; - } - if (incompressible || freesurface) { - Mean_ProjVel = 0.5 * (node[iPoint]->GetProjVel(Normal) + node[jPoint]->GetProjVel(Normal)); - Mean_BetaInc2 = 0.5 * (node[iPoint]->GetBetaInc2() + node[jPoint]->GetBetaInc2()); - Mean_DensityInc = 0.5 * (node[iPoint]->GetDensityInc() + node[jPoint]->GetDensityInc()); - Mean_SoundSpeed = sqrt(Mean_ProjVel*Mean_ProjVel + (Mean_BetaInc2/Mean_DensityInc)*Area*Area); - } - - /*--- Adjustment for grid movement ---*/ - - if (grid_movement) { - su2double *GridVel_i = geometry->node[iPoint]->GetGridVel(); - su2double *GridVel_j = geometry->node[jPoint]->GetGridVel(); - ProjVel_i = 0.0; ProjVel_j =0.0; - for (iDim = 0; iDim < nDim; iDim++) { - ProjVel_i += GridVel_i[iDim]*Normal[iDim]; - ProjVel_j += GridVel_j[iDim]*Normal[iDim]; - } - Mean_ProjVel -= 0.5 * (ProjVel_i + ProjVel_j) ; - } - - /*--- Inviscid contribution ---*/ - - Lambda = fabs(Mean_ProjVel) + Mean_SoundSpeed ; - if (geometry->node[iPoint]->GetDomain()) node[iPoint]->AddMax_Lambda_Inv(Lambda); - if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddMax_Lambda_Inv(Lambda); - - /*--- Viscous contribution ---*/ - - if (compressible) { - Mean_LaminarVisc = 0.5*(node[iPoint]->GetLaminarViscosity() + node[jPoint]->GetLaminarViscosity()); - Mean_EddyVisc = 0.5*(node[iPoint]->GetEddyViscosity() + node[jPoint]->GetEddyViscosity()); - Mean_Density = 0.5*(node[iPoint]->GetSolution(0) + node[jPoint]->GetSolution(0)); - } - if (incompressible || freesurface) { - Mean_LaminarVisc = 0.5*(node[iPoint]->GetLaminarViscosityInc() + node[jPoint]->GetLaminarViscosityInc()); - Mean_EddyVisc = 0.5*(node[iPoint]->GetEddyViscosityInc() + node[jPoint]->GetEddyViscosityInc()); - Mean_Density = 0.5*(node[iPoint]->GetDensityInc() + node[jPoint]->GetDensityInc()); - } - - Lambda_1 = (4.0/3.0)*(Mean_LaminarVisc + Mean_EddyVisc); - //TODO (REAL_GAS) removing Gamma it cannot work with FLUIDPROP - Lambda_2 = (1.0 + (Prandtl_Lam/Prandtl_Turb)*(Mean_EddyVisc/Mean_LaminarVisc))*(Gamma*Mean_LaminarVisc/Prandtl_Lam); - Lambda = (Lambda_1 + Lambda_2)*Area*Area/Mean_Density; - - if (geometry->node[iPoint]->GetDomain()) node[iPoint]->AddMax_Lambda_Visc(Lambda); - if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddMax_Lambda_Visc(Lambda); - - } - - /*--- Loop boundary edges ---*/ - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - - /*--- Point identification, Normal vector and area ---*/ - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); - - /*--- Mean Values ---*/ - - if (compressible) { - Mean_ProjVel = node[iPoint]->GetProjVel(Normal); - Mean_SoundSpeed = node[iPoint]->GetSoundSpeed() * Area; - } - if (incompressible || freesurface) { - Mean_ProjVel = node[iPoint]->GetProjVel(Normal); - Mean_BetaInc2 = node[iPoint]->GetBetaInc2(); - Mean_DensityInc = node[iPoint]->GetDensityInc(); - Mean_SoundSpeed = sqrt(Mean_ProjVel*Mean_ProjVel + (Mean_BetaInc2/Mean_DensityInc)*Area*Area); - } - - /*--- Adjustment for grid movement ---*/ - - if (grid_movement) { - su2double *GridVel = geometry->node[iPoint]->GetGridVel(); - ProjVel = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - ProjVel += GridVel[iDim]*Normal[iDim]; - Mean_ProjVel -= ProjVel; - } - - /*--- Inviscid contribution ---*/ - - Lambda = fabs(Mean_ProjVel) + Mean_SoundSpeed; - if (geometry->node[iPoint]->GetDomain()) { - node[iPoint]->AddMax_Lambda_Inv(Lambda); - } - - /*--- Viscous contribution ---*/ - - if (compressible) { - Mean_LaminarVisc = node[iPoint]->GetLaminarViscosity(); - Mean_EddyVisc = node[iPoint]->GetEddyViscosity(); - Mean_Density = node[iPoint]->GetSolution(0); - } - if (incompressible || freesurface) { - Mean_LaminarVisc = 0.5*(node[iPoint]->GetLaminarViscosityInc() + node[jPoint]->GetLaminarViscosityInc()); - Mean_EddyVisc = 0.5*(node[iPoint]->GetEddyViscosityInc() + node[jPoint]->GetEddyViscosityInc()); - Mean_Density = 0.5*(node[iPoint]->GetDensityInc() + node[jPoint]->GetDensityInc()); - } - - Lambda_1 = (4.0/3.0)*(Mean_LaminarVisc + Mean_EddyVisc); - Lambda_2 = (1.0 + (Prandtl_Lam/Prandtl_Turb)*(Mean_EddyVisc/Mean_LaminarVisc))*(Gamma*Mean_LaminarVisc/Prandtl_Lam); - Lambda = (Lambda_1 + Lambda_2)*Area*Area/Mean_Density; - - if (geometry->node[iPoint]->GetDomain()) node[iPoint]->AddMax_Lambda_Visc(Lambda); - - } - } - - /*--- Each element uses their own speed, steady state simulation ---*/ - - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - Vol = geometry->node[iPoint]->GetVolume(); - - if (Vol != 0.0) { - Local_Delta_Time = config->GetCFL(iMesh)*Vol / node[iPoint]->GetMax_Lambda_Inv(); - Local_Delta_Time_Visc = config->GetCFL(iMesh)*K_v*Vol*Vol/ node[iPoint]->GetMax_Lambda_Visc(); - Local_Delta_Time = min(Local_Delta_Time, Local_Delta_Time_Visc); - Global_Delta_Time = min(Global_Delta_Time, Local_Delta_Time); - Min_Delta_Time = min(Min_Delta_Time, Local_Delta_Time); - Max_Delta_Time = max(Max_Delta_Time, Local_Delta_Time); - if (Local_Delta_Time > config->GetMax_DeltaTime()) - Local_Delta_Time = config->GetMax_DeltaTime(); - node[iPoint]->SetDelta_Time(Local_Delta_Time); - } - else { - node[iPoint]->SetDelta_Time(0.0); - } - - } - - - /*--- Compute the max and the min dt (in parallel) ---*/ - if (config->GetConsole_Output_Verb() == VERB_HIGH) { -#ifdef HAVE_MPI - su2double rbuf_time, sbuf_time; - sbuf_time = Min_Delta_Time; - SU2_MPI::Reduce(&sbuf_time, &rbuf_time, 1, MPI_DOUBLE, MPI_MIN, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Bcast(&rbuf_time, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - Min_Delta_Time = rbuf_time; - - sbuf_time = Max_Delta_Time; - SU2_MPI::Reduce(&sbuf_time, &rbuf_time, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Bcast(&rbuf_time, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - Max_Delta_Time = rbuf_time; -#endif - } - - /*--- For exact time solution use the minimum delta time of the whole mesh ---*/ - if (config->GetUnsteady_Simulation() == TIME_STEPPING) { -#ifdef HAVE_MPI - su2double rbuf_time, sbuf_time; - sbuf_time = Global_Delta_Time; - SU2_MPI::Reduce(&sbuf_time, &rbuf_time, 1, MPI_DOUBLE, MPI_MIN, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Bcast(&rbuf_time, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - Global_Delta_Time = rbuf_time; -#endif - for (iPoint = 0; iPoint < nPointDomain; iPoint++) - node[iPoint]->SetDelta_Time(Global_Delta_Time); - } - - /*--- Recompute the unsteady time step for the dual time strategy - if the unsteady CFL is diferent from 0 ---*/ - if ((dual_time) && (Iteration == 0) && (config->GetUnst_CFL() != 0.0) && (iMesh == MESH_0)) { - Global_Delta_UnstTimeND = config->GetUnst_CFL()*Global_Delta_Time/config->GetCFL(iMesh); - -#ifdef HAVE_MPI - su2double rbuf_time, sbuf_time; - sbuf_time = Global_Delta_UnstTimeND; - SU2_MPI::Reduce(&sbuf_time, &rbuf_time, 1, MPI_DOUBLE, MPI_MIN, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Bcast(&rbuf_time, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - Global_Delta_UnstTimeND = rbuf_time; -#endif - config->SetDelta_UnstTimeND(Global_Delta_UnstTimeND); - } - - /*--- The pseudo local time (explicit integration) cannot be greater than the physical time ---*/ - if (dual_time) - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - if (!implicit) { - Local_Delta_Time = min((2.0/3.0)*config->GetDelta_UnstTimeND(), node[iPoint]->GetDelta_Time()); - node[iPoint]->SetDelta_Time(Local_Delta_Time); - } - } - -} - -void CNSSolver::Viscous_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config, unsigned short iMesh, unsigned short iRKStep) { - - unsigned long iPoint, jPoint, iEdge; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Points, coordinates and normal vector in edge ---*/ - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[jPoint]->GetCoord()); - numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); - - /*--- Primitive and secondary variables ---*/ - - numerics->SetPrimitive(node[iPoint]->GetPrimitive(), node[jPoint]->GetPrimitive()); - numerics->SetSecondary(node[iPoint]->GetSecondary(), node[jPoint]->GetSecondary()); - - /*--- Gradient and limiters ---*/ - - numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[jPoint]->GetGradient_Primitive()); - numerics->SetPrimVarLimiter(node[iPoint]->GetLimiter_Primitive(), node[jPoint]->GetLimiter_Primitive()); - - /*--- Turbulent kinetic energy ---*/ - - if (config->GetKind_Turb_Model() == SST) - numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), - solver_container[TURB_SOL]->node[jPoint]->GetSolution(0)); - - /*--- Compute and update residual ---*/ - - numerics->ComputeResidual(Res_Visc, Jacobian_i, Jacobian_j, config); - - LinSysRes.SubtractBlock(iPoint, Res_Visc); - LinSysRes.AddBlock(jPoint, Res_Visc); - - /*--- Implicit part ---*/ - - if (implicit) { - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - Jacobian.SubtractBlock(iPoint, jPoint, Jacobian_j); - Jacobian.AddBlock(jPoint, iPoint, Jacobian_i); - Jacobian.AddBlock(jPoint, jPoint, Jacobian_j); - } - - } - -} - -void CNSSolver::Viscous_Forces(CGeometry *geometry, CConfig *config) { - - unsigned long iVertex, iPoint, iPointNormal; - unsigned short Boundary, Monitoring, iMarker, iMarker_Monitoring, iDim, jDim; - su2double Viscosity = 0.0, div_vel, *Normal, MomentDist[3] = {0.0, 0.0, 0.0}, WallDist[3] = {0.0, 0.0, 0.0}, - *Coord, *Coord_Normal, Area, WallShearStress, TauNormal, factor, RefTemp, RefVel2, - RefDensity, GradTemperature, Density = 0.0, WallDistMod, FrictionVel, - Mach2Vel, Mach_Motion, UnitNormal[3] = {0.0, 0.0, 0.0}, TauElem[3] = {0.0, 0.0, 0.0}, TauTangent[3] = {0.0, 0.0, 0.0}, - Tau[3][3] = {{0.0, 0.0, 0.0},{0.0, 0.0, 0.0},{0.0, 0.0, 0.0}}, Force[3] = {0.0, 0.0, 0.0}, Cp, thermal_conductivity, MaxNorm = 8.0, - Grad_Vel[3][3] = {{0.0, 0.0, 0.0},{0.0, 0.0, 0.0},{0.0, 0.0, 0.0}}, Grad_Temp[3] = {0.0, 0.0, 0.0}, - delta[3][3] = {{1.0, 0.0, 0.0},{0.0,1.0,0.0},{0.0,0.0,1.0}}; - -#ifdef HAVE_MPI - su2double MyAllBound_CDrag_Visc, MyAllBound_CLift_Visc, MyAllBound_CSideForce_Visc, MyAllBound_CMx_Visc, MyAllBound_CMy_Visc, MyAllBound_CMz_Visc, MyAllBound_CFx_Visc, MyAllBound_CFy_Visc, MyAllBound_CFz_Visc, MyAllBound_CT_Visc, MyAllBound_CQ_Visc, MyAllBound_HeatFlux_Visc, MyAllBound_MaxHeatFlux_Visc, *MySurface_CLift_Visc = NULL, *MySurface_CDrag_Visc = NULL, *MySurface_CSideForce_Visc = NULL, *MySurface_CEff_Visc = NULL, *MySurface_CFx_Visc = NULL, *MySurface_CFy_Visc = NULL, *MySurface_CFz_Visc = NULL, *MySurface_CMx_Visc = NULL, *MySurface_CMy_Visc = NULL, *MySurface_CMz_Visc = NULL; -#endif - - string Marker_Tag, Monitoring_Tag; - - su2double Alpha = config->GetAoA()*PI_NUMBER/180.0; - su2double Beta = config->GetAoS()*PI_NUMBER/180.0; - su2double RefAreaCoeff = config->GetRefAreaCoeff(); - su2double RefLengthMoment = config->GetRefLengthMoment(); - su2double Gas_Constant = config->GetGas_ConstantND(); - su2double *Origin = config->GetRefOriginMoment(0); - bool grid_movement = config->GetGrid_Movement(); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - su2double Prandtl_Lam = config->GetPrandtl_Lam(); - - /*--- 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 (grid_movement) { - 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]; - } - - factor = 1.0 / (0.5*RefDensity*RefAreaCoeff*RefVel2); - - /*--- Variables initialization ---*/ - - AllBound_CDrag_Visc = 0.0; AllBound_CLift_Visc = 0.0; AllBound_CSideForce_Visc = 0.0; - AllBound_CMx_Visc = 0.0; AllBound_CMy_Visc = 0.0; AllBound_CMz_Visc = 0.0; - AllBound_CFx_Visc = 0.0; AllBound_CFy_Visc = 0.0; AllBound_CFz_Visc = 0.0; - AllBound_CT_Visc = 0.0; AllBound_CQ_Visc = 0.0; AllBound_CMerit_Visc = 0.0; - AllBound_HeatFlux_Visc = 0.0; AllBound_MaxHeatFlux_Visc = 0.0; AllBound_CEff_Visc = 0.0; - - for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { - Surface_CLift_Visc[iMarker_Monitoring] = 0.0; Surface_CDrag_Visc[iMarker_Monitoring] = 0.0; - Surface_CSideForce_Visc[iMarker_Monitoring] = 0.0; Surface_CEff_Visc[iMarker_Monitoring] = 0.0; - Surface_CFx_Visc[iMarker_Monitoring] = 0.0; Surface_CFy_Visc[iMarker_Monitoring] = 0.0; - Surface_CFz_Visc[iMarker_Monitoring] = 0.0; Surface_CMx_Visc[iMarker_Monitoring] = 0.0; - Surface_CMy_Visc[iMarker_Monitoring] = 0.0; Surface_CMz_Visc[iMarker_Monitoring] = 0.0; - } - - /*--- Loop over the Navier-Stokes markers ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - Boundary = config->GetMarker_All_KindBC(iMarker); - Monitoring = config->GetMarker_All_Monitoring(iMarker); - - /*--- Obtain the origin for the moment computation for a particular marker ---*/ - - if (Monitoring == YES) { - for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { - Monitoring_Tag = config->GetMarker_Monitoring(iMarker_Monitoring); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); - if (Marker_Tag == Monitoring_Tag) - Origin = config->GetRefOriginMoment(iMarker_Monitoring); - } - } - - if ((Boundary == HEAT_FLUX) || (Boundary == ISOTHERMAL)) { - - /*--- Forces initialization at each Marker ---*/ - - CDrag_Visc[iMarker] = 0.0; CLift_Visc[iMarker] = 0.0; CSideForce_Visc[iMarker] = 0.0; - CMx_Visc[iMarker] = 0.0; CMy_Visc[iMarker] = 0.0; CMz_Visc[iMarker] = 0.0; - CFx_Visc[iMarker] = 0.0; CFy_Visc[iMarker] = 0.0; CFz_Visc[iMarker] = 0.0; - CT_Visc[iMarker] = 0.0; CQ_Visc[iMarker] = 0.0; CMerit_Visc[iMarker] = 0.0; - Heat_Visc[iMarker] = 0.0; MaxHeatFlux_Visc[iMarker] = 0.0; CEff_Visc[iMarker] = 0.0; - - for (iDim = 0; iDim < nDim; iDim++) ForceViscous[iDim] = 0.0; - MomentViscous[0] = 0.0; MomentViscous[1] = 0.0; MomentViscous[2] = 0.0; - - /*--- Loop over the vertices to compute the forces ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - iPointNormal = geometry->vertex[iMarker][iVertex]->GetNormal_Neighbor(); - - Coord = geometry->node[iPoint]->GetCoord(); - Coord_Normal = geometry->node[iPointNormal]->GetCoord(); - - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - - for (iDim = 0; iDim < nDim; iDim++) { - for (jDim = 0 ; jDim < nDim; jDim++) { - Grad_Vel[iDim][jDim] = node[iPoint]->GetGradient_Primitive(iDim+1, jDim); - } - Grad_Temp[iDim] = node[iPoint]->GetGradient_Primitive(0, iDim); - } - - if (compressible) { - Viscosity = node[iPoint]->GetLaminarViscosity(); - Density = node[iPoint]->GetDensity(); - } - if (incompressible || freesurface) { - Viscosity = node[iPoint]->GetLaminarViscosityInc(); - Density = node[iPoint]->GetDensityInc(); - } - - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); - for (iDim = 0; iDim < nDim; iDim++) { - UnitNormal[iDim] = Normal[iDim]/Area; - MomentDist[iDim] = Coord[iDim] - Origin[iDim]; - } - - /*--- Evaluate Tau ---*/ - - div_vel = 0.0; for (iDim = 0; iDim < nDim; iDim++) div_vel += Grad_Vel[iDim][iDim]; - - for (iDim = 0; iDim < nDim; iDim++) { - for (jDim = 0 ; jDim < nDim; jDim++) { - Tau[iDim][jDim] = Viscosity*(Grad_Vel[jDim][iDim] + Grad_Vel[iDim][jDim]) - TWO3*Viscosity*div_vel*delta[iDim][jDim]; - } - } - - /*--- Project Tau in each surface element ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - TauElem[iDim] = 0.0; - for (jDim = 0; jDim < nDim; jDim++) { - TauElem[iDim] += Tau[iDim][jDim]*UnitNormal[jDim]; - } - } - - /*--- Compute wall shear stress (using the stress tensor) ---*/ - - 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); - - for (iDim = 0; iDim < nDim; iDim++) WallDist[iDim] = (Coord[iDim] - Coord_Normal[iDim]); - WallDistMod = 0.0; for (iDim = 0; iDim < nDim; iDim++) WallDistMod += WallDist[iDim]*WallDist[iDim]; WallDistMod = sqrt(WallDistMod); - - /*--- Compute wall skin friction coefficient, and heat flux on the wall ---*/ - - CSkinFriction[iMarker][iVertex] = WallShearStress / (0.5*RefDensity*RefVel2); - - /*--- Compute y+ and non-dimensional velocity ---*/ - - FrictionVel = sqrt(fabs(WallShearStress)/Density); - YPlus[iMarker][iVertex] = WallDistMod*FrictionVel/(Viscosity/Density); - - /*--- Compute total and maximum heat flux on the wall ---*/ - - if (compressible) { - - GradTemperature = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - GradTemperature -= Grad_Temp[iDim]*UnitNormal[iDim]; - - Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; - thermal_conductivity = Cp * Viscosity/Prandtl_Lam; - HeatFlux[iMarker][iVertex] = -thermal_conductivity*GradTemperature; - Heat_Visc[iMarker] += HeatFlux[iMarker][iVertex]*Area; - MaxHeatFlux_Visc[iMarker] += pow(HeatFlux[iMarker][iVertex], MaxNorm); - - } - - /*--- Note that y+, and heat are computed at the - halo cells (for visualization purposes), but not the forces ---*/ - - if ((geometry->node[iPoint]->GetDomain()) && (Monitoring == YES)) { - - /*--- Force computation ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - Force[iDim] = TauElem[iDim]*Area*factor; - ForceViscous[iDim] += Force[iDim]; - } - - /*--- Moment with respect to the reference axis ---*/ - - if (iDim == 3) { - MomentViscous[0] += (Force[2]*MomentDist[1] - Force[1]*MomentDist[2])/RefLengthMoment; - MomentViscous[1] += (Force[0]*MomentDist[2] - Force[2]*MomentDist[0])/RefLengthMoment; - } - MomentViscous[2] += (Force[1]*MomentDist[0] - Force[0]*MomentDist[1])/RefLengthMoment; - - } - - } - - /*--- Project forces and store the non-dimensional coefficients ---*/ - - if (Monitoring == YES) { - if (nDim == 2) { - CDrag_Visc[iMarker] = ForceViscous[0]*cos(Alpha) + ForceViscous[1]*sin(Alpha); - CLift_Visc[iMarker] = -ForceViscous[0]*sin(Alpha) + ForceViscous[1]*cos(Alpha); - CEff_Visc[iMarker] = CLift_Visc[iMarker] / (CDrag_Visc[iMarker]+EPS); - CMz_Visc[iMarker] = MomentViscous[2]; - CFx_Visc[iMarker] = ForceViscous[0]; - CFy_Visc[iMarker] = ForceViscous[1]; - CT_Visc[iMarker] = -CFx_Visc[iMarker]; - CQ_Visc[iMarker] = -CMz_Visc[iMarker]; - CMerit_Visc[iMarker] = CT_Visc[iMarker] / (CQ_Visc[iMarker]+EPS); - MaxHeatFlux_Visc[iMarker] = pow(MaxHeatFlux_Visc[iMarker], 1.0/MaxNorm); - } - if (nDim == 3) { - CDrag_Visc[iMarker] = ForceViscous[0]*cos(Alpha)*cos(Beta) + ForceViscous[1]*sin(Beta) + ForceViscous[2]*sin(Alpha)*cos(Beta); - CLift_Visc[iMarker] = -ForceViscous[0]*sin(Alpha) + ForceViscous[2]*cos(Alpha); - CSideForce_Visc[iMarker] = -ForceViscous[0]*sin(Beta)*cos(Alpha) + ForceViscous[1]*cos(Beta) - ForceViscous[2]*sin(Beta)*sin(Alpha); - CEff_Visc[iMarker] = CLift_Visc[iMarker]/(CDrag_Visc[iMarker] + EPS); - CMx_Visc[iMarker] = MomentViscous[0]; - CMy_Visc[iMarker] = MomentViscous[1]; - CMz_Visc[iMarker] = MomentViscous[2]; - CFx_Visc[iMarker] = ForceViscous[0]; - CFy_Visc[iMarker] = ForceViscous[1]; - CFz_Visc[iMarker] = ForceViscous[2]; - CT_Visc[iMarker] = -CFz_Visc[iMarker]; - CQ_Visc[iMarker] = -CMz_Visc[iMarker]; - CMerit_Visc[iMarker] = CT_Visc[iMarker] / (CQ_Visc[iMarker] + EPS); - MaxHeatFlux_Visc[iMarker] = pow(MaxHeatFlux_Visc[iMarker], 1.0/MaxNorm); - } - - AllBound_CDrag_Visc += CDrag_Visc[iMarker]; - AllBound_CLift_Visc += CLift_Visc[iMarker]; - AllBound_CSideForce_Visc += CSideForce_Visc[iMarker]; - AllBound_CMx_Visc += CMx_Visc[iMarker]; - AllBound_CMy_Visc += CMy_Visc[iMarker]; - AllBound_CMz_Visc += CMz_Visc[iMarker]; - AllBound_CFx_Visc += CFx_Visc[iMarker]; - AllBound_CFy_Visc += CFy_Visc[iMarker]; - AllBound_CFz_Visc += CFz_Visc[iMarker]; - AllBound_CT_Visc += CT_Visc[iMarker]; - AllBound_CQ_Visc += CQ_Visc[iMarker]; - AllBound_HeatFlux_Visc += Heat_Visc[iMarker]; - AllBound_MaxHeatFlux_Visc += pow(MaxHeatFlux_Visc[iMarker], MaxNorm); - - /*--- Compute the coefficients per surface ---*/ - - for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { - Monitoring_Tag = config->GetMarker_Monitoring(iMarker_Monitoring); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); - if (Marker_Tag == Monitoring_Tag) { - Surface_CLift_Visc[iMarker_Monitoring] += CLift_Visc[iMarker]; - Surface_CDrag_Visc[iMarker_Monitoring] += CDrag_Visc[iMarker]; - Surface_CSideForce_Visc[iMarker_Monitoring] += CSideForce_Visc[iMarker]; - Surface_CEff_Visc[iMarker_Monitoring] += CEff_Visc[iMarker]; - Surface_CFx_Visc[iMarker_Monitoring] += CFx_Visc[iMarker]; - Surface_CFy_Visc[iMarker_Monitoring] += CFy_Visc[iMarker]; - Surface_CFz_Visc[iMarker_Monitoring] += CFz_Visc[iMarker]; - Surface_CMx_Visc[iMarker_Monitoring] += CMx_Visc[iMarker]; - Surface_CMy_Visc[iMarker_Monitoring] += CMy_Visc[iMarker]; - Surface_CMz_Visc[iMarker_Monitoring] += CMz_Visc[iMarker]; - } - } - - } - - } - } - - /*--- Update some global coeffients ---*/ - - AllBound_CEff_Visc = AllBound_CLift_Visc / (AllBound_CDrag_Visc + EPS); - AllBound_CMerit_Visc = AllBound_CT_Visc / (AllBound_CQ_Visc + EPS); - AllBound_MaxHeatFlux_Visc = pow(AllBound_MaxHeatFlux_Visc, 1.0/MaxNorm); - - -#ifdef HAVE_MPI - - /*--- Add AllBound information using all the nodes ---*/ - - MyAllBound_CDrag_Visc = AllBound_CDrag_Visc; AllBound_CDrag_Visc = 0.0; - MyAllBound_CLift_Visc = AllBound_CLift_Visc; AllBound_CLift_Visc = 0.0; - MyAllBound_CSideForce_Visc = AllBound_CSideForce_Visc; AllBound_CSideForce_Visc = 0.0; - AllBound_CEff_Visc = 0.0; - MyAllBound_CMx_Visc = AllBound_CMx_Visc; AllBound_CMx_Visc = 0.0; - MyAllBound_CMy_Visc = AllBound_CMy_Visc; AllBound_CMy_Visc = 0.0; - MyAllBound_CMz_Visc = AllBound_CMz_Visc; AllBound_CMz_Visc = 0.0; - MyAllBound_CFx_Visc = AllBound_CFx_Visc; AllBound_CFx_Visc = 0.0; - MyAllBound_CFy_Visc = AllBound_CFy_Visc; AllBound_CFy_Visc = 0.0; - MyAllBound_CFz_Visc = AllBound_CFz_Visc; AllBound_CFz_Visc = 0.0; - MyAllBound_CT_Visc = AllBound_CT_Visc; AllBound_CT_Visc = 0.0; - MyAllBound_CQ_Visc = AllBound_CQ_Visc; AllBound_CQ_Visc = 0.0; - AllBound_CMerit_Visc = 0.0; - MyAllBound_HeatFlux_Visc = AllBound_HeatFlux_Visc; AllBound_HeatFlux_Visc = 0.0; - MyAllBound_MaxHeatFlux_Visc = pow(AllBound_MaxHeatFlux_Visc, MaxNorm); AllBound_MaxHeatFlux_Visc = 0.0; - - SU2_MPI::Allreduce(&MyAllBound_CDrag_Visc, &AllBound_CDrag_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CLift_Visc, &AllBound_CLift_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CSideForce_Visc, &AllBound_CSideForce_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - AllBound_CEff_Visc = AllBound_CLift_Visc / (AllBound_CDrag_Visc + EPS); - SU2_MPI::Allreduce(&MyAllBound_CMx_Visc, &AllBound_CMx_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CMy_Visc, &AllBound_CMy_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CMz_Visc, &AllBound_CMz_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CFx_Visc, &AllBound_CFx_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CFy_Visc, &AllBound_CFy_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CFz_Visc, &AllBound_CFz_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CT_Visc, &AllBound_CT_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_CQ_Visc, &AllBound_CQ_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - AllBound_CMerit_Visc = AllBound_CT_Visc / (AllBound_CQ_Visc + EPS); - SU2_MPI::Allreduce(&MyAllBound_HeatFlux_Visc, &AllBound_HeatFlux_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyAllBound_MaxHeatFlux_Visc, &AllBound_MaxHeatFlux_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - AllBound_MaxHeatFlux_Visc = pow(AllBound_MaxHeatFlux_Visc, 1.0/MaxNorm); - - /*--- Add the forces on the surfaces using all the nodes ---*/ - - MySurface_CLift_Visc = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CDrag_Visc = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CSideForce_Visc = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CEff_Visc = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CFx_Visc = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CFy_Visc = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CFz_Visc = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CMx_Visc = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CMy_Visc = new su2double[config->GetnMarker_Monitoring()]; - MySurface_CMz_Visc = new su2double[config->GetnMarker_Monitoring()]; - - for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { - - MySurface_CLift_Visc[iMarker_Monitoring] = Surface_CLift_Visc[iMarker_Monitoring]; - MySurface_CDrag_Visc[iMarker_Monitoring] = Surface_CDrag_Visc[iMarker_Monitoring]; - MySurface_CSideForce_Visc[iMarker_Monitoring] = Surface_CSideForce_Visc[iMarker_Monitoring]; - MySurface_CEff_Visc[iMarker_Monitoring] = Surface_CEff_Visc[iMarker_Monitoring]; - MySurface_CFx_Visc[iMarker_Monitoring] = Surface_CFx_Visc[iMarker_Monitoring]; - MySurface_CFy_Visc[iMarker_Monitoring] = Surface_CFy_Visc[iMarker_Monitoring]; - MySurface_CFz_Visc[iMarker_Monitoring] = Surface_CFz_Visc[iMarker_Monitoring]; - MySurface_CMx_Visc[iMarker_Monitoring] = Surface_CMx_Visc[iMarker_Monitoring]; - MySurface_CMy_Visc[iMarker_Monitoring] = Surface_CMy_Visc[iMarker_Monitoring]; - MySurface_CMz_Visc[iMarker_Monitoring] = Surface_CMz_Visc[iMarker_Monitoring]; - - Surface_CLift_Visc[iMarker_Monitoring] = 0.0; - Surface_CDrag_Visc[iMarker_Monitoring] = 0.0; - Surface_CSideForce_Visc[iMarker_Monitoring] = 0.0; - Surface_CEff_Visc[iMarker_Monitoring] = 0.0; - Surface_CFx_Visc[iMarker_Monitoring] = 0.0; - Surface_CFy_Visc[iMarker_Monitoring] = 0.0; - Surface_CFz_Visc[iMarker_Monitoring] = 0.0; - Surface_CMx_Visc[iMarker_Monitoring] = 0.0; - Surface_CMy_Visc[iMarker_Monitoring] = 0.0; - Surface_CMz_Visc[iMarker_Monitoring] = 0.0; - } - - SU2_MPI::Allreduce(MySurface_CLift_Visc, Surface_CLift_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(MySurface_CDrag_Visc, Surface_CDrag_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(MySurface_CSideForce_Visc, Surface_CSideForce_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) - Surface_CEff_Visc[iMarker_Monitoring] = Surface_CLift_Visc[iMarker_Monitoring] / (Surface_CDrag_Visc[iMarker_Monitoring] + EPS); - SU2_MPI::Allreduce(MySurface_CFx_Visc, Surface_CFx_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(MySurface_CFy_Visc, Surface_CFy_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(MySurface_CFz_Visc, Surface_CFz_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(MySurface_CMx_Visc, Surface_CMx_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(MySurface_CMy_Visc, Surface_CMy_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(MySurface_CMz_Visc, Surface_CMz_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - - delete [] MySurface_CLift_Visc; delete [] MySurface_CDrag_Visc; delete [] MySurface_CSideForce_Visc; - delete [] MySurface_CEff_Visc; delete [] MySurface_CFx_Visc; delete [] MySurface_CFy_Visc; - delete [] MySurface_CFz_Visc; delete [] MySurface_CMx_Visc; delete [] MySurface_CMy_Visc; - delete [] MySurface_CMz_Visc; - -#endif - - /*--- Update the total coefficients (note that all the nodes have the same value)---*/ - - Total_CDrag += AllBound_CDrag_Visc; - Total_CLift += AllBound_CLift_Visc; - Total_CSideForce += AllBound_CSideForce_Visc; - Total_CEff = Total_CLift / (Total_CDrag + EPS); - Total_CMx += AllBound_CMx_Visc; - Total_CMy += AllBound_CMy_Visc; - Total_CMz += AllBound_CMz_Visc; - Total_CFx += AllBound_CFx_Visc; - Total_CFy += AllBound_CFy_Visc; - Total_CFz += AllBound_CFz_Visc; - Total_CT += AllBound_CT_Visc; - Total_CQ += AllBound_CQ_Visc; - Total_CMerit = AllBound_CT_Visc / (AllBound_CQ_Visc + EPS); - Total_Heat = AllBound_HeatFlux_Visc; - Total_MaxHeat = AllBound_MaxHeatFlux_Visc; - - /*--- Update the total coefficients per surface (note that all the nodes have the same value)---*/ - - for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { - Surface_CLift[iMarker_Monitoring] += Surface_CLift_Visc[iMarker_Monitoring]; - Surface_CDrag[iMarker_Monitoring] += Surface_CDrag_Visc[iMarker_Monitoring]; - Surface_CSideForce[iMarker_Monitoring] += Surface_CSideForce_Visc[iMarker_Monitoring]; - Surface_CEff[iMarker_Monitoring] = Surface_CLift[iMarker_Monitoring] / (Surface_CDrag[iMarker_Monitoring] + EPS); - Surface_CFx[iMarker_Monitoring] += Surface_CFx_Visc[iMarker_Monitoring]; - Surface_CFy[iMarker_Monitoring] += Surface_CFy_Visc[iMarker_Monitoring]; - Surface_CFz[iMarker_Monitoring] += Surface_CFz_Visc[iMarker_Monitoring]; - Surface_CMx[iMarker_Monitoring] += Surface_CMx_Visc[iMarker_Monitoring]; - Surface_CMy[iMarker_Monitoring] += Surface_CMy_Visc[iMarker_Monitoring]; - Surface_CMz[iMarker_Monitoring] += Surface_CMz_Visc[iMarker_Monitoring]; - } - -} - -void CNSSolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned short iDim, jDim, iVar, jVar; - unsigned long iVertex, iPoint, Point_Normal, total_index; - - su2double Wall_HeatFlux, dist_ij, *Coord_i, *Coord_j, theta2; - su2double thetax, thetay, thetaz, etax, etay, etaz, pix, piy, piz, factor; - su2double ProjGridVel, *GridVel, GridVel2, *Normal, Area, Pressure = 0.0; - su2double total_viscosity, div_vel, Density, tau_vel[3] = {0.0, 0.0, 0.0}, UnitNormal[3] = {0.0, 0.0, 0.0}; - su2double laminar_viscosity = 0.0, eddy_viscosity = 0.0, Grad_Vel[3][3] = {{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}}, - tau[3][3] = {{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}}; - su2double delta[3][3] = {{1.0, 0.0, 0.0},{0.0,1.0,0.0},{0.0,0.0,1.0}}; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool grid_movement = config->GetGrid_Movement(); - - /*--- Identify the boundary by string name ---*/ - - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - - /*--- Get the specified wall heat flux from config ---*/ - - Wall_HeatFlux = config->GetWall_HeatFlux(Marker_Tag); - - /*--- Loop over all of the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Compute dual-grid area and boundary normal ---*/ - - Normal = geometry->vertex[val_marker][iVertex]->GetNormal(); - - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Area += Normal[iDim]*Normal[iDim]; - Area = sqrt (Area); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = -Normal[iDim]/Area; - - /*--- Initialize the convective & viscous residuals to zero ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - Res_Conv[iVar] = 0.0; - Res_Visc[iVar] = 0.0; - } - - /*--- Store the corrected velocity at the wall which will - be zero (v = 0), unless there are moving walls (v = u_wall)---*/ - - if (grid_movement) { - GridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = GridVel[iDim]; - } else { - for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = 0.0; - } - - /*--- Impose the value of the velocity as a strong boundary - condition (Dirichlet). Fix the velocity and remove any - contribution to the residual at this node. ---*/ - - if (compressible) node[iPoint]->SetVelocity_Old(Vector); - if (incompressible || freesurface) node[iPoint]->SetVelocityInc_Old(Vector); - - for (iDim = 0; iDim < nDim; iDim++) - LinSysRes.SetBlock_Zero(iPoint, iDim+1); - node[iPoint]->SetVel_ResTruncError_Zero(); - - /*--- Apply a weak boundary condition for the energy equation. - Compute the residual due to the prescribed heat flux. ---*/ - - if (compressible) Res_Visc[nDim+1] = Wall_HeatFlux * Area; - - /*--- If the wall is moving, there are additional residual contributions - due to pressure (p v_wall.n) and shear stress (tau.v_wall.n). ---*/ - - if (grid_movement) { - - /*--- Get the grid velocity at the current boundary node ---*/ - - GridVel = geometry->node[iPoint]->GetGridVel(); - ProjGridVel = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - ProjGridVel += GridVel[iDim]*UnitNormal[iDim]*Area; - - /*--- Retrieve other primitive quantities and viscosities ---*/ - - Density = node[iPoint]->GetSolution(0); - if (compressible) { - Pressure = node[iPoint]->GetPressure(); - laminar_viscosity = node[iPoint]->GetLaminarViscosity(); - eddy_viscosity = node[iPoint]->GetEddyViscosity(); - } - if (incompressible || freesurface) { - Pressure = node[iPoint]->GetPressureInc(); - laminar_viscosity = node[iPoint]->GetLaminarViscosityInc(); - eddy_viscosity = node[iPoint]->GetEddyViscosityInc(); - } - total_viscosity = laminar_viscosity + eddy_viscosity; - - for (iDim = 0; iDim < nDim; iDim++) { - for (jDim = 0 ; jDim < nDim; jDim++) { - Grad_Vel[iDim][jDim] = node[iPoint]->GetGradient_Primitive(iDim+1, jDim); - } - } - - /*--- Divergence of the velocity ---*/ - - div_vel = 0.0; for (iDim = 0 ; iDim < nDim; iDim++) div_vel += Grad_Vel[iDim][iDim]; - - /*--- Compute the viscous stress tensor ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - for (jDim = 0; jDim < nDim; jDim++) { - tau[iDim][jDim] = total_viscosity*( Grad_Vel[jDim][iDim]+Grad_Vel[iDim][jDim] ) - TWO3*total_viscosity*div_vel*delta[iDim][jDim]; - } - } - - /*--- Dot product of the stress tensor with the grid velocity ---*/ - - for (iDim = 0 ; iDim < nDim; iDim++) { - tau_vel[iDim] = 0.0; - for (jDim = 0 ; jDim < nDim; jDim++) - tau_vel[iDim] += tau[iDim][jDim]*GridVel[jDim]; - } - - /*--- Compute the convective and viscous residuals (energy eqn.) ---*/ - - Res_Conv[nDim+1] = Pressure*ProjGridVel; - for (iDim = 0 ; iDim < nDim; iDim++) - Res_Visc[nDim+1] += tau_vel[iDim]*UnitNormal[iDim]*Area; - - /*--- Implicit Jacobian contributions due to moving walls ---*/ - - if (implicit) { - - /*--- Jacobian contribution related to the pressure term ---*/ - - GridVel2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - GridVel2 += GridVel[iDim]*GridVel[iDim]; - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - Jacobian_i[iVar][jVar] = 0.0; - Jacobian_i[nDim+1][0] = 0.5*(Gamma-1.0)*GridVel2*ProjGridVel; - for (jDim = 0; jDim < nDim; jDim++) - Jacobian_i[nDim+1][jDim+1] = -(Gamma-1.0)*GridVel[jDim]*ProjGridVel; - Jacobian_i[nDim+1][nDim+1] = (Gamma-1.0)*ProjGridVel; - - /*--- Add the block to the Global Jacobian structure ---*/ - - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - /*--- Now the Jacobian contribution related to the shear stress ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - Jacobian_i[iVar][jVar] = 0.0; - - /*--- Compute closest normal neighbor ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Get coordinates of i & nearest normal and compute distance ---*/ - - Coord_i = geometry->node[iPoint]->GetCoord(); - Coord_j = geometry->node[Point_Normal]->GetCoord(); - - dist_ij = 0; - for (iDim = 0; iDim < nDim; iDim++) - dist_ij += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); - dist_ij = sqrt(dist_ij); - - theta2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - theta2 += UnitNormal[iDim]*UnitNormal[iDim]; - - factor = total_viscosity*Area/(Density*dist_ij); - - if (nDim == 2) { - thetax = theta2 + UnitNormal[0]*UnitNormal[0]/3.0; - thetay = theta2 + UnitNormal[1]*UnitNormal[1]/3.0; - - etaz = UnitNormal[0]*UnitNormal[1]/3.0; - - pix = GridVel[0]*thetax + GridVel[1]*etaz; - piy = GridVel[0]*etaz + GridVel[1]*thetay; - - Jacobian_i[nDim+1][0] -= factor*(-pix*GridVel[0]+piy*GridVel[1]); - Jacobian_i[nDim+1][1] -= factor*pix; - Jacobian_i[nDim+1][2] -= factor*piy; - } else { - thetax = theta2 + UnitNormal[0]*UnitNormal[0]/3.0; - thetay = theta2 + UnitNormal[1]*UnitNormal[1]/3.0; - thetaz = theta2 + UnitNormal[2]*UnitNormal[2]/3.0; - - etaz = UnitNormal[0]*UnitNormal[1]/3.0; - etax = UnitNormal[1]*UnitNormal[2]/3.0; - etay = UnitNormal[0]*UnitNormal[2]/3.0; - - pix = GridVel[0]*thetax + GridVel[1]*etaz + GridVel[2]*etay; - piy = GridVel[0]*etaz + GridVel[1]*thetay + GridVel[2]*etax; - piz = GridVel[0]*etay + GridVel[1]*etax + GridVel[2]*thetaz; - - Jacobian_i[nDim+1][0] -= factor*(-pix*GridVel[0]+piy*GridVel[1]+piz*GridVel[2]); - Jacobian_i[nDim+1][1] -= factor*pix; - Jacobian_i[nDim+1][2] -= factor*piy; - Jacobian_i[nDim+1][3] -= factor*piz; - } - - /*--- Subtract the block from the Global Jacobian structure ---*/ - - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - } - - /*--- Convective contribution to the residual at the wall ---*/ - - LinSysRes.AddBlock(iPoint, Res_Conv); - - /*--- Viscous contribution to the residual at the wall ---*/ - - LinSysRes.SubtractBlock(iPoint, Res_Visc); - - /*--- Enforce the no-slip boundary condition in a strong way by - modifying the velocity-rows of the Jacobian (1 on the diagonal). ---*/ - - if (implicit) { - for (iVar = 1; iVar <= nDim; iVar++) { - total_index = iPoint*nVar+iVar; - Jacobian.DeleteValsRowi(total_index); - } - } - - } - } -} - -void CNSSolver::BC_Isothermal_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned short iVar, jVar, iDim, jDim; - unsigned long iVertex, iPoint, Point_Normal, total_index; - - su2double *Normal, *Coord_i, *Coord_j, Area, dist_ij, theta2; - su2double Twall, dTdn, dTdrho, thermal_conductivity; - su2double thetax, thetay, thetaz, etax, etay, etaz, pix, piy, piz, factor; - su2double ProjGridVel, *GridVel, GridVel2, Pressure = 0.0, Density, Vel2; - su2double total_viscosity, div_vel, tau_vel[3] = {0.0,0.0,0.0}, UnitNormal[3] = {0.0,0.0,0.0}; - su2double laminar_viscosity, eddy_viscosity, Grad_Vel[3][3] = {{1.0, 0.0, 0.0},{0.0,1.0,0.0},{0.0,0.0,1.0}}, - tau[3][3] = {{0.0, 0.0, 0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}}, delta[3][3] = {{1.0, 0.0, 0.0},{0.0,1.0,0.0},{0.0,0.0,1.0}}; - - su2double Prandtl_Lam = config->GetPrandtl_Lam(); - su2double Prandtl_Turb = config->GetPrandtl_Turb(); - su2double Gas_Constant = config->GetGas_ConstantND(); - su2double Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; - - bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool grid_movement = config->GetGrid_Movement(); - - /*--- Identify the boundary ---*/ - - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - - /*--- Retrieve the specified wall temperature ---*/ - - Twall = config->GetIsothermal_Temperature(Marker_Tag)/config->GetTemperature_Ref(); - - /*--- Loop over boundary points ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Compute dual-grid area and boundary normal ---*/ - - Normal = geometry->vertex[val_marker][iVertex]->GetNormal(); - - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt (Area); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = -Normal[iDim]/Area; - - /*--- Calculate useful quantities ---*/ - - theta2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - theta2 += UnitNormal[iDim]*UnitNormal[iDim]; - - /*--- Compute closest normal neighbor ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Get coordinates of i & nearest normal and compute distance ---*/ - - Coord_i = geometry->node[iPoint]->GetCoord(); - Coord_j = geometry->node[Point_Normal]->GetCoord(); - dist_ij = 0; - for (iDim = 0; iDim < nDim; iDim++) - dist_ij += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); - dist_ij = sqrt(dist_ij); - - /*--- Store the corrected velocity at the wall which will - be zero (v = 0), unless there is grid motion (v = u_wall)---*/ - - if (grid_movement) { - GridVel = geometry->node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = GridVel[iDim]; - } - else { - for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = 0.0; - } - - /*--- Initialize the convective & viscous residuals to zero ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - Res_Conv[iVar] = 0.0; - Res_Visc[iVar] = 0.0; - } - - /*--- Set the residual, truncation error and velocity value on the boundary ---*/ - - if (compressible) node[iPoint]->SetVelocity_Old(Vector); - if (incompressible || freesurface) node[iPoint]->SetVelocityInc_Old(Vector); - - for (iDim = 0; iDim < nDim; iDim++) - LinSysRes.SetBlock_Zero(iPoint, iDim+1); - node[iPoint]->SetVel_ResTruncError_Zero(); - - /*--- Compute the normal gradient in temperature using Twall ---*/ - - dTdn = -(node[Point_Normal]->GetPrimitive(0) - Twall)/dist_ij; - - /*--- Get transport coefficients ---*/ - - laminar_viscosity = node[iPoint]->GetLaminarViscosity(); - eddy_viscosity = node[iPoint]->GetEddyViscosity(); - thermal_conductivity = Cp * ( laminar_viscosity/Prandtl_Lam + eddy_viscosity/Prandtl_Turb); - - // work in progress on real-gases... - //thermal_conductivity = node[iPoint]->GetThermalConductivity(); - //Cp = node[iPoint]->GetSpecificHeatCp(); - //thermal_conductivity += Cp*eddy_viscosity/Prandtl_Turb; - - /*--- Apply a weak boundary condition for the energy equation. - Compute the residual due to the prescribed heat flux. ---*/ - - Res_Visc[nDim+1] = thermal_conductivity * dTdn * Area; - - /*--- Calculate Jacobian for implicit time stepping ---*/ - - if (implicit) { - - for (iVar = 0; iVar < nVar; iVar ++) - for (jVar = 0; jVar < nVar; jVar ++) - Jacobian_i[iVar][jVar] = 0.0; - - /*--- Calculate useful quantities ---*/ - - Density = node[iPoint]->GetPrimitive(nDim+2); - Vel2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Vel2 += node[iPoint]->GetPrimitive(iDim+1) * node[iPoint]->GetPrimitive(iDim+1); - dTdrho = 1.0/Density * ( -Twall + (Gamma-1.0)/Gas_Constant*(Vel2/2.0) ); - - /*--- Enforce the no-slip boundary condition in a strong way ---*/ - - for (iVar = 1; iVar <= nDim; iVar++) { - total_index = iPoint*nVar+iVar; - Jacobian.DeleteValsRowi(total_index); - } - - /*--- Add contributions to the Jacobian from the weak enforcement of the energy equations ---*/ - - Jacobian_i[nDim+1][0] = -thermal_conductivity*theta2/dist_ij * dTdrho * Area; - Jacobian_i[nDim+1][nDim+1] = -thermal_conductivity*theta2/dist_ij * (Gamma-1.0)/(Gas_Constant*Density) * Area; - - /*--- Subtract the block from the Global Jacobian structure ---*/ - - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - - /*--- If the wall is moving, there are additional residual contributions - due to pressure (p v_wall.n) and shear stress (tau.v_wall.n). ---*/ - - if (grid_movement) { - - /*--- Get the grid velocity at the current boundary node ---*/ - - GridVel = geometry->node[iPoint]->GetGridVel(); - ProjGridVel = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - ProjGridVel += GridVel[iDim]*UnitNormal[iDim]*Area; - - /*--- Retrieve other primitive quantities and viscosities ---*/ - - Density = node[iPoint]->GetSolution(0); - if (compressible) { - Pressure = node[iPoint]->GetPressure(); - laminar_viscosity = node[iPoint]->GetLaminarViscosity(); - eddy_viscosity = node[iPoint]->GetEddyViscosity(); - } - if (incompressible || freesurface) { - Pressure = node[iPoint]->GetPressureInc(); - laminar_viscosity = node[iPoint]->GetLaminarViscosityInc(); - eddy_viscosity = node[iPoint]->GetEddyViscosityInc(); - } - - total_viscosity = laminar_viscosity + eddy_viscosity; - - for (iDim = 0; iDim < nDim; iDim++) { - for (jDim = 0 ; jDim < nDim; jDim++) { - Grad_Vel[iDim][jDim] = node[iPoint]->GetGradient_Primitive(iDim+1, jDim); - } - } - - /*--- Divergence of the velocity ---*/ - - div_vel = 0.0; for (iDim = 0 ; iDim < nDim; iDim++) div_vel += Grad_Vel[iDim][iDim]; - - /*--- Compute the viscous stress tensor ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - for (jDim = 0; jDim < nDim; jDim++) { - tau[iDim][jDim] = total_viscosity*( Grad_Vel[jDim][iDim] + Grad_Vel[iDim][jDim] ) - TWO3*total_viscosity*div_vel*delta[iDim][jDim]; - } - - /*--- Dot product of the stress tensor with the grid velocity ---*/ - - for (iDim = 0 ; iDim < nDim; iDim++) { - tau_vel[iDim] = 0.0; - for (jDim = 0 ; jDim < nDim; jDim++) - tau_vel[iDim] += tau[iDim][jDim]*GridVel[jDim]; - } - - /*--- Compute the convective and viscous residuals (energy eqn.) ---*/ - - Res_Conv[nDim+1] = Pressure*ProjGridVel; - for (iDim = 0 ; iDim < nDim; iDim++) - Res_Visc[nDim+1] += tau_vel[iDim]*UnitNormal[iDim]*Area; - - /*--- Implicit Jacobian contributions due to moving walls ---*/ - - if (implicit) { - - /*--- Jacobian contribution related to the pressure term ---*/ - - GridVel2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - GridVel2 += GridVel[iDim]*GridVel[iDim]; - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - Jacobian_i[iVar][jVar] = 0.0; - - Jacobian_i[nDim+1][0] = 0.5*(Gamma-1.0)*GridVel2*ProjGridVel; - for (jDim = 0; jDim < nDim; jDim++) - Jacobian_i[nDim+1][jDim+1] = -(Gamma-1.0)*GridVel[jDim]*ProjGridVel; - Jacobian_i[nDim+1][nDim+1] = (Gamma-1.0)*ProjGridVel; - - /*--- Add the block to the Global Jacobian structure ---*/ - - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - /*--- Now the Jacobian contribution related to the shear stress ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - Jacobian_i[iVar][jVar] = 0.0; - - factor = total_viscosity*Area/(Density*dist_ij); - - if (nDim == 2) { - thetax = theta2 + UnitNormal[0]*UnitNormal[0]/3.0; - thetay = theta2 + UnitNormal[1]*UnitNormal[1]/3.0; - - etaz = UnitNormal[0]*UnitNormal[1]/3.0; - - pix = GridVel[0]*thetax + GridVel[1]*etaz; - piy = GridVel[0]*etaz + GridVel[1]*thetay; - - Jacobian_i[nDim+1][0] -= factor*(-pix*GridVel[0]+piy*GridVel[1]); - Jacobian_i[nDim+1][1] -= factor*pix; - Jacobian_i[nDim+1][2] -= factor*piy; - } - else { - thetax = theta2 + UnitNormal[0]*UnitNormal[0]/3.0; - thetay = theta2 + UnitNormal[1]*UnitNormal[1]/3.0; - thetaz = theta2 + UnitNormal[2]*UnitNormal[2]/3.0; - - etaz = UnitNormal[0]*UnitNormal[1]/3.0; - etax = UnitNormal[1]*UnitNormal[2]/3.0; - etay = UnitNormal[0]*UnitNormal[2]/3.0; - - pix = GridVel[0]*thetax + GridVel[1]*etaz + GridVel[2]*etay; - piy = GridVel[0]*etaz + GridVel[1]*thetay + GridVel[2]*etax; - piz = GridVel[0]*etay + GridVel[1]*etax + GridVel[2]*thetaz; - - Jacobian_i[nDim+1][0] -= factor*(-pix*GridVel[0]+piy*GridVel[1]+piz*GridVel[2]); - Jacobian_i[nDim+1][1] -= factor*pix; - Jacobian_i[nDim+1][2] -= factor*piy; - Jacobian_i[nDim+1][3] -= factor*piz; - } - - /*--- Subtract the block from the Global Jacobian structure ---*/ - - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - } - - } - - /*--- Convective contribution to the residual at the wall ---*/ - - LinSysRes.AddBlock(iPoint, Res_Conv); - - /*--- Viscous contribution to the residual at the wall ---*/ - - LinSysRes.SubtractBlock(iPoint, Res_Visc); - - /*--- Enforce the no-slip boundary condition in a strong way by - modifying the velocity-rows of the Jacobian (1 on the diagonal). ---*/ - - if (implicit) { - for (iVar = 1; iVar <= nDim; iVar++) { - total_index = iPoint*nVar+iVar; - Jacobian.DeleteValsRowi(total_index); - } - } - - } - } -} +/*! + * \file solution_direct_mean.cpp + * \brief Main subrotuines for solving direct problems (Euler, Navier-Stokes, etc.). + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/solver_structure.hpp" + +CEulerSolver::CEulerSolver(void) : CSolver() { + + /*--- Basic array initialization ---*/ + + CDrag_Inv = NULL; CLift_Inv = NULL; CSideForce_Inv = NULL; CEff_Inv = NULL; + CMx_Inv = NULL; CMy_Inv = NULL; CMz_Inv = NULL; + CFx_Inv = NULL; CFy_Inv = NULL; CFz_Inv = NULL; + + CPressure = NULL; CPressureTarget = NULL; HeatFlux = NULL; HeatFluxTarget = NULL; YPlus = NULL; + ForceInviscid = NULL; MomentInviscid = NULL; + + /*--- Surface based array initialization ---*/ + + Surface_CLift_Inv = NULL; Surface_CDrag_Inv = NULL; Surface_CSideForce_Inv = NULL; Surface_CEff_Inv = NULL; + Surface_CFx_Inv = NULL; Surface_CFy_Inv = NULL; Surface_CFz_Inv = NULL; + Surface_CMx_Inv = NULL; Surface_CMy_Inv = NULL; Surface_CMz_Inv = NULL; + + Surface_CLift = NULL; Surface_CDrag = NULL; Surface_CSideForce = NULL; Surface_CEff = NULL; + Surface_CFx = NULL; Surface_CFy = NULL; Surface_CFz = NULL; + Surface_CMx = NULL; Surface_CMy = NULL; Surface_CMz = NULL; + + /*--- Rotorcraft simulation array initialization ---*/ + + CMerit_Inv = NULL; CT_Inv = NULL; CQ_Inv = NULL; + + /*--- Supersonic simulation array initialization ---*/ + + CEquivArea_Inv = NULL; + CNearFieldOF_Inv = NULL; + + /*--- Engine simulation array initialization ---*/ + + Inflow_MassFlow = NULL; Inflow_Pressure = NULL; + Inflow_Mach = NULL; Inflow_Area = NULL; + Bleed_MassFlow = NULL; Bleed_Pressure = NULL; + Bleed_Temperature = NULL; Inflow_Area = NULL; + Exhaust_Pressure = NULL; Exhaust_Temperature = NULL; + Exhaust_MassFlow = NULL; Exhaust_Area = NULL; + + /*--- Numerical methods array initialization ---*/ + + iPoint_UndLapl = NULL; + jPoint_UndLapl = NULL; + LowMach_Precontioner = NULL; + Primitive = NULL; Primitive_i = NULL; Primitive_j = NULL; + CharacPrimVar = NULL; + + /*--- Fixed CL mode initialization (cauchy criteria) ---*/ + + Cauchy_Value = 0; + Cauchy_Func = 0; + Old_Func = 0; + New_Func = 0; + Cauchy_Counter = 0; + Cauchy_Serie = NULL; + +} + +CEulerSolver::CEulerSolver(CGeometry *geometry, CConfig *config, unsigned short iMesh) : CSolver() { + + unsigned long iPoint, index, counter_local = 0, counter_global = 0, iVertex; + unsigned short iVar, iDim, iMarker, nLineLets; + su2double StaticEnergy, Density, Velocity2, Pressure, Temperature, dull_val; + int Unst_RestartIter; + ifstream restart_file; + unsigned short iZone = config->GetiZone(); + unsigned short nZone = geometry->GetnZone(); + bool restart = (config->GetRestart() || config->GetRestart_Flow()); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + bool roe_turkel = (config->GetKind_Upwind_Flow() == TURKEL); + bool adjoint = config->GetAdjoint(); + string filename = config->GetSolution_FlowFileName(); + + unsigned short direct_diff = config->GetDirectDiff(); + unsigned short nMarkerTurboPerf = config->Get_nMarkerTurboPerf(); + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Array initialization ---*/ + + CDrag_Inv = NULL; CLift_Inv = NULL; CSideForce_Inv = NULL; CEff_Inv = NULL; + CMx_Inv = NULL; CMy_Inv = NULL; CMz_Inv = NULL; + CFx_Inv = NULL; CFy_Inv = NULL; CFz_Inv = NULL; + + Surface_CLift_Inv = NULL; Surface_CDrag_Inv = NULL; Surface_CSideForce_Inv = NULL; Surface_CEff_Inv = NULL; + Surface_CFx_Inv = NULL; Surface_CFy_Inv = NULL; Surface_CFz_Inv = NULL; + Surface_CMx_Inv = NULL; Surface_CMy_Inv = NULL; Surface_CMz_Inv = NULL; + + Surface_CLift = NULL; Surface_CDrag = NULL; Surface_CSideForce = NULL; Surface_CEff = NULL; + Surface_CFx = NULL; Surface_CFy = NULL; Surface_CFz = NULL; + Surface_CMx = NULL; Surface_CMy = NULL; Surface_CMz = NULL; + + ForceInviscid = NULL; MomentInviscid = NULL; + CPressure = NULL; CPressureTarget = NULL; HeatFlux = NULL; + HeatFluxTarget = NULL; YPlus = NULL; + + CMerit_Inv = NULL; CT_Inv = NULL; CQ_Inv = NULL; + + CEquivArea_Inv = NULL; CNearFieldOF_Inv = NULL; + + Inflow_MassFlow = NULL; Exhaust_MassFlow = NULL; Exhaust_Area = NULL; Exhaust_Pressure = NULL; + Inflow_Pressure = NULL; Inflow_Mach = NULL; Inflow_Area = NULL; Exhaust_Temperature = NULL; + Bleed_MassFlow = NULL; Bleed_Pressure = NULL; Bleed_Temperature = NULL; Bleed_Area = NULL; + + iPoint_UndLapl = NULL; jPoint_UndLapl = NULL; + LowMach_Precontioner = NULL; + Primitive = NULL; Primitive_i = NULL; Primitive_j = NULL; + Secondary = NULL; Secondary_i = NULL; Secondary_j = NULL; + CharacPrimVar = NULL; + Cauchy_Serie = NULL; + + /*--- Set the gamma value ---*/ + + Gamma = config->GetGamma(); + Gamma_Minus_One = Gamma - 1.0; + + /*--- Define geometry constants in the solver structure + Compressible flow, primitive variables (T, vx, vy, vz, P, rho, h, c, lamMu, EddyMu, ThCond, Cp) + Incompressible flow, primitive variables (P, vx, vy, vz, rho, beta, lamMu, EddyMu). + FreeSurface Incompressible flow, primitive variables (P, vx, vy, vz, rho, beta, lamMu, EddyMu, LevelSet, Dist). + ---*/ + + nDim = geometry->GetnDim(); + + if (incompressible) { nVar = nDim+1; nPrimVar = nDim+5; nPrimVarGrad = nDim+3; } + if (freesurface) { nVar = nDim+2; nPrimVar = nDim+7; nPrimVarGrad = nDim+6; } + if (compressible) { nVar = nDim+2; + nPrimVar = nDim+9; nPrimVarGrad = nDim+4; + nSecondaryVar = 2; nSecondaryVarGrad = 2; + } + + nMarker = config->GetnMarker_All(); + nPoint = geometry->GetnPoint(); + nPointDomain = geometry->GetnPointDomain(); + + /*--- Perform the non-dimensionalization for the flow equations using the + specified reference values. ---*/ + + SetNondimensionalization(geometry, config, iMesh); + + /*--- Allocate the node variables ---*/ + + node = new CVariable*[nPoint]; + + /*--- Define some auxiliary vectors related to the residual ---*/ + + Residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; + Residual_RMS = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_RMS[iVar] = 0.0; + Residual_Max = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_Max[iVar] = 0.0; + Residual_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_i[iVar] = 0.0; + Residual_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_j[iVar] = 0.0; + Res_Conv = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Conv[iVar] = 0.0; + Res_Visc = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Visc[iVar] = 0.0; + Res_Sour = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Sour[iVar] = 0.0; + + /*--- Define some structures for locating max residuals ---*/ + + Point_Max = new unsigned long[nVar]; for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; + Point_Max_Coord = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Point_Max_Coord[iVar] = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; + } + + /*--- Define some auxiliary vectors related to the solution ---*/ + + Solution = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; + Solution_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_i[iVar] = 0.0; + Solution_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_j[iVar] = 0.0; + + /*--- Define some auxiliary vectors related to the geometry ---*/ + + Vector = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = 0.0; + Vector_i = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_i[iDim] = 0.0; + Vector_j = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_j[iDim] = 0.0; + + /*--- Define some auxiliary vectors related to the primitive solution ---*/ + + Primitive = new su2double[nPrimVar]; for (iVar = 0; iVar < nPrimVar; iVar++) Primitive[iVar] = 0.0; + Primitive_i = new su2double[nPrimVar]; for (iVar = 0; iVar < nPrimVar; iVar++) Primitive_i[iVar] = 0.0; + Primitive_j = new su2double[nPrimVar]; for (iVar = 0; iVar < nPrimVar; iVar++) Primitive_j[iVar] = 0.0; + + /*--- Define some auxiliary vectors related to the Secondary solution ---*/ + + Secondary = new su2double[nSecondaryVar]; for (iVar = 0; iVar < nSecondaryVar; iVar++) Secondary[iVar] = 0.0; + Secondary_i = new su2double[nSecondaryVar]; for (iVar = 0; iVar < nSecondaryVar; iVar++) Secondary_i[iVar] = 0.0; + Secondary_j = new su2double[nSecondaryVar]; for (iVar = 0; iVar < nSecondaryVar; iVar++) Secondary_j[iVar] = 0.0; + + /*--- Define some auxiliary vectors related to the undivided lapalacian ---*/ + + if (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED) { + iPoint_UndLapl = new su2double [nPoint]; + jPoint_UndLapl = new su2double [nPoint]; + } + + /*--- Define some auxiliary vectors related to low-speed preconditioning ---*/ + + if (roe_turkel) { + LowMach_Precontioner = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar ++) + LowMach_Precontioner[iVar] = new su2double[nVar]; + } + + /*--- Initialize the solution and right hand side vectors for storing + the residuals and updating the solution (always needed even for + explicit schemes). ---*/ + + LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); + LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); + + /*--- Jacobians and vector structures for implicit computations ---*/ + + if (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT) { + + Jacobian_i = new su2double* [nVar]; + Jacobian_j = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Jacobian_i[iVar] = new su2double [nVar]; + Jacobian_j[iVar] = new su2double [nVar]; + } + + if (rank == MASTER_NODE) cout << "Initialize Jacobian structure (Euler). MG level: " << iMesh <<"." << endl; + Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); + + if ((config->GetKind_Linear_Solver_Prec() == LINELET) || + (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { + nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); + if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; + } + + } + + else { + if (rank == MASTER_NODE) cout << "Explicit scheme. No Jacobian structure (Euler). MG level: " << iMesh <<"." << endl; + } + + /*--- Define some auxiliary vectors for computing flow variable + gradients by least squares, S matrix := inv(R)*traspose(inv(R)), + c vector := transpose(WA)*(Wb) ---*/ + + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { + + Smatrix = new su2double* [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Smatrix[iDim] = new su2double [nDim]; + + cvector = new su2double* [nPrimVarGrad]; + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + cvector[iVar] = new su2double [nDim]; + + } + + /*--- Store the value of the characteristic primitive variables at the boundaries ---*/ + + CharacPrimVar = new su2double** [nMarker]; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + CharacPrimVar[iMarker] = new su2double* [geometry->nVertex[iMarker]]; + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + CharacPrimVar[iMarker][iVertex] = new su2double [nPrimVar]; + for (iVar = 0; iVar < nPrimVar; iVar++) { + CharacPrimVar[iMarker][iVertex][iVar] = 0.0; + } + } + } + + /*--- Force definition and coefficient arrays for all of the markers ---*/ + + CPressure = new su2double* [nMarker]; + CPressureTarget = new su2double* [nMarker]; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + CPressure[iMarker] = new su2double [geometry->nVertex[iMarker]]; + CPressureTarget[iMarker] = new su2double [geometry->nVertex[iMarker]]; + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + CPressure[iMarker][iVertex] = 0.0; + CPressureTarget[iMarker][iVertex] = 0.0; + } + } + + /*--- Non-dimensional coefficients ---*/ + + ForceInviscid = new su2double[nDim]; + MomentInviscid = new su2double[3]; + CDrag_Inv = new su2double[nMarker]; + CLift_Inv = new su2double[nMarker]; + CSideForce_Inv = new su2double[nMarker]; + CMx_Inv = new su2double[nMarker]; + CMy_Inv = new su2double[nMarker]; + CMz_Inv = new su2double[nMarker]; + CEff_Inv = new su2double[nMarker]; + CFx_Inv = new su2double[nMarker]; + CFy_Inv = new su2double[nMarker]; + CFz_Inv = new su2double[nMarker]; + + Surface_CLift_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CDrag_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CSideForce_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CEff_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CFx_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CFy_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CFz_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CMx_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CMy_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CMz_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CLift = new su2double[config->GetnMarker_Monitoring()]; + Surface_CDrag = new su2double[config->GetnMarker_Monitoring()]; + Surface_CSideForce = new su2double[config->GetnMarker_Monitoring()]; + Surface_CEff = new su2double[config->GetnMarker_Monitoring()]; + Surface_CFx = new su2double[config->GetnMarker_Monitoring()]; + Surface_CFy = new su2double[config->GetnMarker_Monitoring()]; + Surface_CFz = new su2double[config->GetnMarker_Monitoring()]; + Surface_CMx = new su2double[config->GetnMarker_Monitoring()]; + Surface_CMy = new su2double[config->GetnMarker_Monitoring()]; + Surface_CMz = new su2double[config->GetnMarker_Monitoring()]; + + /*--- Rotorcraft coefficients ---*/ + + CT_Inv = new su2double[nMarker]; + CQ_Inv = new su2double[nMarker]; + CMerit_Inv = new su2double[nMarker]; + + /*--- Supersonic coefficients ---*/ + + CEquivArea_Inv = new su2double[nMarker]; + CNearFieldOF_Inv = new su2double[nMarker]; + + /*--- Engine simulation ---*/ + + Inflow_MassFlow = new su2double[nMarker]; + Inflow_Pressure = new su2double[nMarker]; + Inflow_Mach = new su2double[nMarker]; + Inflow_Area = new su2double[nMarker]; + + Exhaust_MassFlow = new su2double[nMarker]; + Exhaust_Pressure = new su2double[nMarker]; + Exhaust_Temperature = new su2double[nMarker]; + Exhaust_Area = new su2double[nMarker]; + + Bleed_MassFlow = new su2double[nMarker]; + Bleed_Pressure = new su2double[nMarker]; + Bleed_Temperature = new su2double[nMarker]; + Bleed_Area = new su2double[nMarker]; + + /*--- Init total coefficients ---*/ + + Total_CDrag = 0.0; Total_CLift = 0.0; Total_CSideForce = 0.0; + Total_CMx = 0.0; Total_CMy = 0.0; Total_CMz = 0.0; + Total_CEff = 0.0; Total_CEquivArea = 0.0; Total_CNearFieldOF = 0.0; + Total_CFx = 0.0; Total_CFy = 0.0; Total_CFz = 0.0; + Total_CT = 0.0; Total_CQ = 0.0; Total_CMerit = 0.0; + Total_MaxHeat = 0.0; Total_Heat = 0.0; + Total_CpDiff = 0.0; Total_HeatFluxDiff = 0.0; + + /*--- Read farfield conditions ---*/ + + Density_Inf = config->GetDensity_FreeStreamND(); + Pressure_Inf = config->GetPressure_FreeStreamND(); + Velocity_Inf = config->GetVelocity_FreeStreamND(); + Energy_Inf = config->GetEnergy_FreeStreamND(); + Temperature_Inf = config->GetTemperature_FreeStreamND(); + Mach_Inf = config->GetMach(); + + /*--- Initialize the secondary values for direct derivative approxiations ---*/ + + switch(direct_diff){ + case NO_DERIVATIVE: + /*--- Default ---*/ + break; + case D_DENSITY: + SU2_TYPE::SetDerivative(Density_Inf, 1.0); + break; + case D_PRESSURE: + SU2_TYPE::SetDerivative(Pressure_Inf, 1.0); + break; + case D_TEMPERATURE: + SU2_TYPE::SetDerivative(Temperature_Inf, 1.0); + break; + case D_MACH: case D_AOA: + case D_SIDESLIP: case D_REYNOLDS: + case D_TURB2LAM: case D_DESIGN: + /*--- Already done in postprocessing of config ---*/ + break; + default: + break; + } + + + /*--- Initializate fan face pressure, fan face mach number, and mass flow rate ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + Inflow_MassFlow[iMarker] = 0.0; + Inflow_Mach[iMarker] = Mach_Inf; + Inflow_Pressure[iMarker] = Pressure_Inf; + Inflow_Area[iMarker] = 0.0; + + Exhaust_MassFlow[iMarker] = 0.0; + Exhaust_Temperature[iMarker] = Temperature_Inf; + Exhaust_Pressure[iMarker] = Pressure_Inf; + Exhaust_Area[iMarker] = 0.0; + + Bleed_MassFlow[iMarker] = 0.0; + Bleed_Temperature[iMarker] = Temperature_Inf; + Bleed_Pressure[iMarker] = Pressure_Inf; + Bleed_Area[iMarker] = 0.0; + } + + /*--- Initializate quantities for the mixing process ---*/ + + AveragedVelocity = new su2double* [nMarker]; + AveragedNormal = new su2double* [nMarker]; + AveragedGridVel = new su2double* [nMarker]; + AveragedFlux = new su2double* [nMarker]; + TotalFlux = new su2double* [nMarker]; + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + AveragedVelocity[iMarker] = new su2double [nDim]; + AveragedNormal[iMarker] = new su2double [nDim]; + AveragedGridVel[iMarker] = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) { + AveragedVelocity[iMarker][iDim] = 0.0; + AveragedNormal[iMarker][iDim] = 0.0; + AveragedGridVel [iMarker][iDim] = 0.0; + } + } + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + AveragedFlux[iMarker] = new su2double [nVar]; + TotalFlux[iMarker] = new su2double [nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + AveragedFlux[iMarker][iVar] = 0.0; + TotalFlux[iMarker][iVar] = 0.0; + } + } + + AveragedNormalVelocity = new su2double[nMarker]; + AveragedTangVelocity = new su2double[nMarker]; + ExtAveragedNormalVelocity = new su2double[nMarker]; + ExtAveragedTangVelocity = new su2double[nMarker]; + MassFlow= new su2double[nMarker]; + FlowAngle= new su2double[nMarker]; + AveragedEnthalpy = new su2double[nMarker]; + AveragedPressure = new su2double[nMarker]; + AveragedTotPressure = new su2double[nMarker]; + AveragedTotTemperature = new su2double[nMarker]; + ExtAveragedTotPressure = new su2double[nMarker]; + ExtAveragedTotTemperature = new su2double[nMarker]; + AveragedDensity = new su2double[nMarker]; + ExtAveragedPressure = new su2double[nMarker]; + ExtAveragedDensity = new su2double[nMarker]; + AveragedSoundSpeed= new su2double[nMarker]; + AveragedEntropy = new su2double[nMarker]; + AveragedTangGridVelocity = new su2double[nMarker]; + AveragedMach = new su2double[nMarker]; + AveragedNormalMach = new su2double[nMarker]; + AveragedTangMach = new su2double[nMarker]; + + + /*--- Initializate quantities for turboperformace ---*/ + + TotalStaticEfficiency = new su2double[nMarkerTurboPerf]; + TotalTotalEfficiency = new su2double[nMarkerTurboPerf]; + KineticEnergyLoss= new su2double[nMarkerTurboPerf]; + TotalPressureLoss= new su2double[nMarkerTurboPerf]; + MassFlowIn= new su2double[nMarkerTurboPerf]; + MassFlowOut= new su2double[nMarkerTurboPerf]; + FlowAngleIn= new su2double[nMarkerTurboPerf]; + FlowAngleOut= new su2double[nMarkerTurboPerf]; + EulerianWork= new su2double[nMarkerTurboPerf]; + TotalEnthalpyIn= new su2double[nMarkerTurboPerf]; + PressureRatio= new su2double[nMarkerTurboPerf]; + PressureOut= new su2double[nMarkerTurboPerf]; + EnthalpyOut= new su2double[nMarkerTurboPerf]; + MachIn= new su2double[nMarkerTurboPerf]; + MachOut= new su2double[nMarkerTurboPerf]; + NormalMachIn= new su2double[nMarkerTurboPerf]; + NormalMachOut= new su2double[nMarkerTurboPerf]; + VelocityOutIs= new su2double[nMarkerTurboPerf]; + + for (iMarker = 0; iMarker < nMarkerTurboPerf; iMarker++){ + TotalStaticEfficiency[iMarker]= 0.0; + TotalTotalEfficiency[iMarker]= 0.0; + KineticEnergyLoss[iMarker]= 0.0; + TotalPressureLoss[iMarker]= 0.0; + MassFlowIn[iMarker]= 0.0; + MassFlowOut[iMarker]= 0.0; + FlowAngleIn[iMarker]= 0.0; + FlowAngleOut[iMarker]= 0.0; + EulerianWork[iMarker]= 0.0; + TotalEnthalpyIn[iMarker]= 0.0; + PressureRatio[iMarker]= 0.0; + PressureOut[iMarker]= 0.0; + EnthalpyOut[iMarker]= 0.0; + MachIn[iMarker]= 0.0; + MachOut[iMarker]= 0.0; + NormalMachIn[iMarker]= 0.0; + NormalMachOut[iMarker]= 0.0; + VelocityOutIs[iMarker]= 0.0; + } + + + /*--- Initialize the cauchy critera array for fixed CL mode ---*/ + + if (config->GetFixed_CL_Mode()) + + Cauchy_Serie = new su2double [config->GetCauchy_Elems()+1]; + + /*--- Check for a restart and set up the variables at each node + appropriately. Coarse multigrid levels will be intitially set to + the farfield values bc the solver will immediately interpolate + the solution from the finest mesh to the coarser levels. ---*/ + + if (!restart || (iMesh != MESH_0)) { + + /*--- Restart the solution from the free-stream state ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint++) + node[iPoint] = new CEulerVariable(Density_Inf, Velocity_Inf, Energy_Inf, nDim, nVar, config); + + } else { + + /*--- Modify file name for an unsteady restart ---*/ + + if (dual_time) { + + if (adjoint) { Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_AdjointIter()) - 1; } + else if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_RestartIter())-1; + else + Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_RestartIter())-2; + + filename = config->GetUnsteady_FileName(filename, Unst_RestartIter); + } + if (nZone >1) + filename= config->GetRestart_FlowFileName(filename, iZone); + + /*--- Open the restart file, throw an error if this fails. ---*/ + + restart_file.open(filename.data(), ios::in); + if (restart_file.fail()) { + if (rank == MASTER_NODE) + cout << "There is no flow restart file!! " << filename.data() << "."<< endl; + exit(EXIT_FAILURE); + } + + /*--- In case this is a parallel simulation, we need to perform the + Global2Local index transformation first. ---*/ + + long *Global2Local = new long[geometry->GetGlobal_nPointDomain()]; + + /*--- First, set all indices to a negative value by default ---*/ + + for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) + Global2Local[iPoint] = -1; + + /*--- Now fill array with the transform values only for local points ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) + Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; + + /*--- Read all lines in the restart file ---*/ + + long iPoint_Local; + unsigned long iPoint_Global_Local = 0, iPoint_Global = 0; string text_line; + unsigned short rbuf_NotMatching = 0, sbuf_NotMatching = 0; + + /*--- The first line is the header ---*/ + + getline (restart_file, text_line); + + while (getline (restart_file, text_line)) { + istringstream point_line(text_line); + + /*--- Retrieve local index. If this node from the restart file lives + on a different processor, the value of iPoint_Local will be -1. + Otherwise, the local index for this node on the current processor + will be returned and used to instantiate the vars. ---*/ + + iPoint_Local = Global2Local[iPoint_Global]; + + /*--- Load the solution for this node. Note that the first entry + on the restart file line is the global index, followed by the + node coordinates, and then the conservative variables. ---*/ + + if (iPoint_Local >= 0) { + if (compressible) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3] >> Solution[4]; + } + if (incompressible) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; + } + if (freesurface) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3] >> Solution[4]; + } + node[iPoint_Local] = new CEulerVariable(Solution, nDim, nVar, config); + iPoint_Global_Local++; + } + iPoint_Global++; + } + + /*--- Detect a wrong solution file ---*/ + + if (iPoint_Global_Local < nPointDomain) { sbuf_NotMatching = 1; } + +#ifndef HAVE_MPI + rbuf_NotMatching = sbuf_NotMatching; +#else + SU2_MPI::Allreduce(&sbuf_NotMatching, &rbuf_NotMatching, 1, MPI_UNSIGNED_SHORT, MPI_SUM, MPI_COMM_WORLD); +#endif + + if (rbuf_NotMatching != 0) { + if (rank == MASTER_NODE) { + cout << endl << "The solution file " << filename.data() << " doesn't match with the mesh file!" << endl; + cout << "It could be empty lines at the end of the file." << endl << endl; + } +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Barrier(MPI_COMM_WORLD); + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + } + + /*--- Instantiate the variable class with an arbitrary solution + at any halo/periodic nodes. The initial solution can be arbitrary, + because a send/recv is performed immediately in the solver. ---*/ + + for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) + node[iPoint] = new CEulerVariable(Solution, nDim, nVar, config); + + /*--- Close the restart file ---*/ + + restart_file.close(); + + /*--- Free memory needed for the transformation ---*/ + + delete [] Global2Local; + + } + + /*--- Check that the initial solution is physical, report any non-physical nodes ---*/ + + if (compressible) { + + counter_local = 0; + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + + Density = node[iPoint]->GetSolution(0); + + Velocity2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Velocity2 += (node[iPoint]->GetSolution(iDim+1)/Density)*(node[iPoint]->GetSolution(iDim+1)/Density); + + StaticEnergy= node[iPoint]->GetSolution(nDim+1)/Density - 0.5*Velocity2; + + FluidModel->SetTDState_rhoe(Density, StaticEnergy); + Pressure= FluidModel->GetPressure(); + Temperature= FluidModel->GetTemperature(); + + /*--- Use the values at the infinity ---*/ + + if ((Pressure < 0.0) || (Density < 0.0) || (Temperature < 0.0)) { + Solution[0] = Density_Inf; + for (iDim = 0; iDim < nDim; iDim++) + Solution[iDim+1] = Velocity_Inf[iDim]*Density_Inf; + Solution[nDim+1] = Energy_Inf*Density_Inf; + node[iPoint]->SetSolution(Solution); + node[iPoint]->SetSolution_Old(Solution); + counter_local++; + } + + } + + /*--- Warning message about non-physical points ---*/ + + if (config->GetConsole_Output_Verb() == VERB_HIGH) { +#ifdef HAVE_MPI + SU2_MPI::Reduce(&counter_local, &counter_global, 1, MPI_UNSIGNED_LONG, MPI_SUM, MASTER_NODE, MPI_COMM_WORLD); +#else + counter_global = counter_local; +#endif + if ((rank == MASTER_NODE) && (counter_global != 0)) + cout << "Warning. The original solution contains "<< counter_global << " points that are not physical." << endl; + } + + } + + /*--- Define solver parameters needed for execution of destructor ---*/ + + if (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED ) space_centered = true; + else space_centered = false; + + if (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT) euler_implicit = true; + else euler_implicit = false; + + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) least_squares = true; + else least_squares = false; + + /*--- Perform the MPI communication of the solution ---*/ + + Set_MPI_Solution(geometry, config); + +} + +CEulerSolver::~CEulerSolver(void) { + unsigned short iVar, iMarker; + + /*--- Array deallocation ---*/ + if (CDrag_Inv != NULL) delete [] CDrag_Inv; + if (CLift_Inv != NULL) delete [] CLift_Inv; + if (CSideForce_Inv != NULL) delete [] CSideForce_Inv; + if (CMx_Inv != NULL) delete [] CMx_Inv; + if (CMy_Inv != NULL) delete [] CMy_Inv; + if (CMz_Inv != NULL) delete [] CMz_Inv; + if (CFx_Inv != NULL) delete [] CFx_Inv; + if (CFy_Inv != NULL) delete [] CFy_Inv; + if (CFz_Inv != NULL) delete [] CFz_Inv; + if (Surface_CLift_Inv != NULL) delete[] Surface_CLift_Inv; + if (Surface_CDrag_Inv != NULL) delete[] Surface_CDrag_Inv; + if (Surface_CSideForce_Inv != NULL) delete[] Surface_CSideForce_Inv; + if (Surface_CEff_Inv != NULL) delete[] Surface_CEff_Inv; + if (Surface_CFx_Inv != NULL) delete [] Surface_CFx_Inv; + if (Surface_CFy_Inv != NULL) delete [] Surface_CFy_Inv; + if (Surface_CFz_Inv != NULL) delete [] Surface_CFz_Inv; + if (Surface_CMx_Inv != NULL) delete [] Surface_CMx_Inv; + if (Surface_CMy_Inv != NULL) delete [] Surface_CMy_Inv; + if (Surface_CMz_Inv != NULL) delete [] Surface_CMz_Inv; + if (Surface_CLift != NULL) delete [] Surface_CLift; + if (Surface_CDrag != NULL) delete [] Surface_CDrag; + if (Surface_CSideForce != NULL) delete [] Surface_CSideForce; + if (Surface_CEff != NULL) delete [] Surface_CEff; + if (Surface_CFx != NULL) delete [] Surface_CFx; + if (Surface_CFy != NULL) delete [] Surface_CFy; + if (Surface_CFz != NULL) delete [] Surface_CFz; + if (Surface_CMx != NULL) delete [] Surface_CMx; + if (Surface_CMy != NULL) delete [] Surface_CMy; + if (Surface_CMz != NULL) delete [] Surface_CMz; + if (CEff_Inv != NULL) delete [] CEff_Inv; + if (CMerit_Inv != NULL) delete [] CMerit_Inv; + if (CT_Inv != NULL) delete [] CT_Inv; + if (CQ_Inv != NULL) delete [] CQ_Inv; + if (CEquivArea_Inv != NULL) delete [] CEquivArea_Inv; + if (CNearFieldOF_Inv != NULL) delete [] CNearFieldOF_Inv; + if (ForceInviscid != NULL) delete [] ForceInviscid; + if (MomentInviscid != NULL) delete [] MomentInviscid; + if (Inflow_MassFlow != NULL) delete [] Inflow_MassFlow; + if (Exhaust_MassFlow != NULL) delete [] Exhaust_MassFlow; + if (Exhaust_Area != NULL) delete [] Exhaust_Area; + if (Inflow_Pressure != NULL) delete [] Inflow_Pressure; + if (Inflow_Mach != NULL) delete [] Inflow_Mach; + if (Inflow_Area != NULL) delete [] Inflow_Area; + if (Bleed_Pressure != NULL) delete [] Bleed_Pressure; + if (Bleed_Temperature != NULL) delete [] Bleed_Temperature; + if (Exhaust_Pressure != NULL) delete [] Exhaust_Pressure; + if (Exhaust_Temperature != NULL) delete [] Exhaust_Temperature; + if (Bleed_Area != NULL) delete [] Bleed_Area; + if (iPoint_UndLapl != NULL) delete [] iPoint_UndLapl; + if (jPoint_UndLapl != NULL) delete [] jPoint_UndLapl; + if (Primitive != NULL) delete [] Primitive; + if (Primitive_i != NULL) delete [] Primitive_i; + if (Primitive_j != NULL) delete [] Primitive_j; + // if (Secondary != NULL) delete [] Secondary; + if (Secondary_i != NULL) delete [] Secondary_i; + if (Secondary_j != NULL) delete [] Secondary_j; + + if (LowMach_Precontioner != NULL) { + for (iVar = 0; iVar < nVar; iVar ++) + delete LowMach_Precontioner[iVar]; + delete [] LowMach_Precontioner; + } + + if (CPressure != NULL) { + for (iMarker = 0; iMarker < nMarker; iMarker++) + delete CPressure[iMarker]; + delete [] CPressure; + } + + if (CPressureTarget != NULL) { + for (iMarker = 0; iMarker < nMarker; iMarker++) + delete CPressureTarget[iMarker]; + delete [] CPressureTarget; + } + + // if (CharacPrimVar != NULL) { + // for (iMarker = 0; iMarker < nMarker; iMarker++) { + // for (iVertex = 0; iVertex < nVertex; iVertex++) { + // delete CharacPrimVar[iMarker][iVertex]; + // } + // } + // delete [] CharacPrimVar; + // } + + if (HeatFlux != NULL) { + for (iMarker = 0; iMarker < nMarker; iMarker++) { + delete HeatFlux[iMarker]; + } + delete [] HeatFlux; + } + + if (HeatFluxTarget != NULL) { + for (iMarker = 0; iMarker < nMarker; iMarker++) { + delete HeatFluxTarget[iMarker]; + } + delete [] HeatFluxTarget; + } + + if (YPlus != NULL) { + for (iMarker = 0; iMarker < nMarker; iMarker++) { + delete YPlus[iMarker]; + } + delete [] YPlus; + } + + if (Cauchy_Serie != NULL) + delete [] Cauchy_Serie; + +} + +void CEulerSolver::Set_MPI_Solution(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_U = new su2double [nBufferR_Vector]; + Buffer_Send_U = new su2double[nBufferS_Vector]; + + /*--- Copy the solution that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution(iVar); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); + +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_U; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = Buffer_Receive_U[iVar*nVertexR+iVertex]; + + /*--- Rotate the momentum components. ---*/ + if (nDim == 2) { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex]; + } + else { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex] + + rotMatrix[0][2]*Buffer_Receive_U[3*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex] + + rotMatrix[1][2]*Buffer_Receive_U[3*nVertexR+iVertex]; + Solution[3] = rotMatrix[2][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[2][1]*Buffer_Receive_U[2*nVertexR+iVertex] + + rotMatrix[2][2]*Buffer_Receive_U[3*nVertexR+iVertex]; + } + + /*--- Copy transformed conserved variables back into buffer. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetSolution(iVar, Solution[iVar]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_U; + + } + + } + +} + +void CEulerSolver::Set_MPI_Solution_Old(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, + *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_U = new su2double [nBufferR_Vector]; + Buffer_Send_U = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution_Old(iVar); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); + +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_U; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = Buffer_Receive_U[iVar*nVertexR+iVertex]; + + /*--- Rotate the momentum components. ---*/ + if (nDim == 2) { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex]; + } + else { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_U[2*nVertexR+iVertex] + + rotMatrix[0][2]*Buffer_Receive_U[3*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_U[2*nVertexR+iVertex] + + rotMatrix[1][2]*Buffer_Receive_U[3*nVertexR+iVertex]; + Solution[3] = rotMatrix[2][0]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[2][1]*Buffer_Receive_U[2*nVertexR+iVertex] + + rotMatrix[2][2]*Buffer_Receive_U[3*nVertexR+iVertex]; + } + + /*--- Copy transformed conserved variables back into buffer. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetSolution_Old(iVar, Solution[iVar]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_U; + + } + + } +} + +void CEulerSolver::Set_MPI_Undivided_Laplacian(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, + *Buffer_Receive_Undivided_Laplacian = NULL, *Buffer_Send_Undivided_Laplacian = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_Undivided_Laplacian = new su2double [nBufferR_Vector]; + Buffer_Send_Undivided_Laplacian = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_Undivided_Laplacian[iVar*nVertexS+iVertex] = node[iPoint]->GetUndivided_Laplacian(iVar); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Undivided_Laplacian, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_Undivided_Laplacian, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); + +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_Undivided_Laplacian[iVar*nVertexR+iVertex] = Buffer_Send_Undivided_Laplacian[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_Undivided_Laplacian; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = Buffer_Receive_Undivided_Laplacian[iVar*nVertexR+iVertex]; + + /*--- Rotate the momentum components. ---*/ + if (nDim == 2) { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex]; + } + else { + Solution[1] = rotMatrix[0][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex] + + rotMatrix[0][2]*Buffer_Receive_Undivided_Laplacian[3*nVertexR+iVertex]; + Solution[2] = rotMatrix[1][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex] + + rotMatrix[1][2]*Buffer_Receive_Undivided_Laplacian[3*nVertexR+iVertex]; + Solution[3] = rotMatrix[2][0]*Buffer_Receive_Undivided_Laplacian[1*nVertexR+iVertex] + + rotMatrix[2][1]*Buffer_Receive_Undivided_Laplacian[2*nVertexR+iVertex] + + rotMatrix[2][2]*Buffer_Receive_Undivided_Laplacian[3*nVertexR+iVertex]; + } + + /*--- Copy transformed conserved variables back into buffer. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetUndivided_Laplacian(iVar, Solution[iVar]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_Undivided_Laplacian; + + } + + } + +} + +void CEulerSolver::Set_MPI_MaxEigenvalue(CGeometry *geometry, CConfig *config) { + unsigned short iMarker, MarkerS, MarkerR, *Buffer_Receive_Neighbor = NULL, *Buffer_Send_Neighbor = NULL; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double *Buffer_Receive_Lambda = NULL, *Buffer_Send_Lambda = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS; nBufferR_Vector = nVertexR; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_Lambda = new su2double [nBufferR_Vector]; + Buffer_Send_Lambda = new su2double[nBufferS_Vector]; + Buffer_Receive_Neighbor = new unsigned short [nBufferR_Vector]; + Buffer_Send_Neighbor = new unsigned short[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + Buffer_Send_Lambda[iVertex] = node[iPoint]->GetLambda(); + Buffer_Send_Neighbor[iVertex] = geometry->node[iPoint]->GetnPoint(); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Lambda, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_Lambda, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); + SU2_MPI::Sendrecv(Buffer_Send_Neighbor, nBufferS_Vector, MPI_UNSIGNED_SHORT, send_to, 1, + Buffer_Receive_Neighbor, nBufferR_Vector, MPI_UNSIGNED_SHORT, receive_from, 1, MPI_COMM_WORLD, &status); + +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + Buffer_Receive_Lambda[iVertex] = Buffer_Send_Lambda[iVertex]; + Buffer_Receive_Neighbor[iVertex] = Buffer_Send_Neighbor[iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_Lambda; + delete [] Buffer_Send_Neighbor; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + node[iPoint]->SetLambda(Buffer_Receive_Lambda[iVertex]); + geometry->node[iPoint]->SetnNeighbor(Buffer_Receive_Neighbor[iVertex]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_Lambda; + delete [] Buffer_Receive_Neighbor; + + } + + } +} + +void CEulerSolver::Set_MPI_Dissipation_Switch(CGeometry *geometry, CConfig *config) { + unsigned short iMarker, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double *Buffer_Receive_Lambda = NULL, *Buffer_Send_Lambda = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS; nBufferR_Vector = nVertexR; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_Lambda = new su2double [nBufferR_Vector]; + Buffer_Send_Lambda = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + Buffer_Send_Lambda[iVertex] = node[iPoint]->GetSensor(); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Lambda, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_Lambda, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); + +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + Buffer_Receive_Lambda[iVertex] = Buffer_Send_Lambda[iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_Lambda; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + node[iPoint]->SetSensor(Buffer_Receive_Lambda[iVertex]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_Lambda; + + } + + } +} + +void CEulerSolver::Set_MPI_Solution_Gradient(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, + *Buffer_Receive_Gradient = NULL, *Buffer_Send_Gradient = NULL; + + su2double **Gradient = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + Gradient[iVar] = new su2double[nDim]; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar*nDim; nBufferR_Vector = nVertexR*nVar*nDim; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_Gradient = new su2double [nBufferR_Vector]; + Buffer_Send_Gradient = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Gradient[iDim*nVar*nVertexS+iVar*nVertexS+iVertex] = node[iPoint]->GetGradient(iVar, iDim); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Gradient, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_Gradient, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); + +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex] = Buffer_Send_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_Gradient; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Gradient[iVar][iDim] = Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; + + /*--- Need to rotate the gradients for all conserved variables. ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + if (nDim == 2) { + Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; + } + else { + Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][2] = rotMatrix[2][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; + } + } + + /*--- Store the received information ---*/ + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + node[iPoint]->SetGradient(iVar, iDim, Gradient[iVar][iDim]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_Gradient; + + } + + } + + for (iVar = 0; iVar < nVar; iVar++) + delete [] Gradient[iVar]; + delete [] Gradient; + +} + +void CEulerSolver::Set_MPI_Solution_Limiter(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, + *Buffer_Receive_Limit = NULL, *Buffer_Send_Limit = NULL; + + su2double *Limiter = new su2double [nVar]; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_Limit = new su2double [nBufferR_Vector]; + Buffer_Send_Limit = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_Limit[iVar*nVertexS+iVertex] = node[iPoint]->GetLimiter(iVar); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Limit, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_Limit, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); + +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_Limit[iVar*nVertexR+iVertex] = Buffer_Send_Limit[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_Limit; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + Limiter[iVar] = Buffer_Receive_Limit[iVar*nVertexR+iVertex]; + + /*--- Rotate the momentum components. ---*/ + if (nDim == 2) { + Limiter[1] = rotMatrix[0][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_Limit[2*nVertexR+iVertex]; + Limiter[2] = rotMatrix[1][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_Limit[2*nVertexR+iVertex]; + } + else { + Limiter[1] = rotMatrix[0][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + + rotMatrix[0][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; + Limiter[2] = rotMatrix[1][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + + rotMatrix[1][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; + Limiter[3] = rotMatrix[2][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[2][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + + rotMatrix[2][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; + } + + /*--- Copy transformed conserved variables back into buffer. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetLimiter(iVar, Limiter[iVar]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_Limit; + + } + + } + + delete [] Limiter; + +} + +void CEulerSolver::Set_MPI_Primitive_Gradient(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, + *Buffer_Receive_Gradient = NULL, *Buffer_Send_Gradient = NULL; + + su2double **Gradient = new su2double* [nPrimVarGrad]; + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + Gradient[iVar] = new su2double[nDim]; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nPrimVarGrad*nDim; nBufferR_Vector = nVertexR*nPrimVarGrad*nDim; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_Gradient = new su2double [nBufferR_Vector]; + Buffer_Send_Gradient = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Gradient[iDim*nPrimVarGrad*nVertexS+iVar*nVertexS+iVertex] = node[iPoint]->GetGradient_Primitive(iVar, iDim); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Gradient, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_Gradient, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); + +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Receive_Gradient[iDim*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] = Buffer_Send_Gradient[iDim*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_Gradient; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Gradient[iVar][iDim] = Buffer_Receive_Gradient[iDim*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex]; + + /*--- Need to rotate the gradients for all conserved variables. ---*/ + for (iVar = 0; iVar < nPrimVarGrad; iVar++) { + if (nDim == 2) { + Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex]; + } + else { + Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][2]*Buffer_Receive_Gradient[2*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][2]*Buffer_Receive_Gradient[2*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][2] = rotMatrix[2][0]*Buffer_Receive_Gradient[0*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][1]*Buffer_Receive_Gradient[1*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][2]*Buffer_Receive_Gradient[2*nPrimVarGrad*nVertexR+iVar*nVertexR+iVertex]; + } + } + + /*--- Store the received information ---*/ + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + node[iPoint]->SetGradient_Primitive(iVar, iDim, Gradient[iVar][iDim]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_Gradient; + + } + + } + + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + delete [] Gradient[iVar]; + delete [] Gradient; + +} + +void CEulerSolver::Set_MPI_Primitive_Limiter(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, + *Buffer_Receive_Limit = NULL, *Buffer_Send_Limit = NULL; + + su2double *Limiter = new su2double [nPrimVarGrad]; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nPrimVarGrad; nBufferR_Vector = nVertexR*nPrimVarGrad; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_Limit = new su2double [nBufferR_Vector]; + Buffer_Send_Limit = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + Buffer_Send_Limit[iVar*nVertexS+iVertex] = node[iPoint]->GetLimiter_Primitive(iVar); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Limit, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_Limit, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); + +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + Buffer_Receive_Limit[iVar*nVertexR+iVertex] = Buffer_Send_Limit[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_Limit; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + Limiter[iVar] = Buffer_Receive_Limit[iVar*nVertexR+iVertex]; + + /*--- Rotate the momentum components. ---*/ + if (nDim == 2) { + Limiter[1] = rotMatrix[0][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_Limit[2*nVertexR+iVertex]; + Limiter[2] = rotMatrix[1][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_Limit[2*nVertexR+iVertex]; + } + else { + Limiter[1] = rotMatrix[0][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + + rotMatrix[0][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; + Limiter[2] = rotMatrix[1][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + + rotMatrix[1][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; + Limiter[3] = rotMatrix[2][0]*Buffer_Receive_Limit[1*nVertexR+iVertex] + + rotMatrix[2][1]*Buffer_Receive_Limit[2*nVertexR+iVertex] + + rotMatrix[2][2]*Buffer_Receive_Limit[3*nVertexR+iVertex]; + } + + /*--- Copy transformed conserved variables back into buffer. ---*/ + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + node[iPoint]->SetLimiter_Primitive(iVar, Limiter[iVar]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_Limit; + + } + + } + + delete [] Limiter; + +} + +//void CEulerSolver::Set_MPI_Secondary_Gradient(CGeometry *geometry, CConfig *config) { +// unsigned short iVar, iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; +// unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; +// su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, +// *Buffer_Receive_Gradient = NULL, *Buffer_Send_Gradient = NULL; +// int send_to, receive_from; +// +// su2double **Gradient = new su2double* [nSecondaryVarGrad]; +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) +// Gradient[iVar] = new su2double[nDim]; +// +//#ifdef HAVE_MPI +// MPI_Status status; +//#endif +// +// for (iMarker = 0; iMarker < nMarker; iMarker++) { +// +// if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && +// (config->GetMarker_All_SendRecv(iMarker) > 0)) { +// +// MarkerS = iMarker; MarkerR = iMarker+1; +// +// send_to = config->GetMarker_All_SendRecv(MarkerS)-1; +// receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +// +// nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; +// nBufferS_Vector = nVertexS*nSecondaryVarGrad*nDim; nBufferR_Vector = nVertexR*nSecondaryVarGrad*nDim; +// +// /*--- Allocate Receive and send buffers ---*/ +// Buffer_Receive_Gradient = new su2double [nBufferR_Vector]; +// Buffer_Send_Gradient = new su2double[nBufferS_Vector]; +// +// /*--- Copy the solution old that should be sended ---*/ +// for (iVertex = 0; iVertex < nVertexS; iVertex++) { +// iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) +// for (iDim = 0; iDim < nDim; iDim++) +// Buffer_Send_Gradient[iDim*nSecondaryVarGrad*nVertexS+iVar*nVertexS+iVertex] = node[iPoint]->GetGradient_Secondary(iVar, iDim); +// } +// +//#ifdef HAVE_MPI +// +// /*--- Send/Receive information using Sendrecv ---*/ +// SU2_MPI::Sendrecv(Buffer_Send_Gradient, nBufferS_Vector, MPI_DOUBLE, send_to, 0, +// Buffer_Receive_Gradient, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); +// +//#else +// +// /*--- Receive information without MPI ---*/ +// for (iVertex = 0; iVertex < nVertexR; iVertex++) { +// iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) +// for (iDim = 0; iDim < nDim; iDim++) +// Buffer_Receive_Gradient[iDim*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] = Buffer_Send_Gradient[iDim*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex]; +// } +// +//#endif +// +// /*--- Deallocate send buffer ---*/ +// delete [] Buffer_Send_Gradient; +// +// /*--- Do the coordinate transformation ---*/ +// for (iVertex = 0; iVertex < nVertexR; iVertex++) { +// +// /*--- Find point and its type of transformation ---*/ +// iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); +// iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); +// +// /*--- Retrieve the supplied periodic information. ---*/ +// angles = config->GetPeriodicRotation(iPeriodic_Index); +// +// /*--- Store angles separately for clarity. ---*/ +// theta = angles[0]; phi = angles[1]; psi = angles[2]; +// cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); +// sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); +// +// /*--- Compute the rotation matrix. Note that the implicit +// ordering is rotation about the x-axis, y-axis, +// then z-axis. Note that this is the transpose of the matrix +// used during the preprocessing stage. ---*/ +// rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; +// rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; +// rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; +// +// /*--- Copy conserved variables before performing transformation. ---*/ +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) +// for (iDim = 0; iDim < nDim; iDim++) +// Gradient[iVar][iDim] = Buffer_Receive_Gradient[iDim*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex]; +// +// /*--- Need to rotate the gradients for all conserved variables. ---*/ +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { +// if (nDim == 2) { +// Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex]; +// Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex]; +// } +// else { +// Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][2]*Buffer_Receive_Gradient[2*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex]; +// Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][2]*Buffer_Receive_Gradient[2*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex]; +// Gradient[iVar][2] = rotMatrix[2][0]*Buffer_Receive_Gradient[0*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][1]*Buffer_Receive_Gradient[1*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][2]*Buffer_Receive_Gradient[2*nSecondaryVarGrad*nVertexR+iVar*nVertexR+iVertex]; +// } +// } +// +// /*--- Store the received information ---*/ +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) +// for (iDim = 0; iDim < nDim; iDim++) +// node[iPoint]->SetGradient_Secondary(iVar, iDim, Gradient[iVar][iDim]); +// +// } +// +// /*--- Deallocate receive buffer ---*/ +// delete [] Buffer_Receive_Gradient; +// +// } +// +// } +// +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) +// delete [] Gradient[iVar]; +// delete [] Gradient; +// +//} + +//void CEulerSolver::Set_MPI_Secondary_Limiter(CGeometry *geometry, CConfig *config) { +// unsigned short iVar, iMarker, MarkerS, MarkerR; +// unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; +// su2double *Buffer_Receive_Limit = NULL, *Buffer_Send_Limit = NULL; +// int send_to, receive_from; +// +// su2double *Limiter = new su2double [nSecondaryVarGrad]; +// +//#ifdef HAVE_MPI +// MPI_Status status; +//#endif +// +// for (iMarker = 0; iMarker < nMarker; iMarker++) { +// +// if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && +// (config->GetMarker_All_SendRecv(iMarker) > 0)) { +// +// MarkerS = iMarker; MarkerR = iMarker+1; +// +// send_to = config->GetMarker_All_SendRecv(MarkerS)-1; +// receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +// +// nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; +// nBufferS_Vector = nVertexS*nSecondaryVarGrad; nBufferR_Vector = nVertexR*nSecondaryVarGrad; +// +// /*--- Allocate Receive and send buffers ---*/ +// Buffer_Receive_Limit = new su2double [nBufferR_Vector]; +// Buffer_Send_Limit = new su2double[nBufferS_Vector]; +// +// /*--- Copy the solution old that should be sended ---*/ +// for (iVertex = 0; iVertex < nVertexS; iVertex++) { +// iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) +// Buffer_Send_Limit[iVar*nVertexS+iVertex] = node[iPoint]->GetLimiter_Secondary(iVar); +// } +// +//#ifdef HAVE_MPI +// +// /*--- Send/Receive information using Sendrecv ---*/ +// SU2_MPI::Sendrecv(Buffer_Send_Limit, nBufferS_Vector, MPI_DOUBLE, send_to, 0, +// Buffer_Receive_Limit, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); +// +//#else +// +// /*--- Receive information without MPI ---*/ +// for (iVertex = 0; iVertex < nVertexR; iVertex++) { +// iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) +// Buffer_Receive_Limit[iVar*nVertexR+iVertex] = Buffer_Send_Limit[iVar*nVertexR+iVertex]; +// } +// +//#endif +// +// /*--- Deallocate send buffer ---*/ +// delete [] Buffer_Send_Limit; +// +// /*--- Do the coordinate transformation ---*/ +// for (iVertex = 0; iVertex < nVertexR; iVertex++) { +// +// /*--- Find point and its type of transformation ---*/ +// iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); +// +// /*--- Copy conserved variables before performing transformation. ---*/ +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) +// Limiter[iVar] = Buffer_Receive_Limit[iVar*nVertexR+iVertex]; +// +// /*--- Copy transformed conserved variables back into buffer. ---*/ +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) +// node[iPoint]->SetLimiter_Secondary(iVar, Limiter[iVar]); +// +// } +// +// /*--- Deallocate receive buffer ---*/ +// delete [] Buffer_Receive_Limit; +// +// } +// +// } +// +// delete [] Limiter; +// +//} + +void CEulerSolver::SetNondimensionalization(CGeometry *geometry, CConfig *config, unsigned short iMesh) { + + su2double Temperature_FreeStream = 0.0, Mach2Vel_FreeStream = 0.0, ModVel_FreeStream = 0.0, + Energy_FreeStream = 0.0, ModVel_FreeStreamND = 0.0, Velocity_Reynolds = 0.0, + Omega_FreeStream = 0.0, Omega_FreeStreamND = 0.0, Viscosity_FreeStream = 0.0, + Density_FreeStream = 0.0, Pressure_FreeStream = 0.0, Tke_FreeStream = 0.0, + Length_Ref = 0.0, Density_Ref = 0.0, Pressure_Ref = 0.0, Velocity_Ref = 0.0, + Temperature_Ref = 0.0, Time_Ref = 0.0, Omega_Ref = 0.0, Force_Ref = 0.0, + Gas_Constant_Ref = 0.0, Viscosity_Ref = 0.0, Conductivity_Ref = 0.0, Energy_Ref= 0.0, + Froude = 0.0, Pressure_FreeStreamND = 0.0, Density_FreeStreamND = 0.0, + Temperature_FreeStreamND = 0.0, Gas_ConstantND = 0.0, + Velocity_FreeStreamND[3] = {0.0, 0.0, 0.0}, Viscosity_FreeStreamND = 0.0, + Tke_FreeStreamND = 0.0, Energy_FreeStreamND = 0.0, + Total_UnstTimeND = 0.0, Delta_UnstTimeND = 0.0, TgammaR = 0.0; + + unsigned short iDim; + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Local variables ---*/ + + su2double Alpha = config->GetAoA()*PI_NUMBER/180.0; + su2double Beta = config->GetAoS()*PI_NUMBER/180.0; + su2double Mach = config->GetMach(); + su2double Reynolds = config->GetReynolds(); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool unsteady = (config->GetUnsteady_Simulation() != NO); + bool viscous = config->GetViscous(); + bool grid_movement = config->GetGrid_Movement(); + bool gravity = config->GetGravityForce(); + bool turbulent = (config->GetKind_Solver() == RANS) || (config->GetKind_Solver() == DISC_ADJ_RANS); + bool tkeNeeded = ((turbulent) && (config->GetKind_Turb_Model() == SST)); + bool free_stream_temp = (config->GetKind_FreeStreamOption() == TEMPERATURE_FS); + bool standard_air = (config->GetKind_FluidModel() == STANDARD_AIR); + bool reynolds_init = (config->GetKind_InitOption() == REYNOLDS); + bool aeroelastic = config->GetAeroelastic_Simulation(); + + /*--- Set temperature via the flutter speed index ---*/ + if (aeroelastic) { + su2double vf = config->GetAeroelastic_Flutter_Speed_Index(); + su2double w_alpha = config->GetAeroelastic_Frequency_Pitch(); + su2double b = config->GetLength_Reynolds()/2.0; // airfoil semichord, Reynolds length is by defaul 1.0 + su2double mu = config->GetAeroelastic_Airfoil_Mass_Ratio(); + // The temperature times gamma times the gas constant. Depending on the FluidModel temp is calculated below. + TgammaR = ((vf*vf)*(b*b)*(w_alpha*w_alpha)*mu) / (Mach*Mach); + } + + /*--- Compressible non dimensionalization ---*/ + + if (compressible) { + + /*--- Compute the Free Stream velocity, using the Mach number ---*/ + + Pressure_FreeStream = config->GetPressure_FreeStream(); + Density_FreeStream = config->GetDensity_FreeStream(); + Temperature_FreeStream = config->GetTemperature_FreeStream(); + + switch (config->GetKind_FluidModel()) { + + case STANDARD_AIR: + + if (config->GetSystemMeasurements() == SI) config->SetGas_Constant(287.058); + else if (config->GetSystemMeasurements() == US) config->SetGas_Constant(1716.49); + + FluidModel = new CIdealGas(1.4, config->GetGas_Constant()); + if (free_stream_temp) { + if (aeroelastic) { + Temperature_FreeStream = TgammaR / (config->GetGas_Constant()*1.4); + config->SetTemperature_FreeStream(Temperature_FreeStream); + } + FluidModel->SetTDState_PT(Pressure_FreeStream, Temperature_FreeStream); + Density_FreeStream = FluidModel->GetDensity(); + config->SetDensity_FreeStream(Density_FreeStream); + } + else { + FluidModel->SetTDState_Prho(Pressure_FreeStream, Density_FreeStream ); + Temperature_FreeStream = FluidModel->GetTemperature(); + config->SetTemperature_FreeStream(Temperature_FreeStream); + } + break; + + case IDEAL_GAS: + + FluidModel = new CIdealGas(Gamma, config->GetGas_Constant()); + if (free_stream_temp) { + FluidModel->SetTDState_PT(Pressure_FreeStream, Temperature_FreeStream); + Density_FreeStream = FluidModel->GetDensity(); + config->SetDensity_FreeStream(Density_FreeStream); + } + else { + FluidModel->SetTDState_Prho(Pressure_FreeStream, Density_FreeStream ); + Temperature_FreeStream = FluidModel->GetTemperature(); + config->SetTemperature_FreeStream(Temperature_FreeStream); + } + break; + + case VW_GAS: + + FluidModel = new CVanDerWaalsGas(Gamma, config->GetGas_Constant(), + config->GetPressure_Critical(), config->GetTemperature_Critical()); + if (free_stream_temp) { + FluidModel->SetTDState_PT(Pressure_FreeStream, Temperature_FreeStream); + Density_FreeStream = FluidModel->GetDensity(); + config->SetDensity_FreeStream(Density_FreeStream); + } + else { + FluidModel->SetTDState_Prho(Pressure_FreeStream, Density_FreeStream ); + Temperature_FreeStream = FluidModel->GetTemperature(); + config->SetTemperature_FreeStream(Temperature_FreeStream); + } + break; + + case PR_GAS: + + FluidModel = new CPengRobinson(Gamma, config->GetGas_Constant(), config->GetPressure_Critical(), + config->GetTemperature_Critical(), config->GetAcentric_Factor()); + if (free_stream_temp) { + FluidModel->SetTDState_PT(Pressure_FreeStream, Temperature_FreeStream); + Density_FreeStream = FluidModel->GetDensity(); + config->SetDensity_FreeStream(Density_FreeStream); + } + else { + FluidModel->SetTDState_Prho(Pressure_FreeStream, Density_FreeStream ); + Temperature_FreeStream = FluidModel->GetTemperature(); + config->SetTemperature_FreeStream(Temperature_FreeStream); + } + break; + + } + + Mach2Vel_FreeStream = FluidModel->GetSoundSpeed(); + + /*--- Compute the Free Stream velocity, using the Mach number ---*/ + + if (nDim == 2) { + config->GetVelocity_FreeStream()[0] = cos(Alpha)*Mach*Mach2Vel_FreeStream; + config->GetVelocity_FreeStream()[1] = sin(Alpha)*Mach*Mach2Vel_FreeStream; + } + if (nDim == 3) { + config->GetVelocity_FreeStream()[0] = cos(Alpha)*cos(Beta)*Mach*Mach2Vel_FreeStream; + config->GetVelocity_FreeStream()[1] = sin(Beta)*Mach*Mach2Vel_FreeStream; + config->GetVelocity_FreeStream()[2] = sin(Alpha)*cos(Beta)*Mach*Mach2Vel_FreeStream; + } + + /*--- Compute the modulus of the free stream velocity ---*/ + + ModVel_FreeStream = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + ModVel_FreeStream += config->GetVelocity_FreeStream()[iDim]*config->GetVelocity_FreeStream()[iDim]; + ModVel_FreeStream = sqrt(ModVel_FreeStream); config->SetModVel_FreeStream(ModVel_FreeStream); + + /*--- Viscous initialization ---*/ + + if (viscous) { + + /*--- Reynolds based initialization ---*/ + + if (reynolds_init) { + + /*--- First, check if there is mesh motion. If yes, use the Mach + number relative to the body to initialize the flow. ---*/ + + if (grid_movement) Velocity_Reynolds = config->GetMach_Motion()*Mach2Vel_FreeStream; + else Velocity_Reynolds = ModVel_FreeStream; + + /*--- Change of measurement system, hard coded value working only with STANDAR AIR model ---*/ + + if (standard_air) { + if (config->GetSystemMeasurements() == SI) { + config->SetMu_RefND(1.716E-5); + config->SetMu_SND(110.4); + config->SetMu_Temperature_RefND(273.15); + } + if (config->GetSystemMeasurements() == US) { + config->SetMu_RefND(3.62E-7); + config->SetMu_SND(198.72); + config->SetMu_Temperature_RefND(518.7); + } + } + + /*--- For viscous flows, pressure will be computed from a density + that is found from the Reynolds number. The viscosity is computed + from the dimensional version of Sutherland's law ---*/ + + FluidModel->SetLaminarViscosityModel(config); + + Viscosity_FreeStream = FluidModel->GetLaminarViscosity(); + config->SetViscosity_FreeStream(Viscosity_FreeStream); + + Density_FreeStream = Reynolds*Viscosity_FreeStream/(Velocity_Reynolds*config->GetLength_Reynolds()); + config->SetDensity_FreeStream(Density_FreeStream); + FluidModel->SetTDState_rhoT(Density_FreeStream, Temperature_FreeStream); + Pressure_FreeStream = FluidModel->GetPressure(); + config->SetPressure_FreeStream(Pressure_FreeStream); + Energy_FreeStream = FluidModel->GetStaticEnergy() + 0.5*ModVel_FreeStream*ModVel_FreeStream; + + } + + /*--- Thermodynamics quantities based initialization ---*/ + + else { + + FluidModel->SetLaminarViscosityModel(config); + Viscosity_FreeStream = FluidModel->GetLaminarViscosity(); + config->SetViscosity_FreeStream(Viscosity_FreeStream); + Energy_FreeStream = FluidModel->GetStaticEnergy() + 0.5*ModVel_FreeStream*ModVel_FreeStream; + + } + + /*--- Turbulence kinetic energy ---*/ + + Tke_FreeStream = 3.0/2.0*(ModVel_FreeStream*ModVel_FreeStream*config->GetTurbulenceIntensity_FreeStream()*config->GetTurbulenceIntensity_FreeStream()); + + } + else { + + /*--- For inviscid flow, energy is calculated from the specified + FreeStream quantities using the proper gas law. ---*/ + + Energy_FreeStream = FluidModel->GetStaticEnergy() + 0.5*ModVel_FreeStream*ModVel_FreeStream; + + } + + /*-- Compute the freestream energy. ---*/ + + if (tkeNeeded) { Energy_FreeStream += Tke_FreeStream; }; config->SetEnergy_FreeStream(Energy_FreeStream); + + /*--- Compute non dimensional quantities. By definition, + Lref is one because we have converted the grid to meters. ---*/ + + if (config->GetRef_NonDim() == DIMENSIONAL) { + Pressure_Ref = 1.0; + Density_Ref = 1.0; + Temperature_Ref = 1.0; + } + else if (config->GetRef_NonDim() == FREESTREAM_PRESS_EQ_ONE) { + Pressure_Ref = Pressure_FreeStream; // Pressure_FreeStream = 1.0 + Density_Ref = Density_FreeStream; // Density_FreeStream = 1.0 + Temperature_Ref = Temperature_FreeStream; // Temperature_FreeStream = 1.0 + } + else if (config->GetRef_NonDim() == FREESTREAM_VEL_EQ_MACH) { + Pressure_Ref = Gamma*Pressure_FreeStream; // Pressure_FreeStream = 1.0/Gamma + Density_Ref = Density_FreeStream; // Density_FreeStream = 1.0 + Temperature_Ref = Temperature_FreeStream; // Temp_FreeStream = 1.0 + } + else if (config->GetRef_NonDim() == FREESTREAM_VEL_EQ_ONE) { + Pressure_Ref = Mach*Mach*Gamma*Pressure_FreeStream; // Pressure_FreeStream = 1.0/(Gamma*(M_inf)^2) + Density_Ref = Density_FreeStream; // Density_FreeStream = 1.0 + Temperature_Ref = Temperature_FreeStream; // Temp_FreeStream = 1.0 + } + config->SetPressure_Ref(Pressure_Ref); + config->SetDensity_Ref(Density_Ref); + config->SetTemperature_Ref(Temperature_Ref); + + Length_Ref = 1.0; config->SetLength_Ref(Length_Ref); + Velocity_Ref = sqrt(config->GetPressure_Ref()/config->GetDensity_Ref()); config->SetVelocity_Ref(Velocity_Ref); + Time_Ref = Length_Ref/Velocity_Ref; config->SetTime_Ref(Time_Ref); + Omega_Ref = Velocity_Ref/Length_Ref; config->SetOmega_Ref(Omega_Ref); + Force_Ref = Velocity_Ref*Velocity_Ref/Length_Ref; config->SetForce_Ref(Force_Ref); + Gas_Constant_Ref = Velocity_Ref*Velocity_Ref/config->GetTemperature_Ref(); config->SetGas_Constant_Ref(Gas_Constant_Ref); + Viscosity_Ref = config->GetDensity_Ref()*Velocity_Ref*Length_Ref; config->SetViscosity_Ref(Viscosity_Ref); + Conductivity_Ref = Viscosity_Ref*Gas_Constant_Ref; config->SetConductivity_Ref(Conductivity_Ref); + Froude = ModVel_FreeStream/sqrt(STANDART_GRAVITY*Length_Ref); config->SetFroude(Froude); + + } + + /*--- Incompressible non dimensionalization ---*/ + + else { + + /*--- Reference length = 1 (by default) + Reference density = liquid density or freestream + Reference viscosity = liquid viscosity or freestream + Reference velocity = liquid velocity or freestream + Reference pressure = Reference density * Reference velocity * Reference velocity + Reynolds number based on the liquid or reference viscosity ---*/ + + Pressure_FreeStream = 0.0; config->SetPressure_FreeStream(Pressure_FreeStream); + Density_FreeStream = config->GetDensity_FreeStream(); + ModVel_FreeStream = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + ModVel_FreeStream += config->GetVelocity_FreeStream()[iDim]*config->GetVelocity_FreeStream()[iDim]; + ModVel_FreeStream = sqrt(ModVel_FreeStream); config->SetModVel_FreeStream(ModVel_FreeStream); + + /*--- Additional reference values defined by Pref, Tref, Rho_ref. By definition, + Lref is one because we have converted the grid to meters.---*/ + + Length_Ref = config->GetLength_Reynolds(); config->SetLength_Ref(Length_Ref); + Density_Ref = Density_FreeStream; config->SetDensity_Ref(Density_Ref); + Velocity_Ref = ModVel_FreeStream; config->SetVelocity_Ref(Velocity_Ref); + Pressure_Ref = Density_Ref*(Velocity_Ref*Velocity_Ref); config->SetPressure_Ref(Pressure_Ref); + + if (viscous) { + Viscosity_FreeStream = config->GetViscosity_FreeStream(); + Reynolds = Density_Ref*Velocity_Ref*Length_Ref / Viscosity_FreeStream; config->SetReynolds(Reynolds); + Viscosity_Ref = Viscosity_FreeStream * Reynolds; config->SetViscosity_Ref(Viscosity_Ref); + } + + /*--- Compute Mach number ---*/ + + Mach = ModVel_FreeStream / sqrt(config->GetBulk_Modulus()/Density_FreeStream); config->SetMach(Mach); + + /*--- Compute Alpha angle ---*/ + + if (nDim == 2) Alpha = atan(config->GetVelocity_FreeStream()[1]/config->GetVelocity_FreeStream()[0])*180.0/PI_NUMBER; + else Alpha = atan(config->GetVelocity_FreeStream()[2]/config->GetVelocity_FreeStream()[0])*180.0/PI_NUMBER; + config->SetAoA(Alpha); + + /*--- Compute Beta angle ---*/ + + if (nDim == 2) Beta = 0.0; + else Beta = asin(config->GetVelocity_FreeStream()[1]/ModVel_FreeStream)*180.0/PI_NUMBER; + config->SetAoS(Beta); + + /*--- Compute Froude ---*/ + + Froude = ModVel_FreeStream/sqrt(STANDART_GRAVITY*Length_Ref); config->SetFroude(Froude); + Time_Ref = Length_Ref/Velocity_Ref; config->SetTime_Ref(Time_Ref); + + } + + /*--- Divide by reference values, to compute the non-dimensional free-stream values ---*/ + + Pressure_FreeStreamND = Pressure_FreeStream/config->GetPressure_Ref(); config->SetPressure_FreeStreamND(Pressure_FreeStreamND); + Density_FreeStreamND = Density_FreeStream/config->GetDensity_Ref(); config->SetDensity_FreeStreamND(Density_FreeStreamND); + + for (iDim = 0; iDim < nDim; iDim++) { + Velocity_FreeStreamND[iDim] = config->GetVelocity_FreeStream()[iDim]/Velocity_Ref; config->SetVelocity_FreeStreamND(Velocity_FreeStreamND[iDim], iDim); + } + + Temperature_FreeStreamND = Temperature_FreeStream/config->GetTemperature_Ref(); config->SetTemperature_FreeStreamND(Temperature_FreeStreamND); + + Gas_ConstantND = config->GetGas_Constant()/Gas_Constant_Ref; config->SetGas_ConstantND(Gas_ConstantND); + + + ModVel_FreeStreamND = 0.0; + for (iDim = 0; iDim < nDim; iDim++) ModVel_FreeStreamND += Velocity_FreeStreamND[iDim]*Velocity_FreeStreamND[iDim]; + ModVel_FreeStreamND = sqrt(ModVel_FreeStreamND); config->SetModVel_FreeStreamND(ModVel_FreeStreamND); + + Viscosity_FreeStreamND = Viscosity_FreeStream / Viscosity_Ref; config->SetViscosity_FreeStreamND(Viscosity_FreeStreamND); + + Tke_FreeStream = 3.0/2.0*(ModVel_FreeStream*ModVel_FreeStream*config->GetTurbulenceIntensity_FreeStream()*config->GetTurbulenceIntensity_FreeStream()); + config->SetTke_FreeStream(Tke_FreeStream); + + Tke_FreeStreamND = 3.0/2.0*(ModVel_FreeStreamND*ModVel_FreeStreamND*config->GetTurbulenceIntensity_FreeStream()*config->GetTurbulenceIntensity_FreeStream()); + config->SetTke_FreeStreamND(Tke_FreeStreamND); + + Omega_FreeStream = Density_FreeStream*Tke_FreeStream/(Viscosity_FreeStream*config->GetTurb2LamViscRatio_FreeStream()); + config->SetOmega_FreeStream(Omega_FreeStream); + + Omega_FreeStreamND = Density_FreeStreamND*Tke_FreeStreamND/(Viscosity_FreeStreamND*config->GetTurb2LamViscRatio_FreeStream()); + config->SetOmega_FreeStreamND(Omega_FreeStreamND); + + /*--- Initialize the dimensionless Fluid Model that will be used to solve the dimensionless problem ---*/ + + switch (config->GetKind_FluidModel()) { + + case STANDARD_AIR: + FluidModel = new CIdealGas(1.4, Gas_ConstantND); + FluidModel->SetEnergy_Prho(Pressure_FreeStreamND, Density_FreeStreamND); + break; + + case IDEAL_GAS: + FluidModel = new CIdealGas(Gamma, Gas_ConstantND); + FluidModel->SetEnergy_Prho(Pressure_FreeStreamND, Density_FreeStreamND); + break; + + case VW_GAS: + FluidModel = new CVanDerWaalsGas(Gamma, Gas_ConstantND, config->GetPressure_Critical() /config->GetPressure_Ref(), + config->GetTemperature_Critical()/config->GetTemperature_Ref()); + FluidModel->SetEnergy_Prho(Pressure_FreeStreamND, Density_FreeStreamND); + break; + + case PR_GAS: + FluidModel = new CPengRobinson(Gamma, Gas_ConstantND, config->GetPressure_Critical() /config->GetPressure_Ref(), + config->GetTemperature_Critical()/config->GetTemperature_Ref(), config->GetAcentric_Factor()); + FluidModel->SetEnergy_Prho(Pressure_FreeStreamND, Density_FreeStreamND); + break; + + } + + Energy_FreeStreamND = FluidModel->GetStaticEnergy() + 0.5*ModVel_FreeStreamND*ModVel_FreeStreamND; + + if (viscous) { + + /*--- Constant viscosity model ---*/ + config->SetMu_ConstantND(config->GetMu_ConstantND()/Viscosity_Ref); + + /*--- Sutherland's model ---*/ + + config->SetMu_RefND(config->GetMu_RefND()/Viscosity_Ref); + config->SetMu_SND(config->GetMu_SND()/config->GetTemperature_Ref()); + config->SetMu_Temperature_RefND(config->GetMu_Temperature_RefND()/config->GetTemperature_Ref()); + + /* constant thermal conductivity model */ + config->SetKt_ConstantND(config->GetKt_ConstantND()/Conductivity_Ref); + + FluidModel->SetLaminarViscosityModel(config); + FluidModel->SetThermalConductivityModel(config); + + } + + if (tkeNeeded) { Energy_FreeStreamND += Tke_FreeStreamND; }; config->SetEnergy_FreeStreamND(Energy_FreeStreamND); + + Energy_Ref = Energy_FreeStream/Energy_FreeStreamND; config->SetEnergy_Ref(Energy_Ref); + + Total_UnstTimeND = config->GetTotal_UnstTime() / Time_Ref; config->SetTotal_UnstTimeND(Total_UnstTimeND); + Delta_UnstTimeND = config->GetDelta_UnstTime() / Time_Ref; config->SetDelta_UnstTimeND(Delta_UnstTimeND); + + /*--- Write output to the console if this is the master node and first domain ---*/ + + if ((rank == MASTER_NODE) && (iMesh == MESH_0)) { + + cout.precision(6); + + if (compressible) { + if (viscous) { + cout << "Viscous flow: Computing pressure using the ideal gas law" << endl; + cout << "based on the free-stream temperature and a density computed" << endl; + cout << "from the Reynolds number." << endl; + } else { + cout << "Inviscid flow: Computing density based on free-stream" << endl; + cout << "temperature and pressure using the ideal gas law." << endl; + } + } + + if (grid_movement) cout << "Force coefficients computed using MACH_MOTION." << endl; + else cout << "Force coefficients computed using free-stream values." << endl; + + if (incompressible || freesurface) { + cout << "Viscous and Inviscid flow: rho_ref, and vel_ref" << endl; + cout << "are based on the free-stream values, p_ref = rho_ref*vel_ref^2." << endl; + cout << "The free-stream value of the pressure is 0." << endl; + cout << "Mach number: "<< config->GetMach() << ", computed using the Bulk modulus." << endl; + cout << "Angle of attack (deg): "<< config->GetAoA() << ", computed using the the free-stream velocity." << endl; + cout << "Side slip angle (deg): "<< config->GetAoS() << ", computed using the the free-stream velocity." << endl; + if (viscous) cout << "Reynolds number: " << config->GetReynolds() << ", computed using free-stream values."<< endl; + cout << "Only dimensional computation, the grid should be dimensional." << endl; + } + + cout <<"-- Input conditions:"<< endl; + + if (compressible) { + switch (config->GetKind_FluidModel()) { + + case STANDARD_AIR: + cout << "Fluid Model: STANDARD_AIR "<< endl; + cout << "Specific gas constant: " << config->GetGas_Constant(); + if (config->GetSystemMeasurements() == SI) cout << " N.m/kg.K." << endl; + else if (config->GetSystemMeasurements() == US) cout << " lbf.ft/slug.R." << endl; + cout << "Specific gas constant (non-dim): " << config->GetGas_ConstantND()<< endl; + cout << "Specific Heat Ratio: "<< Gamma << endl; + break; + + case IDEAL_GAS: + cout << "Fluid Model: IDEAL_GAS "<< endl; + cout << "Specific gas constant: " << config->GetGas_Constant() << " N.m/kg.K." << endl; + cout << "Specific gas constant (non-dim): " << config->GetGas_ConstantND()<< endl; + cout << "Specific Heat Ratio: "<< Gamma << endl; + break; + + case VW_GAS: + cout << "Fluid Model: Van der Waals "<< endl; + cout << "Specific gas constant: " << config->GetGas_Constant() << " N.m/kg.K." << endl; + cout << "Specific gas constant (non-dim): " << config->GetGas_ConstantND()<< endl; + cout << "Specific Heat Ratio: "<< Gamma << endl; + cout << "Critical Pressure: " << config->GetPressure_Critical() << " Pa." << endl; + cout << "Critical Temperature: " << config->GetTemperature_Critical() << " K." << endl; + cout << "Critical Pressure (non-dim): " << config->GetPressure_Critical() /config->GetPressure_Ref() << endl; + cout << "Critical Temperature (non-dim) : " << config->GetTemperature_Critical() /config->GetTemperature_Ref() << endl; + break; + + case PR_GAS: + cout << "Fluid Model: Peng-Robinson "<< endl; + cout << "Specific gas constant: " << config->GetGas_Constant() << " N.m/kg.K." << endl; + cout << "Specific gas constant (non-dim): " << config->GetGas_ConstantND()<< endl; + cout << "Specific Heat Ratio: "<< Gamma << endl; + cout << "Critical Pressure: " << config->GetPressure_Critical() << " Pa." << endl; + cout << "Critical Temperature: " << config->GetTemperature_Critical() << " K." << endl; + cout << "Critical Pressure (non-dim): " << config->GetPressure_Critical() /config->GetPressure_Ref() << endl; + cout << "Critical Temperature (non-dim) : " << config->GetTemperature_Critical() /config->GetTemperature_Ref() << endl; + break; + + } + if (viscous) { + switch (config->GetKind_ViscosityModel()) { + + case CONSTANT_VISCOSITY: + cout << "Viscosity Model: CONSTANT_VISCOSITY "<< endl; + cout << "Laminar Viscosity: " << config->GetMu_ConstantND()*Viscosity_Ref; + if (config->GetSystemMeasurements() == SI) cout << " N.s/m^2." << endl; + else if (config->GetSystemMeasurements() == US) cout << " lbf.s/ft^2." << endl; + cout << "Laminar Viscosity (non-dim): " << config->GetMu_ConstantND()<< endl; + break; + + case SUTHERLAND: + cout << "Viscosity Model: SUTHERLAND "<< endl; + cout << "Ref. Laminar Viscosity: " << config->GetMu_RefND()*Viscosity_Ref; + if (config->GetSystemMeasurements() == SI) cout << " N.s/m^2." << endl; + else if (config->GetSystemMeasurements() == US) cout << " lbf.s/ft^2." << endl; + cout << "Ref. Temperature: " << config->GetMu_Temperature_RefND()*config->GetTemperature_Ref(); + if (config->GetSystemMeasurements() == SI) cout << " K." << endl; + else if (config->GetSystemMeasurements() == US) cout << " R." << endl; + cout << "Sutherland Constant: "<< config->GetMu_SND()*config->GetTemperature_Ref(); + if (config->GetSystemMeasurements() == SI) cout << " K." << endl; + else if (config->GetSystemMeasurements() == US) cout << " R." << endl; + cout << "Laminar Viscosity (non-dim): " << config->GetMu_ConstantND()<< endl; + cout << "Ref. Temperature (non-dim): " << config->GetMu_Temperature_RefND()<< endl; + cout << "Sutherland constant (non-dim): "<< config->GetMu_SND()<< endl; + break; + + } + switch (config->GetKind_ConductivityModel()) { + + case CONSTANT_PRANDTL: + cout << "Conductivity Model: CONSTANT_PRANDTL "<< endl; + cout << "Prandtl: " << config->GetPrandtl_Lam()<< endl; + break; + + case CONSTANT_CONDUCTIVITY: + cout << "Conductivity Model: CONSTANT_CONDUCTIVITY "<< endl; + cout << "Molecular Conductivity: " << config->GetKt_ConstantND()*Conductivity_Ref<< " W/m^2.K." << endl; + cout << "Molecular Conductivity (non-dim): " << config->GetKt_ConstantND()<< endl; + break; + + } + } + } + + if (incompressible || freesurface) { + cout << "Bulk modulus: " << config->GetBulk_Modulus(); + if (config->GetSystemMeasurements() == SI) cout << " Pa." << endl; + else if (config->GetSystemMeasurements() == US) cout << " psf." << endl; + cout << "Artificial compressibility factor: " << config->GetArtComp_Factor(); + if (config->GetSystemMeasurements() == SI) cout << " Pa." << endl; + else if (config->GetSystemMeasurements() == US) cout << " psf." << endl; + } + + cout << "Free-stream static pressure: " << config->GetPressure_FreeStream(); + if (config->GetSystemMeasurements() == SI) cout << " Pa." << endl; + else if (config->GetSystemMeasurements() == US) cout << " psf." << endl; + + cout << "Free-stream total pressure: " << config->GetPressure_FreeStream() * pow( 1.0+Mach*Mach*0.5*(Gamma-1.0), Gamma/(Gamma-1.0) ); + if (config->GetSystemMeasurements() == SI) cout << " Pa." << endl; + else if (config->GetSystemMeasurements() == US) cout << " psf." << endl; + + if (compressible) { + cout << "Free-stream temperature: " << config->GetTemperature_FreeStream(); + if (config->GetSystemMeasurements() == SI) cout << " K." << endl; + else if (config->GetSystemMeasurements() == US) cout << " R." << endl; + } + + cout << "Free-stream density: " << config->GetDensity_FreeStream(); + if (config->GetSystemMeasurements() == SI) cout << " kg/m^3." << endl; + else if (config->GetSystemMeasurements() == US) cout << " slug/ft^3." << endl; + + if (nDim == 2) { + cout << "Free-stream velocity: (" << config->GetVelocity_FreeStream()[0] << ", "; + cout << config->GetVelocity_FreeStream()[1] << ")"; + } + if (nDim == 3) { + cout << "Free-stream velocity: (" << config->GetVelocity_FreeStream()[0] << ", "; + cout << config->GetVelocity_FreeStream()[1] << ", " << config->GetVelocity_FreeStream()[2] << ")"; + } + if (config->GetSystemMeasurements() == SI) cout << " m/s. "; + else if (config->GetSystemMeasurements() == US) cout << " ft/s. "; + + cout << "Magnitude: " << config->GetModVel_FreeStream(); + if (config->GetSystemMeasurements() == SI) cout << " m/s." << endl; + else if (config->GetSystemMeasurements() == US) cout << " ft/s." << endl; + + if (compressible) { + cout << "Free-stream total energy per unit mass: " << config->GetEnergy_FreeStream(); + if (config->GetSystemMeasurements() == SI) cout << " m^2/s^2." << endl; + else if (config->GetSystemMeasurements() == US) cout << " ft^2/s^2." << endl; + } + + if (viscous) { + cout << "Free-stream viscosity: " << config->GetViscosity_FreeStream(); + if (config->GetSystemMeasurements() == SI) cout << " N.s/m^2." << endl; + else if (config->GetSystemMeasurements() == US) cout << " lbf.s/ft^2." << endl; + if (turbulent) { + cout << "Free-stream turb. kinetic energy per unit mass: " << config->GetTke_FreeStream(); + if (config->GetSystemMeasurements() == SI) cout << " m^2/s^2." << endl; + else if (config->GetSystemMeasurements() == US) cout << " ft^2/s^2." << endl; + cout << "Free-stream specific dissipation: " << config->GetOmega_FreeStream(); + if (config->GetSystemMeasurements() == SI) cout << " 1/s." << endl; + else if (config->GetSystemMeasurements() == US) cout << " 1/s." << endl; + } + } + + if (unsteady) { cout << "Total time: " << config->GetTotal_UnstTime() << " s. Time step: " << config->GetDelta_UnstTime() << " s." << endl; } + + /*--- Print out reference values. ---*/ + + cout <<"-- Reference values:"<< endl; + + if (compressible) { + cout << "Reference specific gas constant: " << config->GetGas_Constant_Ref(); + if (config->GetSystemMeasurements() == SI) cout << " N.m/kg.K." << endl; + else if (config->GetSystemMeasurements() == US) cout << " lbf.ft/slug.R." << endl; + } + + cout << "Reference pressure: " << config->GetPressure_Ref(); + if (config->GetSystemMeasurements() == SI) cout << " Pa." << endl; + else if (config->GetSystemMeasurements() == US) cout << " psf." << endl; + + if (compressible) { + cout << "Reference temperature: " << config->GetTemperature_Ref(); + if (config->GetSystemMeasurements() == SI) cout << " K." << endl; + else if (config->GetSystemMeasurements() == US) cout << " R." << endl; + } + + cout << "Reference density: " << config->GetDensity_Ref(); + if (config->GetSystemMeasurements() == SI) cout << " kg/m^3." << endl; + else if (config->GetSystemMeasurements() == US) cout << " slug/ft^3." << endl; + + cout << "Reference velocity: " << config->GetVelocity_Ref(); + if (config->GetSystemMeasurements() == SI) cout << " m/s." << endl; + else if (config->GetSystemMeasurements() == US) cout << " ft/s." << endl; + + if (compressible) { + cout << "Reference energy per unit mass: " << config->GetEnergy_Ref(); + if (config->GetSystemMeasurements() == SI) cout << " m^2/s^2." << endl; + else if (config->GetSystemMeasurements() == US) cout << " ft^2/s^2." << endl; + } + + if (incompressible || freesurface) { + cout << "Reference length: " << config->GetLength_Ref(); + if (config->GetSystemMeasurements() == SI) cout << " m." << endl; + else if (config->GetSystemMeasurements() == US) cout << " in." << endl; + } + + if (viscous) { + cout << "Reference viscosity: " << config->GetViscosity_Ref(); + if (config->GetSystemMeasurements() == SI) cout << " N.s/m^2." << endl; + else if (config->GetSystemMeasurements() == US) cout << " lbf.s/ft^2." << endl; + if (compressible){ + cout << "Reference conductivity: " << config->GetConductivity_Ref(); + if (config->GetSystemMeasurements() == SI) cout << " W/m^2.K." << endl; + else if (config->GetSystemMeasurements() == US) cout << " lbf/ft.s.R." << endl; + } + } + + + if (unsteady) cout << "Reference time: " << config->GetTime_Ref() <<" s." << endl; + + /*--- Print out resulting non-dim values here. ---*/ + + cout << "-- Resulting non-dimensional state:" << endl; + cout << "Mach number (non-dim): " << config->GetMach() << endl; + if (viscous) { + cout << "Reynolds number (non-dim): " << config->GetReynolds() <<". Re length: " << config->GetLength_Reynolds(); + if (config->GetSystemMeasurements() == SI) cout << " m." << endl; + else if (config->GetSystemMeasurements() == US) cout << " ft." << endl; + } + if (gravity) { + cout << "Froude number (non-dim): " << Froude << endl; + cout << "Lenght of the baseline wave (non-dim): " << 2.0*PI_NUMBER*Froude*Froude << endl; + } + + if (compressible) { + cout << "Specific gas constant (non-dim): " << config->GetGas_ConstantND() << endl; + cout << "Free-stream temperature (non-dim): " << config->GetTemperature_FreeStreamND() << endl; + } + + cout << "Free-stream pressure (non-dim): " << config->GetPressure_FreeStreamND() << endl; + + cout << "Free-stream density (non-dim): " << config->GetDensity_FreeStreamND() << endl; + + if (nDim == 2) { + cout << "Free-stream velocity (non-dim): (" << config->GetVelocity_FreeStreamND()[0] << ", "; + cout << config->GetVelocity_FreeStreamND()[1] << "). "; + } else { + cout << "Free-stream velocity (non-dim): (" << config->GetVelocity_FreeStreamND()[0] << ", "; + cout << config->GetVelocity_FreeStreamND()[1] << ", " << config->GetVelocity_FreeStreamND()[2] << "). "; + } + cout << "Magnitude: " << config->GetModVel_FreeStreamND() << endl; + + if (compressible) + cout << "Free-stream total energy per unit mass (non-dim): " << config->GetEnergy_FreeStreamND() << endl; + + if (viscous) { + cout << "Free-stream viscosity (non-dim): " << config->GetViscosity_FreeStreamND() << endl; + if (turbulent) { + cout << "Free-stream turb. kinetic energy (non-dim): " << config->GetTke_FreeStreamND() << endl; + cout << "Free-stream specific dissipation (non-dim): " << config->GetOmega_FreeStreamND() << endl; + } + } + + if (unsteady) { + cout << "Total time (non-dim): " << config->GetTotal_UnstTimeND() << endl; + cout << "Time step (non-dim): " << config->GetDelta_UnstTimeND() << endl; + } + + cout << endl; + + } + +} + +void CEulerSolver::SetInitialCondition(CGeometry **geometry, CSolver ***solver_container, CConfig *config, unsigned long ExtIter) { + + unsigned long iPoint, Point_Fine; + unsigned short iMesh, iChildren, iVar, iDim; + su2double Density, Pressure, yFreeSurface, PressFreeSurface, Froude, yCoord, Velx, Vely, Velz, RhoVelx, RhoVely, RhoVelz, YCoord = 0.0, + ZCoord = 0.0, DensityInc, ViscosityInc, Heaviside, LevelSet, lambda, Area_Children, Area_Parent, LevelSet_Fine, epsilon, + *Solution_Fine, *Solution, PressRef, yCoordRef; + + unsigned short nDim = geometry[MESH_0]->GetnDim(); + bool restart = (config->GetRestart() || config->GetRestart_Flow()); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool rans = ((config->GetKind_Solver() == RANS) || + (config->GetKind_Solver() == ADJ_RANS) || + (config->GetKind_Solver() == DISC_ADJ_RANS)); + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + bool gravity = (config->GetGravityForce() == YES); + bool engine_intake = config->GetEngine_Intake(); + + + /*--- Set the location and value of the free-surface ---*/ + + if (freesurface) { + + for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { + + for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { + + /*--- Set initial boundary condition at iter 0 ---*/ + + if ((ExtIter == 0) && (!restart)) { + + /*--- Compute the level set value in all the MG levels (basic case, distance to + the Y/Z plane, and interpolate the solution to the coarse levels ---*/ + + if (iMesh == MESH_0) { + YCoord = geometry[iMesh]->node[iPoint]->GetCoord(1); + if (nDim == 2) LevelSet = YCoord - config->GetFreeSurface_Zero(); + else { + ZCoord = geometry[iMesh]->node[iPoint]->GetCoord(2); + LevelSet = ZCoord - config->GetFreeSurface_Zero(); + } + solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(nDim+1, LevelSet); + } + else { + Area_Parent = geometry[iMesh]->node[iPoint]->GetVolume(); + LevelSet = 0.0; + for (iChildren = 0; iChildren < geometry[iMesh]->node[iPoint]->GetnChildren_CV(); iChildren++) { + Point_Fine = geometry[iMesh]->node[iPoint]->GetChildren_CV(iChildren); + Area_Children = geometry[iMesh-1]->node[Point_Fine]->GetVolume(); + LevelSet_Fine = solver_container[iMesh-1][FLOW_SOL]->node[Point_Fine]->GetSolution(nDim+1); + LevelSet += LevelSet_Fine*Area_Children/Area_Parent; + } + solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(nDim+1, LevelSet); + } + + /*--- Compute the flow solution using the level set value. ---*/ + + epsilon = config->GetFreeSurface_Thickness(); + Heaviside = 0.0; + if (LevelSet < -epsilon) Heaviside = 1.0; + if (fabs(LevelSet) <= epsilon) Heaviside = 1.0 - (0.5*(1.0+(LevelSet/epsilon)+(1.0/PI_NUMBER)*sin(PI_NUMBER*LevelSet/epsilon))); + if (LevelSet > epsilon) Heaviside = 0.0; + + /*--- Set the value of the incompressible density for free surface flows (density ratio g/l) ---*/ + + lambda = config->GetRatioDensity(); + DensityInc = (lambda + (1.0 - lambda)*Heaviside)*config->GetDensity_FreeStreamND(); + solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetDensityInc(DensityInc); + + /*--- Set the value of the incompressible viscosity for free surface flows (viscosity ratio g/l) ---*/ + + lambda = config->GetRatioViscosity(); + ViscosityInc = (lambda + (1.0 - lambda)*Heaviside)*config->GetViscosity_FreeStreamND(); + solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetLaminarViscosityInc(ViscosityInc); + + /*--- Update solution with the new pressure ---*/ + + yFreeSurface = config->GetFreeSurface_Zero(); + PressFreeSurface = solver_container[iMesh][FLOW_SOL]->GetPressure_Inf(); + Density = solver_container[iMesh][FLOW_SOL]->node[iPoint]->GetDensityInc(); + Froude = config->GetFroude(); + yCoord = geometry[iMesh]->node[iPoint]->GetCoord(nDim-1); + Pressure = PressFreeSurface + Density*((yFreeSurface-yCoord)/(Froude*Froude)); + solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(0, Pressure); + + /*--- Update solution with the new velocity ---*/ + + Velx = solver_container[iMesh][FLOW_SOL]->GetVelocity_Inf(0); + Vely = solver_container[iMesh][FLOW_SOL]->GetVelocity_Inf(1); + RhoVelx = Velx * Density; RhoVely = Vely * Density; + solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(1, RhoVelx); + solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(2, RhoVely); + if (nDim == 3) { + Velz = solver_container[iMesh][FLOW_SOL]->GetVelocity_Inf(2); + RhoVelz = Velz * Density; + solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(3, RhoVelz); + } + + } + + } + + /*--- Set the MPI communication ---*/ + + solver_container[iMesh][FLOW_SOL]->Set_MPI_Solution(geometry[iMesh], config); + solver_container[iMesh][FLOW_SOL]->Set_MPI_Solution_Old(geometry[iMesh], config); + + } + + } + + /*--- Set the pressure value in simulations with gravity ---*/ + + + if (incompressible && gravity ) { + + + for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { + + for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { + + /*--- Set initial boundary condition at iter 0 ---*/ + + if ((ExtIter == 0) && (!restart)) { + + /*--- Update solution with the new pressure ---*/ + + PressRef = solver_container[iMesh][FLOW_SOL]->GetPressure_Inf(); + Density = solver_container[iMesh][FLOW_SOL]->GetDensity_Inf(); + yCoordRef = 0.0; + yCoord = geometry[iMesh]->node[iPoint]->GetCoord(nDim-1); + Pressure = PressRef + Density*((yCoordRef-yCoord)/(config->GetFroude()*config->GetFroude())); + solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(0, Pressure); + + } + + } + + /*--- Set the MPI communication ---*/ + + solver_container[iMesh][FLOW_SOL]->Set_MPI_Solution(geometry[iMesh], config); + solver_container[iMesh][FLOW_SOL]->Set_MPI_Solution_Old(geometry[iMesh], config); + + } + + } + + + /*--- Set subsonic initial condition for engine intakes ---*/ + + if (engine_intake) { + + /*--- Set initial boundary condition at iteration 0 ---*/ + + if ((ExtIter == 0) && (!restart)) { + + su2double Velocity_Box[3] = {0.0, 0.0, 0.0}, Velocity_BoxND[3] = {0.0, 0.0, 0.0}, Viscosity_Box, + Density_Box, Density_BoxND, Pressure_Box, Pressure_BoxND, ModVel_Box, ModVel_BoxND, Energy_BoxND, + T_ref = 0.0, S = 0.0, Mu_ref = 0.0, *Coord, MinCoordValues[3], + MaxCoordValues[3], *Subsonic_Engine_Box; + + su2double Mach = 0.40; + su2double Alpha = config->GetAoA()*PI_NUMBER/180.0; + su2double Beta = config->GetAoS()*PI_NUMBER/180.0; + + su2double Gamma_Minus_One = Gamma - 1.0; + su2double Gas_Constant = config->GetGas_Constant(); + + su2double Temperature_Box = config->GetTemperature_FreeStream(); + su2double Mach2Vel_Box = sqrt(Gamma*Gas_Constant*Temperature_Box); + + for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { + + for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { + + Velocity_Box[0] = cos(Alpha)*cos(Beta)*Mach*Mach2Vel_Box; + Velocity_Box[1] = sin(Beta)*Mach*Mach2Vel_Box; + Velocity_Box[2] = sin(Alpha)*cos(Beta)*Mach*Mach2Vel_Box; + + ModVel_Box = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + ModVel_Box += Velocity_Box[iDim]*Velocity_Box[iDim]; + } + ModVel_Box = sqrt(ModVel_Box); + + if (config->GetViscous()) { + if (config->GetSystemMeasurements() == SI) { T_ref = 273.15; S = 110.4; Mu_ref = 1.716E-5; } + if (config->GetSystemMeasurements() == US) { T_ref = 518.7; S = 198.72; Mu_ref = 3.62E-7; } + Viscosity_Box = Mu_ref*(pow(Temperature_Box/T_ref, 1.5) * (T_ref+S)/(Temperature_Box+S)); + Density_Box = config->GetReynolds()*Viscosity_Box/(ModVel_Box*config->GetLength_Reynolds()); + Pressure_Box = Density_Box*Gas_Constant*Temperature_Box; + } + else { + Pressure_Box = config->GetPressure_FreeStream(); + Density_Box = Pressure_Box/(Gas_Constant*Temperature_Box); + } + + Density_BoxND = Density_Box/config->GetDensity_Ref(); + Pressure_BoxND = Pressure_Box/config->GetPressure_Ref(); + + for (iDim = 0; iDim < nDim; iDim++) { + Velocity_BoxND[iDim] = Velocity_Box[iDim]/config->GetVelocity_Ref(); + } + + ModVel_BoxND = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + ModVel_BoxND += Velocity_BoxND[iDim]*Velocity_BoxND[iDim]; + } + ModVel_BoxND = sqrt(ModVel_BoxND); + + Energy_BoxND = Pressure_BoxND/(Density_BoxND*Gamma_Minus_One)+0.5*ModVel_BoxND*ModVel_BoxND; + + Coord = geometry[iMesh]->node[iPoint]->GetCoord(); + + Subsonic_Engine_Box = config->GetSubsonic_Engine_Box(); + + MinCoordValues[0] = Subsonic_Engine_Box[0]; MinCoordValues[1] = Subsonic_Engine_Box[1]; MinCoordValues[2] = Subsonic_Engine_Box[2]; + MaxCoordValues[0] = Subsonic_Engine_Box[3]; MaxCoordValues[1] = Subsonic_Engine_Box[4]; MaxCoordValues[2] = Subsonic_Engine_Box[5]; + + if (((Coord[0] >= MinCoordValues[0]) && (Coord[0] <= MaxCoordValues[0])) && + ((Coord[1] >= MinCoordValues[1]) && (Coord[1] <= MaxCoordValues[1])) && + ((Coord[2] >= MinCoordValues[2]) && (Coord[2] <= MaxCoordValues[2]))) { + + solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(0, Density_BoxND); + for (iDim = 0; iDim < nDim; iDim++) + solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(iDim+1, Density_BoxND*Velocity_BoxND[iDim]); + solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(nVar-1, Density_BoxND*Energy_BoxND); + + solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution_Old(0, Density_BoxND); + for (iDim = 0; iDim < nDim; iDim++) + solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution_Old(iDim+1, Density_BoxND*Velocity_BoxND[iDim]); + solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution_Old(nVar-1, Density_BoxND*Energy_BoxND); + + } + + } + + /*--- Set the MPI communication ---*/ + + solver_container[iMesh][FLOW_SOL]->Set_MPI_Solution(geometry[iMesh], config); + solver_container[iMesh][FLOW_SOL]->Set_MPI_Solution_Old(geometry[iMesh], config); + + } + + } + + } + + /*--- If restart solution, then interpolate the flow solution to + all the multigrid levels, this is important with the dual time strategy ---*/ + + if (restart && (ExtIter == 0)) { + + Solution = new su2double[nVar]; + for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++) { + for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { + Area_Parent = geometry[iMesh]->node[iPoint]->GetVolume(); + for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; + for (iChildren = 0; iChildren < geometry[iMesh]->node[iPoint]->GetnChildren_CV(); iChildren++) { + Point_Fine = geometry[iMesh]->node[iPoint]->GetChildren_CV(iChildren); + Area_Children = geometry[iMesh-1]->node[Point_Fine]->GetVolume(); + Solution_Fine = solver_container[iMesh-1][FLOW_SOL]->node[Point_Fine]->GetSolution(); + for (iVar = 0; iVar < nVar; iVar++) { + Solution[iVar] += Solution_Fine[iVar]*Area_Children/Area_Parent; + } + } + solver_container[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(Solution); + } + solver_container[iMesh][FLOW_SOL]->Set_MPI_Solution(geometry[iMesh], config); + } + delete [] Solution; + + /*--- Interpolate the turblence variable also, if needed ---*/ + + if (rans) { + + unsigned short nVar_Turb = solver_container[MESH_0][TURB_SOL]->GetnVar(); + Solution = new su2double[nVar_Turb]; + for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++) { + for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { + Area_Parent = geometry[iMesh]->node[iPoint]->GetVolume(); + for (iVar = 0; iVar < nVar_Turb; iVar++) Solution[iVar] = 0.0; + for (iChildren = 0; iChildren < geometry[iMesh]->node[iPoint]->GetnChildren_CV(); iChildren++) { + Point_Fine = geometry[iMesh]->node[iPoint]->GetChildren_CV(iChildren); + Area_Children = geometry[iMesh-1]->node[Point_Fine]->GetVolume(); + Solution_Fine = solver_container[iMesh-1][TURB_SOL]->node[Point_Fine]->GetSolution(); + for (iVar = 0; iVar < nVar_Turb; iVar++) { + Solution[iVar] += Solution_Fine[iVar]*Area_Children/Area_Parent; + } + } + solver_container[iMesh][TURB_SOL]->node[iPoint]->SetSolution(Solution); + } + solver_container[iMesh][TURB_SOL]->Set_MPI_Solution(geometry[iMesh], config); + solver_container[iMesh][TURB_SOL]->Postprocessing(geometry[iMesh], solver_container[iMesh], config, iMesh); + } + delete [] Solution; + } + + } + + /*--- The value of the solution for the first iteration of the dual time ---*/ + + if (dual_time && (ExtIter == 0 || (restart && (long)ExtIter == config->GetUnst_RestartIter()))) { + + /*--- Push back the initial condition to previous solution containers + for a 1st-order restart or when simply intitializing to freestream. ---*/ + + for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { + for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { + solver_container[iMesh][FLOW_SOL]->node[iPoint]->Set_Solution_time_n(); + solver_container[iMesh][FLOW_SOL]->node[iPoint]->Set_Solution_time_n1(); + if (rans) { + solver_container[iMesh][TURB_SOL]->node[iPoint]->Set_Solution_time_n(); + solver_container[iMesh][TURB_SOL]->node[iPoint]->Set_Solution_time_n1(); + } + } + } + + if ((restart && (long)ExtIter == config->GetUnst_RestartIter()) && + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)) { + + /*--- Load an additional restart file for a 2nd-order restart ---*/ + + solver_container[MESH_0][FLOW_SOL]->LoadRestart(geometry, solver_container, config, SU2_TYPE::Int(config->GetUnst_RestartIter()-1)); + + /*--- Load an additional restart file for the turbulence model ---*/ + if (rans) + solver_container[MESH_0][TURB_SOL]->LoadRestart(geometry, solver_container, config, SU2_TYPE::Int(config->GetUnst_RestartIter()-1)); + + /*--- Push back this new solution to time level N. ---*/ + + for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { + for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { + solver_container[iMesh][FLOW_SOL]->node[iPoint]->Set_Solution_time_n(); + if (rans) { + solver_container[iMesh][TURB_SOL]->node[iPoint]->Set_Solution_time_n(); + } + } + } + } + } +} + +void CEulerSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { + + unsigned long ErrorCounter = 0; + +#ifdef HAVE_MPI + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + unsigned long ExtIter = config->GetExtIter(); + bool adjoint = config->GetAdjoint(); + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool low_fidelity = (config->GetLowFidelitySim() && (iMesh == MESH_1)); + bool second_order = ((config->GetSpatialOrder_Flow() == SECOND_ORDER) || (config->GetSpatialOrder_Flow() == SECOND_ORDER_LIMITER) || (adjoint && config->GetKind_ConvNumScheme_AdjFlow() == ROE)); + bool limiter = ((config->GetSpatialOrder_Flow() == SECOND_ORDER_LIMITER) && (!low_fidelity) && (ExtIter <= config->GetLimiterIter())); + bool center = (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED) || (adjoint && config->GetKind_ConvNumScheme_AdjFlow() == SPACE_CENTERED); + bool center_jst = center && (config->GetKind_Centered_Flow() == JST); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool engine = ((config->GetnMarker_EngineInflow() != 0) || (config->GetnMarker_EngineBleed() != 0) || (config->GetnMarker_EngineExhaust() != 0)); + bool actuator_disk = ((config->GetnMarker_ActDisk_Inlet() != 0) || (config->GetnMarker_ActDisk_Outlet() != 0)); + bool fixed_cl = config->GetFixed_CL_Mode(); + + /*--- Compute the engine properties ---*/ + + if (engine) { GetEngine_Properties(geometry, config, iMesh, Output); } + + /*--- Compute the actuator disk properties ---*/ + + if (actuator_disk) { GetActuatorDisk_Properties(geometry, config, iMesh, Output); } + + /*--- Update the angle of attack at the far-field for fixed CL calculations. ---*/ + + if (fixed_cl) { SetFarfield_AoA(geometry, solver_container, config, iMesh, Output); } + + /*--- Compute distance function to zero level set (Set LevelSet and Distance primitive variables)---*/ + + if (freesurface) { SetFreeSurface_Distance(geometry, config); } + + /*--- Set the primitive variables ---*/ + + ErrorCounter = SetPrimitive_Variables(solver_container, config, Output); + + /*--- Upwind second order reconstruction ---*/ + + if ((second_order && !center) && ((iMesh == MESH_0) || low_fidelity) && !Output) { + + /*--- Gradient computation ---*/ + + if (config->GetKind_Gradient_Method() == GREEN_GAUSS) { + SetPrimitive_Gradient_GG(geometry, config); + // if (compressible && !ideal_gas) SetSecondary_Gradient_GG(geometry, config); + } + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { + SetPrimitive_Gradient_LS(geometry, config); + // if (compressible && !ideal_gas) SetSecondary_Gradient_LS(geometry, config); + } + + + /*--- Limiter computation ---*/ + + if ((limiter) && (iMesh == MESH_0) && !Output) { + SetPrimitive_Limiter(geometry, config); + // if (compressible && !ideal_gas) SetSecondary_Limiter(geometry, config); + } + + } + + /*--- Artificial dissipation ---*/ + + if (center && !Output) { + SetMax_Eigenvalue(geometry, config); + if ((center_jst) && ((iMesh == MESH_0) || low_fidelity)) { + SetDissipation_Switch(geometry, config); + SetUndivided_Laplacian(geometry, config); + } + } + + /*--- Initialize the Jacobian matrices ---*/ + + if (implicit && !config->GetDiscrete_Adjoint()) Jacobian.SetValZero(); + + /*--- Error message ---*/ + + if (config->GetConsole_Output_Verb() == VERB_HIGH) { +#ifdef HAVE_MPI + unsigned long MyErrorCounter = ErrorCounter; ErrorCounter = 0; + SU2_MPI::Allreduce(&MyErrorCounter, &ErrorCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); +#endif + if (iMesh == MESH_0) config->SetNonphysical_Points(ErrorCounter); + } + +} + +void CEulerSolver::Postprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, + unsigned short iMesh) { } + +unsigned long CEulerSolver::SetPrimitive_Variables(CSolver **solver_container, CConfig *config, bool Output) { + + unsigned long iPoint, ErrorCounter = 0; + bool RightSol = true; + + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + + for (iPoint = 0; iPoint < nPoint; iPoint ++) { + + /*--- Initialize the non-physical points vector ---*/ + + node[iPoint]->SetNon_Physical(false); + + /*--- Incompressible flow, primitive variables nDim+3, (P, vx, vy, vz, rho, beta), + FreeSurface Incompressible flow, primitive variables nDim+4, (P, vx, vy, vz, rho, beta, dist), + Compressible flow, primitive variables nDim+5, (T, vx, vy, vz, P, rho, h, c, lamMu, eddyMu, ThCond, Cp) ---*/ + + if (compressible) { + RightSol = node[iPoint]->SetPrimVar_Compressible(FluidModel); + node[iPoint]->SetSecondaryVar_Compressible(FluidModel); + } + + if (incompressible) { + RightSol = node[iPoint]->SetPrimVar_Incompressible(Density_Inf, config); + } + + + if (freesurface){ + RightSol = node[iPoint]->SetPrimVar_FreeSurface(config); + } + + if (!RightSol) { node[iPoint]->SetNon_Physical(true); ErrorCounter++; } + + /*--- Initialize the convective, source and viscous residual vector ---*/ + + if (!Output) LinSysRes.SetBlock_Zero(iPoint); + + } + + return ErrorCounter; +} +void CEulerSolver::SetTime_Step(CGeometry *geometry, CSolver **solver_container, CConfig *config, + unsigned short iMesh, unsigned long Iteration) { + + su2double *Normal, Area, Vol, Mean_SoundSpeed = 0.0, Mean_ProjVel = 0.0, Mean_BetaInc2, Lambda, Local_Delta_Time, Mean_DensityInc, Mean_LevelSet, + Global_Delta_Time = 1E6, Global_Delta_UnstTimeND, ProjVel, ProjVel_i, ProjVel_j, Delta = 0.0, a, b, c, e, f; + unsigned long iEdge, iVertex, iPoint, jPoint; + unsigned short iDim, iMarker; + + su2double epsilon = config->GetFreeSurface_Thickness(); + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool grid_movement = config->GetGrid_Movement(); + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + + Min_Delta_Time = 1.E6; Max_Delta_Time = 0.0; + + /*--- Set maximum inviscid eigenvalue to zero, and compute sound speed ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) + node[iPoint]->SetMax_Lambda_Inv(0.0); + + /*--- Loop interior edges ---*/ + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Point identification, Normal vector and area ---*/ + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + + Normal = geometry->edge[iEdge]->GetNormal(); + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); + + /*--- Mean Values ---*/ + + if (compressible) { + Mean_ProjVel = 0.5 * (node[iPoint]->GetProjVel(Normal) + node[jPoint]->GetProjVel(Normal)); + Mean_SoundSpeed = 0.5 * (node[iPoint]->GetSoundSpeed() + node[jPoint]->GetSoundSpeed()) * Area; + } + if (incompressible) { + Mean_ProjVel = 0.5 * (node[iPoint]->GetProjVel(Normal) + node[jPoint]->GetProjVel(Normal)); + Mean_BetaInc2 = 0.5 * (node[iPoint]->GetBetaInc2() + node[jPoint]->GetBetaInc2()); + Mean_DensityInc = 0.5 * (node[iPoint]->GetDensityInc() + node[jPoint]->GetDensityInc()); + Mean_SoundSpeed = sqrt(Mean_ProjVel*Mean_ProjVel + (Mean_BetaInc2/Mean_DensityInc)*Area*Area); + } + if (freesurface) { + Mean_ProjVel = 0.5 * (node[iPoint]->GetProjVel(Normal) + node[jPoint]->GetProjVel(Normal)); + Mean_BetaInc2 = 0.5 * (node[iPoint]->GetBetaInc2() + node[jPoint]->GetBetaInc2()); + Mean_DensityInc = 0.5 * (node[iPoint]->GetDensityInc() + node[jPoint]->GetDensityInc()); + Mean_LevelSet = 0.5 * (node[iPoint]->GetLevelSet() + node[jPoint]->GetLevelSet()); + + if (Mean_LevelSet < -epsilon) Delta = 0.0; + if (fabs(Mean_LevelSet) <= epsilon) Delta = 0.5*(1.0+cos(PI_NUMBER*Mean_LevelSet/epsilon))/epsilon; + if (Mean_LevelSet > epsilon) Delta = 0.0; + + a = Mean_BetaInc2/Mean_DensityInc, b = Mean_LevelSet/Mean_DensityInc; + c = (1.0 - config->GetRatioDensity())*Delta*config->GetDensity_FreeStreamND(); + e = (2.0*fabs(Mean_ProjVel) + b*c*fabs(Mean_ProjVel)), f = sqrt(4.0*a*Area*Area + e*e); + Mean_SoundSpeed = 0.5*f; + Mean_ProjVel = 0.5*e; + + } + + /*--- Adjustment for grid movement ---*/ + + if (grid_movement) { + su2double *GridVel_i = geometry->node[iPoint]->GetGridVel(); + su2double *GridVel_j = geometry->node[jPoint]->GetGridVel(); + ProjVel_i = 0.0; ProjVel_j = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + ProjVel_i += GridVel_i[iDim]*Normal[iDim]; + ProjVel_j += GridVel_j[iDim]*Normal[iDim]; + } + Mean_ProjVel -= 0.5 * (ProjVel_i + ProjVel_j); + } + + /*--- Inviscid contribution ---*/ + + Lambda = fabs(Mean_ProjVel) + Mean_SoundSpeed; + if (geometry->node[iPoint]->GetDomain()) node[iPoint]->AddMax_Lambda_Inv(Lambda); + if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddMax_Lambda_Inv(Lambda); + + } + + /*--- Loop boundary edges ---*/ + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + + /*--- Point identification, Normal vector and area ---*/ + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); + + /*--- Mean Values ---*/ + + if (compressible) { + Mean_ProjVel = node[iPoint]->GetProjVel(Normal); + Mean_SoundSpeed = node[iPoint]->GetSoundSpeed() * Area; + } + if (incompressible) { + Mean_ProjVel = node[iPoint]->GetProjVel(Normal); + Mean_BetaInc2 = node[iPoint]->GetBetaInc2(); + Mean_DensityInc = node[iPoint]->GetDensityInc(); + Mean_SoundSpeed = sqrt(Mean_ProjVel*Mean_ProjVel + (Mean_BetaInc2/Mean_DensityInc)*Area*Area); + } + if (freesurface) { + Mean_ProjVel = node[iPoint]->GetProjVel(Normal); + Mean_BetaInc2 = node[iPoint]->GetBetaInc2(); + Mean_DensityInc = node[iPoint]->GetDensityInc(); + Mean_LevelSet = node[iPoint]->GetLevelSet(); + + if (Mean_LevelSet < -epsilon) Delta = 0.0; + if (fabs(Mean_LevelSet) <= epsilon) Delta = 0.5*(1.0+cos(PI_NUMBER*Mean_LevelSet/epsilon))/epsilon; + if (Mean_LevelSet > epsilon) Delta = 0.0; + + a = Mean_BetaInc2/Mean_DensityInc; b = Mean_LevelSet/Mean_DensityInc; + c = (1.0 - config->GetRatioDensity())*Delta*config->GetDensity_FreeStreamND(); + e = (2.0*fabs(Mean_ProjVel) + b*c*fabs(Mean_ProjVel)); f = sqrt(4.0*a*Area*Area + e*e); + Mean_SoundSpeed = 0.5*f; + Mean_ProjVel = 0.5*e; + } + + /*--- Adjustment for grid movement ---*/ + + if (grid_movement) { + su2double *GridVel = geometry->node[iPoint]->GetGridVel(); + ProjVel = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + ProjVel += GridVel[iDim]*Normal[iDim]; + Mean_ProjVel -= ProjVel; + } + + /*--- Inviscid contribution ---*/ + Lambda = fabs(Mean_ProjVel) + Mean_SoundSpeed; + if (geometry->node[iPoint]->GetDomain()) { + node[iPoint]->AddMax_Lambda_Inv(Lambda); + } + + } + } + + /*--- Each element uses their own speed, steady state simulation ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + Vol = geometry->node[iPoint]->GetVolume(); + + if (Vol != 0.0) { + Local_Delta_Time = config->GetCFL(iMesh)*Vol / node[iPoint]->GetMax_Lambda_Inv(); + Global_Delta_Time = min(Global_Delta_Time, Local_Delta_Time); + Min_Delta_Time = min(Min_Delta_Time, Local_Delta_Time); + Max_Delta_Time = max(Max_Delta_Time, Local_Delta_Time); + if (Local_Delta_Time > config->GetMax_DeltaTime()) + Local_Delta_Time = config->GetMax_DeltaTime(); + node[iPoint]->SetDelta_Time(Local_Delta_Time); + } + else { + node[iPoint]->SetDelta_Time(0.0); + } + + } + + + /*--- Compute the max and the min dt (in parallel) ---*/ + if (config->GetConsole_Output_Verb() == VERB_HIGH) { +#ifdef HAVE_MPI + su2double rbuf_time, sbuf_time; + sbuf_time = Min_Delta_Time; + SU2_MPI::Reduce(&sbuf_time, &rbuf_time, 1, MPI_DOUBLE, MPI_MIN, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Bcast(&rbuf_time, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + Min_Delta_Time = rbuf_time; + + sbuf_time = Max_Delta_Time; + SU2_MPI::Reduce(&sbuf_time, &rbuf_time, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Bcast(&rbuf_time, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + Max_Delta_Time = rbuf_time; +#endif + } + + /*--- For exact time solution use the minimum delta time of the whole mesh ---*/ + + if (config->GetUnsteady_Simulation() == TIME_STEPPING) { +#ifdef HAVE_MPI + su2double rbuf_time, sbuf_time; + sbuf_time = Global_Delta_Time; + SU2_MPI::Reduce(&sbuf_time, &rbuf_time, 1, MPI_DOUBLE, MPI_MIN, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Bcast(&rbuf_time, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + Global_Delta_Time = rbuf_time; +#endif + for (iPoint = 0; iPoint < nPointDomain; iPoint++) + node[iPoint]->SetDelta_Time(Global_Delta_Time); + } + + /*--- Recompute the unsteady time step for the dual time strategy + if the unsteady CFL is diferent from 0 ---*/ + + if ((dual_time) && (Iteration == 0) && (config->GetUnst_CFL() != 0.0) && (iMesh == MESH_0)) { + Global_Delta_UnstTimeND = config->GetUnst_CFL()*Global_Delta_Time/config->GetCFL(iMesh); + +#ifdef HAVE_MPI + su2double rbuf_time, sbuf_time; + sbuf_time = Global_Delta_UnstTimeND; + SU2_MPI::Reduce(&sbuf_time, &rbuf_time, 1, MPI_DOUBLE, MPI_MIN, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Bcast(&rbuf_time, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + Global_Delta_UnstTimeND = rbuf_time; +#endif + config->SetDelta_UnstTimeND(Global_Delta_UnstTimeND); + } + + /*--- The pseudo local time (explicit integration) cannot be greater than the physical time ---*/ + + if (dual_time) + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + if (!implicit) { + Local_Delta_Time = min((2.0/3.0)*config->GetDelta_UnstTimeND(), node[iPoint]->GetDelta_Time()); + node[iPoint]->SetDelta_Time(Local_Delta_Time); + } + } + +} + +void CEulerSolver::Centered_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config, unsigned short iMesh, unsigned short iRKStep) { + + unsigned long iEdge, iPoint, jPoint; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool second_order = ((config->GetKind_Centered_Flow() == JST) && (iMesh == MESH_0)); + bool low_fidelity = (config->GetLowFidelitySim() && (iMesh == MESH_1)); + bool grid_movement = config->GetGrid_Movement(); + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Points in edge, set normal vectors, and number of neighbors ---*/ + + iPoint = geometry->edge[iEdge]->GetNode(0); jPoint = geometry->edge[iEdge]->GetNode(1); + numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); + numerics->SetNeighbor(geometry->node[iPoint]->GetnNeighbor(), geometry->node[jPoint]->GetnNeighbor()); + + /*--- Set primitive variables w/o reconstruction ---*/ + + numerics->SetPrimitive(node[iPoint]->GetPrimitive(), node[jPoint]->GetPrimitive()); + + /*--- Set the largest convective eigenvalue ---*/ + + numerics->SetLambda(node[iPoint]->GetLambda(), node[jPoint]->GetLambda()); + + /*--- Set undivided laplacian an pressure based sensor ---*/ + + if ((second_order || low_fidelity)) { + numerics->SetUndivided_Laplacian(node[iPoint]->GetUndivided_Laplacian(), node[jPoint]->GetUndivided_Laplacian()); + numerics->SetSensor(node[iPoint]->GetSensor(), node[jPoint]->GetSensor()); + } + + /*--- Grid movement ---*/ + + if (grid_movement) { + numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[jPoint]->GetGridVel()); + } + + /*--- Compute residuals, and Jacobians ---*/ + + numerics->ComputeResidual(Res_Conv, Jacobian_i, Jacobian_j, config); + + /*--- Update convective and artificial dissipation residuals ---*/ + + LinSysRes.AddBlock(iPoint, Res_Conv); + LinSysRes.SubtractBlock(jPoint, Res_Conv); + + /*--- Set implicit computation ---*/ + if (implicit) { + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + Jacobian.AddBlock(iPoint, jPoint, Jacobian_j); + Jacobian.SubtractBlock(jPoint, iPoint, Jacobian_i); + Jacobian.SubtractBlock(jPoint, jPoint, Jacobian_j); + } + } + +} + +void CEulerSolver::Upwind_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config, unsigned short iMesh) { + + su2double **Gradient_i, **Gradient_j, Project_Grad_i, Project_Grad_j, RoeVelocity[3] = {0.0,0.0,0.0}, R, sq_vel, RoeEnthalpy, + *V_i, *V_j, *S_i, *S_j, *Limiter_i = NULL, *Limiter_j = NULL, YDistance, GradHidrosPress, sqvel, Non_Physical = 1.0; + unsigned long iEdge, iPoint, jPoint, counter_local = 0, counter_global = 0; + unsigned short iDim, iVar; + bool neg_density_i = false, neg_density_j = false, neg_pressure_i = false, neg_pressure_j = false, neg_sound_speed = false; + + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool low_fidelity = (config->GetLowFidelitySim() && (iMesh == MESH_1)); + bool second_order = (((config->GetSpatialOrder_Flow() == SECOND_ORDER) || (config->GetSpatialOrder_Flow() == SECOND_ORDER_LIMITER)) && ((iMesh == MESH_0) || low_fidelity)); + bool limiter = ((config->GetSpatialOrder_Flow() == SECOND_ORDER_LIMITER) && !low_fidelity); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool grid_movement = config->GetGrid_Movement(); + bool roe_turkel = (config->GetKind_Upwind_Flow() == TURKEL); + bool ideal_gas = (config->GetKind_FluidModel() == STANDARD_AIR || config->GetKind_FluidModel() == IDEAL_GAS ); + + /*--- Loop over all the edges ---*/ + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Points in edge and normal vectors ---*/ + + iPoint = geometry->edge[iEdge]->GetNode(0); jPoint = geometry->edge[iEdge]->GetNode(1); + numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); + + /*--- Roe Turkel preconditioning ---*/ + + if (roe_turkel) { + sqvel = 0.0; + for (iDim = 0; iDim < nDim; iDim ++) + sqvel += config->GetVelocity_FreeStream()[iDim]*config->GetVelocity_FreeStream()[iDim]; + numerics->SetVelocity2_Inf(sqvel); + } + + /*--- Grid movement ---*/ + + if (grid_movement) + numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[jPoint]->GetGridVel()); + + /*--- Get primitive variables ---*/ + + V_i = node[iPoint]->GetPrimitive(); V_j = node[jPoint]->GetPrimitive(); + S_i = node[iPoint]->GetSecondary(); S_j = node[jPoint]->GetSecondary(); + + /*--- The zero order reconstruction includes the gradient + of the hydrostatic pressure constribution ---*/ + + if (freesurface) { + + YDistance = 0.5*(geometry->node[jPoint]->GetCoord(nDim-1)-geometry->node[iPoint]->GetCoord(nDim-1)); + GradHidrosPress = node[iPoint]->GetDensityInc()/(config->GetFroude()*config->GetFroude()); + Primitive_i[0] = V_i[0] - GradHidrosPress*YDistance; + GradHidrosPress = node[jPoint]->GetDensityInc()/(config->GetFroude()*config->GetFroude()); + Primitive_j[0] = V_j[0] + GradHidrosPress*YDistance; + + for (iVar = 1; iVar < nPrimVar; iVar++) { + Primitive_i[iVar] = V_i[iVar]+EPS; + Primitive_j[iVar] = V_j[iVar]+EPS; + } + + } + + /*--- High order reconstruction using MUSCL strategy ---*/ + + if (second_order) { + + for (iDim = 0; iDim < nDim; iDim++) { + Vector_i[iDim] = 0.5*(geometry->node[jPoint]->GetCoord(iDim) - geometry->node[iPoint]->GetCoord(iDim)); + Vector_j[iDim] = 0.5*(geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim)); + } + + Gradient_i = node[iPoint]->GetGradient_Primitive(); + Gradient_j = node[jPoint]->GetGradient_Primitive(); + if (limiter) { + Limiter_i = node[iPoint]->GetLimiter_Primitive(); + Limiter_j = node[jPoint]->GetLimiter_Primitive(); + } + + for (iVar = 0; iVar < nPrimVarGrad; iVar++) { + Project_Grad_i = 0.0; Project_Grad_j = 0.0; + Non_Physical = node[iPoint]->GetNon_Physical()*node[jPoint]->GetNon_Physical(); + for (iDim = 0; iDim < nDim; iDim++) { + Project_Grad_i += Vector_i[iDim]*Gradient_i[iVar][iDim]*Non_Physical; + Project_Grad_j += Vector_j[iDim]*Gradient_j[iVar][iDim]*Non_Physical; + } + if (limiter) { + Primitive_i[iVar] = V_i[iVar] + Limiter_i[iVar]*Project_Grad_i; + Primitive_j[iVar] = V_j[iVar] + Limiter_j[iVar]*Project_Grad_j; + } + else { + Primitive_i[iVar] = V_i[iVar] + Project_Grad_i; + Primitive_j[iVar] = V_j[iVar] + Project_Grad_j; + } + } + + /*--- Recompute the extrapolated quantities in a + thermodynamic consistent way ---*/ + + if (!ideal_gas) { ComputeConsExtrapolation(config); } + + /*--- Check for non-physical solutions after reconstruction. If found, + use the cell-average value of the solution. This results in a locally + first-order approximation, but this is typically only active + during the start-up of a calculation. If non-physical, use the + cell-averaged state. ---*/ + + if (compressible) { + + neg_pressure_i = (Primitive_i[nDim+1] < 0.0); neg_pressure_j = (Primitive_j[nDim+1] < 0.0); + neg_density_i = (Primitive_i[nDim+2] < 0.0); neg_density_j = (Primitive_j[nDim+2] < 0.0); + + R = sqrt(fabs(Primitive_j[nDim+2]/Primitive_i[nDim+2])); + sq_vel = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + RoeVelocity[iDim] = (R*Primitive_j[iDim+1]+Primitive_i[iDim+1])/(R+1); + sq_vel += RoeVelocity[iDim]*RoeVelocity[iDim]; + } + RoeEnthalpy = (R*Primitive_j[nDim+3]+Primitive_i[nDim+3])/(R+1); + neg_sound_speed = ((Gamma-1)*(RoeEnthalpy-0.5*sq_vel) < 0.0); + + } + + if (neg_sound_speed) { + for (iVar = 0; iVar < nPrimVar; iVar++) { + Primitive_i[iVar] = V_i[iVar]; + Primitive_j[iVar] = V_j[iVar]; } + if (compressible) { + Secondary_i[0] = S_i[0]; Secondary_i[1] = S_i[1]; + Secondary_j[0] = S_i[0]; Secondary_j[1] = S_i[1]; } + counter_local++; + } + + if (neg_density_i || neg_pressure_i) { + for (iVar = 0; iVar < nPrimVar; iVar++) Primitive_i[iVar] = V_i[iVar]; + if (compressible) { Secondary_i[0] = S_i[0]; Secondary_i[1] = S_i[1]; } + counter_local++; + } + + if (neg_density_j || neg_pressure_j) { + for (iVar = 0; iVar < nPrimVar; iVar++) Primitive_j[iVar] = V_j[iVar]; + if (compressible) { Secondary_j[0] = S_j[0]; Secondary_j[1] = S_j[1]; } + counter_local++; + } + + numerics->SetPrimitive(Primitive_i, Primitive_j); + numerics->SetSecondary(Secondary_i, Secondary_j); + + } + else { + + /*--- Set conservative variables without reconstruction ---*/ + + numerics->SetPrimitive(V_i, V_j); + numerics->SetSecondary(S_i, S_j); + + if (freesurface) { + numerics->SetPrimitive(Primitive_i, Primitive_j); + } + + } + + /*--- Compute the residual ---*/ + + numerics->ComputeResidual(Res_Conv, Jacobian_i, Jacobian_j, config); + + /*--- Update residual value ---*/ + + LinSysRes.AddBlock(iPoint, Res_Conv); + LinSysRes.SubtractBlock(jPoint, Res_Conv); + + /*--- Set implicit Jacobians ---*/ + + if (implicit) { + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + Jacobian.AddBlock(iPoint, jPoint, Jacobian_j); + Jacobian.SubtractBlock(jPoint, iPoint, Jacobian_i); + Jacobian.SubtractBlock(jPoint, jPoint, Jacobian_j); + } + + /*--- Roe Turkel preconditioning, set the value of beta ---*/ + + if (roe_turkel) { + node[iPoint]->SetPreconditioner_Beta(numerics->GetPrecond_Beta()); + node[jPoint]->SetPreconditioner_Beta(numerics->GetPrecond_Beta()); + } + + } + + /*--- Warning message about non-physical reconstructions ---*/ + + if (config->GetConsole_Output_Verb() == VERB_HIGH) { +#ifdef HAVE_MPI + SU2_MPI::Reduce(&counter_local, &counter_global, 1, MPI_UNSIGNED_LONG, MPI_SUM, MASTER_NODE, MPI_COMM_WORLD); +#else + counter_global = counter_local; +#endif + if (iMesh == MESH_0) config->SetNonphysical_Reconstr(counter_global); + } + +} + +void CEulerSolver::ComputeConsExtrapolation(CConfig *config) { + + unsigned short iDim; + + su2double density_i = Primitive_i[nDim+2]; + su2double pressure_i = Primitive_i[nDim+1]; + su2double velocity2_i = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + velocity2_i += Primitive_i[iDim+1]*Primitive_i[iDim+1]; + } + + FluidModel->SetTDState_Prho(pressure_i, density_i); + + Primitive_i[0]= FluidModel->GetTemperature(); + Primitive_i[nDim+3]= FluidModel->GetStaticEnergy() + Primitive_i[nDim+1]/Primitive_i[nDim+2] + 0.5*velocity2_i; + Primitive_i[nDim+4]= FluidModel->GetSoundSpeed(); + Secondary_i[0]=FluidModel->GetdPdrho_e(); + Secondary_i[1]=FluidModel->GetdPde_rho(); + + + su2double density_j = Primitive_j[nDim+2]; + su2double pressure_j = Primitive_j[nDim+1]; + su2double velocity2_j = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + velocity2_j += Primitive_j[iDim+1]*Primitive_j[iDim+1]; + } + + FluidModel->SetTDState_Prho(pressure_j, density_j); + + Primitive_j[0]= FluidModel->GetTemperature(); + Primitive_j[nDim+3]= FluidModel->GetStaticEnergy() + Primitive_j[nDim+1]/Primitive_j[nDim+2] + 0.5*velocity2_j; + Primitive_j[nDim+4]=FluidModel->GetSoundSpeed(); + Secondary_j[0]=FluidModel->GetdPdrho_e(); + Secondary_j[1]=FluidModel->GetdPde_rho(); + +} + +void CEulerSolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, + CConfig *config, unsigned short iMesh) { + + unsigned short iVar, jVar; + unsigned long iPoint; + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool rotating_frame = config->GetRotating_Frame(); + bool axisymmetric = config->GetAxisymmetric(); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool gravity = (config->GetGravityForce() == YES); + bool time_spectral = (config->GetUnsteady_Simulation() == TIME_SPECTRAL); + bool windgust = config->GetWind_Gust(); + + /*--- Initialize the source residual to zero ---*/ + for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; + + if (rotating_frame) { + + /*--- Loop over all points ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Load the conservative variables ---*/ + numerics->SetConservative(node[iPoint]->GetSolution(), + node[iPoint]->GetSolution()); + + /*--- Load the volume of the dual mesh cell ---*/ + numerics->SetVolume(geometry->node[iPoint]->GetVolume()); + + /*--- Compute the rotating frame source residual ---*/ + numerics->ComputeResidual(Residual, Jacobian_i, config); + + /*--- Add the source residual to the total ---*/ + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Add the implicit Jacobian contribution ---*/ + if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + } + } + + if (axisymmetric) { + + /*--- Zero out Jacobian structure ---*/ + if (implicit) { + for (iVar = 0; iVar < nVar; iVar ++) + for (unsigned short jVar = 0; jVar < nVar; jVar ++) + Jacobian_i[iVar][jVar] = 0.0; + } + + /*--- loop over points ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Set solution ---*/ + numerics->SetConservative(node[iPoint]->GetSolution(), node[iPoint]->GetSolution()); + + if (incompressible || freesurface) { + /*--- Set incompressible density ---*/ + numerics->SetDensityInc(node[iPoint]->GetDensityInc(), node[iPoint]->GetDensityInc()); + } + + /*--- Set control volume ---*/ + numerics->SetVolume(geometry->node[iPoint]->GetVolume()); + + /*--- Set y coordinate ---*/ + numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[iPoint]->GetCoord()); + + /*--- Compute Source term Residual ---*/ + numerics->ComputeResidual(Residual, Jacobian_i, config); + + /*--- Add Residual ---*/ + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Implicit part ---*/ + if (implicit) + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + } + } + + if (gravity) { + + /*--- loop over points ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Set solution ---*/ + numerics->SetConservative(node[iPoint]->GetSolution(), node[iPoint]->GetSolution()); + + /*--- Set incompressible density ---*/ + if (incompressible || freesurface) { + numerics->SetDensityInc(node[iPoint]->GetDensityInc(), node[iPoint]->GetDensityInc()); + } + + /*--- Set control volume ---*/ + numerics->SetVolume(geometry->node[iPoint]->GetVolume()); + + /*--- Compute Source term Residual ---*/ + numerics->ComputeResidual(Residual, config); + + /*--- Add Residual ---*/ + LinSysRes.AddBlock(iPoint, Residual); + + } + + } + + if (freesurface) { + + unsigned long iPoint; + su2double Vol, x_o, x_od, x, z, levelset, DampingFactor; + su2double factor = config->GetFreeSurface_Damping_Length(); + + x_o = config->GetFreeSurface_Outlet(); + x_od = x_o - factor*2.0*PI_NUMBER*config->GetFroude()*config->GetFroude(); + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + Vol = geometry->node[iPoint]->GetVolume(); + x = geometry->node[iPoint]->GetCoord()[0]; + z = geometry->node[iPoint]->GetCoord()[nDim-1]-config->GetFreeSurface_Zero(); + levelset = node[iPoint]->GetSolution(nDim+1); + + DampingFactor = 0.0; + if (x >= x_od) + DampingFactor = config->GetFreeSurface_Damping_Coeff()*pow((x-x_od)/(x_o-x_od), 2.0); + + for (iVar = 0; iVar < nVar; iVar++) { + Residual[iVar] = 0.0; + for (jVar = 0; jVar < nVar; jVar++) + Jacobian_i[iVar][jVar] = 0.0; + } + + Residual[nDim+1] = Vol*(levelset-z)*DampingFactor; + Jacobian_i[nDim+1][nDim+1] = Vol*DampingFactor; + + LinSysRes.AddBlock(iPoint, Residual); + if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + } + + } + + if (time_spectral) { + + su2double Volume, Source; + + /*--- loop over points ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Get control volume ---*/ + Volume = geometry->node[iPoint]->GetVolume(); + + /*--- Get stored time spectral source term ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + Source = node[iPoint]->GetTimeSpectral_Source(iVar); + Residual[iVar] = Source*Volume; + } + + /*--- Add Residual ---*/ + LinSysRes.AddBlock(iPoint, Residual); + + } + } + + if (windgust) { + + /*--- Loop over all points ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Load the wind gust ---*/ + numerics->SetWindGust(node[iPoint]->GetWindGust(), node[iPoint]->GetWindGust()); + + /*--- Load the wind gust derivatives ---*/ + numerics->SetWindGustDer(node[iPoint]->GetWindGustDer(), node[iPoint]->GetWindGustDer()); + + /*--- Load the primitive variables ---*/ + numerics->SetPrimitive(node[iPoint]->GetPrimitive(), node[iPoint]->GetPrimitive()); + + /*--- Load the volume of the dual mesh cell ---*/ + numerics->SetVolume(geometry->node[iPoint]->GetVolume()); + + /*--- Compute the rotating frame source residual ---*/ + numerics->ComputeResidual(Residual, Jacobian_i, config); + + /*--- Add the source residual to the total ---*/ + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Add the implicit Jacobian contribution ---*/ + if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + } + } + +} + +void CEulerSolver::Source_Template(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config, unsigned short iMesh) { + + /* This method should be used to call any new source terms for a particular problem*/ + /* This method calls the new child class in CNumerics, where the new source term should be implemented. */ + + /* Next we describe how to get access to some important quanties for this method */ + /* Access to all points in the current geometric mesh by saying: nPointDomain */ + /* Get the vector of conservative variables at some point iPoint = node[iPoint]->GetSolution() */ + /* Get the volume (or area in 2D) associated with iPoint = node[iPoint]->GetVolume() */ + /* Get the vector of geometric coordinates of point iPoint = node[iPoint]->GetCoord() */ + +} + +void CEulerSolver::SetMax_Eigenvalue(CGeometry *geometry, CConfig *config) { + + su2double *Normal, Area, Mean_SoundSpeed = 0.0, Mean_ProjVel = 0.0, Mean_BetaInc2, Lambda, Mean_DensityInc, + ProjVel, ProjVel_i, ProjVel_j, *GridVel, *GridVel_i, *GridVel_j; + unsigned long iEdge, iVertex, iPoint, jPoint; + unsigned short iDim, iMarker; + + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool grid_movement = config->GetGrid_Movement(); + + /*--- Set maximum inviscid eigenvalue to zero, and compute sound speed ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + node[iPoint]->SetLambda(0.0); + } + + /*--- Loop interior edges ---*/ + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Point identification, Normal vector and area ---*/ + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + + Normal = geometry->edge[iEdge]->GetNormal(); + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); + + /*--- Mean Values ---*/ + + if (compressible) { + Mean_ProjVel = 0.5 * (node[iPoint]->GetProjVel(Normal) + node[jPoint]->GetProjVel(Normal)); + Mean_SoundSpeed = 0.5 * (node[iPoint]->GetSoundSpeed() + node[jPoint]->GetSoundSpeed()) * Area; + } + if (incompressible || freesurface) { + Mean_ProjVel = 0.5 * (node[iPoint]->GetProjVel(Normal) + node[jPoint]->GetProjVel(Normal)); + Mean_BetaInc2 = 0.5 * (node[iPoint]->GetBetaInc2() + node[jPoint]->GetBetaInc2()); + Mean_DensityInc = 0.5 * (node[iPoint]->GetDensityInc() + node[jPoint]->GetDensityInc()); + Mean_SoundSpeed = sqrt(Mean_ProjVel*Mean_ProjVel + (Mean_BetaInc2/Mean_DensityInc)*Area*Area); + } + + /*--- Adjustment for grid movement ---*/ + + if (grid_movement) { + GridVel_i = geometry->node[iPoint]->GetGridVel(); + GridVel_j = geometry->node[jPoint]->GetGridVel(); + ProjVel_i = 0.0; ProjVel_j =0.0; + for (iDim = 0; iDim < nDim; iDim++) { + ProjVel_i += GridVel_i[iDim]*Normal[iDim]; + ProjVel_j += GridVel_j[iDim]*Normal[iDim]; + } + Mean_ProjVel -= 0.5 * (ProjVel_i + ProjVel_j); + } + + /*--- Inviscid contribution ---*/ + + Lambda = fabs(Mean_ProjVel) + Mean_SoundSpeed; + if (geometry->node[iPoint]->GetDomain()) node[iPoint]->AddLambda(Lambda); + if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddLambda(Lambda); + + } + + /*--- Loop boundary edges ---*/ + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + + /*--- Point identification, Normal vector and area ---*/ + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); + + /*--- Mean Values ---*/ + + if (compressible) { + Mean_ProjVel = node[iPoint]->GetProjVel(Normal); + Mean_SoundSpeed = node[iPoint]->GetSoundSpeed() * Area; + } + if (incompressible || freesurface) { + Mean_ProjVel = node[iPoint]->GetProjVel(Normal); + Mean_BetaInc2 = node[iPoint]->GetBetaInc2(); + Mean_DensityInc = node[iPoint]->GetDensityInc(); + Mean_SoundSpeed = sqrt(Mean_ProjVel*Mean_ProjVel + (Mean_BetaInc2/Mean_DensityInc)*Area*Area); + } + + /*--- Adjustment for grid movement ---*/ + + if (grid_movement) { + GridVel = geometry->node[iPoint]->GetGridVel(); + ProjVel = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + ProjVel += GridVel[iDim]*Normal[iDim]; + Mean_ProjVel -= ProjVel; + } + + /*--- Inviscid contribution ---*/ + + Lambda = fabs(Mean_ProjVel) + Mean_SoundSpeed; + if (geometry->node[iPoint]->GetDomain()) { + node[iPoint]->AddLambda(Lambda); + } + + } + } + + /*--- MPI parallelization ---*/ + + Set_MPI_MaxEigenvalue(geometry, config); + +} + +void CEulerSolver::SetUndivided_Laplacian(CGeometry *geometry, CConfig *config) { + + unsigned long iPoint, jPoint, iEdge; + su2double Pressure_i = 0, Pressure_j = 0, *Diff; + unsigned short iVar; + bool boundary_i, boundary_j; + + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + + Diff = new su2double[nVar]; + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) + node[iPoint]->SetUnd_LaplZero(); + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + + /*--- Solution differences ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Diff[iVar] = node[iPoint]->GetSolution(iVar) - node[jPoint]->GetSolution(iVar); + + /*--- Correction for compressible flows which use the enthalpy ---*/ + + if (compressible) { + Pressure_i = node[iPoint]->GetPressure(); + Pressure_j = node[jPoint]->GetPressure(); + Diff[nVar-1] = (node[iPoint]->GetSolution(nVar-1) + Pressure_i) - (node[jPoint]->GetSolution(nVar-1) + Pressure_j); + } + + boundary_i = geometry->node[iPoint]->GetPhysicalBoundary(); + boundary_j = geometry->node[jPoint]->GetPhysicalBoundary(); + + /*--- Both points inside the domain, or both in the boundary ---*/ + + if ((!boundary_i && !boundary_j) || (boundary_i && boundary_j)) { + if (geometry->node[iPoint]->GetDomain()) node[iPoint]->SubtractUnd_Lapl(Diff); + if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddUnd_Lapl(Diff); + } + + /*--- iPoint inside the domain, jPoint on the boundary ---*/ + + if (!boundary_i && boundary_j) + if (geometry->node[iPoint]->GetDomain()) node[iPoint]->SubtractUnd_Lapl(Diff); + + /*--- jPoint inside the domain, iPoint on the boundary ---*/ + + if (boundary_i && !boundary_j) + if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddUnd_Lapl(Diff); + + } + + /*--- MPI parallelization ---*/ + + Set_MPI_Undivided_Laplacian(geometry, config); + + delete [] Diff; + +} + +void CEulerSolver::SetDissipation_Switch(CGeometry *geometry, CConfig *config) { + + unsigned long iEdge, iPoint, jPoint; + su2double Pressure_i = 0.0, Pressure_j = 0.0; + bool boundary_i, boundary_j; + + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + + /*--- Reset variables to store the undivided pressure ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + iPoint_UndLapl[iPoint] = 0.0; + jPoint_UndLapl[iPoint] = 0.0; + } + + /*--- Evaluate the pressure sensor ---*/ + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + + /*--- Get the pressure, or density for incompressible solvers ---*/ + + if (compressible) { + Pressure_i = node[iPoint]->GetPressure(); + Pressure_j = node[jPoint]->GetPressure(); + } + if (incompressible || freesurface) { + Pressure_i = node[iPoint]->GetDensityInc(); + Pressure_j = node[jPoint]->GetDensityInc(); + } + + boundary_i = geometry->node[iPoint]->GetPhysicalBoundary(); + boundary_j = geometry->node[jPoint]->GetPhysicalBoundary(); + + /*--- Both points inside the domain, or both on the boundary ---*/ + + if ((!boundary_i && !boundary_j) || (boundary_i && boundary_j)) { + if (geometry->node[iPoint]->GetDomain()) { iPoint_UndLapl[iPoint] += (Pressure_j - Pressure_i); jPoint_UndLapl[iPoint] += (Pressure_i + Pressure_j); } + if (geometry->node[jPoint]->GetDomain()) { iPoint_UndLapl[jPoint] += (Pressure_i - Pressure_j); jPoint_UndLapl[jPoint] += (Pressure_i + Pressure_j); } + } + + /*--- iPoint inside the domain, jPoint on the boundary ---*/ + + if (!boundary_i && boundary_j) + if (geometry->node[iPoint]->GetDomain()) { iPoint_UndLapl[iPoint] += (Pressure_j - Pressure_i); jPoint_UndLapl[iPoint] += (Pressure_i + Pressure_j); } + + /*--- jPoint inside the domain, iPoint on the boundary ---*/ + + if (boundary_i && !boundary_j) + if (geometry->node[jPoint]->GetDomain()) { iPoint_UndLapl[jPoint] += (Pressure_i - Pressure_j); jPoint_UndLapl[jPoint] += (Pressure_i + Pressure_j); } + + } + + /*--- Set pressure switch for each point ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) + node[iPoint]->SetSensor(fabs(iPoint_UndLapl[iPoint]) / jPoint_UndLapl[iPoint]); + + /*--- MPI parallelization ---*/ + + Set_MPI_Dissipation_Switch(geometry, config); + +} + +void CEulerSolver::Inviscid_Forces(CGeometry *geometry, CConfig *config) { + + unsigned long iVertex, iPoint; + unsigned short iDim, iMarker, Boundary, Monitoring, iMarker_Monitoring; + su2double Pressure = 0.0, *Normal = NULL, MomentDist[3] = {0.0,0.0,0.0}, *Coord, Area, + factor, NFPressOF, RefVel2, RefTemp, RefDensity, RefPressure, Mach2Vel, Mach_Motion, + Force[3] = {0.0,0.0,0.0}; + string Marker_Tag, Monitoring_Tag; + +#ifdef HAVE_MPI + su2double MyAllBound_CDrag_Inv, MyAllBound_CLift_Inv, MyAllBound_CSideForce_Inv, MyAllBound_CMx_Inv, MyAllBound_CMy_Inv, MyAllBound_CMz_Inv, MyAllBound_CFx_Inv, MyAllBound_CFy_Inv, MyAllBound_CFz_Inv, MyAllBound_CT_Inv, MyAllBound_CQ_Inv, MyAllBound_CNearFieldOF_Inv, *MySurface_CLift_Inv = NULL, *MySurface_CDrag_Inv = NULL, *MySurface_CSideForce_Inv = NULL, *MySurface_CEff_Inv = NULL, *MySurface_CFx_Inv = NULL, *MySurface_CFy_Inv = NULL, *MySurface_CFz_Inv = NULL, *MySurface_CMx_Inv = NULL, *MySurface_CMy_Inv = NULL, *MySurface_CMz_Inv = NULL; +#endif + + su2double Alpha = config->GetAoA()*PI_NUMBER/180.0; + su2double Beta = config->GetAoS()*PI_NUMBER/180.0; + su2double RefAreaCoeff = config->GetRefAreaCoeff(); + su2double RefLengthMoment = config->GetRefLengthMoment(); + su2double Gas_Constant = config->GetGas_ConstantND(); + su2double *Origin = config->GetRefOriginMoment(0); + bool grid_movement = config->GetGrid_Movement(); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + + /*--- 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; + RefPressure = Pressure_Inf; + if (grid_movement) { + 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]; + } + + factor = 1.0 / (0.5*RefDensity*RefAreaCoeff*RefVel2); + + /*-- Variables initialization ---*/ + + Total_CDrag = 0.0; Total_CLift = 0.0; Total_CSideForce = 0.0; Total_CEff = 0.0; + Total_CMx = 0.0; Total_CMy = 0.0; Total_CMz = 0.0; + Total_CFx = 0.0; Total_CFy = 0.0; Total_CFz = 0.0; + Total_CT = 0.0; Total_CQ = 0.0; Total_CMerit = 0.0; + Total_CNearFieldOF = 0.0; Total_Heat = 0.0; Total_MaxHeat = 0.0; + + AllBound_CDrag_Inv = 0.0; AllBound_CLift_Inv = 0.0; AllBound_CSideForce_Inv = 0.0; + AllBound_CMx_Inv = 0.0; AllBound_CMy_Inv = 0.0; AllBound_CMz_Inv = 0.0; + AllBound_CFx_Inv = 0.0; AllBound_CFy_Inv = 0.0; AllBound_CFz_Inv = 0.0; + AllBound_CT_Inv = 0.0; AllBound_CQ_Inv = 0.0; AllBound_CMerit_Inv = 0.0; + AllBound_CNearFieldOF_Inv = 0.0; AllBound_CEff_Inv = 0.0; + + for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { + Surface_CLift_Inv[iMarker_Monitoring] = 0.0; Surface_CDrag_Inv[iMarker_Monitoring] = 0.0; + Surface_CSideForce_Inv[iMarker_Monitoring] = 0.0; Surface_CEff_Inv[iMarker_Monitoring] = 0.0; + Surface_CFx_Inv[iMarker_Monitoring] = 0.0; Surface_CFy_Inv[iMarker_Monitoring] = 0.0; + Surface_CFz_Inv[iMarker_Monitoring] = 0.0; Surface_CMx_Inv[iMarker_Monitoring] = 0.0; + Surface_CMy_Inv[iMarker_Monitoring] = 0.0; Surface_CMz_Inv[iMarker_Monitoring] = 0.0; + Surface_CLift[iMarker_Monitoring] = 0.0; Surface_CDrag[iMarker_Monitoring] = 0.0; + Surface_CSideForce[iMarker_Monitoring] = 0.0; Surface_CEff[iMarker_Monitoring] = 0.0; + Surface_CFx[iMarker_Monitoring] = 0.0; Surface_CFy[iMarker_Monitoring] = 0.0; + Surface_CFz[iMarker_Monitoring] = 0.0; Surface_CMx[iMarker_Monitoring] = 0.0; + Surface_CMy[iMarker_Monitoring] = 0.0; Surface_CMz[iMarker_Monitoring] = 0.0; + } + + /*--- Loop over the Euler and Navier-Stokes markers ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + Boundary = config->GetMarker_All_KindBC(iMarker); + Monitoring = config->GetMarker_All_Monitoring(iMarker); + + /*--- Obtain the origin for the moment computation for a particular marker ---*/ + + if (Monitoring == YES) { + for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { + Monitoring_Tag = config->GetMarker_Monitoring(iMarker_Monitoring); + Marker_Tag = config->GetMarker_All_TagBound(iMarker); + if (Marker_Tag == Monitoring_Tag) + Origin = config->GetRefOriginMoment(iMarker_Monitoring); + } + } + + if ((Boundary == EULER_WALL) || (Boundary == HEAT_FLUX) || + (Boundary == ISOTHERMAL) || (Boundary == NEARFIELD_BOUNDARY)) { + + /*--- Forces initialization at each Marker ---*/ + + CDrag_Inv[iMarker] = 0.0; CLift_Inv[iMarker] = 0.0; CSideForce_Inv[iMarker] = 0.0; + CMx_Inv[iMarker] = 0.0; CMy_Inv[iMarker] = 0.0; CMz_Inv[iMarker] = 0.0; + CFx_Inv[iMarker] = 0.0; CFy_Inv[iMarker] = 0.0; CFz_Inv[iMarker] = 0.0; + CT_Inv[iMarker] = 0.0; CQ_Inv[iMarker] = 0.0; CMerit_Inv[iMarker] = 0.0; + CNearFieldOF_Inv[iMarker] = 0.0; CEff_Inv[iMarker] = 0.0; + + for (iDim = 0; iDim < nDim; iDim++) ForceInviscid[iDim] = 0.0; + MomentInviscid[0] = 0.0; MomentInviscid[1] = 0.0; MomentInviscid[2] = 0.0; + NFPressOF = 0.0; + + /*--- Loop over the vertices to compute the forces ---*/ + + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (compressible) Pressure = node[iPoint]->GetPressure(); + if (incompressible || freesurface) Pressure = node[iPoint]->GetPressureInc(); + + CPressure[iMarker][iVertex] = (Pressure - RefPressure)*factor*RefAreaCoeff; + + /*--- Note that the pressure coefficient is computed at the + halo cells (for visualization purposes), but not the forces ---*/ + + if ( (geometry->node[iPoint]->GetDomain()) && (Monitoring == YES) ) { + + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + Coord = geometry->node[iPoint]->GetCoord(); + + /*--- Quadratic objective function for the near-field. + This uses the infinity pressure regardless of Mach number. ---*/ + + NFPressOF += 0.5*(Pressure - Pressure_Inf)*(Pressure - Pressure_Inf)*Normal[nDim-1]; + + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); + for (iDim = 0; iDim < nDim; iDim++) { + MomentDist[iDim] = Coord[iDim] - Origin[iDim]; + } + + /*--- Force computation, note the minus sign due to the + orientation of the normal (outward) ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + Force[iDim] = -(Pressure - Pressure_Inf)*Normal[iDim]*factor; + ForceInviscid[iDim] += Force[iDim]; + } + + /*--- Moment with respect to the reference axis ---*/ + + if (nDim == 3) { + MomentInviscid[0] += (Force[2]*MomentDist[1]-Force[1]*MomentDist[2])/RefLengthMoment; + MomentInviscid[1] += (Force[0]*MomentDist[2]-Force[2]*MomentDist[0])/RefLengthMoment; + } + MomentInviscid[2] += (Force[1]*MomentDist[0]-Force[0]*MomentDist[1])/RefLengthMoment; + } + + } + + /*--- Project forces and store the non-dimensional coefficients ---*/ + + if (Monitoring == YES) { + + if (Boundary != NEARFIELD_BOUNDARY) { + if (nDim == 2) { + CDrag_Inv[iMarker] = ForceInviscid[0]*cos(Alpha) + ForceInviscid[1]*sin(Alpha); + CLift_Inv[iMarker] = -ForceInviscid[0]*sin(Alpha) + ForceInviscid[1]*cos(Alpha); + CEff_Inv[iMarker] = CLift_Inv[iMarker] / (CDrag_Inv[iMarker]+EPS); + CMz_Inv[iMarker] = MomentInviscid[2]; + CFx_Inv[iMarker] = ForceInviscid[0]; + CFy_Inv[iMarker] = ForceInviscid[1]; + CT_Inv[iMarker] = -CFx_Inv[iMarker]; + CQ_Inv[iMarker] = -CMz_Inv[iMarker]; + CMerit_Inv[iMarker] = CT_Inv[iMarker] / (CQ_Inv[iMarker] + EPS); + } + if (nDim == 3) { + CDrag_Inv[iMarker] = ForceInviscid[0]*cos(Alpha)*cos(Beta) + ForceInviscid[1]*sin(Beta) + ForceInviscid[2]*sin(Alpha)*cos(Beta); + CLift_Inv[iMarker] = -ForceInviscid[0]*sin(Alpha) + ForceInviscid[2]*cos(Alpha); + CSideForce_Inv[iMarker] = -ForceInviscid[0]*sin(Beta)*cos(Alpha) + ForceInviscid[1]*cos(Beta) - ForceInviscid[2]*sin(Beta)*sin(Alpha); + CEff_Inv[iMarker] = CLift_Inv[iMarker] / (CDrag_Inv[iMarker] + EPS); + CMx_Inv[iMarker] = MomentInviscid[0]; + CMy_Inv[iMarker] = MomentInviscid[1]; + CMz_Inv[iMarker] = MomentInviscid[2]; + CFx_Inv[iMarker] = ForceInviscid[0]; + CFy_Inv[iMarker] = ForceInviscid[1]; + CFz_Inv[iMarker] = ForceInviscid[2]; + CT_Inv[iMarker] = -CFz_Inv[iMarker]; + CQ_Inv[iMarker] = -CMz_Inv[iMarker]; + CMerit_Inv[iMarker] = CT_Inv[iMarker] / (CQ_Inv[iMarker] + EPS); + } + + AllBound_CDrag_Inv += CDrag_Inv[iMarker]; + AllBound_CLift_Inv += CLift_Inv[iMarker]; + AllBound_CSideForce_Inv += CSideForce_Inv[iMarker]; + AllBound_CEff_Inv = AllBound_CLift_Inv / (AllBound_CDrag_Inv + EPS); + AllBound_CMx_Inv += CMx_Inv[iMarker]; + AllBound_CMy_Inv += CMy_Inv[iMarker]; + AllBound_CMz_Inv += CMz_Inv[iMarker]; + AllBound_CFx_Inv += CFx_Inv[iMarker]; + AllBound_CFy_Inv += CFy_Inv[iMarker]; + AllBound_CFz_Inv += CFz_Inv[iMarker]; + AllBound_CT_Inv += CT_Inv[iMarker]; + AllBound_CQ_Inv += CQ_Inv[iMarker]; + AllBound_CMerit_Inv = AllBound_CT_Inv / (AllBound_CQ_Inv + EPS); + + /*--- Compute the coefficients per surface ---*/ + + for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { + Monitoring_Tag = config->GetMarker_Monitoring(iMarker_Monitoring); + Marker_Tag = config->GetMarker_All_TagBound(iMarker); + if (Marker_Tag == Monitoring_Tag) { + Surface_CLift_Inv[iMarker_Monitoring] += CLift_Inv[iMarker]; + Surface_CDrag_Inv[iMarker_Monitoring] += CDrag_Inv[iMarker]; + Surface_CSideForce_Inv[iMarker_Monitoring] += CSideForce_Inv[iMarker]; + Surface_CEff_Inv[iMarker_Monitoring] = CLift_Inv[iMarker] / (CDrag_Inv[iMarker] + EPS); + Surface_CFx_Inv[iMarker_Monitoring] += CFx_Inv[iMarker]; + Surface_CFy_Inv[iMarker_Monitoring] += CFy_Inv[iMarker]; + Surface_CFz_Inv[iMarker_Monitoring] += CFz_Inv[iMarker]; + Surface_CMx_Inv[iMarker_Monitoring] += CMx_Inv[iMarker]; + Surface_CMy_Inv[iMarker_Monitoring] += CMy_Inv[iMarker]; + Surface_CMz_Inv[iMarker_Monitoring] += CMz_Inv[iMarker]; + } + } + + } + + /*--- At the Nearfield SU2 only cares about the pressure coeffient ---*/ + + else { + CNearFieldOF_Inv[iMarker] = NFPressOF; + AllBound_CNearFieldOF_Inv += CNearFieldOF_Inv[iMarker]; + } + + } + + + } + } + +#ifdef HAVE_MPI + + /*--- Add AllBound information using all the nodes ---*/ + + MyAllBound_CDrag_Inv = AllBound_CDrag_Inv; AllBound_CDrag_Inv = 0.0; + MyAllBound_CLift_Inv = AllBound_CLift_Inv; AllBound_CLift_Inv = 0.0; + MyAllBound_CSideForce_Inv = AllBound_CSideForce_Inv; AllBound_CSideForce_Inv = 0.0; + AllBound_CEff_Inv = 0.0; + MyAllBound_CMx_Inv = AllBound_CMx_Inv; AllBound_CMx_Inv = 0.0; + MyAllBound_CMy_Inv = AllBound_CMy_Inv; AllBound_CMy_Inv = 0.0; + MyAllBound_CMz_Inv = AllBound_CMz_Inv; AllBound_CMz_Inv = 0.0; + MyAllBound_CFx_Inv = AllBound_CFx_Inv; AllBound_CFx_Inv = 0.0; + MyAllBound_CFy_Inv = AllBound_CFy_Inv; AllBound_CFy_Inv = 0.0; + MyAllBound_CFz_Inv = AllBound_CFz_Inv; AllBound_CFz_Inv = 0.0; + MyAllBound_CT_Inv = AllBound_CT_Inv; AllBound_CT_Inv = 0.0; + MyAllBound_CQ_Inv = AllBound_CQ_Inv; AllBound_CQ_Inv = 0.0; + AllBound_CMerit_Inv = 0.0; + MyAllBound_CNearFieldOF_Inv = AllBound_CNearFieldOF_Inv; AllBound_CNearFieldOF_Inv = 0.0; + + SU2_MPI::Allreduce(&MyAllBound_CDrag_Inv, &AllBound_CDrag_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CLift_Inv, &AllBound_CLift_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CSideForce_Inv, &AllBound_CSideForce_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + AllBound_CEff_Inv = AllBound_CLift_Inv / (AllBound_CDrag_Inv + EPS); + SU2_MPI::Allreduce(&MyAllBound_CMx_Inv, &AllBound_CMx_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CMy_Inv, &AllBound_CMy_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CMz_Inv, &AllBound_CMz_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CFx_Inv, &AllBound_CFx_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CFy_Inv, &AllBound_CFy_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CFz_Inv, &AllBound_CFz_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CT_Inv, &AllBound_CT_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CQ_Inv, &AllBound_CQ_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + AllBound_CMerit_Inv = AllBound_CT_Inv / (AllBound_CQ_Inv + EPS); + SU2_MPI::Allreduce(&MyAllBound_CNearFieldOF_Inv, &AllBound_CNearFieldOF_Inv, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + + /*--- Add the forces on the surfaces using all the nodes ---*/ + + MySurface_CLift_Inv = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CDrag_Inv = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CSideForce_Inv = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CEff_Inv = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CFx_Inv = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CFy_Inv = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CFz_Inv = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CMx_Inv = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CMy_Inv = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CMz_Inv = new su2double[config->GetnMarker_Monitoring()]; + + for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { + MySurface_CLift_Inv[iMarker_Monitoring] = Surface_CLift_Inv[iMarker_Monitoring]; + MySurface_CDrag_Inv[iMarker_Monitoring] = Surface_CDrag_Inv[iMarker_Monitoring]; + MySurface_CSideForce_Inv[iMarker_Monitoring] = Surface_CSideForce_Inv[iMarker_Monitoring]; + MySurface_CEff_Inv[iMarker_Monitoring] = Surface_CEff_Inv[iMarker_Monitoring]; + MySurface_CFx_Inv[iMarker_Monitoring] = Surface_CFx_Inv[iMarker_Monitoring]; + MySurface_CFy_Inv[iMarker_Monitoring] = Surface_CFy_Inv[iMarker_Monitoring]; + MySurface_CFz_Inv[iMarker_Monitoring] = Surface_CFz_Inv[iMarker_Monitoring]; + MySurface_CMx_Inv[iMarker_Monitoring] = Surface_CMx_Inv[iMarker_Monitoring]; + MySurface_CMy_Inv[iMarker_Monitoring] = Surface_CMy_Inv[iMarker_Monitoring]; + MySurface_CMz_Inv[iMarker_Monitoring] = Surface_CMz_Inv[iMarker_Monitoring]; + + Surface_CLift_Inv[iMarker_Monitoring] = 0.0; + Surface_CDrag_Inv[iMarker_Monitoring] = 0.0; + Surface_CSideForce_Inv[iMarker_Monitoring] = 0.0; + Surface_CEff_Inv[iMarker_Monitoring] = 0.0; + Surface_CFx_Inv[iMarker_Monitoring] = 0.0; + Surface_CFy_Inv[iMarker_Monitoring] = 0.0; + Surface_CFz_Inv[iMarker_Monitoring] = 0.0; + Surface_CMx_Inv[iMarker_Monitoring] = 0.0; + Surface_CMy_Inv[iMarker_Monitoring] = 0.0; + Surface_CMz_Inv[iMarker_Monitoring] = 0.0; + } + + SU2_MPI::Allreduce(MySurface_CLift_Inv, Surface_CLift_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(MySurface_CDrag_Inv, Surface_CDrag_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(MySurface_CSideForce_Inv, Surface_CSideForce_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) + Surface_CEff_Inv[iMarker_Monitoring] = Surface_CLift_Inv[iMarker_Monitoring] / (Surface_CDrag_Inv[iMarker_Monitoring] + EPS); + SU2_MPI::Allreduce(MySurface_CFx_Inv, Surface_CFx_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(MySurface_CFy_Inv, Surface_CFy_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(MySurface_CFz_Inv, Surface_CFz_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(MySurface_CMx_Inv, Surface_CMx_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(MySurface_CMy_Inv, Surface_CMy_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(MySurface_CMz_Inv, Surface_CMz_Inv, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + + delete [] MySurface_CLift_Inv; delete [] MySurface_CDrag_Inv; delete [] MySurface_CSideForce_Inv; + delete [] MySurface_CEff_Inv; delete [] MySurface_CFx_Inv; delete [] MySurface_CFy_Inv; + delete [] MySurface_CFz_Inv; delete [] MySurface_CMx_Inv; delete [] MySurface_CMy_Inv; + delete [] MySurface_CMz_Inv; + +#endif + + /*--- Update the total coefficients (note that all the nodes have the same value) ---*/ + + Total_CDrag = AllBound_CDrag_Inv; + Total_CLift = AllBound_CLift_Inv; + Total_CSideForce = AllBound_CSideForce_Inv; + Total_CEff = Total_CLift / (Total_CDrag + EPS); + Total_CMx = AllBound_CMx_Inv; + Total_CMy = AllBound_CMy_Inv; + Total_CMz = AllBound_CMz_Inv; + Total_CFx = AllBound_CFx_Inv; + Total_CFy = AllBound_CFy_Inv; + Total_CFz = AllBound_CFz_Inv; + Total_CT = AllBound_CT_Inv; + Total_CQ = AllBound_CQ_Inv; + Total_CMerit = Total_CT / (Total_CQ + EPS); + Total_CNearFieldOF = AllBound_CNearFieldOF_Inv; + + /*--- Update the total coefficients per surface (note that all the nodes have the same value)---*/ + + for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { + Surface_CLift[iMarker_Monitoring] = Surface_CLift_Inv[iMarker_Monitoring]; + Surface_CDrag[iMarker_Monitoring] = Surface_CDrag_Inv[iMarker_Monitoring]; + Surface_CSideForce[iMarker_Monitoring] = Surface_CSideForce_Inv[iMarker_Monitoring]; + Surface_CEff[iMarker_Monitoring] = Surface_CLift_Inv[iMarker_Monitoring] / (Surface_CDrag_Inv[iMarker_Monitoring] + EPS); + Surface_CFx[iMarker_Monitoring] = Surface_CFx_Inv[iMarker_Monitoring]; + Surface_CFy[iMarker_Monitoring] = Surface_CFy_Inv[iMarker_Monitoring]; + Surface_CFz[iMarker_Monitoring] = Surface_CFz_Inv[iMarker_Monitoring]; + Surface_CMx[iMarker_Monitoring] = Surface_CMx_Inv[iMarker_Monitoring]; + Surface_CMy[iMarker_Monitoring] = Surface_CMy_Inv[iMarker_Monitoring]; + Surface_CMz[iMarker_Monitoring] = Surface_CMz_Inv[iMarker_Monitoring]; + } + +} + +void CEulerSolver::TurboPerformance(CSolver *solver, CConfig *config, unsigned short inMarker, unsigned short outMarker, unsigned short Kind_TurboPerf, unsigned short inMarkerTP ){ + + su2double avgVel2In, avgVel2Out,avgVelRel2In, avgVelRel2Out, avgGridVel2In, avgGridVel2Out, avgTotalEnthalpyIn= 0.0,avgTotalRothalpyIn, + avgTotalEnthalpyOut, avgTotalRothalpyOut, avgTotalEnthalpyOutIs, avgEnthalpyOut, avgEnthalpyOutIs, + avgPressureOut, avgTotalRelPressureIn, avgTotalRelPressureOut, avgEntropyIn, avgEntropyOut; + unsigned short iDim; + + + /*--- compute or retrieve inlet information ---*/ + avgVelRel2In= 0.0; + avgGridVel2In= 0.0; + avgVel2In= 0.0; + for (iDim = 0; iDim < nDim; iDim++){ + avgVelRel2In +=( AveragedVelocity[inMarker][iDim] - AveragedGridVel[inMarker][iDim])*( AveragedVelocity[inMarker][iDim] - AveragedGridVel[inMarker][iDim]); + avgGridVel2In += AveragedGridVel[inMarker][iDim]*AveragedGridVel[inMarker][iDim]; + avgVel2In += AveragedVelocity[inMarker][iDim]*AveragedVelocity[inMarker][iDim]; + } + + avgTotalRothalpyIn = AveragedEnthalpy[inMarker] + 0.5*avgVelRel2In - 0.5*avgGridVel2In; + avgTotalEnthalpyIn = AveragedEnthalpy[inMarker] + 0.5*avgVel2In; + avgEntropyIn = AveragedEntropy[inMarker]; + FluidModel->SetTDState_hs(avgTotalRothalpyIn, avgEntropyIn); + avgTotalRelPressureIn = FluidModel->GetPressure(); + + + + /*--- compute or retrieve outlet information ---*/ + avgVelRel2Out = 0.0; + avgGridVel2Out = 0.0; + avgVel2Out = 0.0; + for (iDim = 0; iDim < nDim; iDim++){ + avgVelRel2Out += (solver->GetAveragedVelocity(outMarker)[iDim]- solver->GetAveragedGridVelocity(outMarker)[iDim])*(solver->GetAveragedVelocity(outMarker)[iDim]- solver->GetAveragedGridVelocity(outMarker)[iDim]); + avgGridVel2Out += solver->GetAveragedGridVelocity(outMarker)[iDim]*solver->GetAveragedGridVelocity(outMarker)[iDim]; + avgVel2Out += solver->GetAveragedVelocity(outMarker)[iDim]*solver->GetAveragedVelocity(outMarker)[iDim]; + } + avgTotalRothalpyOut = solver->GetAveragedEnthalpy(outMarker) + 0.5*avgVelRel2Out - 0.5*avgGridVel2Out; + avgTotalEnthalpyOut = solver->GetAveragedEnthalpy(outMarker) + 0.5*avgVel2Out; + avgEntropyOut = solver->GetAveragedEntropy(outMarker); + avgEnthalpyOut = solver->GetAveragedEnthalpy(outMarker); + FluidModel->SetTDState_hs(avgTotalRothalpyOut, avgEntropyOut); + avgTotalRelPressureOut = FluidModel->GetPressure(); + avgPressureOut= solver->GetAveragedPressure(outMarker); + + /*--- compute outlet isoentropic conditions ---*/ + FluidModel->SetTDState_Ps(avgPressureOut, avgEntropyIn); + avgEnthalpyOutIs = FluidModel->GetStaticEnergy() + avgPressureOut/FluidModel->GetDensity(); + avgTotalEnthalpyOutIs = avgEnthalpyOutIs + 0.5*avgVel2Out; + + /*--- store turboperformance informations ---*/ + PressureOut[inMarkerTP] = avgPressureOut; + PressureRatio[inMarkerTP] = avgTotalRelPressureIn/avgPressureOut; + + switch(Kind_TurboPerf){ + case BLADE: + + TotalPressureLoss[inMarkerTP] = (avgTotalRelPressureIn - avgTotalRelPressureOut)/(avgTotalRelPressureOut - avgPressureOut) ; + KineticEnergyLoss[inMarkerTP] = (avgEnthalpyOut - avgEnthalpyOutIs)/(avgTotalRothalpyIn - avgEnthalpyOut + 0.5*avgGridVel2Out); + EulerianWork[inMarkerTP] = avgTotalEnthalpyIn - avgTotalEnthalpyOut; + TotalEnthalpyIn[inMarkerTP] = avgTotalRothalpyIn; + FlowAngleIn[inMarkerTP]= FlowAngle[inMarker]; + FlowAngleOut[inMarkerTP]= solver->GetFlowAngle(outMarker); + MassFlowIn[inMarkerTP]= MassFlow[inMarker]; + MassFlowOut[inMarkerTP]= solver->GetMassFlow(outMarker); + MachIn[inMarkerTP]= AveragedMach[inMarker]; + MachOut[inMarkerTP]= solver->GetAveragedMach(outMarker); + NormalMachIn[inMarkerTP]= AveragedNormalMach[inMarker]; + NormalMachOut[inMarkerTP]= solver->GetAveragedNormalMach(outMarker); + EnthalpyOut[inMarkerTP]= avgEnthalpyOut; + VelocityOutIs[inMarkerTP]=sqrt(2.0*(avgTotalRothalpyIn - avgEnthalpyOut + 0.5*avgGridVel2Out)); + break; + + case STAGE: case TURBINE: + + TotalTotalEfficiency[inMarkerTP] = (avgTotalEnthalpyIn - avgTotalEnthalpyOut)/(avgTotalEnthalpyIn - avgTotalEnthalpyOutIs); + TotalStaticEfficiency[inMarkerTP] = (avgTotalEnthalpyIn - avgTotalEnthalpyOut)/(avgTotalEnthalpyIn - avgEnthalpyOutIs); + TotalEnthalpyIn[inMarkerTP]= avgTotalEnthalpyIn; + EnthalpyOut[inMarkerTP] = avgTotalEnthalpyOut; + break; + + default: + cout << "Warning! Invalid TurboPerformance option!" << endl; + exit(EXIT_FAILURE); + break; + } + + + + + +} + +void CEulerSolver::ExplicitRK_Iteration(CGeometry *geometry, CSolver **solver_container, + CConfig *config, unsigned short iRKStep) { + su2double *Residual, *Res_TruncError, Vol, Delta, Res; + unsigned short iVar; + unsigned long iPoint; + + su2double RK_AlphaCoeff = config->Get_Alpha_RKStep(iRKStep); + bool adjoint = config->GetAdjoint(); + + for (iVar = 0; iVar < nVar; iVar++) { + SetRes_RMS(iVar, 0.0); + SetRes_Max(iVar, 0.0, 0); + } + + /*--- Update the solution ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + Vol = geometry->node[iPoint]->GetVolume(); + Delta = node[iPoint]->GetDelta_Time() / Vol; + + Res_TruncError = node[iPoint]->GetResTruncError(); + Residual = LinSysRes.GetBlock(iPoint); + + if (!adjoint) { + for (iVar = 0; iVar < nVar; iVar++) { + Res = Residual[iVar] + Res_TruncError[iVar]; + node[iPoint]->AddSolution(iVar, -Res*Delta*RK_AlphaCoeff); + AddRes_RMS(iVar, Res*Res); + AddRes_Max(iVar, fabs(Res), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); + } + } + + } + + /*--- MPI solution ---*/ + + Set_MPI_Solution(geometry, config); + + /*--- Compute the root mean square residual ---*/ + + SetResidual_RMS(geometry, config); + + +} + +void CEulerSolver::ExplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { + su2double *local_Residual, *local_Res_TruncError, Vol, Delta, Res; + unsigned short iVar; + unsigned long iPoint; + + bool adjoint = config->GetAdjoint(); + + for (iVar = 0; iVar < nVar; iVar++) { + SetRes_RMS(iVar, 0.0); + SetRes_Max(iVar, 0.0, 0); + } + + /*--- Update the solution ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + Vol = geometry->node[iPoint]->GetVolume(); + Delta = node[iPoint]->GetDelta_Time() / Vol; + + local_Res_TruncError = node[iPoint]->GetResTruncError(); + local_Residual = LinSysRes.GetBlock(iPoint); + + if (!adjoint) { + for (iVar = 0; iVar < nVar; iVar++) { + Res = local_Residual[iVar] + local_Res_TruncError[iVar]; + node[iPoint]->AddSolution(iVar, -Res*Delta); + AddRes_RMS(iVar, Res*Res); + AddRes_Max(iVar, fabs(Res), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); + } + } + + } + + /*--- MPI solution ---*/ + + Set_MPI_Solution(geometry, config); + + /*--- Compute the root mean square residual ---*/ + + SetResidual_RMS(geometry, config); + +} + +void CEulerSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { + + unsigned short iVar, jVar; + unsigned long iPoint, total_index, IterLinSol = 0; + su2double Delta, *local_Res_TruncError, Vol; + + bool adjoint = config->GetAdjoint(); + bool roe_turkel = config->GetKind_Upwind_Flow() == TURKEL; + + /*--- Set maximum residual to zero ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + SetRes_RMS(iVar, 0.0); + SetRes_Max(iVar, 0.0, 0); + } + + /*--- Build implicit system ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Read the residual ---*/ + + local_Res_TruncError = node[iPoint]->GetResTruncError(); + + /*--- Read the volume ---*/ + + Vol = geometry->node[iPoint]->GetVolume(); + + /*--- Modify matrix diagonal to assure diagonal dominance ---*/ + + + if (node[iPoint]->GetDelta_Time() != 0.0) { + Delta = Vol / node[iPoint]->GetDelta_Time(); + if (roe_turkel) { + SetPreconditioner(config, iPoint); + for (iVar = 0; iVar < nVar; iVar ++ ) + for (jVar = 0; jVar < nVar; jVar ++ ) + LowMach_Precontioner[iVar][jVar] = Delta*LowMach_Precontioner[iVar][jVar]; + Jacobian.AddBlock(iPoint, iPoint, LowMach_Precontioner); + } + else { + Jacobian.AddVal2Diag(iPoint, Delta); + } + } + else { + Jacobian.SetVal2Diag(iPoint, 1.0); + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar + iVar; + LinSysRes[total_index] = 0.0; + local_Res_TruncError[iVar] = 0.0; + } + } + + /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar + iVar; + LinSysRes[total_index] = - (LinSysRes[total_index] + local_Res_TruncError[iVar]); + LinSysSol[total_index] = 0.0; + AddRes_RMS(iVar, LinSysRes[total_index]*LinSysRes[total_index]); + AddRes_Max(iVar, fabs(LinSysRes[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); + } + } + + /*--- Initialize residual and solution at the ghost points ---*/ + + for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar + iVar; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + } + } + + /*--- Solve or smooth the linear system ---*/ + + CSysSolve system; + IterLinSol = system.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); + + /*--- The the number of iterations of the linear solver ---*/ + + SetIterLinSolver(IterLinSol); + + /*--- Update solution (system written in terms of increments) ---*/ + + if (!adjoint) { + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + node[iPoint]->AddSolution(iVar, config->GetRelaxation_Factor_Flow()*LinSysSol[iPoint*nVar+iVar]); + } + } + } + + /*--- MPI solution ---*/ + + Set_MPI_Solution(geometry, config); + + /*--- Compute the root mean square residual ---*/ + + SetResidual_RMS(geometry, config); + +} + +void CEulerSolver::SetPrimitive_Gradient_GG(CGeometry *geometry, CConfig *config) { + unsigned long iPoint, jPoint, iEdge, iVertex; + unsigned short iDim, iVar, iMarker; + su2double *PrimVar_Vertex, *PrimVar_i, *PrimVar_j, PrimVar_Average, + Partial_Gradient, Partial_Res, *Normal; + + /*--- Gradient primitive variables compressible (temp, vx, vy, vz, P, rho) + Gradient primitive variables incompressible (rho, vx, vy, vz, beta) ---*/ + PrimVar_Vertex = new su2double [nPrimVarGrad]; + PrimVar_i = new su2double [nPrimVarGrad]; + PrimVar_j = new su2double [nPrimVarGrad]; + + /*--- Set Gradient_Primitive to zero ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) + node[iPoint]->SetGradient_PrimitiveZero(nPrimVarGrad); + + /*--- Loop interior edges ---*/ + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + + for (iVar = 0; iVar < nPrimVarGrad; iVar++) { + PrimVar_i[iVar] = node[iPoint]->GetPrimitive(iVar); + PrimVar_j[iVar] = node[jPoint]->GetPrimitive(iVar); + } + + Normal = geometry->edge[iEdge]->GetNormal(); + for (iVar = 0; iVar < nPrimVarGrad; iVar++) { + PrimVar_Average = 0.5 * ( PrimVar_i[iVar] + PrimVar_j[iVar] ); + for (iDim = 0; iDim < nDim; iDim++) { + Partial_Res = PrimVar_Average*Normal[iDim]; + if (geometry->node[iPoint]->GetDomain()) + node[iPoint]->AddGradient_Primitive(iVar, iDim, Partial_Res); + if (geometry->node[jPoint]->GetDomain()) + node[jPoint]->SubtractGradient_Primitive(iVar, iDim, Partial_Res); + } + } + } + + /*--- Loop boundary edges ---*/ + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if (geometry->node[iPoint]->GetDomain()) { + + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + PrimVar_Vertex[iVar] = node[iPoint]->GetPrimitive(iVar); + + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + for (iDim = 0; iDim < nDim; iDim++) { + Partial_Res = PrimVar_Vertex[iVar]*Normal[iDim]; + node[iPoint]->SubtractGradient_Primitive(iVar, iDim, Partial_Res); + } + } + } + } + + /*--- Update gradient value ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + for (iVar = 0; iVar < nPrimVarGrad; iVar++) { + for (iDim = 0; iDim < nDim; iDim++) { + Partial_Gradient = node[iPoint]->GetGradient_Primitive(iVar, iDim) / (geometry->node[iPoint]->GetVolume()); + node[iPoint]->SetGradient_Primitive(iVar, iDim, Partial_Gradient); + } + } + } + + delete [] PrimVar_Vertex; + delete [] PrimVar_i; + delete [] PrimVar_j; + + Set_MPI_Primitive_Gradient(geometry, config); + +} + +void CEulerSolver::SetPrimitive_Gradient_LS(CGeometry *geometry, CConfig *config) { + + unsigned short iVar, iDim, jDim, iNeigh; + unsigned long iPoint, jPoint; + su2double *PrimVar_i, *PrimVar_j, *Coord_i, *Coord_j, r11, r12, r13, r22, r23, r23_a, + r23_b, r33, weight, product, z11, z12, z13, z22, z23, z33, detR2; + bool singular; + + /*--- Loop over points of the grid ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Set the value of the singular ---*/ + singular = false; + + /*--- Get coordinates ---*/ + + Coord_i = geometry->node[iPoint]->GetCoord(); + + /*--- Get primitives from CVariable ---*/ + + PrimVar_i = node[iPoint]->GetPrimitive(); + + /*--- Inizialization of variables ---*/ + + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + cvector[iVar][iDim] = 0.0; + + r11 = 0.0; r12 = 0.0; r13 = 0.0; r22 = 0.0; + r23 = 0.0; r23_a = 0.0; r23_b = 0.0; r33 = 0.0; + + for (iNeigh = 0; iNeigh < geometry->node[iPoint]->GetnPoint(); iNeigh++) { + jPoint = geometry->node[iPoint]->GetPoint(iNeigh); + Coord_j = geometry->node[jPoint]->GetCoord(); + + PrimVar_j = node[jPoint]->GetPrimitive(); + + weight = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + weight += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); + + /*--- Sumations for entries of upper triangular matrix R ---*/ + + if (weight != 0.0) { + + r11 += (Coord_j[0]-Coord_i[0])*(Coord_j[0]-Coord_i[0])/weight; + r12 += (Coord_j[0]-Coord_i[0])*(Coord_j[1]-Coord_i[1])/weight; + r22 += (Coord_j[1]-Coord_i[1])*(Coord_j[1]-Coord_i[1])/weight; + + if (nDim == 3) { + r13 += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; + r23_a += (Coord_j[1]-Coord_i[1])*(Coord_j[2]-Coord_i[2])/weight; + r23_b += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; + r33 += (Coord_j[2]-Coord_i[2])*(Coord_j[2]-Coord_i[2])/weight; + } + + /*--- Entries of c:= transpose(A)*b ---*/ + + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + cvector[iVar][iDim] += (Coord_j[iDim]-Coord_i[iDim])*(PrimVar_j[iVar]-PrimVar_i[iVar])/weight; + + } + + } + + /*--- Entries of upper triangular matrix R ---*/ + + if (r11 >= 0.0) r11 = sqrt(r11); else r11 = 0.0; + if (r11 != 0.0) r12 = r12/r11; else r12 = 0.0; + if (r22-r12*r12 >= 0.0) r22 = sqrt(r22-r12*r12); else r22 = 0.0; + + if (nDim == 3) { + if (r11 != 0.0) r13 = r13/r11; else r13 = 0.0; + if ((r22 != 0.0) && (r11*r22 != 0.0)) r23 = r23_a/r22 - r23_b*r12/(r11*r22); else r23 = 0.0; + if (r33-r23*r23-r13*r13 >= 0.0) r33 = sqrt(r33-r23*r23-r13*r13); else r33 = 0.0; + } + + /*--- Compute determinant ---*/ + + if (nDim == 2) detR2 = (r11*r22)*(r11*r22); + else detR2 = (r11*r22*r33)*(r11*r22*r33); + + /*--- Detect singular matrices ---*/ + + if (abs(detR2) <= EPS) { detR2 = 1.0; singular = true; } + + /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ + + if (singular) { + for (iDim = 0; iDim < nDim; iDim++) + for (jDim = 0; jDim < nDim; jDim++) + Smatrix[iDim][jDim] = 0.0; + } + else { + if (nDim == 2) { + Smatrix[0][0] = (r12*r12+r22*r22)/detR2; + Smatrix[0][1] = -r11*r12/detR2; + Smatrix[1][0] = Smatrix[0][1]; + Smatrix[1][1] = r11*r11/detR2; + } + else { + z11 = r22*r33; z12 = -r12*r33; z13 = r12*r23-r13*r22; + z22 = r11*r33; z23 = -r11*r23; z33 = r11*r22; + Smatrix[0][0] = (z11*z11+z12*z12+z13*z13)/detR2; + Smatrix[0][1] = (z12*z22+z13*z23)/detR2; + Smatrix[0][2] = (z13*z33)/detR2; + Smatrix[1][0] = Smatrix[0][1]; + Smatrix[1][1] = (z22*z22+z23*z23)/detR2; + Smatrix[1][2] = (z23*z33)/detR2; + Smatrix[2][0] = Smatrix[0][2]; + Smatrix[2][1] = Smatrix[1][2]; + Smatrix[2][2] = (z33*z33)/detR2; + } + } + + /*--- Computation of the gradient: S*c ---*/ + for (iVar = 0; iVar < nPrimVarGrad; iVar++) { + for (iDim = 0; iDim < nDim; iDim++) { + product = 0.0; + for (jDim = 0; jDim < nDim; jDim++) { + product += Smatrix[iDim][jDim]*cvector[iVar][jDim]; + } + + node[iPoint]->SetGradient_Primitive(iVar, iDim, product); + } + } + + } + + Set_MPI_Primitive_Gradient(geometry, config); + +} + +void CEulerSolver::SetPrimitive_Limiter(CGeometry *geometry, CConfig *config) { + + unsigned long iEdge, iPoint, jPoint; + unsigned short iVar, iDim; + su2double **Gradient_i, **Gradient_j, *Coord_i, *Coord_j, *Primitive_i, *Primitive_j, + dave, LimK, eps2, eps1, dm, dp, du, y, limiter; + + /*--- Initialize solution max and solution min and the limiter in the entire domain --*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + for (iVar = 0; iVar < nPrimVarGrad; iVar++) { + node[iPoint]->SetSolution_Max(iVar, -EPS); + node[iPoint]->SetSolution_Min(iVar, EPS); + node[iPoint]->SetLimiter_Primitive(iVar, 2.0); + } + } + + /*--- Establish bounds for Spekreijse monotonicity by finding max & min values of neighbor variables --*/ + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Point identification, Normal vector and area ---*/ + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + + /*--- Get the primitive variables ---*/ + + Primitive_i = node[iPoint]->GetPrimitive(); + Primitive_j = node[jPoint]->GetPrimitive(); + + /*--- Compute the maximum, and minimum values for nodes i & j ---*/ + + for (iVar = 0; iVar < nPrimVarGrad; iVar++) { + du = (Primitive_j[iVar] - Primitive_i[iVar]); + node[iPoint]->SetSolution_Min(iVar, min(node[iPoint]->GetSolution_Min(iVar), du)); + node[iPoint]->SetSolution_Max(iVar, max(node[iPoint]->GetSolution_Max(iVar), du)); + node[jPoint]->SetSolution_Min(iVar, min(node[jPoint]->GetSolution_Min(iVar), -du)); + node[jPoint]->SetSolution_Max(iVar, max(node[jPoint]->GetSolution_Max(iVar), -du)); + } + + } + + + /*--- Barth-Jespersen limiter with Venkatakrishnan modification ---*/ + + if (config->GetKind_SlopeLimit_Flow() == BARTH_JESPERSEN) { + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + Gradient_i = node[iPoint]->GetGradient_Primitive(); + Gradient_j = node[jPoint]->GetGradient_Primitive(); + Coord_i = geometry->node[iPoint]->GetCoord(); + Coord_j = geometry->node[jPoint]->GetCoord(); + + for (iVar = 0; iVar < nPrimVarGrad; iVar++) { + + /*--- Calculate the interface left gradient, delta- (dm) ---*/ + + dm = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + dm += 0.5*(Coord_j[iDim]-Coord_i[iDim])*Gradient_i[iVar][iDim]; + + if (dm == 0.0) { limiter = 2.0; } + else { + if ( dm > 0.0 ) dp = node[iPoint]->GetSolution_Max(iVar); + else dp = node[iPoint]->GetSolution_Min(iVar); + limiter = dp/dm; + } + + if (limiter < node[iPoint]->GetLimiter_Primitive(iVar)) + node[iPoint]->SetLimiter_Primitive(iVar, limiter); + + /*--- Calculate the interface right gradient, delta+ (dp) ---*/ + + dm = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + dm += 0.5*(Coord_i[iDim]-Coord_j[iDim])*Gradient_j[iVar][iDim]; + + if (dm == 0.0) { limiter = 2.0; } + else { + if ( dm > 0.0 ) dp = node[jPoint]->GetSolution_Max(iVar); + else dp = node[jPoint]->GetSolution_Min(iVar); + limiter = dp/dm; + } + + if (limiter < node[jPoint]->GetLimiter_Primitive(iVar)) + node[jPoint]->SetLimiter_Primitive(iVar, limiter); + + } + + } + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + for (iVar = 0; iVar < nPrimVarGrad; iVar++) { + y = node[iPoint]->GetLimiter_Primitive(iVar); + limiter = (y*y + 2.0*y) / (y*y + y + 2.0); + node[iPoint]->SetLimiter_Primitive(iVar, limiter); + } + } + + } + + /*--- Venkatakrishnan limiter ---*/ + + if (config->GetKind_SlopeLimit_Flow() == VENKATAKRISHNAN) { + + /*-- Get limiter parameters from the configuration file ---*/ + + dave = config->GetRefElemLength(); + LimK = config->GetLimiterCoeff(); + eps1 = LimK*dave; + eps2 = eps1*eps1*eps1; + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + Gradient_i = node[iPoint]->GetGradient_Primitive(); + Gradient_j = node[jPoint]->GetGradient_Primitive(); + Coord_i = geometry->node[iPoint]->GetCoord(); + Coord_j = geometry->node[jPoint]->GetCoord(); + + for (iVar = 0; iVar < nPrimVarGrad; iVar++) { + + /*--- Calculate the interface left gradient, delta- (dm) ---*/ + + dm = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + dm += 0.5*(Coord_j[iDim]-Coord_i[iDim])*Gradient_i[iVar][iDim]; + + /*--- Calculate the interface right gradient, delta+ (dp) ---*/ + + if ( dm > 0.0 ) dp = node[iPoint]->GetSolution_Max(iVar); + else dp = node[iPoint]->GetSolution_Min(iVar); + + limiter = ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); + + if (limiter < node[iPoint]->GetLimiter_Primitive(iVar)) + node[iPoint]->SetLimiter_Primitive(iVar, limiter); + + /*-- Repeat for point j on the edge ---*/ + + dm = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + dm += 0.5*(Coord_i[iDim]-Coord_j[iDim])*Gradient_j[iVar][iDim]; + + if ( dm > 0.0 ) dp = node[jPoint]->GetSolution_Max(iVar); + else dp = node[jPoint]->GetSolution_Min(iVar); + + limiter = ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); + + if (limiter < node[jPoint]->GetLimiter_Primitive(iVar)) + node[jPoint]->SetLimiter_Primitive(iVar, limiter); + } + + } + + } + + /*--- Limiter MPI ---*/ + + Set_MPI_Primitive_Limiter(geometry, config); + +} + +//void CEulerSolver::SetSecondary_Gradient_GG(CGeometry *geometry, CConfig *config) { +// unsigned long iPoint, jPoint, iEdge, iVertex; +// unsigned short iDim, iVar, iMarker; +// su2double *SecondaryVar_Vertex, *SecondaryVar_i, *SecondaryVar_j, SecondaryVar_Average, +// Partial_Gradient, Partial_Res, *Normal; +// +// /*--- Gradient Secondary variables compressible (temp, vx, vy, vz, P, rho) +// Gradient Secondary variables incompressible (rho, vx, vy, vz, beta) ---*/ +// SecondaryVar_Vertex = new su2double [nSecondaryVarGrad]; +// SecondaryVar_i = new su2double [nSecondaryVarGrad]; +// SecondaryVar_j = new su2double [nSecondaryVarGrad]; +// +// /*--- Set Gradient_Secondary to zero ---*/ +// for (iPoint = 0; iPoint < nPointDomain; iPoint++) +// node[iPoint]->SetGradient_SecondaryZero(nSecondaryVarGrad); +// +// /*--- Loop interior edges ---*/ +// for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { +// iPoint = geometry->edge[iEdge]->GetNode(0); +// jPoint = geometry->edge[iEdge]->GetNode(1); +// +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { +// SecondaryVar_i[iVar] = node[iPoint]->GetSecondary(iVar); +// SecondaryVar_j[iVar] = node[jPoint]->GetSecondary(iVar); +// } +// +// Normal = geometry->edge[iEdge]->GetNormal(); +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { +// SecondaryVar_Average = 0.5 * ( SecondaryVar_i[iVar] + SecondaryVar_j[iVar] ); +// for (iDim = 0; iDim < nDim; iDim++) { +// Partial_Res = SecondaryVar_Average*Normal[iDim]; +// if (geometry->node[iPoint]->GetDomain()) +// node[iPoint]->AddGradient_Secondary(iVar, iDim, Partial_Res); +// if (geometry->node[jPoint]->GetDomain()) +// node[jPoint]->SubtractGradient_Secondary(iVar, iDim, Partial_Res); +// } +// } +// } +// +// /*--- Loop boundary edges ---*/ +// for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { +// for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { +// iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); +// if (geometry->node[iPoint]->GetDomain()) { +// +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) +// SecondaryVar_Vertex[iVar] = node[iPoint]->GetSecondary(iVar); +// +// Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) +// for (iDim = 0; iDim < nDim; iDim++) { +// Partial_Res = SecondaryVar_Vertex[iVar]*Normal[iDim]; +// node[iPoint]->SubtractGradient_Secondary(iVar, iDim, Partial_Res); +// } +// } +// } +// } +// +// /*--- Update gradient value ---*/ +// for (iPoint = 0; iPoint < nPointDomain; iPoint++) { +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { +// for (iDim = 0; iDim < nDim; iDim++) { +// Partial_Gradient = node[iPoint]->GetGradient_Secondary(iVar, iDim) / (geometry->node[iPoint]->GetVolume()); +// node[iPoint]->SetGradient_Secondary(iVar, iDim, Partial_Gradient); +// } +// } +// } +// +// delete [] SecondaryVar_Vertex; +// delete [] SecondaryVar_i; +// delete [] SecondaryVar_j; +// +// Set_MPI_Secondary_Gradient(geometry, config); +// +//} + +//void CEulerSolver::SetSecondary_Gradient_LS(CGeometry *geometry, CConfig *config) { +// +// unsigned short iVar, iDim, jDim, iNeigh; +// unsigned long iPoint, jPoint; +// su2double *SecondaryVar_i, *SecondaryVar_j, *Coord_i, *Coord_j, r11, r12, r13, r22, r23, r23_a, +// r23_b, r33, weight, product, z11, z12, z13, z22, z23, z33, detR2; +// bool singular; +// +// /*--- Loop over points of the grid ---*/ +// +// for (iPoint = 0; iPoint < nPointDomain; iPoint++) { +// +// /*--- Set the value of the singular ---*/ +// singular = false; +// +// /*--- Get coordinates ---*/ +// +// Coord_i = geometry->node[iPoint]->GetCoord(); +// +// /*--- Get Secondarys from CVariable ---*/ +// +// SecondaryVar_i = node[iPoint]->GetSecondary(); +// +// /*--- Inizialization of variables ---*/ +// +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) +// for (iDim = 0; iDim < nDim; iDim++) +// cvector[iVar][iDim] = 0.0; +// +// r11 = 0.0; r12 = 0.0; r13 = 0.0; r22 = 0.0; +// r23 = 0.0; r23_a = 0.0; r23_b = 0.0; r33 = 0.0; detR2 = 0.0; +// +// for (iNeigh = 0; iNeigh < geometry->node[iPoint]->GetnPoint(); iNeigh++) { +// jPoint = geometry->node[iPoint]->GetPoint(iNeigh); +// Coord_j = geometry->node[jPoint]->GetCoord(); +// +// SecondaryVar_j = node[jPoint]->GetSecondary(); +// +// weight = 0.0; +// for (iDim = 0; iDim < nDim; iDim++) +// weight += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); +// +// /*--- Sumations for entries of upper triangular matrix R ---*/ +// +// if (weight != 0.0) { +// +// r11 += (Coord_j[0]-Coord_i[0])*(Coord_j[0]-Coord_i[0])/weight; +// r12 += (Coord_j[0]-Coord_i[0])*(Coord_j[1]-Coord_i[1])/weight; +// r22 += (Coord_j[1]-Coord_i[1])*(Coord_j[1]-Coord_i[1])/weight; +// +// if (nDim == 3) { +// r13 += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; +// r23_a += (Coord_j[1]-Coord_i[1])*(Coord_j[2]-Coord_i[2])/weight; +// r23_b += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; +// r33 += (Coord_j[2]-Coord_i[2])*(Coord_j[2]-Coord_i[2])/weight; +// } +// +// /*--- Entries of c:= transpose(A)*b ---*/ +// +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) +// for (iDim = 0; iDim < nDim; iDim++) +// cvector[iVar][iDim] += (Coord_j[iDim]-Coord_i[iDim])*(SecondaryVar_j[iVar]-SecondaryVar_i[iVar])/weight; +// +// } +// +// } +// +// /*--- Entries of upper triangular matrix R ---*/ +// +// if (r11 >= 0.0) r11 = sqrt(r11); else r11 = 0.0; +// if (r11 != 0.0) r12 = r12/r11; else r12 = 0.0; +// if (r22-r12*r12 >= 0.0) r22 = sqrt(r22-r12*r12); else r22 = 0.0; +// +// if (nDim == 3) { +// if (r11 != 0.0) r13 = r13/r11; else r13 = 0.0; +// if ((r22 != 0.0) && (r11*r22 != 0.0)) r23 = r23_a/r22 - r23_b*r12/(r11*r22); else r23 = 0.0; +// if (r33-r23*r23-r13*r13 >= 0.0) r33 = sqrt(r33-r23*r23-r13*r13); else r33 = 0.0; +// } +// +// /*--- Compute determinant ---*/ +// +// if (nDim == 2) detR2 = (r11*r22)*(r11*r22); +// else detR2 = (r11*r22*r33)*(r11*r22*r33); +// +// /*--- Detect singular matrices ---*/ +// +// if (abs(detR2) <= EPS) { detR2 = 1.0; singular = true; } +// +// /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ +// +// if (singular) { +// for (iDim = 0; iDim < nDim; iDim++) +// for (jDim = 0; jDim < nDim; jDim++) +// Smatrix[iDim][jDim] = 0.0; +// } +// else { +// if (nDim == 2) { +// Smatrix[0][0] = (r12*r12+r22*r22)/detR2; +// Smatrix[0][1] = -r11*r12/detR2; +// Smatrix[1][0] = Smatrix[0][1]; +// Smatrix[1][1] = r11*r11/detR2; +// } +// else { +// z11 = r22*r33; z12 = -r12*r33; z13 = r12*r23-r13*r22; +// z22 = r11*r33; z23 = -r11*r23; z33 = r11*r22; +// Smatrix[0][0] = (z11*z11+z12*z12+z13*z13)/detR2; +// Smatrix[0][1] = (z12*z22+z13*z23)/detR2; +// Smatrix[0][2] = (z13*z33)/detR2; +// Smatrix[1][0] = Smatrix[0][1]; +// Smatrix[1][1] = (z22*z22+z23*z23)/detR2; +// Smatrix[1][2] = (z23*z33)/detR2; +// Smatrix[2][0] = Smatrix[0][2]; +// Smatrix[2][1] = Smatrix[1][2]; +// Smatrix[2][2] = (z33*z33)/detR2; +// } +// } +// +// /*--- Computation of the gradient: S*c ---*/ +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { +// for (iDim = 0; iDim < nDim; iDim++) { +// product = 0.0; +// for (jDim = 0; jDim < nDim; jDim++) { +// product += Smatrix[iDim][jDim]*cvector[iVar][jDim]; +// } +// +// node[iPoint]->SetGradient_Secondary(iVar, iDim, product); +// } +// } +// +// } +// +// Set_MPI_Secondary_Gradient(geometry, config); +// +//} + +//void CEulerSolver::SetSecondary_Limiter(CGeometry *geometry, CConfig *config) { +// +// unsigned long iEdge, iPoint, jPoint; +// unsigned short iVar, iDim; +// su2double **Gradient_i, **Gradient_j, *Coord_i, *Coord_j, *Secondary_i, *Secondary_j, +// dave, LimK, eps2, dm, dp, du, limiter; +// +// /*--- Initialize solution max and solution min in the entire domain --*/ +// for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { +// node[iPoint]->SetSolution_Max(iVar, -EPS); +// node[iPoint]->SetSolution_Min(iVar, EPS); +// } +// } +// +// /*--- Establish bounds for Spekreijse monotonicity by finding max & min values of neighbor variables --*/ +// for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { +// +// /*--- Point identification, Normal vector and area ---*/ +// iPoint = geometry->edge[iEdge]->GetNode(0); +// jPoint = geometry->edge[iEdge]->GetNode(1); +// +// /*--- Get the conserved variables ---*/ +// Secondary_i = node[iPoint]->GetSecondary(); +// Secondary_j = node[jPoint]->GetSecondary(); +// +// /*--- Compute the maximum, and minimum values for nodes i & j ---*/ +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { +// du = (Secondary_j[iVar] - Secondary_i[iVar]); +// node[iPoint]->SetSolution_Min(iVar, min(node[iPoint]->GetSolution_Min(iVar), du)); +// node[iPoint]->SetSolution_Max(iVar, max(node[iPoint]->GetSolution_Max(iVar), du)); +// node[jPoint]->SetSolution_Min(iVar, min(node[jPoint]->GetSolution_Min(iVar), -du)); +// node[jPoint]->SetSolution_Max(iVar, max(node[jPoint]->GetSolution_Max(iVar), -du)); +// } +// } +// +// /*--- Initialize the limiter --*/ +// for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { +// node[iPoint]->SetLimiter_Secondary(iVar, 2.0); +// } +// } +// +// /*--- Venkatakrishnan limiter ---*/ +// +// if (config->GetKind_SlopeLimit() == VENKATAKRISHNAN) { +// +// /*-- Get limiter parameters from the configuration file ---*/ +// dave = config->GetRefElemLength(); +// LimK = config->GetLimiterCoeff(); +// eps2 = pow((LimK*dave), 3.0); +// +// for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { +// +// iPoint = geometry->edge[iEdge]->GetNode(0); +// jPoint = geometry->edge[iEdge]->GetNode(1); +// Gradient_i = node[iPoint]->GetGradient_Secondary(); +// Gradient_j = node[jPoint]->GetGradient_Secondary(); +// Coord_i = geometry->node[iPoint]->GetCoord(); +// Coord_j = geometry->node[jPoint]->GetCoord(); +// +// for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { +// +// /*--- Calculate the interface left gradient, delta- (dm) ---*/ +// dm = 0.0; +// for (iDim = 0; iDim < nDim; iDim++) +// dm += 0.5*(Coord_j[iDim]-Coord_i[iDim])*Gradient_i[iVar][iDim]; +// +// /*--- Calculate the interface right gradient, delta+ (dp) ---*/ +// if ( dm > 0.0 ) dp = node[iPoint]->GetSolution_Max(iVar); +// else dp = node[iPoint]->GetSolution_Min(iVar); +// +// limiter = ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); +// +// if (limiter < node[iPoint]->GetLimiter_Secondary(iVar)) +// if (geometry->node[iPoint]->GetDomain()) node[iPoint]->SetLimiter_Secondary(iVar, limiter); +// +// /*-- Repeat for point j on the edge ---*/ +// dm = 0.0; +// for (iDim = 0; iDim < nDim; iDim++) +// dm += 0.5*(Coord_i[iDim]-Coord_j[iDim])*Gradient_j[iVar][iDim]; +// +// if ( dm > 0.0 ) dp = node[jPoint]->GetSolution_Max(iVar); +// else dp = node[jPoint]->GetSolution_Min(iVar); +// +// limiter = ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); +// +// if (limiter < node[jPoint]->GetLimiter_Secondary(iVar)) +// if (geometry->node[jPoint]->GetDomain()) node[jPoint]->SetLimiter_Secondary(iVar, limiter); +// } +// } +// } +// +// /*--- Limiter MPI ---*/ +// Set_MPI_Secondary_Limiter(geometry, config); +// +//} + +void CEulerSolver::SetPreconditioner(CConfig *config, unsigned long iPoint) { + unsigned short iDim, jDim, iVar, jVar; + su2double Beta, local_Mach, Beta2, rho, enthalpy, soundspeed, sq_vel; + su2double *U_i = NULL; + su2double Beta_min = config->GetminTurkelBeta(); + su2double Beta_max = config->GetmaxTurkelBeta(); + + + /*--- Variables to calculate the preconditioner parameter Beta ---*/ + local_Mach = sqrt(node[iPoint]->GetVelocity2())/node[iPoint]->GetSoundSpeed(); + Beta = max(Beta_min, min(local_Mach, Beta_max)); + Beta2 = Beta*Beta; + + U_i = node[iPoint]->GetSolution(); + + rho = U_i[0]; + enthalpy = node[iPoint]->GetEnthalpy(); + soundspeed = node[iPoint]->GetSoundSpeed(); + sq_vel = node[iPoint]->GetVelocity2(); + + /*---Calculating the inverse of the preconditioning matrix that multiplies the time derivative */ + LowMach_Precontioner[0][0] = 0.5*sq_vel; + LowMach_Precontioner[0][nVar-1] = 1.0; + for (iDim = 0; iDim < nDim; iDim ++) + LowMach_Precontioner[0][1+iDim] = -1.0*U_i[iDim+1]/rho; + + for (iDim = 0; iDim < nDim; iDim ++) { + LowMach_Precontioner[iDim+1][0] = 0.5*sq_vel*U_i[iDim+1]/rho; + LowMach_Precontioner[iDim+1][nVar-1] = U_i[iDim+1]/rho; + for (jDim = 0; jDim < nDim; jDim ++) { + LowMach_Precontioner[iDim+1][1+jDim] = -1.0*U_i[jDim+1]/rho*U_i[iDim+1]/rho; + } + } + + LowMach_Precontioner[nVar-1][0] = 0.5*sq_vel*enthalpy; + LowMach_Precontioner[nVar-1][nVar-1] = enthalpy; + for (iDim = 0; iDim < nDim; iDim ++) + LowMach_Precontioner[nVar-1][1+iDim] = -1.0*U_i[iDim+1]/rho*enthalpy; + + + for (iVar = 0; iVar < nVar; iVar ++ ) { + for (jVar = 0; jVar < nVar; jVar ++ ) { + LowMach_Precontioner[iVar][jVar] = (1.0/(Beta2+EPS) - 1.0) * (Gamma-1.0)/(soundspeed*soundspeed)*LowMach_Precontioner[iVar][jVar]; + if (iVar == jVar) + LowMach_Precontioner[iVar][iVar] += 1.0; + } + } + +} + +void CEulerSolver::GetEngine_Properties(CGeometry *geometry, CConfig *config, unsigned short iMesh, bool Output) { + + unsigned short iDim, iMarker, iMarker_EngineInflow, iMarker_EngineBleed, iMarker_EngineExhaust, iVar; + unsigned long iVertex, iPoint; + su2double Pressure, Temperature, Velocity[3], Velocity2, MassFlow, Density, Energy, Area, + Mach, SoundSpeed, Flow_Dir[3], alpha; + + su2double Gas_Constant = config->GetGas_ConstantND(); + unsigned short nMarker_EngineInflow = config->GetnMarker_EngineInflow(); + unsigned short nMarker_EngineBleed = config->GetnMarker_EngineBleed(); + unsigned short nMarker_EngineExhaust = config->GetnMarker_EngineExhaust(); + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Compute the numerical fan face Mach number, and the total area of the inflow ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + Inflow_MassFlow[iMarker] = 0.0; + Inflow_Mach[iMarker] = 0.0; + Inflow_Pressure[iMarker] = 0.0; + Inflow_Area[iMarker] = 0.0; + + Bleed_MassFlow[iMarker] = 0.0; + Bleed_Pressure[iMarker] = 0.0; + Bleed_Temperature[iMarker] = 0.0; + Bleed_Area[iMarker] = 0.0; + + Exhaust_MassFlow[iMarker] = 0.0; + Exhaust_Pressure[iMarker] = 0.0; + Exhaust_Temperature[iMarker] = 0.0; + Exhaust_Area[iMarker] = 0.0; + + if (config->GetMarker_All_KindBC(iMarker) == ENGINE_INFLOW) { + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + geometry->vertex[iMarker][iVertex]->GetNormal(Vector); + + Density = node[iPoint]->GetSolution(0); + Velocity2 = 0.0; Area = 0.0; MassFlow = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Area += Vector[iDim]*Vector[iDim]; + Velocity[iDim] = node[iPoint]->GetSolution(iDim+1)/Density; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + MassFlow -= Vector[iDim]*node[iPoint]->GetSolution(iDim+1); + } + + Area = sqrt (Area); + Energy = node[iPoint]->GetSolution(nVar-1)/Density; + Pressure = Gamma_Minus_One*Density*(Energy-0.5*Velocity2); + SoundSpeed = sqrt(Gamma*Pressure/Density); + Mach = sqrt(Velocity2)/SoundSpeed; + + /*--- Compute the Inflow_MassFlow, Inflow_Pressure, Inflow_Mach, and Inflow_Area ---*/ + + Inflow_MassFlow[iMarker] += MassFlow; + Inflow_Pressure[iMarker] += Pressure*Area; + Inflow_Mach[iMarker] += Mach*Area; + Inflow_Area[iMarker] += Area; + + } + } + + } + + if (config->GetMarker_All_KindBC(iMarker) == ENGINE_BLEED) { + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + geometry->vertex[iMarker][iVertex]->GetNormal(Vector); + + Density = node[iPoint]->GetSolution(0); + Velocity2 = 0.0; Area = 0.0; MassFlow = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Area += Vector[iDim]*Vector[iDim]; + Velocity[iDim] = node[iPoint]->GetSolution(iDim+1)/Density; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + MassFlow += Vector[iDim]*node[iPoint]->GetSolution(iDim+1); + } + + Area = sqrt (Area); + Energy = node[iPoint]->GetSolution(nVar-1)/Density; + Pressure = Gamma_Minus_One*Density*(Energy-0.5*Velocity2); + Temperature = Pressure / (Gas_Constant * Density); + + /*--- Compute the Bleed_MassFlow, Bleed_Pressure, Bleed_Temperature, and Bleed_Area ---*/ + + Bleed_MassFlow[iMarker] += MassFlow; + Bleed_Pressure[iMarker] += Pressure*Area; + Bleed_Temperature[iMarker] += Temperature*Area; + Bleed_Area[iMarker] += Area; + + } + } + + } + + if (config->GetMarker_All_KindBC(iMarker) == ENGINE_EXHAUST) { + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + geometry->vertex[iMarker][iVertex]->GetNormal(Vector); + + Density = node[iPoint]->GetSolution(0); + Velocity2 = 0.0; Area = 0.0; MassFlow = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Area += Vector[iDim]*Vector[iDim]; + Velocity[iDim] = node[iPoint]->GetSolution(iDim+1)/Density; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + MassFlow += Vector[iDim]*node[iPoint]->GetSolution(iDim+1); + } + + Area = sqrt (Area); + Energy = node[iPoint]->GetSolution(nVar-1)/Density; + Pressure = Gamma_Minus_One*Density*(Energy-0.5*Velocity2); + Temperature = Pressure / (Gas_Constant * Density); + + /*--- Compute the mass Exhaust_MassFlow ---*/ + + Exhaust_MassFlow[iMarker] += MassFlow; + Exhaust_Pressure[iMarker] += Pressure*Area; + Exhaust_Temperature[iMarker] += Temperature*Area; + Exhaust_Area[iMarker] += Area; + + } + } + + } + + } + + /*--- Copy to the appropriate structure ---*/ + + su2double *Inflow_MassFlow_Local = new su2double [nMarker_EngineInflow]; + su2double *Inflow_Mach_Local = new su2double [nMarker_EngineInflow]; + su2double *Inflow_Pressure_Local = new su2double [nMarker_EngineInflow]; + su2double *Inflow_Area_Local = new su2double [nMarker_EngineInflow]; + + su2double *Inflow_MassFlow_Total = new su2double [nMarker_EngineInflow]; + su2double *Inflow_Mach_Total = new su2double [nMarker_EngineInflow]; + su2double *Inflow_Pressure_Total = new su2double [nMarker_EngineInflow]; + su2double *Inflow_Area_Total = new su2double [nMarker_EngineInflow]; + + for (iMarker_EngineInflow = 0; iMarker_EngineInflow < nMarker_EngineInflow; iMarker_EngineInflow++) { + Inflow_MassFlow_Local[iMarker_EngineInflow] = 0.0; + Inflow_Mach_Local[iMarker_EngineInflow] = 0.0; + Inflow_Pressure_Local[iMarker_EngineInflow] = 0.0; + Inflow_Area_Local[iMarker_EngineInflow] = 0.0; + + Inflow_MassFlow_Total[iMarker_EngineInflow] = 0.0; + Inflow_Mach_Total[iMarker_EngineInflow] = 0.0; + Inflow_Pressure_Total[iMarker_EngineInflow] = 0.0; + Inflow_Area_Total[iMarker_EngineInflow] = 0.0; + } + + su2double *Bleed_MassFlow_Local = new su2double [nMarker_EngineBleed]; + su2double *Bleed_Temperature_Local = new su2double [nMarker_EngineBleed]; + su2double *Bleed_Pressure_Local = new su2double [nMarker_EngineBleed]; + su2double *Bleed_Area_Local = new su2double [nMarker_EngineBleed]; + + su2double *Bleed_MassFlow_Total = new su2double [nMarker_EngineBleed]; + su2double *Bleed_Temperature_Total = new su2double [nMarker_EngineBleed]; + su2double *Bleed_Pressure_Total = new su2double [nMarker_EngineBleed]; + su2double *Bleed_Area_Total = new su2double [nMarker_EngineBleed]; + + for (iMarker_EngineBleed = 0; iMarker_EngineBleed < nMarker_EngineBleed; iMarker_EngineBleed++) { + Bleed_MassFlow_Local[iMarker_EngineBleed] = 0.0; + Bleed_Temperature_Local[iMarker_EngineBleed] = 0.0; + Bleed_Pressure_Local[iMarker_EngineBleed] = 0.0; + Bleed_Area_Local[iMarker_EngineBleed] = 0.0; + + Bleed_MassFlow_Total[iMarker_EngineBleed] = 0.0; + Bleed_Temperature_Total[iMarker_EngineBleed] = 0.0; + Bleed_Pressure_Total[iMarker_EngineBleed] = 0.0; + Bleed_Area_Total[iMarker_EngineBleed] = 0.0; + } + + su2double *Exhaust_MassFlow_Local = new su2double [nMarker_EngineExhaust]; + su2double *Exhaust_Temperature_Local = new su2double [nMarker_EngineExhaust]; + su2double *Exhaust_Pressure_Local = new su2double [nMarker_EngineExhaust]; + su2double *Exhaust_Area_Local = new su2double [nMarker_EngineExhaust]; + + su2double *Exhaust_MassFlow_Total = new su2double [nMarker_EngineExhaust]; + su2double *Exhaust_Temperature_Total = new su2double [nMarker_EngineExhaust]; + su2double *Exhaust_Pressure_Total = new su2double [nMarker_EngineExhaust]; + su2double *Exhaust_Area_Total = new su2double [nMarker_EngineExhaust]; + + for (iMarker_EngineExhaust = 0; iMarker_EngineExhaust < nMarker_EngineExhaust; iMarker_EngineExhaust++) { + Exhaust_MassFlow_Local[iMarker_EngineExhaust] = 0.0; + Exhaust_Temperature_Local[iMarker_EngineExhaust] = 0.0; + Exhaust_Pressure_Local[iMarker_EngineExhaust] = 0.0; + Exhaust_Area_Local[iMarker_EngineExhaust] = 0.0; + + Exhaust_MassFlow_Total[iMarker_EngineExhaust] = 0.0; + Exhaust_Temperature_Total[iMarker_EngineExhaust] = 0.0; + Exhaust_Pressure_Total[iMarker_EngineExhaust] = 0.0; + Exhaust_Area_Total[iMarker_EngineExhaust] = 0.0; + } + + /*--- Compute the numerical fan face Mach number, mach number, temperature and the total area ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) == ENGINE_INFLOW) { + + for (iMarker_EngineInflow = 0; iMarker_EngineInflow < nMarker_EngineInflow; iMarker_EngineInflow++) { + + /*--- Add the Inflow_MassFlow, Inflow_Mach, Inflow_Pressure and Inflow_Area to the particular boundary ---*/ + + if (config->GetMarker_All_TagBound(iMarker) == config->GetMarker_EngineInflow(iMarker_EngineInflow)) { + Inflow_MassFlow_Local[iMarker_EngineInflow] += Inflow_MassFlow[iMarker]; + Inflow_Mach_Local[iMarker_EngineInflow] += Inflow_Mach[iMarker]; + Inflow_Pressure_Local[iMarker_EngineInflow] += Inflow_Pressure[iMarker]; + Inflow_Area_Local[iMarker_EngineInflow] += Inflow_Area[iMarker]; + } + + } + + } + + if (config->GetMarker_All_KindBC(iMarker) == ENGINE_BLEED) { + + for (iMarker_EngineBleed = 0; iMarker_EngineBleed < nMarker_EngineBleed; iMarker_EngineBleed++) { + + /*--- Add the Bleed_MassFlow, Bleed_Temperature, Bleed_Pressure and Bleed_Area to the particular boundary ---*/ + + if (config->GetMarker_All_TagBound(iMarker) == config->GetMarker_EngineBleed(iMarker_EngineBleed)) { + Bleed_MassFlow_Local[iMarker_EngineBleed] += Bleed_MassFlow[iMarker]; + Bleed_Temperature_Local[iMarker_EngineBleed] += Bleed_Temperature[iMarker]; + Bleed_Pressure_Local[iMarker_EngineBleed] += Bleed_Pressure[iMarker]; + Bleed_Area_Local[iMarker_EngineBleed] += Bleed_Area[iMarker]; + } + + } + + } + + if (config->GetMarker_All_KindBC(iMarker) == ENGINE_EXHAUST) { + + for (iMarker_EngineExhaust= 0; iMarker_EngineExhaust < nMarker_EngineExhaust; iMarker_EngineExhaust++) { + + /*--- Add the Exhaust_MassFlow, and Exhaust_Area to the particular boundary ---*/ + + if (config->GetMarker_All_TagBound(iMarker) == config->GetMarker_EngineExhaust(iMarker_EngineExhaust)) { + Exhaust_MassFlow_Local[iMarker_EngineExhaust] += Exhaust_MassFlow[iMarker]; + Exhaust_Temperature_Local[iMarker_EngineExhaust] += Exhaust_Temperature[iMarker]; + Exhaust_Pressure_Local[iMarker_EngineExhaust] += Exhaust_Pressure[iMarker]; + Exhaust_Area_Local[iMarker_EngineExhaust] += Exhaust_Area[iMarker]; + } + + } + + } + + } + +#ifdef HAVE_MPI + + SU2_MPI::Allreduce(Inflow_MassFlow_Local, Inflow_MassFlow_Total, nMarker_EngineInflow, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(Inflow_Mach_Local, Inflow_Mach_Total, nMarker_EngineInflow, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(Inflow_Pressure_Local, Inflow_Pressure_Total, nMarker_EngineInflow, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(Inflow_Area_Local, Inflow_Area_Total, nMarker_EngineInflow, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + + SU2_MPI::Allreduce(Bleed_MassFlow_Local, Bleed_MassFlow_Total, nMarker_EngineBleed, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(Bleed_Temperature_Local, Bleed_Temperature_Total, nMarker_EngineBleed, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(Bleed_Pressure_Local, Bleed_Pressure_Total, nMarker_EngineBleed, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(Bleed_Area_Local, Bleed_Area_Total, nMarker_EngineBleed, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + + SU2_MPI::Allreduce(Exhaust_MassFlow_Local, Exhaust_MassFlow_Total, nMarker_EngineExhaust, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(Exhaust_Temperature_Local, Exhaust_Temperature_Total, nMarker_EngineExhaust, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(Exhaust_Pressure_Local, Exhaust_Pressure_Total, nMarker_EngineExhaust, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(Exhaust_Area_Local, Exhaust_Area_Total, nMarker_EngineExhaust, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + +#else + + for (iMarker_EngineInflow = 0; iMarker_EngineInflow < nMarker_EngineInflow; iMarker_EngineInflow++) { + Inflow_MassFlow_Total[iMarker_EngineInflow] = Inflow_MassFlow_Local[iMarker_EngineInflow]; + Inflow_Mach_Total[iMarker_EngineInflow] = Inflow_Mach_Local[iMarker_EngineInflow]; + Inflow_Pressure_Total[iMarker_EngineInflow] = Inflow_Pressure_Local[iMarker_EngineInflow]; + Inflow_Area_Total[iMarker_EngineInflow] = Inflow_Area_Local[iMarker_EngineInflow]; + } + + for (iMarker_EngineBleed = 0; iMarker_EngineBleed < nMarker_EngineBleed; iMarker_EngineBleed++) { + Bleed_MassFlow_Total[iMarker_EngineBleed] = Bleed_MassFlow_Local[iMarker_EngineBleed]; + Bleed_Temperature_Total[iMarker_EngineBleed] = Bleed_Temperature_Local[iMarker_EngineBleed]; + Bleed_Pressure_Total[iMarker_EngineBleed] = Bleed_Pressure_Local[iMarker_EngineBleed]; + Bleed_Area_Total[iMarker_EngineBleed] = Bleed_Area_Local[iMarker_EngineBleed]; + } + + for (iMarker_EngineExhaust = 0; iMarker_EngineExhaust < nMarker_EngineExhaust; iMarker_EngineExhaust++) { + Exhaust_MassFlow_Total[iMarker_EngineExhaust] = Exhaust_MassFlow_Local[iMarker_EngineExhaust]; + Exhaust_Temperature_Total[iMarker_EngineExhaust] = Exhaust_Temperature_Local[iMarker_EngineExhaust]; + Exhaust_Pressure_Total[iMarker_EngineExhaust] = Exhaust_Pressure_Local[iMarker_EngineExhaust]; + Exhaust_Area_Total[iMarker_EngineExhaust] = Exhaust_Area_Local[iMarker_EngineExhaust]; + } + +#endif + + /*--- Compute the value of Inflow_Area_Total, and Inflow_Pressure_Total, and + set the value in the config structure for future use ---*/ + + for (iMarker_EngineInflow = 0; iMarker_EngineInflow < nMarker_EngineInflow; iMarker_EngineInflow++) { + if (Inflow_Area_Total[iMarker_EngineInflow] != 0.0) Inflow_Mach_Total[iMarker_EngineInflow] /= Inflow_Area_Total[iMarker_EngineInflow]; + else Inflow_Mach_Total[iMarker_EngineInflow] = 0.0; + if (Inflow_Area_Total[iMarker_EngineInflow] != 0.0) Inflow_Pressure_Total[iMarker_EngineInflow] /= Inflow_Area_Total[iMarker_EngineInflow]; + else Inflow_Pressure_Total[iMarker_EngineInflow] = 0.0; + + if (iMesh == MESH_0) { + config->SetInflow_Mach(iMarker_EngineInflow, Inflow_Mach_Total[iMarker_EngineInflow]); + config->SetInflow_Pressure(iMarker_EngineInflow, Inflow_Pressure_Total[iMarker_EngineInflow]); + } + + } + + /*--- Compute the value of Bleed_Area_Total, and Bleed_Pressure_Total, and + set the value in the config structure for future use ---*/ + + for (iMarker_EngineBleed = 0; iMarker_EngineBleed < nMarker_EngineBleed; iMarker_EngineBleed++) { + if (Bleed_Area_Total[iMarker_EngineBleed] != 0.0) Bleed_Temperature_Total[iMarker_EngineBleed] /= Bleed_Area_Total[iMarker_EngineBleed]; + else Bleed_Temperature_Total[iMarker_EngineBleed] = 0.0; + if (Bleed_Area_Total[iMarker_EngineBleed] != 0.0) Bleed_Pressure_Total[iMarker_EngineBleed] /= Bleed_Area_Total[iMarker_EngineBleed]; + else Bleed_Pressure_Total[iMarker_EngineBleed] = 0.0; + + if (iMesh == MESH_0) { + config->SetBleed_Temperature(iMarker_EngineBleed, Bleed_Temperature_Total[iMarker_EngineBleed]); + config->SetBleed_MassFlow(iMarker_EngineBleed, Bleed_MassFlow_Total[iMarker_EngineBleed]); + config->SetBleed_Pressure(iMarker_EngineBleed, Bleed_Pressure_Total[iMarker_EngineBleed]); + } + + } + + /*--- Compute the value of Exhaust_Area_Total, and Exhaust_Pressure_Total, and + set the value in the config structure for future use ---*/ + + for (iMarker_EngineExhaust = 0; iMarker_EngineExhaust < nMarker_EngineExhaust; iMarker_EngineExhaust++) { + if (Exhaust_Area_Total[iMarker_EngineExhaust] != 0.0) Exhaust_Temperature_Total[iMarker_EngineExhaust] /= Exhaust_Area_Total[iMarker_EngineExhaust]; + else Exhaust_Temperature_Total[iMarker_EngineExhaust] = 0.0; + if (Exhaust_Area_Total[iMarker_EngineExhaust] != 0.0) Exhaust_Pressure_Total[iMarker_EngineExhaust] /= Exhaust_Area_Total[iMarker_EngineExhaust]; + else Exhaust_Pressure_Total[iMarker_EngineExhaust] = 0.0; + + if (iMesh == MESH_0) { + config->SetExhaust_Temperature(iMarker_EngineExhaust, Exhaust_Temperature_Total[iMarker_EngineExhaust]); + config->SetExhaust_Pressure(iMarker_EngineExhaust, Exhaust_Pressure_Total[iMarker_EngineExhaust]); + } + + } + + bool write_heads = (((config->GetExtIter() % (config->GetWrt_Con_Freq()*40)) == 0)); + + if ((rank == MASTER_NODE) && (iMesh == MESH_0) && write_heads && Output) { + + cout.precision(4); + cout.setf(ios::fixed, ios::floatfield); + + cout << endl << "---------------------------- Engine properties --------------------------" << endl; + for (iMarker_EngineInflow = 0; iMarker_EngineInflow < nMarker_EngineInflow; iMarker_EngineInflow++) { + cout << "Engine inflow ("<< config->GetMarker_EngineInflow(iMarker_EngineInflow); + if (config->GetSystemMeasurements() == SI) cout << "): Mass flow (kg/s): "; + else if (config->GetSystemMeasurements() == US) cout << "): Mass flow (slug/s): "; + cout << Inflow_MassFlow_Total[iMarker_EngineInflow] * config->GetDensity_Ref() * config->GetVelocity_Ref() + << ", Mach: " << Inflow_Mach_Total[iMarker_EngineInflow]; + if (config->GetSystemMeasurements() == SI) cout << ", Area (m^2): "; + else if (config->GetSystemMeasurements() == US) cout << ", Area (ft^2): "; + cout << Inflow_Area_Total[iMarker_EngineInflow] <<"."<< endl; + } + + for (iMarker_EngineBleed = 0; iMarker_EngineBleed < nMarker_EngineBleed; iMarker_EngineBleed++) { + cout << "Engine bleed ("<< config->GetMarker_EngineBleed(iMarker_EngineBleed); + if (config->GetSystemMeasurements() == SI) cout << "): Mass flow (kg/s): "; + else if (config->GetSystemMeasurements() == US) cout << "): Mass flow (slug/s): "; + cout << Bleed_MassFlow_Total[iMarker_EngineBleed] * config->GetDensity_Ref() * config->GetVelocity_Ref(); + if (config->GetSystemMeasurements() == SI) cout << ", Temp (K): "; + else if (config->GetSystemMeasurements() == US) cout << ", Temp (R): "; + cout << Bleed_Temperature_Total[iMarker_EngineBleed] * config->GetTemperature_Ref(); + if (config->GetSystemMeasurements() == SI) cout << ", Area (m^2): "; + else if (config->GetSystemMeasurements() == US) cout << ", Area (ft^2): "; + cout << Bleed_Area_Total[iMarker_EngineBleed] <<"."<< endl; + } + + for (iMarker_EngineExhaust = 0; iMarker_EngineExhaust < nMarker_EngineExhaust; iMarker_EngineExhaust++) { + cout << "Engine exhaust ("<< config->GetMarker_EngineExhaust(iMarker_EngineExhaust); + if (config->GetSystemMeasurements() == SI) cout << "): Mass flow (kg/s): "; + else if (config->GetSystemMeasurements() == US) cout << "): Mass flow (slug/s): "; + cout << Exhaust_MassFlow_Total[iMarker_EngineExhaust] * config->GetDensity_Ref() * config->GetVelocity_Ref(); + if (config->GetSystemMeasurements() == SI) cout << ", Temp (K): "; + else if (config->GetSystemMeasurements() == US) cout << ", Temp (R): "; + cout << Exhaust_Temperature_Total[iMarker_EngineExhaust] * config->GetTemperature_Ref(); + if (config->GetSystemMeasurements() == SI) cout << ", Pressure (Pa): "; + else if (config->GetSystemMeasurements() == US) cout << ", Pressure (psf): "; + cout << Exhaust_Pressure_Total[iMarker_EngineExhaust] * config->GetPressure_Ref(); + if (config->GetSystemMeasurements() == SI) cout << ", Area (m^2): "; + else if (config->GetSystemMeasurements() == US) cout << ", Area (ft^2): "; + cout << Exhaust_Area_Total[iMarker_EngineExhaust] <<"."<< endl; + } + cout << "-------------------------------------------------------------------------" << endl; + + } + + /*--- Check the flow orientation in the engine ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == ENGINE_INFLOW) || + (config->GetMarker_All_KindBC(iMarker) == ENGINE_EXHAUST) || + (config->GetMarker_All_KindBC(iMarker) == ENGINE_BLEED)) { + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[iMarker][iVertex]->GetNormal(Vector); + + for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = -Vector[iDim]; + + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Area += Vector[iDim]*Vector[iDim]; + Area = sqrt (Area); + + /*--- Compute unitary vector ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + Vector[iDim] /= Area; + + /*--- The flow direction is defined by the local velocity on the surface ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + Flow_Dir[iDim] = node[iPoint]->GetSolution(iDim+1) / node[iPoint]->GetSolution(0); + + /*--- Dot product of normal and flow direction. ---*/ + + alpha = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + alpha += Vector[iDim]*Flow_Dir[iDim]; + + /*--- Flow in the wrong direction. ---*/ + + if (((config->GetMarker_All_KindBC(iMarker) == ENGINE_EXHAUST) || + (config->GetMarker_All_KindBC(iMarker) == ENGINE_BLEED)) && (alpha > 0.0)) { + + /*--- Copy the old solution ---*/ + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetSolution(iVar, node[iPoint]->GetSolution_Old(iVar)); + + } + + if ((config->GetMarker_All_KindBC(iMarker) == ENGINE_INFLOW) && (alpha < 0.0)) { + + /*--- Copy the old solution ---*/ + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetSolution(iVar, node[iPoint]->GetSolution_Old(iVar)); + + } + + } + + } + + } + + + delete [] Inflow_MassFlow_Local; + delete [] Inflow_Mach_Local; + delete [] Inflow_Pressure_Local; + delete [] Inflow_Area_Local; + + delete [] Inflow_MassFlow_Total; + delete [] Inflow_Mach_Total; + delete [] Inflow_Pressure_Total; + delete [] Inflow_Area_Total; + + delete [] Exhaust_MassFlow_Local; + delete [] Exhaust_Temperature_Local; + delete [] Exhaust_Pressure_Local; + delete [] Exhaust_Area_Local; + + delete [] Exhaust_MassFlow_Total; + delete [] Exhaust_Temperature_Total; + delete [] Exhaust_Pressure_Total; + delete [] Exhaust_Area_Total; + + delete [] Bleed_MassFlow_Local; + delete [] Bleed_Temperature_Local; + delete [] Bleed_Pressure_Local; + delete [] Bleed_Area_Local; + + delete [] Bleed_MassFlow_Total; + delete [] Bleed_Temperature_Total; + delete [] Bleed_Pressure_Total; + delete [] Bleed_Area_Total; + +} + +void CEulerSolver::GetActuatorDisk_Properties(CGeometry *geometry, CConfig *config, unsigned short iMesh, bool Output) { + + unsigned short iDim, iMarker; + unsigned long iVertex, iPoint; + su2double Pressure, Temperature, Velocity[3], Velocity2, MassFlow, Density, Energy, Area; + unsigned short iMarker_ActDiskInlet, iMarker_ActDiskOutlet; + + su2double Gas_Constant = config->GetGas_ConstantND(); + + unsigned short nMarker_ActDiskInlet = config->GetnMarker_ActDisk_Inlet(); + unsigned short nMarker_ActDiskOutlet = config->GetnMarker_ActDisk_Outlet(); + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + su2double *Inlet_MassFlow = new su2double [config->GetnMarker_All()]; + su2double *Inlet_Pressure = new su2double [config->GetnMarker_All()]; + su2double *Inlet_Temperature = new su2double [config->GetnMarker_All()]; + su2double *Inlet_Area = new su2double [config->GetnMarker_All()]; + + su2double *Outlet_MassFlow = new su2double [config->GetnMarker_All()]; + su2double *Outlet_Pressure = new su2double [config->GetnMarker_All()]; + su2double *Outlet_Temperature = new su2double [config->GetnMarker_All()]; + su2double *Outlet_Area = new su2double [config->GetnMarker_All()]; + + /*--- Compute the numerical fan face Mach number, and the total area of the inflow ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + Inlet_MassFlow[iMarker] = 0.0; + Inlet_Pressure[iMarker] = 0.0; + Inlet_Temperature[iMarker] = 0.0; + Inlet_Area[iMarker] = 0.0; + + Outlet_MassFlow[iMarker] = 0.0; + Outlet_Pressure[iMarker] = 0.0; + Outlet_Temperature[iMarker] = 0.0; + Outlet_Area[iMarker] = 0.0; + + if (config->GetMarker_All_KindBC(iMarker) == ACTDISK_INLET) { + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + geometry->vertex[iMarker][iVertex]->GetNormal(Vector); + + Density = node[iPoint]->GetSolution(0); + Velocity2 = 0.0; Area = 0.0; MassFlow = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Area += Vector[iDim]*Vector[iDim]; + Velocity[iDim] = node[iPoint]->GetSolution(iDim+1)/Density; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + MassFlow += Vector[iDim]*node[iPoint]->GetSolution(iDim+1); + } + + Area = sqrt (Area); + Energy = node[iPoint]->GetSolution(nVar-1)/Density; + Pressure = Gamma_Minus_One*Density*(Energy-0.5*Velocity2); + Temperature = Pressure / (Gas_Constant * Density); + + /*--- Compute the Inlet_MassFlow, Inlet_Pressure, Inlet_Temperature, and Inlet_Area ---*/ + + Inlet_MassFlow[iMarker] += MassFlow; + Inlet_Pressure[iMarker] += Pressure*Area; + Inlet_Temperature[iMarker] += Temperature*Area; + Inlet_Area[iMarker] += Area; + + } + } + + } + + if (config->GetMarker_All_KindBC(iMarker) == ACTDISK_OUTLET) { + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + geometry->vertex[iMarker][iVertex]->GetNormal(Vector); + + Density = node[iPoint]->GetSolution(0); + Velocity2 = 0.0; Area = 0.0; MassFlow = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Area += Vector[iDim]*Vector[iDim]; + Velocity[iDim] = node[iPoint]->GetSolution(iDim+1)/Density; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + MassFlow += Vector[iDim]*node[iPoint]->GetSolution(iDim+1); + } + + Area = sqrt (Area); + Energy = node[iPoint]->GetSolution(nVar-1)/Density; + Pressure = Gamma_Minus_One*Density*(Energy-0.5*Velocity2); + Temperature = Pressure / (Gas_Constant * Density); + + /*--- Compute the mass Outlet_MassFlow ---*/ + + Outlet_MassFlow[iMarker] += MassFlow; + Outlet_Pressure[iMarker] += Pressure*Area; + Outlet_Temperature[iMarker] += Temperature*Area; + Outlet_Area[iMarker] += Area; + + } + } + + } + + } + + /*--- Copy to the appropriate structure ---*/ + + su2double *Inlet_MassFlow_Local = new su2double [nMarker_ActDiskInlet]; + su2double *Inlet_Temperature_Local = new su2double [nMarker_ActDiskInlet]; + su2double *Inlet_Pressure_Local = new su2double [nMarker_ActDiskInlet]; + su2double *Inlet_Area_Local = new su2double [nMarker_ActDiskInlet]; + + su2double *Inlet_MassFlow_Total = new su2double [nMarker_ActDiskInlet]; + su2double *Inlet_Temperature_Total = new su2double [nMarker_ActDiskInlet]; + su2double *Inlet_Pressure_Total = new su2double [nMarker_ActDiskInlet]; + su2double *Inlet_Area_Total = new su2double [nMarker_ActDiskInlet]; + + for (iMarker_ActDiskInlet = 0; iMarker_ActDiskInlet < nMarker_ActDiskInlet; iMarker_ActDiskInlet++) { + Inlet_MassFlow_Local[iMarker_ActDiskInlet] = 0.0; + Inlet_Temperature_Local[iMarker_ActDiskInlet] = 0.0; + Inlet_Pressure_Local[iMarker_ActDiskInlet] = 0.0; + Inlet_Area_Local[iMarker_ActDiskInlet] = 0.0; + + Inlet_MassFlow_Total[iMarker_ActDiskInlet] = 0.0; + Inlet_Temperature_Total[iMarker_ActDiskInlet] = 0.0; + Inlet_Pressure_Total[iMarker_ActDiskInlet] = 0.0; + Inlet_Area_Total[iMarker_ActDiskInlet] = 0.0; + } + + su2double *Outlet_MassFlow_Local = new su2double [nMarker_ActDiskOutlet]; + su2double *Outlet_Temperature_Local = new su2double [nMarker_ActDiskOutlet]; + su2double *Outlet_Pressure_Local = new su2double [nMarker_ActDiskOutlet]; + su2double *Outlet_Area_Local = new su2double [nMarker_ActDiskOutlet]; + + su2double *Outlet_MassFlow_Total = new su2double [nMarker_ActDiskOutlet]; + su2double *Outlet_Temperature_Total = new su2double [nMarker_ActDiskOutlet]; + su2double *Outlet_Pressure_Total = new su2double [nMarker_ActDiskOutlet]; + su2double *Outlet_Area_Total = new su2double [nMarker_ActDiskOutlet]; + + for (iMarker_ActDiskOutlet = 0; iMarker_ActDiskOutlet < nMarker_ActDiskOutlet; iMarker_ActDiskOutlet++) { + Outlet_MassFlow_Local[iMarker_ActDiskOutlet] = 0.0; + Outlet_Temperature_Local[iMarker_ActDiskOutlet] = 0.0; + Outlet_Pressure_Local[iMarker_ActDiskOutlet] = 0.0; + Outlet_Area_Local[iMarker_ActDiskOutlet] = 0.0; + + Outlet_MassFlow_Total[iMarker_ActDiskOutlet] = 0.0; + Outlet_Temperature_Total[iMarker_ActDiskOutlet] = 0.0; + Outlet_Pressure_Total[iMarker_ActDiskOutlet] = 0.0; + Outlet_Area_Total[iMarker_ActDiskOutlet] = 0.0; + } + + /*--- Compute the numerical fan face Mach number, mach number, temperature and the total area ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) == ACTDISK_INLET) { + + for (iMarker_ActDiskInlet = 0; iMarker_ActDiskInlet < nMarker_ActDiskInlet; iMarker_ActDiskInlet++) { + + /*--- Add the Inlet_MassFlow, Inlet_Temperature, Inlet_Pressure and Inlet_Area to the particular boundary ---*/ + + if (config->GetMarker_All_TagBound(iMarker) == config->GetMarker_ActDisk_Inlet(iMarker_ActDiskInlet)) { + Inlet_MassFlow_Local[iMarker_ActDiskInlet] += Inlet_MassFlow[iMarker]; + Inlet_Temperature_Local[iMarker_ActDiskInlet] += Inlet_Temperature[iMarker]; + Inlet_Pressure_Local[iMarker_ActDiskInlet] += Inlet_Pressure[iMarker]; + Inlet_Area_Local[iMarker_ActDiskInlet] += Inlet_Area[iMarker]; + } + + } + + } + + if (config->GetMarker_All_KindBC(iMarker) == ACTDISK_OUTLET) { + + for (iMarker_ActDiskOutlet= 0; iMarker_ActDiskOutlet < nMarker_ActDiskOutlet; iMarker_ActDiskOutlet++) { + + /*--- Add the Outlet_MassFlow, and Outlet_Area to the particular boundary ---*/ + + if (config->GetMarker_All_TagBound(iMarker) == config->GetMarker_ActDisk_Outlet(iMarker_ActDiskOutlet)) { + Outlet_MassFlow_Local[iMarker_ActDiskOutlet] += Outlet_MassFlow[iMarker]; + Outlet_Temperature_Local[iMarker_ActDiskOutlet] += Outlet_Temperature[iMarker]; + Outlet_Pressure_Local[iMarker_ActDiskOutlet] += Outlet_Pressure[iMarker]; + Outlet_Area_Local[iMarker_ActDiskOutlet] += Outlet_Area[iMarker]; + } + + } + + } + + } + +#ifdef HAVE_MPI + + SU2_MPI::Allreduce(Inlet_MassFlow_Local, Inlet_MassFlow_Total, nMarker_ActDiskInlet, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(Inlet_Temperature_Local, Inlet_Temperature_Total, nMarker_ActDiskInlet, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(Inlet_Pressure_Local, Inlet_Pressure_Total, nMarker_ActDiskInlet, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(Inlet_Area_Local, Inlet_Area_Total, nMarker_ActDiskInlet, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + + SU2_MPI::Allreduce(Outlet_MassFlow_Local, Outlet_MassFlow_Total, nMarker_ActDiskOutlet, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(Outlet_Temperature_Local, Outlet_Temperature_Total, nMarker_ActDiskOutlet, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(Outlet_Pressure_Local, Outlet_Pressure_Total, nMarker_ActDiskOutlet, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(Outlet_Area_Local, Outlet_Area_Total, nMarker_ActDiskOutlet, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + +#else + + for (iMarker_ActDiskInlet = 0; iMarker_ActDiskInlet < nMarker_ActDiskInlet; iMarker_ActDiskInlet++) { + Inlet_MassFlow_Total[iMarker_ActDiskInlet] = Inlet_MassFlow_Local[iMarker_ActDiskInlet]; + Inlet_Temperature_Total[iMarker_ActDiskInlet] = Inlet_Temperature_Local[iMarker_ActDiskInlet]; + Inlet_Pressure_Total[iMarker_ActDiskInlet] = Inlet_Pressure_Local[iMarker_ActDiskInlet]; + Inlet_Area_Total[iMarker_ActDiskInlet] = Inlet_Area_Local[iMarker_ActDiskInlet]; + } + + for (iMarker_ActDiskOutlet = 0; iMarker_ActDiskOutlet < nMarker_ActDiskOutlet; iMarker_ActDiskOutlet++) { + Outlet_MassFlow_Total[iMarker_ActDiskOutlet] = Outlet_MassFlow_Local[iMarker_ActDiskOutlet]; + Outlet_Temperature_Total[iMarker_ActDiskOutlet] = Outlet_Temperature_Local[iMarker_ActDiskOutlet]; + Outlet_Pressure_Total[iMarker_ActDiskOutlet] = Outlet_Pressure_Local[iMarker_ActDiskOutlet]; + Outlet_Area_Total[iMarker_ActDiskOutlet] = Outlet_Area_Local[iMarker_ActDiskOutlet]; + } + +#endif + + /*--- Compute the value of Inlet_Area_Total, and Inlet_Pressure_Total, and + set the value in the config structure for future use ---*/ + + for (iMarker_ActDiskInlet = 0; iMarker_ActDiskInlet < nMarker_ActDiskInlet; iMarker_ActDiskInlet++) { + if (Inlet_Area_Total[iMarker_ActDiskInlet] != 0.0) Inlet_Temperature_Total[iMarker_ActDiskInlet] /= Inlet_Area_Total[iMarker_ActDiskInlet]; + else Inlet_Temperature_Total[iMarker_ActDiskInlet] = 0.0; + if (Inlet_Area_Total[iMarker_ActDiskInlet] != 0.0) Inlet_Pressure_Total[iMarker_ActDiskInlet] /= Inlet_Area_Total[iMarker_ActDiskInlet]; + else Inlet_Pressure_Total[iMarker_ActDiskInlet] = 0.0; + } + + /*--- Compute the value of Outlet_Area_Total, and Outlet_Pressure_Total, and + set the value in the config structure for future use ---*/ + + for (iMarker_ActDiskOutlet = 0; iMarker_ActDiskOutlet < nMarker_ActDiskOutlet; iMarker_ActDiskOutlet++) { + if (Outlet_Area_Total[iMarker_ActDiskOutlet] != 0.0) Outlet_Temperature_Total[iMarker_ActDiskOutlet] /= Outlet_Area_Total[iMarker_ActDiskOutlet]; + else Outlet_Temperature_Total[iMarker_ActDiskOutlet] = 0.0; + if (Outlet_Area_Total[iMarker_ActDiskOutlet] != 0.0) Outlet_Pressure_Total[iMarker_ActDiskOutlet] /= Outlet_Area_Total[iMarker_ActDiskOutlet]; + else Outlet_Pressure_Total[iMarker_ActDiskOutlet] = 0.0; + } + + bool write_heads = (((config->GetExtIter() % (config->GetWrt_Con_Freq()*40)) == 0)); + + if ((rank == MASTER_NODE) && (iMesh == MESH_0) && write_heads && Output) { + + cout.precision(4); + cout.setf(ios::fixed, ios::floatfield); + + cout << endl << "------------------------ Actuator Disk properties -----------------------" << endl; + + for (iMarker_ActDiskInlet = 0; iMarker_ActDiskInlet < nMarker_ActDiskInlet; iMarker_ActDiskInlet++) { + cout << "Actuator Disk Inlet ("<< config->GetMarker_ActDisk_Inlet(iMarker_ActDiskInlet); + if (config->GetSystemMeasurements() == SI) cout << "): Mass flow (kg/s): "; + else if (config->GetSystemMeasurements() == US) cout << "): Mass flow (slug/s): "; + cout << -Inlet_MassFlow_Total[iMarker_ActDiskInlet] * config->GetDensity_Ref() * config->GetVelocity_Ref(); + if (config->GetSystemMeasurements() == SI) cout << ", Temp (K): "; + else if (config->GetSystemMeasurements() == US) cout << ", Temp (R): "; + cout << Inlet_Temperature_Total[iMarker_ActDiskInlet] * config->GetTemperature_Ref(); + if (config->GetSystemMeasurements() == SI) cout << ", Pressure (Pa): "; + else if (config->GetSystemMeasurements() == US) cout << ", Pressure (psf): "; + cout << Inlet_Pressure_Total[iMarker_ActDiskInlet] * config->GetPressure_Ref(); + if (config->GetSystemMeasurements() == SI) cout << ", Area (m^2): "; + else if (config->GetSystemMeasurements() == US) cout << ", Area (ft^2): "; + cout << Inlet_Area_Total[iMarker_ActDiskInlet] <<"."<< endl; + } + + for (iMarker_ActDiskOutlet = 0; iMarker_ActDiskOutlet < nMarker_ActDiskOutlet; iMarker_ActDiskOutlet++) { + cout << "Actuator Disk Outlet ("<< config->GetMarker_ActDisk_Outlet(iMarker_ActDiskOutlet); + if (config->GetSystemMeasurements() == SI) cout << "): Mass flow (kg/s): "; + else if (config->GetSystemMeasurements() == US) cout << "): Mass flow (slug/s): "; + cout << Outlet_MassFlow_Total[iMarker_ActDiskOutlet] * config->GetDensity_Ref() * config->GetVelocity_Ref(); + if (config->GetSystemMeasurements() == SI) cout << ", Temp (K): "; + else if (config->GetSystemMeasurements() == US) cout << ", Temp (R): "; + cout << Outlet_Temperature_Total[iMarker_ActDiskOutlet] * config->GetTemperature_Ref(); + if (config->GetSystemMeasurements() == SI) cout << ", Pressure (Pa): "; + else if (config->GetSystemMeasurements() == US) cout << ", Pressure (psf): "; + cout << Outlet_Pressure_Total[iMarker_ActDiskOutlet] * config->GetPressure_Ref(); + if (config->GetSystemMeasurements() == SI) cout << ", Area (m^2): "; + else if (config->GetSystemMeasurements() == US) cout << ", Area (ft^2): "; + cout << Outlet_Area_Total[iMarker_ActDiskOutlet] <<"."<< endl; + } + cout << "-------------------------------------------------------------------------" << endl; + + } + + delete [] Outlet_MassFlow_Local; + delete [] Outlet_Temperature_Local; + delete [] Outlet_Pressure_Local; + delete [] Outlet_Area_Local; + + delete [] Outlet_MassFlow_Total; + delete [] Outlet_Temperature_Total; + delete [] Outlet_Pressure_Total; + delete [] Outlet_Area_Total; + + delete [] Inlet_MassFlow_Local; + delete [] Inlet_Temperature_Local; + delete [] Inlet_Pressure_Local; + delete [] Inlet_Area_Local; + + delete [] Inlet_MassFlow_Total; + delete [] Inlet_Temperature_Total; + delete [] Inlet_Pressure_Total; + delete [] Inlet_Area_Total; + + + delete [] Inlet_MassFlow; + delete [] Inlet_Pressure; + delete [] Inlet_Temperature; + delete [] Inlet_Area; + + delete [] Outlet_MassFlow; + delete [] Outlet_Pressure; + delete [] Outlet_Temperature; + delete [] Outlet_Area; + +} + +void CEulerSolver::SetFarfield_AoA(CGeometry *geometry, CSolver **solver_container, + CConfig *config, unsigned short iMesh, bool Output) { + + unsigned short iDim, iCounter; + bool Update_AoA = false; + su2double Target_CL, AoA_inc, AoA; + su2double DampingFactor = config->GetDamp_Fixed_CL(); + unsigned long Iter_Fixed_CL = config->GetIter_Fixed_CL(); + unsigned long ExtIter = config->GetExtIter(); + su2double Beta = config->GetAoS()*PI_NUMBER/180.0; + su2double Vel_Infty[3], Vel_Infty_Mag; + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Only the fine mesh level should check the convergence criteria ---*/ + + if (iMesh == MESH_0) { + + /*--- Initialize the update flag to false ---*/ + + Update_AoA = false; + + /*--- Reevaluate Angle of Attack at a fix number of iterations ---*/ + + if (ExtIter % Iter_Fixed_CL == 0) { Update_AoA = true; }; + + /*--- Store the update boolean for use on other mesh levels in the MG ---*/ + + config->SetUpdate_AoA(Update_AoA); + + } + + else { + Update_AoA = config->GetUpdate_AoA(); + } + + /*--- If we are within two digits of convergence in the CL coefficient, + compute an updated value for the AoA at the farfield. We are iterating + on the AoA in order to match the specified fixed lift coefficient. ---*/ + + if (Update_AoA) { + + /*--- Retrieve the specified target CL value. ---*/ + + Target_CL = config->GetTarget_CL(); + + /*--- Retrieve the old AoA. ---*/ + + AoA_old = config->GetAoA()*PI_NUMBER/180.0; + + /*--- Estimate the increment in AoA based on a 2*pi lift curve slope ---*/ + + AoA_inc = (1.0/(2.0*PI_NUMBER))*(Target_CL - Total_CLift); + + /*--- Compute a new value for AoA on the fine mesh only ---*/ + + if (iMesh == MESH_0) + AoA = (1.0 - DampingFactor)*AoA_old + DampingFactor * (AoA_old + AoA_inc); + else + AoA = config->GetAoA()*PI_NUMBER/180.0; + + /*--- 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 ---*/ + + 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); + + /*--- Compute the new freestream velocity with the updated AoA ---*/ + + if (nDim == 2) { + Vel_Infty[0] = cos(AoA)*Vel_Infty_Mag; + Vel_Infty[1] = sin(AoA)*Vel_Infty_Mag; + } + if (nDim == 3) { + Vel_Infty[0] = cos(AoA)*cos(Beta)*Vel_Infty_Mag; + Vel_Infty[1] = sin(Beta)*Vel_Infty_Mag; + Vel_Infty[2] = sin(AoA)*cos(Beta)*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 AoA in config ---*/ + if (iMesh == MESH_0) { + for (iDim = 0; iDim < nDim; iDim++) + config->SetVelocity_FreeStreamND(Vel_Infty[iDim], iDim); + config->SetAoA(AoA*180.0/PI_NUMBER); + } + + /*--- Reset the local cauchy criteria ---*/ + Cauchy_Value = 0.0; + Cauchy_Counter = 0; + for (iCounter = 0; iCounter < config->GetCauchy_Elems(); iCounter++) + Cauchy_Serie[iCounter] = 0.0; + } + + /*--- Output some information to the console with the headers ---*/ + + bool write_heads = (((config->GetExtIter() % (config->GetWrt_Con_Freq()*40)) == 0)); + if ((rank == MASTER_NODE) && (iMesh == MESH_0) && write_heads && Output) { + cout.precision(7); + cout.setf(ios::fixed, ios::floatfield); + cout << endl << "----------------------------- Fixed CL Mode -----------------------------" << endl; + cout << "Target CL: " << config->GetTarget_CL(); + cout << ", Current CL: " << Total_CLift; + cout << ", Current AoA: " << config->GetAoA() << " deg." << endl; + cout << "-------------------------------------------------------------------------" << endl; + } + + +} + +void CEulerSolver::BC_Euler_Wall(CGeometry *geometry, CSolver **solver_container, + CNumerics *numerics, CConfig *config, unsigned short val_marker) { + + unsigned short iDim, iVar, jVar, kVar, jDim; + unsigned long iPoint, iVertex; + su2double Density = 0.0, Pressure = 0.0, *Normal = NULL, *GridVel = NULL, Area, UnitNormal[3], *NormalArea, + ProjGridVel = 0.0, turb_ke; + su2double Density_b, StaticEnergy_b, Enthalpy_b, *Velocity_b, Kappa_b, Chi_b, Energy_b, VelMagnitude2_b, Pressure_b; + su2double Density_i, *Velocity_i, ProjVelocity_i = 0.0, Energy_i, VelMagnitude2_i; + su2double **Jacobian_b, **DubDu; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool grid_movement = config->GetGrid_Movement(); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool tkeNeeded = (((config->GetKind_Solver() == RANS )|| (config->GetKind_Solver() == DISC_ADJ_RANS)) && + (config->GetKind_Turb_Model() == SST)); + + Normal = new su2double[nDim]; + NormalArea = new su2double[nDim]; + Velocity_b = new su2double[nDim]; + Velocity_i = new su2double[nDim]; + Jacobian_b = new su2double*[nVar]; + DubDu = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Jacobian_b[iVar] = new su2double[nVar]; + DubDu[iVar] = new su2double[nVar]; + } + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Normal vector for this vertex (negative for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; + Area = sqrt (Area); + + for (iDim = 0; iDim < nDim; iDim++) { + NormalArea[iDim] = -Normal[iDim]; + UnitNormal[iDim] = -Normal[iDim]/Area; + } + + /*--- Compressible solver ---*/ + + if (compressible) { + + /*--- Get the state i ---*/ + + VelMagnitude2_i = 0.0; ProjVelocity_i = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity_i[iDim] = node[iPoint]->GetVelocity(iDim); + ProjVelocity_i += Velocity_i[iDim]*UnitNormal[iDim]; + VelMagnitude2_i += Velocity_i[iDim]*Velocity_i[iDim]; + } + Density_i = node[iPoint]->GetDensity(); + Energy_i = node[iPoint]->GetEnergy(); + + /*--- Compute the boundary state b ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + Velocity_b[iDim] = Velocity_i[iDim] - ProjVelocity_i * UnitNormal[iDim]; //Force the velocity to be tangential to the surface. + + if (grid_movement) { + GridVel = geometry->node[iPoint]->GetGridVel(); + ProjGridVel = 0.0; + for (iDim = 0; iDim < nDim; iDim++) ProjGridVel += GridVel[iDim]*UnitNormal[iDim]; + for (iDim = 0; iDim < nDim; iDim++) Velocity_b[iDim] += GridVel[iDim] - ProjGridVel * UnitNormal[iDim]; + } + + VelMagnitude2_b = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + VelMagnitude2_b += Velocity_b[iDim] * Velocity_b[iDim]; + + /*--- Compute the residual ---*/ + + turb_ke = 0.0; + if (tkeNeeded) turb_ke = solver_container[TURB_SOL]->node[iPoint]->GetSolution(0); + + Density_b = Density_i; + StaticEnergy_b = Energy_i - 0.5 * VelMagnitude2_i - turb_ke; + Energy_b = StaticEnergy_b + 0.5 * VelMagnitude2_b + turb_ke; + + FluidModel->SetTDState_rhoe(Density_b, StaticEnergy_b); + Kappa_b = FluidModel->GetdPde_rho() / Density_b; + Chi_b = FluidModel->GetdPdrho_e() - Kappa_b * StaticEnergy_b; + Pressure_b = FluidModel->GetPressure(); + Enthalpy_b = Energy_b + Pressure_b/Density_b; + + numerics->GetInviscidProjFlux(&Density_b, Velocity_b, &Pressure_b, &Enthalpy_b, NormalArea, Residual); + + /*--- Grid velocity correction to the energy term ---*/ + if (grid_movement) { + GridVel = geometry->node[iPoint]->GetGridVel(); + ProjGridVel = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + ProjGridVel += GridVel[iDim]*UnitNormal[iDim]; + Residual[nVar-1] += Pressure_b*ProjGridVel*Area; + } + + /*--- Add the Reynolds stress tensor contribution ---*/ + + if (tkeNeeded) { + for (iDim = 0; iDim < nDim; iDim++) + Residual[iDim+1] += (2.0/3.0)*Density_b*turb_ke*NormalArea[iDim]; + } + + } + + /*--- Incompressible solver ---*/ + + if (incompressible || freesurface) { + + /*--- Compute the residual ---*/ + + Pressure = node[iPoint]->GetPressureInc(); + Density = node[iPoint]->GetPressureInc(); + + Residual[0] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Residual[iDim+1] = Pressure*NormalArea[iDim]; + if (compressible || freesurface) { + Residual[nVar-1] = 0.0; + } + + /*--- Add the Reynolds stress tensor contribution ---*/ + + if (tkeNeeded) { + turb_ke = solver_container[TURB_SOL]->node[iPoint]->GetSolution(0); + for (iDim = 0; iDim < nDim; iDim++) + Residual[iDim+1] += (2.0/3.0)*Density*turb_ke*NormalArea[iDim]; + } + + /*--- Adjustment to energy equation due to grid motion ---*/ + + if (grid_movement) { + ProjGridVel = 0.0; + GridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + ProjGridVel += GridVel[iDim]*UnitNormal[iDim]; + Residual[nVar-1] = Pressure*ProjGridVel*Area; + } + + } + + /*--- Add value to the residual ---*/ + + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Form Jacobians for implicit computations ---*/ + + if (implicit) { + + /*--- Initialize Jacobian ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + for (jVar = 0; jVar < nVar; jVar++) + Jacobian_i[iVar][jVar] = 0.0; + } + + /*--- Compressible solver ---*/ + + if (compressible) { + + /*--- Compute DubDu ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + for (jVar = 0; jVar < nVar; jVar++) + DubDu[iVar][jVar]= 0.0; + DubDu[iVar][iVar]= 1.0; + } + + for (iDim = 0; iDim < nDim; iDim++) + for (jDim = 0; jDimGetInviscidProjJac(Velocity_b, &Enthalpy_b, &Chi_b, &Kappa_b, NormalArea, 1, Jacobian_b); + + // Check for grid movement, should be already considered since Jacobian b is computed from u_b + // if (grid_movement) { + // Jacobian_b[nVar-1][0] += 0.5*ProjGridVel*ProjGridVel; + // for (iDim = 0; iDim < nDim; iDim++) + // Jacobian_b[nVar-1][iDim+1] -= ProjGridVel * UnitNormal[iDim]; + // } + + /*--- Compute numerical flux Jacobian at node i ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + for (kVar = 0; kVar < nVar; kVar++) + Jacobian_i[iVar][jVar] += Jacobian_b[iVar][kVar] * DubDu[kVar][jVar]; + + /*--- Add the Jacobian to the sparse matrix ---*/ + + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + } + + /*--- Incompressible solver ---*/ + + if (incompressible || freesurface) { + for (iDim = 0; iDim < nDim; iDim++) + Jacobian_i[iDim+1][0] = -Normal[iDim]; + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + } + + } + } + } + + delete [] Normal; + delete [] NormalArea; + delete [] Velocity_b; + delete [] Velocity_i; + for (iVar = 0; iVar < nVar; iVar++) { + delete [] Jacobian_b[iVar]; + delete [] DubDu[iVar]; + } + delete [] Jacobian_b; + delete [] DubDu; + +} + +void CEulerSolver::BC_Far_Field(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, + CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned short iDim; + unsigned long iVertex, iPoint, Point_Normal; + + su2double *GridVel; + su2double Area, UnitNormal[3] = {0.0,0.0,0.0}; + su2double Density, Pressure, Energy, Velocity[3] = {0.0,0.0,0.0}; + su2double Density_Bound, Pressure_Bound, Vel_Bound[3] = {0.0,0.0,0.0}; + su2double Density_Infty, Pressure_Infty, Vel_Infty[3] = {0.0,0.0,0.0}; + su2double SoundSpeed, Entropy, Velocity2, Vn; + su2double SoundSpeed_Bound, Entropy_Bound, Vel2_Bound, Vn_Bound; + su2double SoundSpeed_Infty, Entropy_Infty, Vel2_Infty, Vn_Infty, Qn_Infty; + su2double RiemannPlus, RiemannMinus; + su2double *V_infty, *V_domain; + + su2double Gas_Constant = config->GetGas_ConstantND(); + + bool implicit = config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT; + bool grid_movement = config->GetGrid_Movement(); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool viscous = config->GetViscous(); + bool tkeNeeded = (((config->GetKind_Solver() == RANS ) || + (config->GetKind_Solver() == DISC_ADJ_RANS)) + && (config->GetKind_Turb_Model() == SST)); + + su2double *Normal = new su2double[nDim]; + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Allocate the value at the infinity ---*/ + V_infty = GetCharacPrimVar(val_marker, iVertex); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Index of the closest interior node ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + /*--- Retrieve solution at the farfield boundary node ---*/ + V_domain = node[iPoint]->GetPrimitive(); + + /*--- Construct solution state at infinity (far-field) ---*/ + + if (compressible) { + + /*--- Construct solution state at infinity for compressible flow by + using Riemann invariants, and then impose a weak boundary condition + by computing the flux using this new state for U. See CFD texts by + Hirsch or Blazek for more detail. Adapted from an original + implementation in the Stanford University multi-block (SUmb) solver + in the routine bcFarfield.f90 written by Edwin van der Weide, + last modified 06-12-2005. First, compute the unit normal at the + boundary nodes. ---*/ + + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; + Area = sqrt(Area); + + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] = Normal[iDim]/Area; + + /*--- Store primitive variables (density, velocities, velocity squared, + energy, pressure, and sound speed) at the boundary node, and set some + other quantities for clarity. Project the current flow velocity vector + at this boundary node into the local normal direction, i.e. compute + v_bound.n. ---*/ + + Density_Bound = V_domain[nDim+2]; + Vel2_Bound = 0.0; Vn_Bound = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Vel_Bound[iDim] = V_domain[iDim+1]; + Vel2_Bound += Vel_Bound[iDim]*Vel_Bound[iDim]; + Vn_Bound += Vel_Bound[iDim]*UnitNormal[iDim]; + } + Pressure_Bound = node[iPoint]->GetPressure(); + SoundSpeed_Bound = sqrt(Gamma*Pressure_Bound/Density_Bound); + Entropy_Bound = pow(Density_Bound, Gamma)/Pressure_Bound; + + /*--- Store the primitive variable state for the freestream. Project + the freestream velocity vector into the local normal direction, + i.e. compute v_infty.n. ---*/ + + Density_Infty = GetDensity_Inf(); + Vel2_Infty = 0.0; Vn_Infty = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Vel_Infty[iDim] = GetVelocity_Inf(iDim); + Vel2_Infty += Vel_Infty[iDim]*Vel_Infty[iDim]; + Vn_Infty += Vel_Infty[iDim]*UnitNormal[iDim]; + } + Pressure_Infty = GetPressure_Inf(); + SoundSpeed_Infty = sqrt(Gamma*Pressure_Infty/Density_Infty); + Entropy_Infty = pow(Density_Infty, Gamma)/Pressure_Infty; + + /*--- Adjust the normal freestream velocity for grid movement ---*/ + + Qn_Infty = Vn_Infty; + if (grid_movement) { + GridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + Qn_Infty -= GridVel[iDim]*UnitNormal[iDim]; + } + + /*--- Compute acoustic Riemann invariants: R = u.n +/- 2c/(gamma-1). + These correspond with the eigenvalues (u+c) and (u-c), respectively, + which represent the acoustic waves. Positive characteristics are + incoming, and a physical boundary condition is imposed (freestream + state). This occurs when either (u.n+c) > 0 or (u.n-c) > 0. Negative + characteristics are leaving the domain, and numerical boundary + conditions are required by extrapolating from the interior state + using the Riemann invariants. This occurs when (u.n+c) < 0 or + (u.n-c) < 0. Note that grid movement is taken into account when + checking the sign of the eigenvalue. ---*/ + + /*--- Check whether (u.n+c) is greater or less than zero ---*/ + + if (Qn_Infty > -SoundSpeed_Infty) { + /*--- Subsonic inflow or outflow ---*/ + RiemannPlus = Vn_Bound + 2.0*SoundSpeed_Bound/Gamma_Minus_One; + } else { + /*--- Supersonic inflow ---*/ + RiemannPlus = Vn_Infty + 2.0*SoundSpeed_Infty/Gamma_Minus_One; + } + + /*--- Check whether (u.n-c) is greater or less than zero ---*/ + + if (Qn_Infty > SoundSpeed_Infty) { + /*--- Supersonic outflow ---*/ + RiemannMinus = Vn_Bound - 2.0*SoundSpeed_Bound/Gamma_Minus_One; + } else { + /*--- Subsonic outflow ---*/ + RiemannMinus = Vn_Infty - 2.0*SoundSpeed_Infty/Gamma_Minus_One; + } + + /*--- Compute a new value for the local normal velocity and speed of + sound from the Riemann invariants. ---*/ + + Vn = 0.5 * (RiemannPlus + RiemannMinus); + SoundSpeed = 0.25 * (RiemannPlus - RiemannMinus)*Gamma_Minus_One; + + /*--- Construct the primitive variable state at the boundary for + computing the flux for the weak boundary condition. The values + that we choose to construct the solution (boundary or freestream) + depend on whether we are at an inflow or outflow. At an outflow, we + choose boundary information (at most one characteristic is incoming), + while at an inflow, we choose infinity values (at most one + characteristic is outgoing). ---*/ + + if (Qn_Infty > 0.0) { + /*--- Outflow conditions ---*/ + for (iDim = 0; iDim < nDim; iDim++) + Velocity[iDim] = Vel_Bound[iDim] + (Vn-Vn_Bound)*UnitNormal[iDim]; + Entropy = Entropy_Bound; + } else { + /*--- Inflow conditions ---*/ + for (iDim = 0; iDim < nDim; iDim++) + Velocity[iDim] = Vel_Infty[iDim] + (Vn-Vn_Infty)*UnitNormal[iDim]; + Entropy = Entropy_Infty; + } + + /*--- Recompute the primitive variables. ---*/ + + Density = pow(Entropy*SoundSpeed*SoundSpeed/Gamma,1.0/Gamma_Minus_One); + Velocity2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity2 += Velocity[iDim]*Velocity[iDim]; + } + Pressure = Density*SoundSpeed*SoundSpeed/Gamma; + Energy = Pressure/(Gamma_Minus_One*Density) + 0.5*Velocity2; + if (tkeNeeded) Energy += GetTke_Inf(); + + /*--- Store new primitive state for computing the flux. ---*/ + + V_infty[0] = Pressure/(Gas_Constant*Density); + for (iDim = 0; iDim < nDim; iDim++) + V_infty[iDim+1] = Velocity[iDim]; + V_infty[nDim+1] = Pressure; + V_infty[nDim+2] = Density; + V_infty[nDim+3] = Energy + Pressure/Density; + + } + if (incompressible) { + + /*--- All the values computed from the infinity ---*/ + + V_infty[0] = GetPressure_Inf(); + for (iDim = 0; iDim < nDim; iDim++) + V_infty[iDim+1] = GetVelocity_Inf(iDim); + V_infty[nDim+1] = GetDensity_Inf(); + V_infty[nDim+2] = config->GetArtComp_Factor(); + + } + if (freesurface) { + + /*--- All the values computed from the infinity ---*/ + + V_infty[0] = GetPressure_Inf(); + for (iDim = 0; iDim < nDim; iDim++) + V_infty[iDim+1] = GetVelocity_Inf(iDim); + V_infty[nDim+1] = GetDensity_Inf(); + V_infty[nDim+2] = config->GetArtComp_Factor(); + + } + + /*--- Set various quantities in the numerics class ---*/ + + conv_numerics->SetPrimitive(V_domain, V_infty); + + if (grid_movement) { + conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), + geometry->node[iPoint]->GetGridVel()); + } + + /*--- Compute the convective residual using an upwind scheme ---*/ + + conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Update residual value ---*/ + + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Convective Jacobian contribution for implicit integration ---*/ + + if (implicit) + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + /*--- Roe Turkel preconditioning, set the value of beta ---*/ + + if (config->GetKind_Upwind() == TURKEL) + node[iPoint]->SetPreconditioner_Beta(conv_numerics->GetPrecond_Beta()); + + /*--- Viscous residual contribution ---*/ + + if (viscous) { + + /*--- Set laminar and eddy viscosity at the infinity ---*/ + + if (compressible) { + V_infty[nDim+5] = node[iPoint]->GetLaminarViscosity(); + V_infty[nDim+6] = node[iPoint]->GetEddyViscosity(); + } + if (incompressible) { + V_infty[nDim+3] = node[iPoint]->GetLaminarViscosityInc(); + V_infty[nDim+4] = node[iPoint]->GetEddyViscosityInc(); + } + + /*--- Set the normal vector and the coordinates ---*/ + + visc_numerics->SetNormal(Normal); + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), + geometry->node[Point_Normal]->GetCoord()); + + /*--- Primitive variables, and gradient ---*/ + + visc_numerics->SetPrimitive(V_domain, V_infty); + visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), + node[iPoint]->GetGradient_Primitive()); + + /*--- Turbulent kinetic energy ---*/ + + if (config->GetKind_Turb_Model() == SST) + visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), + solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); + + /*--- Compute and update viscous residual ---*/ + + visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.SubtractBlock(iPoint, Residual); + + /*--- Viscous Jacobian contribution for implicit integration ---*/ + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + + } + } + + /*--- Free locally allocated memory ---*/ + delete [] Normal; + +} + +void CEulerSolver::BC_Riemann(CGeometry *geometry, CSolver **solver_container, + CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + unsigned short iDim, iVar, jVar, kVar; + unsigned long iVertex, iPoint, Point_Normal; + su2double P_Total, T_Total, P_static, T_static, Rho_static, *Mach, *Flow_Dir, Area, UnitNormal[3]; + su2double *Velocity_b, Velocity2_b, Enthalpy_b, Energy_b, StaticEnergy_b, Density_b, Kappa_b, Chi_b, Pressure_b, Temperature_b; + su2double *Velocity_e, Velocity2_e, VelMag_e, Enthalpy_e, Entropy_e, Energy_e = 0.0, StaticEnthalpy_e, StaticEnergy_e, Density_e = 0.0, Pressure_e; + su2double *Velocity_i, Velocity2_i, Enthalpy_i, Energy_i, StaticEnergy_i, Density_i, Kappa_i, Chi_i, Pressure_i, SoundSpeed_i; + su2double ProjVelocity_i; + su2double **P_Tensor, **invP_Tensor, *Lambda_i, **Jacobian_b, **DubDu, *dw, *u_e, *u_i, *u_b; + su2double *gridVel; + su2double *V_boundary, *V_domain, *S_boundary, *S_domain; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool grid_movement = config->GetGrid_Movement(); + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + bool viscous = config->GetViscous(); + bool gravity = (config->GetGravityForce()); + bool tkeNeeded = (((config->GetKind_Solver() == RANS )|| (config->GetKind_Solver() == DISC_ADJ_RANS)) && + (config->GetKind_Turb_Model() == SST)); + + su2double *Normal, *FlowDirMix, TangVelocity, NormalVelocity; + Normal = new su2double[nDim]; + su2double ext_flow_angle; + + Velocity_i = new su2double[nDim]; + Velocity_b = new su2double[nDim]; + Velocity_e = new su2double[nDim]; + FlowDirMix = new su2double[nDim]; + Lambda_i = new su2double[nVar]; + u_i = new su2double[nVar]; + u_e = new su2double[nVar]; + u_b = new su2double[nVar]; + dw = new su2double[nVar]; + + S_boundary = new su2double[8]; + + P_Tensor = new su2double*[nVar]; + invP_Tensor = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) + { + P_Tensor[iVar] = new su2double[nVar]; + invP_Tensor[iVar] = new su2double[nVar]; + } + + /*--- Loop over all the vertices on this boundary marker ---*/ + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + V_boundary= GetCharacPrimVar(val_marker, iVertex); + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Index of the closest interior node ---*/ + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; + Area = sqrt (Area); + + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] = Normal[iDim]/Area; + + /*--- Retrieve solution at this boundary node ---*/ + V_domain = node[iPoint]->GetPrimitive(); + + /* --- Compute the internal state u_i --- */ + Velocity2_i = 0; + for (iDim=0; iDim < nDim; iDim++) + { + Velocity_i[iDim] = node[iPoint]->GetVelocity(iDim); + Velocity2_i += Velocity_i[iDim]*Velocity_i[iDim]; + } + + + Density_i = node[iPoint]->GetDensity(); + + Energy_i = node[iPoint]->GetEnergy(); + StaticEnergy_i = Energy_i - 0.5*Velocity2_i; + + FluidModel->SetTDState_rhoe(Density_i, StaticEnergy_i); + + Pressure_i = FluidModel->GetPressure(); + Enthalpy_i = Energy_i + Pressure_i/Density_i; + + SoundSpeed_i = FluidModel->GetSoundSpeed(); + + Kappa_i = FluidModel->GetdPde_rho() / Density_i; + Chi_i = FluidModel->GetdPdrho_e() - Kappa_i * StaticEnergy_i; + + ProjVelocity_i = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + ProjVelocity_i += Velocity_i[iDim]*UnitNormal[iDim]; + + /*--- Build the external state u_e from boundary data and internal node ---*/ + + switch(config->GetKind_Data_Riemann(Marker_Tag)) + { + //TODO(turbo), generilize for 3D case + //TODO(turbo), generilize for Inlet and Outlet in for backflow treatment + //TODO(turbo), implement not uniform inlet and radial equilibrium for the outlet + case TOTAL_CONDITIONS_PT: + + /*--- Retrieve the specified total conditions for this boundary. ---*/ + if (gravity) P_Total = config->GetRiemann_Var1(Marker_Tag) - geometry->node[iPoint]->GetCoord(nDim-1)*STANDART_GRAVITY;/// check in which case is true (only freesurface?) + else P_Total = config->GetRiemann_Var1(Marker_Tag); + T_Total = config->GetRiemann_Var2(Marker_Tag); + Flow_Dir = config->GetRiemann_FlowDir(Marker_Tag); + + /*--- Non-dim. the inputs if necessary. ---*/ + P_Total /= config->GetPressure_Ref(); + T_Total /= config->GetTemperature_Ref(); + + /* --- Computes the total state --- */ + FluidModel->SetTDState_PT(P_Total, T_Total); + Enthalpy_e = FluidModel->GetStaticEnergy()+ FluidModel->GetPressure()/FluidModel->GetDensity(); + Entropy_e = FluidModel->GetEntropy(); + + /* --- Compute the boundary state u_e --- */ + Velocity2_e = Velocity2_i; + if (nDim == 2){ + NormalVelocity= -sqrt(Velocity2_e)*Flow_Dir[0]; + TangVelocity= -sqrt(Velocity2_e)*Flow_Dir[1]; + Velocity_e[0]= UnitNormal[0]*NormalVelocity - UnitNormal[1]*TangVelocity; + Velocity_e[1]= UnitNormal[1]*NormalVelocity + UnitNormal[0]*TangVelocity; + }else{ + for (iDim = 0; iDim < nDim; iDim++) + Velocity_e[iDim] = sqrt(Velocity2_e)*Flow_Dir[iDim]; + } + StaticEnthalpy_e = Enthalpy_e - 0.5 * Velocity2_e; + FluidModel->SetTDState_hs(StaticEnthalpy_e, Entropy_e); + Density_e = FluidModel->GetDensity(); + StaticEnergy_e = FluidModel->GetStaticEnergy(); + Energy_e = StaticEnergy_e + 0.5 * Velocity2_e; + if (tkeNeeded) Energy_e += GetTke_Inf(); + break; + + case STATIC_SUPERSONIC_INFLOW_PT: + + /*--- Retrieve the specified total conditions for this boundary. ---*/ + if (gravity) P_static = config->GetRiemann_Var1(Marker_Tag) - geometry->node[iPoint]->GetCoord(nDim-1)*STANDART_GRAVITY;/// check in which case is true (only freesurface?) + else P_static = config->GetRiemann_Var1(Marker_Tag); + T_static = config->GetRiemann_Var2(Marker_Tag); + Mach = config->GetRiemann_FlowDir(Marker_Tag); + + /*--- Non-dim. the inputs if necessary. ---*/ + P_static /= config->GetPressure_Ref(); + T_static /= config->GetTemperature_Ref(); + + /* --- Computes the total state --- */ + FluidModel->SetTDState_PT(P_static, T_static); + + /* --- Compute the boundary state u_e --- */ + Velocity2_e = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity_e[iDim] = Mach[iDim]*FluidModel->GetSoundSpeed(); + Velocity2_e += Velocity_e[iDim]*Velocity_e[iDim]; + } + Density_e = FluidModel->GetDensity(); + StaticEnergy_e = FluidModel->GetStaticEnergy(); + Energy_e = StaticEnergy_e + 0.5 * Velocity2_e; + if (tkeNeeded) Energy_e += GetTke_Inf(); + break; + + case STATIC_SUPERSONIC_INFLOW_PD: + + /*--- Retrieve the specified total conditions for this boundary. ---*/ + + if (gravity) P_static = config->GetRiemann_Var1(Marker_Tag) - geometry->node[iPoint]->GetCoord(nDim-1)*STANDART_GRAVITY;/// check in which case is true (only freesurface?) + else P_static = config->GetRiemann_Var1(Marker_Tag); + Rho_static = config->GetRiemann_Var2(Marker_Tag); + Mach = config->GetRiemann_FlowDir(Marker_Tag); + + /*--- Non-dim. the inputs if necessary. ---*/ + P_static /= config->GetPressure_Ref(); + Rho_static /= config->GetDensity_Ref(); + + /* --- Computes the total state --- */ + FluidModel->SetTDState_Prho(P_static, Rho_static); + + /* --- Compute the boundary state u_e --- */ + Velocity2_e = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity_e[iDim] = Mach[iDim]*FluidModel->GetSoundSpeed(); + Velocity2_e += Velocity_e[iDim]*Velocity_e[iDim]; + } + Density_e = FluidModel->GetDensity(); + StaticEnergy_e = FluidModel->GetStaticEnergy(); + Energy_e = StaticEnergy_e + 0.5 * Velocity2_e; + if (tkeNeeded) Energy_e += GetTke_Inf(); + break; + + case MIXING_IN: + + /*--- Retrieve the specified total conditions for this boundary. ---*/ + P_Total = ExtAveragedTotPressure[val_marker]; + T_Total = ExtAveragedTotTemperature[val_marker]; + ext_flow_angle = atan(ExtAveragedTangVelocity[val_marker]/ExtAveragedNormalVelocity[val_marker]); + FlowDirMix[0] = cos(ext_flow_angle); + FlowDirMix[1] = sin(ext_flow_angle); + + /* --- Computes the total state --- */ + FluidModel->SetTDState_PT(P_Total, T_Total); + Enthalpy_e = FluidModel->GetStaticEnergy()+ FluidModel->GetPressure()/FluidModel->GetDensity(); + Entropy_e = FluidModel->GetEntropy(); + + /* --- Compute the boundary state u_e --- */ + Velocity2_e = Velocity2_i; + if (nDim == 2){ + NormalVelocity= -sqrt(Velocity2_e)*FlowDirMix[0]; + TangVelocity= -sqrt(Velocity2_e)*FlowDirMix[1]; + Velocity_e[0]= UnitNormal[0]*NormalVelocity - UnitNormal[1]*TangVelocity; + Velocity_e[1]= UnitNormal[1]*NormalVelocity + UnitNormal[0]*TangVelocity; + }else{ + for (iDim = 0; iDim < nDim; iDim++) + Velocity_e[iDim] = sqrt(Velocity2_e)*FlowDirMix[iDim]; + } + StaticEnthalpy_e = Enthalpy_e - 0.5 * Velocity2_e; + FluidModel->SetTDState_hs(StaticEnthalpy_e, Entropy_e); + Density_e = FluidModel->GetDensity(); + StaticEnergy_e = FluidModel->GetStaticEnergy(); + Energy_e = StaticEnergy_e + 0.5 * Velocity2_e; + if (tkeNeeded) Energy_e += GetTke_Inf(); + break; + + case DENSITY_VELOCITY: + + /*--- Retrieve the specified density and velocity magnitude ---*/ + Density_e = config->GetRiemann_Var1(Marker_Tag); + VelMag_e = config->GetRiemann_Var2(Marker_Tag); + Flow_Dir = config->GetRiemann_FlowDir(Marker_Tag); + + /*--- Non-dim. the inputs if necessary. ---*/ + Density_e /= config->GetDensity_Ref(); + VelMag_e /= config->GetVelocity_Ref(); + + for (iDim = 0; iDim < nDim; iDim++) + Velocity_e[iDim] = VelMag_e*Flow_Dir[iDim]; + Energy_e = Energy_i; + break; + + case MIXING_OUT: + + /*--- Retrieve the staic pressure for this boundary. ---*/ + Pressure_e = ExtAveragedPressure[val_marker]; + Density_e = Density_i; + + /* --- Compute the boundary state u_e --- */ + FluidModel->SetTDState_Prho(Pressure_e, Density_e); + Velocity2_e = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity_e[iDim] = Velocity_i[iDim]; + Velocity2_e += Velocity_e[iDim]*Velocity_e[iDim]; + } + Energy_e = FluidModel->GetStaticEnergy() + 0.5*Velocity2_e; + break; + + case STATIC_PRESSURE: + + /*--- Retrieve the staic pressure for this boundary. ---*/ + Pressure_e = config->GetRiemann_Var1(Marker_Tag); + Pressure_e /= config->GetPressure_Ref(); + Density_e = Density_i; + + /* --- Compute the boundary state u_e --- */ + FluidModel->SetTDState_Prho(Pressure_e, Density_e); + Velocity2_e = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity_e[iDim] = Velocity_i[iDim]; + Velocity2_e += Velocity_e[iDim]*Velocity_e[iDim]; + } + Energy_e = FluidModel->GetStaticEnergy() + 0.5*Velocity2_e; + break; + + default: + cout << "Warning! Invalid Riemann input!" << endl; + exit(EXIT_FAILURE); + break; + + } + + /*--- Compute P (matrix of right eigenvectors) ---*/ + conv_numerics->GetPMatrix(&Density_i, Velocity_i, &SoundSpeed_i, &Enthalpy_i, &Chi_i, &Kappa_i, UnitNormal, P_Tensor); + + /*--- Compute inverse P (matrix of left eigenvectors)---*/ + conv_numerics->GetPMatrix_inv(invP_Tensor, &Density_i, Velocity_i, &SoundSpeed_i, &Chi_i, &Kappa_i, UnitNormal); + + /*--- eigenvalues contribution due to grid motion ---*/ + if (grid_movement){ + gridVel = geometry->node[iPoint]->GetGridVel(); + + su2double ProjGridVel = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + ProjGridVel += gridVel[iDim]*UnitNormal[iDim]; + ProjVelocity_i -= ProjGridVel; + } + + /*--- Flow eigenvalues ---*/ + for (iDim = 0; iDim < nDim; iDim++) + Lambda_i[iDim] = ProjVelocity_i; + Lambda_i[nVar-2] = ProjVelocity_i + SoundSpeed_i; + Lambda_i[nVar-1] = ProjVelocity_i - SoundSpeed_i; + + /* --- Compute the boundary state u_e --- */ + u_e[0] = Density_e; + for (iDim = 0; iDim < nDim; iDim++) + u_e[iDim+1] = Velocity_e[iDim]*Density_e; + u_e[nVar-1] = Energy_e*Density_e; + + /* --- Compute the boundary state u_i --- */ + u_i[0] = Density_i; + for (iDim = 0; iDim < nDim; iDim++) + u_i[iDim+1] = Velocity_i[iDim]*Density_i; + u_i[nVar-1] = Energy_i*Density_i; + + /*--- Compute the characteristic jumps ---*/ + for (iVar = 0; iVar < nVar; iVar++) + { + dw[iVar] = 0; + for (jVar = 0; jVar < nVar; jVar++) + dw[iVar] += invP_Tensor[iVar][jVar] * (u_e[jVar] - u_i[jVar]); + + } + + /*--- Compute the boundary state u_b using characteristics ---*/ + for (iVar = 0; iVar < nVar; iVar++) + { + u_b[iVar] = u_i[iVar]; + + for (jVar = 0; jVar < nVar; jVar++) + { + if (Lambda_i[jVar] < 0) + { + u_b[iVar] += P_Tensor[iVar][jVar]*dw[jVar]; + + } + } + } + + + /*--- Compute the thermodynamic state in u_b ---*/ + Density_b = u_b[0]; + Velocity2_b = 0; + for (iDim = 0; iDim < nDim; iDim++) + { + Velocity_b[iDim] = u_b[iDim+1]/Density_b; + Velocity2_b += Velocity_b[iDim]*Velocity_b[iDim]; + } + Energy_b = u_b[nVar-1]/Density_b; + StaticEnergy_b = Energy_b - 0.5*Velocity2_b; + FluidModel->SetTDState_rhoe(Density_b, StaticEnergy_b); + Pressure_b = FluidModel->GetPressure(); + Temperature_b = FluidModel->GetTemperature(); + Enthalpy_b = Energy_b + Pressure_b/Density_b; + Kappa_b = FluidModel->GetdPde_rho() / Density_b; + Chi_b = FluidModel->GetdPdrho_e() - Kappa_b * StaticEnergy_b; + + /*--- Compute the residuals ---*/ + conv_numerics->GetInviscidProjFlux(&Density_b, Velocity_b, &Pressure_b, &Enthalpy_b, Normal, Residual); + + /*--- Residual contribution due to grid motion ---*/ + if (grid_movement) { + gridVel = geometry->node[iPoint]->GetGridVel(); + su2double projVelocity = 0.0; + + for (iDim = 0; iDim < nDim; iDim++) + projVelocity += gridVel[iDim]*Normal[iDim]; + for (iVar = 0; iVar < nVar; iVar++) + Residual[iVar] -= projVelocity *(u_b[iVar]); + } + + if (implicit) { + + Jacobian_b = new su2double*[nVar]; + DubDu = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) + { + Jacobian_b[iVar] = new su2double[nVar]; + DubDu[iVar] = new su2double[nVar]; + } + + /*--- Initialize DubDu to unit matrix---*/ + + for (iVar = 0; iVar < nVar; iVar++) + { + for (jVar = 0; jVar < nVar; jVar++) + DubDu[iVar][jVar]= 0; + + DubDu[iVar][iVar]= 1; + } + + /*--- Compute DubDu -= RNL---*/ + for (iVar=0; iVarGetInviscidProjJac(Velocity_b, &Enthalpy_b, &Chi_b, &Kappa_b, Normal, 1.0, Jacobian_b); + + /*--- Jacobian contribution due to grid motion ---*/ + if (grid_movement) + { + gridVel = geometry->node[iPoint]->GetGridVel(); + su2double projVelocity = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + projVelocity += gridVel[iDim]*Normal[iDim]; + for (iVar = 0; iVar < nVar; iVar++){ + Residual[iVar] -= projVelocity *(u_b[iVar]); + Jacobian_b[iVar][iVar] -= projVelocity; + } + + } + + /*--- initiate Jacobian_i to zero matrix ---*/ + for (iVar=0; iVarGetKind_Upwind() == TURKEL) + node[iPoint]->SetPreconditioner_Beta(conv_numerics->GetPrecond_Beta()); + + /*--- Viscous contribution ---*/ + if (viscous) { + + /*--- Primitive variables, using the derived quantities ---*/ + V_boundary[0] = Temperature_b; + for (iDim = 0; iDim < nDim; iDim++) + V_boundary[iDim+1] = Velocity_b[iDim]; + V_boundary[nDim+1] = Pressure_b; + V_boundary[nDim+2] = Density_b; + V_boundary[nDim+3] = Enthalpy_b; + + /*--- Set laminar and eddy viscosity at the infinity ---*/ + V_boundary[nDim+5] = FluidModel->GetLaminarViscosity(); + V_boundary[nDim+6] = node[iPoint]->GetEddyViscosity(); + V_boundary[nDim+7] = FluidModel->GetThermalConductivity(); + V_boundary[nDim+8] = FluidModel->GetCp(); + + /*--- Set the normal vector and the coordinates ---*/ + visc_numerics->SetNormal(Normal); + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + + /*--- Primitive variables, and gradient ---*/ + visc_numerics->SetPrimitive(V_domain, V_boundary); + visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); + + /*--- Secondary variables ---*/ + S_domain = node[iPoint]->GetSecondary(); + + /*--- Compute secondary thermodynamic properties (partial derivatives...) ---*/ + + S_boundary[0]= FluidModel->GetdPdrho_e(); + S_boundary[1]= FluidModel->GetdPde_rho(); + + S_boundary[2]= FluidModel->GetdTdrho_e(); + S_boundary[3]= FluidModel->GetdTde_rho(); + + /*--- Compute secondary thermo-physical properties (partial derivatives...) ---*/ + + S_boundary[4]= FluidModel->Getdmudrho_T(); + S_boundary[5]= FluidModel->GetdmudT_rho(); + + S_boundary[6]= FluidModel->Getdktdrho_T(); + S_boundary[7]= FluidModel->GetdktdT_rho(); + + visc_numerics->SetSecondary(S_domain, S_boundary); + + /*--- Turbulent kinetic energy ---*/ + if (config->GetKind_Turb_Model() == SST) + visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); + + /*--- Compute and update residual ---*/ + visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.SubtractBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + + } + } + + /*--- Free locally allocated memory ---*/ + delete [] Normal; + delete [] Velocity_e; + delete [] Velocity_b; + delete [] Velocity_i; + delete [] FlowDirMix; + + delete [] S_boundary; + delete [] Lambda_i; + delete [] u_i; + delete [] u_e; + delete [] u_b; + delete [] dw; + + + for (iVar = 0; iVar < nVar; iVar++) + { + delete [] P_Tensor[iVar]; + delete [] invP_Tensor[iVar]; + } + delete [] P_Tensor; + delete [] invP_Tensor; + +} + + +void CEulerSolver::Mixing_Process(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short val_Marker) { + + unsigned long iVertex, iPoint, nVert; + unsigned short iDim, iVar; + unsigned short mixing_process = config->GetKind_MixingProcess(); + su2double Pressure = 0.0, Density = 0.0, Enthalpy = 0.0, *Velocity = NULL, *Normal, *gridVel, + Area, TotalArea, TotalAreaPressure, TotalAreaDensity, *TotalAreaVelocity, UnitNormal[3]; + string Marker_Tag, Monitoring_Tag; + su2double val_init_pressure; + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool grid_movement = config->GetGrid_Movement(); + su2double TotalDensity, TotalPressure, *TotalVelocity, TotalNormal, avgVel2, avgTotalEnthaply; + + /*-- Variables declaration and allocation ---*/ + Velocity = new su2double[nDim]; + Normal = new su2double[nDim]; + TotalVelocity = new su2double[nDim]; + TotalAreaVelocity = new su2double[nDim]; + + for (iDim=0; iDimGetnVertex(val_Marker); iVertex++) { + + iPoint = geometry->vertex[val_Marker][iVertex]->GetNode(); + + /*--- Compute the integral fluxes for the boundaries ---*/ + if (compressible) { + Pressure = node[iPoint]->GetPressure(); + Density = node[iPoint]->GetDensity(); + Enthalpy = node[iPoint]->GetEnthalpy(); + } + else { + cout << "!!! Mixing process for incompressible and freesurface does not available yet !!! " << endl; + cout << "Press any key to exit..." << endl; + cin.get(); + exit(1); + } + + /*--- Note that the fluxes from halo cells are discarded ---*/ + if ( (geometry->node[iPoint]->GetDomain()) ) { + nVert++; + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + geometry->vertex[val_Marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); + su2double VelNormal = 0.0, VelSq = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + UnitNormal[iDim] = Normal[iDim]/Area; + Velocity[iDim] = node[iPoint]->GetPrimitive(iDim+1); + VelNormal += UnitNormal[iDim]*Velocity[iDim]; + VelSq += Velocity[iDim]*Velocity[iDim]; + } + + + /*--- Compute the integral fluxes for the boundary of interest ---*/ + + if ((mixing_process == AREA_AVERAGE) || (mixing_process == MIXEDOUT_AVERAGE)){ + + TotalFlux[val_Marker][0] += Area*(Density*VelNormal ); + for (iDim = 1; iDim < nDim+1; iDim++) + TotalFlux[val_Marker][iDim] += Area*(Density*VelNormal*Velocity[iDim -1] + Pressure*UnitNormal[iDim -1] ); + TotalFlux[val_Marker][nDim+1] += Area*(Density*VelNormal*Enthalpy ); + + TotalArea += Area; + TotalAreaPressure += Area*Pressure; + TotalAreaDensity += Area*Density; + for (iDim = 0; iDim < nDim; iDim++) + TotalAreaVelocity[iDim] += Area*Velocity[iDim]; + + }else{ + + TotalDensity += Density; + TotalPressure += Pressure; + for (iDim = 0; iDim < nDim; iDim++) + TotalVelocity[iDim] += Velocity[iDim]; + + + } + for (iDim = 0; iDim < nDim; iDim++) AveragedNormal[val_Marker][iDim] +=Normal[iDim]; + if (grid_movement){ + gridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + AveragedGridVel[val_Marker][iDim] +=gridVel[iDim]; + } + } + } + + /*--- Compute the averaged value for the boundary of interest ---*/ + for (iDim = 0; iDim < nDim; iDim++){ + AveragedNormal[val_Marker][iDim] /=nVert; + TotalNormal+= AveragedNormal[val_Marker][iDim]*AveragedNormal[val_Marker][iDim]; + } + for (iDim = 0; iDim < nDim; iDim++) AveragedNormal[val_Marker][iDim] /=sqrt(TotalNormal); + if (grid_movement){ + for (iDim = 0; iDim < nDim; iDim++) + AveragedGridVel[val_Marker][iDim] /=nVert; + } + + switch(mixing_process){ + + + case ALGEBRAIC_AVERAGE: + AveragedDensity[val_Marker] = TotalDensity / nVert; + AveragedPressure[val_Marker] = TotalPressure / nVert; + for (iDim = 0; iDim < nDim; iDim++) + AveragedVelocity[val_Marker][iDim] = TotalVelocity[iDim] / nVert; + break; + + case AREA_AVERAGE: + AveragedDensity[val_Marker] = TotalAreaDensity / TotalArea; + AveragedPressure[val_Marker] = TotalAreaPressure / TotalArea; + for (iDim = 0; iDim < nDim; iDim++) + AveragedVelocity[val_Marker][iDim] = TotalAreaVelocity[iDim] / TotalArea; + break; + + case MIXEDOUT_AVERAGE: + for (iVar = 0; iVarSetTDState_Prho(AveragedPressure[val_Marker], AveragedDensity[val_Marker]); + AveragedEnthalpy[val_Marker] = FluidModel->GetStaticEnergy() + AveragedPressure[val_Marker]/AveragedDensity[val_Marker]; + AveragedSoundSpeed[val_Marker] = FluidModel->GetSoundSpeed(); + AveragedEntropy[val_Marker] = FluidModel->GetEntropy(); + AveragedNormalVelocity[val_Marker]= AveragedNormal[val_Marker][0]*AveragedVelocity[val_Marker][0] + AveragedNormal[val_Marker][1]*AveragedVelocity[val_Marker][1]; + AveragedTangVelocity[val_Marker]= AveragedNormal[val_Marker][0]*AveragedVelocity[val_Marker][1] - AveragedNormal[val_Marker][1]*AveragedVelocity[val_Marker][0]; + MassFlow[val_Marker]= AveragedDensity[val_Marker]*AveragedNormalVelocity[val_Marker]*TotalArea; + FlowAngle[val_Marker]= atan(AveragedTangVelocity[val_Marker]/AveragedNormalVelocity[val_Marker]); + + /* --- compute total averaged quantities ---*/ + avgVel2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) avgVel2 += AveragedVelocity[val_Marker][iDim]*AveragedVelocity[val_Marker][iDim]; + + avgTotalEnthaply = AveragedEnthalpy[val_Marker] + 0.5*avgVel2; + FluidModel->SetTDState_hs(avgTotalEnthaply,AveragedEntropy[val_Marker]); + AveragedTotTemperature[val_Marker] = FluidModel->GetTemperature(); + AveragedTotPressure[val_Marker] = FluidModel->GetPressure(); + + if(grid_movement){ + AveragedTangGridVelocity[val_Marker] = AveragedNormal[val_Marker][0]*AveragedGridVel[val_Marker][1]-AveragedNormal[val_Marker][1]*AveragedGridVel[val_Marker][0]; + AveragedMach[val_Marker] = sqrt(AveragedNormalVelocity[val_Marker]*AveragedNormalVelocity[val_Marker] + (AveragedTangVelocity[val_Marker] - AveragedTangGridVelocity[val_Marker])*(AveragedTangVelocity[val_Marker] - AveragedTangGridVelocity[val_Marker])); + AveragedMach[val_Marker] /= AveragedSoundSpeed[val_Marker]; + AveragedTangMach[val_Marker] = (AveragedTangVelocity[val_Marker] - AveragedTangGridVelocity[val_Marker])/AveragedSoundSpeed[val_Marker]; + FlowAngle[val_Marker]= atan((AveragedTangVelocity[val_Marker] - AveragedTangGridVelocity[val_Marker])/AveragedNormalVelocity[val_Marker]); + + }else{ + AveragedMach[val_Marker] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + AveragedMach[val_Marker] += AveragedVelocity[val_Marker][iDim]*AveragedVelocity[val_Marker][iDim]; + } + AveragedMach[val_Marker] = sqrt(AveragedMach[val_Marker])/AveragedSoundSpeed[val_Marker]; + AveragedTangMach[val_Marker] = AveragedTangVelocity[val_Marker]/AveragedSoundSpeed[val_Marker]; + + } + + AveragedNormalMach[val_Marker] = AveragedNormalVelocity[val_Marker]/AveragedSoundSpeed[val_Marker]; + + + if ((AveragedDensity[val_Marker]!= AveragedDensity[val_Marker]) or (AveragedEnthalpy[val_Marker]!=AveragedEnthalpy[val_Marker])) + cout<<"nan in mixing process in boundary "<GetMarker_All_TagBound(val_Marker)<< endl; + + /*--- Free locally allocated memory ---*/ + delete [] Velocity; + delete [] Normal; + delete [] TotalVelocity; + delete [] TotalAreaVelocity; +} + +void CEulerSolver::MixedOut_Average (su2double val_init_pressure, su2double *val_Averaged_Flux, su2double *val_normal, + su2double *pressure_mix, su2double *density_mix) { + + unsigned short maxiter = 10; + unsigned short iter = 0; + su2double toll = 1.0e-07; + su2double resdl = 0.0; + + su2double *val_func = new su2double, *val_right_func = new su2double, *val_left_func = new su2double; + su2double deltaP, *p_mix = new su2double, *p_mix_right = new su2double, *p_mix_left = new su2double; + su2double epsilon = 1.0e-04; + su2double relax_factor = 1; + + *pressure_mix = val_init_pressure; + + /*--- Newton-Raphson's method with central difference formula ---*/ + + while ( iter <= maxiter ) { + deltaP = 2*epsilon*(*pressure_mix); + *p_mix_right = *pressure_mix+deltaP/2; + *p_mix_left = *pressure_mix-deltaP/2; + *p_mix = *pressure_mix; + MixedOut_Root_Function(p_mix_right,val_Averaged_Flux,val_normal,val_right_func,density_mix); + MixedOut_Root_Function(p_mix_left,val_Averaged_Flux,val_normal,val_left_func,density_mix); + MixedOut_Root_Function(p_mix,val_Averaged_Flux,val_normal,val_func,density_mix); + su2double der_func = (*val_right_func-*val_left_func) / deltaP; + deltaP = -*val_func/der_func; + resdl = deltaP/val_init_pressure; + *pressure_mix += relax_factor*(deltaP); + + iter += 1; + if ( abs(resdl) <= toll ) { + break; + } + + } + + MixedOut_Root_Function(pressure_mix,val_Averaged_Flux,val_normal,val_func,density_mix); + + /*--- Free locally allocated memory ---*/ + delete val_func; + delete val_right_func; + delete val_left_func; + delete p_mix; + delete p_mix_right; + delete p_mix_left; + +} + +void CEulerSolver::MixedOut_Root_Function(su2double *pressure, su2double *val_Averaged_Flux, su2double *val_normal, su2double *valfunc, su2double *density) { + + su2double velnormal, velsq; + + su2double *vel; + vel = new su2double[nDim]; + + + *valfunc = 0.0; + *density = 0.0; + + velnormal = 0.0; + velsq = 0.0; + + for (unsigned short iDim = 0; iDim < nDim; iDim++) { + vel[iDim] = (val_Averaged_Flux[iDim+1] - (*pressure)*val_normal[iDim]) / val_Averaged_Flux[0]; + velnormal += val_normal[iDim]*vel[iDim]; + velsq += vel[iDim]*vel[iDim]; + } + *density = val_Averaged_Flux[0] / velnormal; + if (*density <= 0) cout << " desnity in mixedout routine negative : " << endl; + FluidModel->SetTDState_Prho(*pressure, *density); + su2double enthalpy = FluidModel->GetStaticEnergy() + (*pressure)/(*density); + *valfunc = val_Averaged_Flux[nDim+1]/val_Averaged_Flux[0] - enthalpy - velsq/2; + if (*valfunc!=*valfunc) cout << " mixedout root func gives nan: " << endl; + + + /*--- Free locally allocated memory ---*/ + delete [] vel; + +} + +void CEulerSolver::Boundary_Fourier(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short val_Marker, vector >& c4k,signed long& nboundaryvertex) { + /* Implementation of Fuorier Transformations for non-regfelcting BC will come soon */ +} + +void CEulerSolver::Boundary_Fourier(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short val_Marker, vector >& c2k,vector >& c3k,signed long& nboundaryvertex) { + /* Implementation of Fuorier Transformations for non-regfelcting BC will come soon */ +} + +void CEulerSolver::BC_NonReflecting(CGeometry *geometry, CSolver **solver_container, + CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + unsigned short iDim, iVar, jVar, kVar; + unsigned long iVertex, iPoint, Point_Normal; + su2double Area, UnitNormal[3]; + + su2double *Velocity_b, Velocity2_b, Enthalpy_b, Energy_b, StaticEnergy_b, Density_b, Kappa_b, Chi_b, Pressure_b, Temperature_b; + su2double *Velocity_i, Velocity2_i, Enthalpy_i, Energy_i, StaticEnergy_i, Density_i, Kappa_i, Chi_i, Pressure_i, SoundSpeed_i; + su2double Pressure_e; + su2double ProjVelocity_i; + su2double **P_Tensor, **invP_Tensor, *Lambda_i, **Jacobian_b, **DubDu, *dw, *u_b; + su2double *gridVel; + su2double *V_boundary, *V_domain, *S_boundary, *S_domain; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool grid_movement = config->GetGrid_Movement(); + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + bool viscous = config->GetViscous(); + su2double *Normal; + + Normal = new su2double[nDim]; + + Velocity_i = new su2double[nDim]; + Velocity_b = new su2double[nDim]; + + + Lambda_i = new su2double[nVar]; + + u_b = new su2double[nVar]; + dw = new su2double[nVar]; + + S_boundary = new su2double[8]; + + P_Tensor = new su2double*[nVar]; + invP_Tensor = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) + { + P_Tensor[iVar] = new su2double[nVar]; + invP_Tensor[iVar] = new su2double[nVar]; + } + + /*--- new declarations ---*/ + std::vector > c4k ;// std::complex c3k[nVertex-OddEven]=0; + std::vector > c2k ;// std::complex c3k[nVertex-OddEven]=0; + std::vector > c3k ;// std::complex c3k[nVertex-OddEven]=0; + + su2double deltaDensity, deltaPressure, AvgMach, deltaTangVelocity, deltaNormalVelocity, cc,rhoc,c1j,c2j,c3j,c4j, + avg_c1, avg_c2, avg_c3, avg_c4,TangVelocity, NormalVelocity, GilesBeta, c4js, dc4js, *delta_c, **R_Matrix, *deltaprim; + + + delta_c = new su2double[nVar]; + deltaprim = new su2double[nVar]; + R_Matrix= new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) + { + R_Matrix[iVar] = new su2double[nVar]; + } + + + Mixing_Process(geometry, solver_container, config, val_marker); + + cc = AveragedSoundSpeed[val_marker]*AveragedSoundSpeed[val_marker]; + rhoc = AveragedSoundSpeed[val_marker]*AveragedDensity[val_marker]; + AvgMach = AveragedMach[val_marker]; + + conv_numerics->GetRMatrix(AveragedSoundSpeed[val_marker], AveragedDensity[val_marker], AveragedNormal[val_marker], R_Matrix); + + // Boundary_Fourier(geometry, solver_container, config, val_marker, c4k, nboundaryvertex); + // Boundary_Fourier(geometry, solver_container, config, val_marker, c2k,c3k,nboundaryvertex); + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + V_boundary= GetCharacPrimVar(val_marker, iVertex); + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Index of the closest interior node ---*/ + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; + Area = sqrt (Area); + + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] = Normal[iDim]/Area; + + /*--- Retrieve solution at this boundary node ---*/ + V_domain = node[iPoint]->GetPrimitive(); + + /*--- Compute the internal state u_i ---*/ + Velocity2_i = 0; + for (iDim = 0; iDim < nDim; iDim++) + { + Velocity_i[iDim] = node[iPoint]->GetVelocity(iDim); + Velocity2_i += Velocity_i[iDim]*Velocity_i[iDim]; + } + + + Density_i = node[iPoint]->GetDensity(); + + Energy_i = node[iPoint]->GetEnergy(); + StaticEnergy_i = Energy_i - 0.5*Velocity2_i; + + FluidModel->SetTDState_rhoe(Density_i, StaticEnergy_i); + + Pressure_i = FluidModel->GetPressure(); + Enthalpy_i = Energy_i + Pressure_i/Density_i; + + SoundSpeed_i = FluidModel->GetSoundSpeed(); + + Kappa_i = FluidModel->GetdPde_rho() / Density_i; + Chi_i = FluidModel->GetdPdrho_e() - Kappa_i * StaticEnergy_i; + + ProjVelocity_i = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + ProjVelocity_i += Velocity_i[iDim]*UnitNormal[iDim]; + + + switch(config->GetKind_Data_NRBC(Marker_Tag)) + { + + //TODO(turbo), generilize for 3D case + //TODO(turbo), generilize for Inlet and Outlet in for backflow treatment + //TODO(turbo), implement not uniform inlet and radial equilibrium for the outlet + + case MIXING_IN: + + /* --- Compute jump of primitive variable --- */ + deltaDensity = ExtAveragedDensity[val_marker] - AveragedDensity[val_marker]; + deltaPressure = ExtAveragedPressure[val_marker] - AveragedPressure[val_marker]; + NormalVelocity= UnitNormal[0]*Velocity_i[0] + UnitNormal[1]*Velocity_i[1]; + deltaTangVelocity= ExtAveragedTangVelocity[val_marker]+AveragedTangVelocity[val_marker]; + deltaNormalVelocity= ExtAveragedNormalVelocity[val_marker]+AveragedNormalVelocity[val_marker]; + + /* --- Compute characteristic jumps --- */ + avg_c1= -cc*deltaDensity +deltaPressure; + avg_c2= (rhoc*deltaTangVelocity); + avg_c3= (rhoc*deltaNormalVelocity +deltaPressure); + c4j= -rhoc*(-NormalVelocity +AveragedNormalVelocity[val_marker]) +(Pressure_i - AveragedPressure[val_marker]); + + /* --- Impose Inlet BC --- */ + delta_c[0] = avg_c1; + delta_c[1] = avg_c2; + delta_c[2] = avg_c3; + delta_c[3] = c4j; + break; + + case MIXING_OUT: + + /* --- Compute jump of primitive variable --- */ + deltaDensity = Density_i - AveragedDensity[val_marker]; + deltaPressure = Pressure_i - AveragedPressure[val_marker]; + TangVelocity= UnitNormal[0]*Velocity_i[1] - UnitNormal[1]*Velocity_i[0]; + NormalVelocity= UnitNormal[0]*Velocity_i[0] + UnitNormal[1]*Velocity_i[1]; + deltaTangVelocity= TangVelocity - AveragedTangVelocity[val_marker]; + deltaNormalVelocity= NormalVelocity - AveragedNormalVelocity[val_marker]; + + /* --- Compute characteristic jumps --- */ + c1j= -cc*deltaDensity +deltaPressure; + c2j= rhoc*deltaTangVelocity; + c3j= rhoc*deltaNormalVelocity + deltaPressure; + avg_c4 = rhoc*(AveragedNormalVelocity[val_marker]+ExtAveragedNormalVelocity[val_marker]) -(AveragedPressure[val_marker]-ExtAveragedPressure[val_marker]); + + /* --- implementation of supersonic NRBC ---*/ + if (AvgMach > 1.001){ + if (AveragedTangVelocity[val_marker] >= 0.0){ + GilesBeta= -sqrt(pow(AvgMach,2)-1.0); + }else{ + GilesBeta= sqrt(pow(AvgMach,2)-1.0); + } + c4js= (2.0 * AveragedNormalMach[val_marker])/(GilesBeta - AveragedTangMach[val_marker])*c2j - (GilesBeta+AveragedTangMach[val_marker])/(GilesBeta-AveragedTangMach[val_marker])*c3j; + dc4js = c4js; + }else{ + dc4js = 0.0; + } + + /* --- Impose Outlet BC --- */ + delta_c[0] = c1j; + delta_c[1] = c2j; + delta_c[2] = c3j; + delta_c[3] = avg_c4 + dc4js; + break; + + case STATIC_PRESSURE: + + Pressure_e = config->GetNRBC_Var1(Marker_Tag); + Pressure_e /= config->GetPressure_Ref(); + + /* --- Compute jump of primitive variable --- */ + deltaDensity = Density_i - AveragedDensity[val_marker]; + deltaPressure = Pressure_i - AveragedPressure[val_marker]; + TangVelocity= UnitNormal[0]*Velocity_i[1] - UnitNormal[1]*Velocity_i[0]; + NormalVelocity= UnitNormal[0]*Velocity_i[0] + UnitNormal[1]*Velocity_i[1]; + deltaTangVelocity= TangVelocity - AveragedTangVelocity[val_marker]; + deltaNormalVelocity= NormalVelocity - AveragedNormalVelocity[val_marker]; + + /* --- Compute characteristic jumps --- */ + c1j= -cc*deltaDensity +deltaPressure; + c2j= rhoc*deltaTangVelocity; + c3j=rhoc*deltaNormalVelocity + deltaPressure; + c4j=-rhoc*deltaNormalVelocity + deltaPressure; + avg_c4 = -2.0*(AveragedPressure[val_marker]-Pressure_e); + + /* --- implementation of supersonic NRBC ---*/ + if (AvgMach > 1.001){ + if (AveragedTangVelocity[val_marker] >= 0.0){ + GilesBeta= -sqrt(pow(AvgMach,2)-1.0); + }else{ + GilesBeta= sqrt(pow(AvgMach,2)-1.0); + } + c4js= (2.0 * AveragedNormalMach[val_marker])/(GilesBeta - AveragedTangMach[val_marker])*c2j - (GilesBeta+AveragedTangMach[val_marker])/(GilesBeta-AveragedTangMach[val_marker])*c3j; + dc4js = c4js; + }else{ + dc4js = 0.0; + } + + /* --- Impose Outlet BC --- */ + delta_c[0] = c1j; + delta_c[1] = c2j; + delta_c[2] = c3j; + delta_c[3] = avg_c4 + dc4js; + break; + + default: + cout << "Warning! Invalid NRBC input!" << endl; + exit(EXIT_FAILURE); + break; + + } + + /*--- Compute primitive jump from characteristic variables ---*/ + for (iVar = 0; iVar < nVar; iVar++) + { + deltaprim[iVar]=0; + for (jVar = 0; jVar < nVar; jVar++) + { + deltaprim[iVar] += R_Matrix[iVar][jVar]*delta_c[jVar]; + } + } + + /*--- Compute P (matrix of right eigenvectors) ---*/ + conv_numerics->GetPMatrix(&Density_i, Velocity_i, &SoundSpeed_i, &Enthalpy_i, &Chi_i, &Kappa_i, UnitNormal, P_Tensor); + + /*--- Compute inverse P (matrix of left eigenvectors)---*/ + conv_numerics->GetPMatrix_inv(invP_Tensor, &Density_i, Velocity_i, &SoundSpeed_i, &Chi_i, &Kappa_i, UnitNormal); + + /*--- eigenvalues contribution due to grid motion ---*/ + if (grid_movement){ + gridVel = geometry->node[iPoint]->GetGridVel(); + su2double ProjGridVel = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + ProjGridVel += gridVel[iDim]*UnitNormal[iDim]; + ProjVelocity_i -= ProjGridVel; + } + + /*--- Flow eigenvalues ---*/ + for (iDim = 0; iDim < nDim; iDim++) + Lambda_i[iDim] = ProjVelocity_i; + Lambda_i[nVar-2] = ProjVelocity_i + SoundSpeed_i; + Lambda_i[nVar-1] = ProjVelocity_i - SoundSpeed_i; + + //TODO(turbo), provide the under relaxation factor sigma from cfg file + su2double sigma; + sigma = 1.0; + + /*--- retrieve boundary variables ---*/ + Density_b = AveragedDensity[val_marker] + sigma*deltaprim[0]; + Pressure_b = AveragedPressure[val_marker] + sigma*deltaprim[3]; + switch(config->GetKind_Data_NRBC(Marker_Tag)){ + case MIXING_IN: + NormalVelocity = AveragedNormalVelocity[val_marker] - sigma*deltaprim[1]; + TangVelocity = AveragedTangVelocity[val_marker] - sigma*deltaprim[2]; + break; + case MIXING_OUT: case STATIC_PRESSURE: + NormalVelocity = AveragedNormalVelocity[val_marker] + sigma*deltaprim[1]; + TangVelocity = AveragedTangVelocity[val_marker] + sigma*deltaprim[2]; + break; + default: + cout << "Warning! Invalid NRBC input!" << endl; + exit(EXIT_FAILURE); + break; + } + + Velocity_b[0] = NormalVelocity*UnitNormal[0] - TangVelocity*UnitNormal[1]; + Velocity_b[1] = NormalVelocity*UnitNormal[1] + TangVelocity*UnitNormal[0]; + Velocity2_b = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity2_b+= Velocity_b[iDim]*Velocity_b[iDim]; + } + + FluidModel->SetTDState_Prho(Pressure_b, Density_b); + Energy_b = FluidModel->GetStaticEnergy() + 0.5*Velocity2_b; + StaticEnergy_b = FluidModel->GetStaticEnergy(); + Temperature_b= FluidModel->GetTemperature(); + Enthalpy_b = Energy_b + Pressure_b/Density_b; + Kappa_b = FluidModel->GetdPde_rho() / Density_b; + Chi_b = FluidModel->GetdPdrho_e() - Kappa_b * StaticEnergy_b; + + /*--- Compute the thermodynamic state in u_b ---*/ + u_b[0]=Density_b; + u_b[1]=Density_b*Velocity_b[0]; + u_b[2]=Density_b*Velocity_b[1]; + u_b[3]=Energy_b*Density_b; + + /*--- Compute the residuals ---*/ + conv_numerics->GetInviscidProjFlux(&Density_b, Velocity_b, &Pressure_b, &Enthalpy_b, Normal, Residual); + + /*--- Residual contribution due to grid motion ---*/ + if (grid_movement) { + gridVel = geometry->node[iPoint]->GetGridVel(); + su2double projVelocity = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + projVelocity += gridVel[iDim]*Normal[iDim]; + for (iVar = 0; iVar < nVar; iVar++) + Residual[iVar] -= projVelocity *(u_b[iVar]); + } + + if (implicit) { + /*--- Residual contribution due to grid motion ---*/ + Jacobian_b = new su2double*[nVar]; + DubDu = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) + { + Jacobian_b[iVar] = new su2double[nVar]; + DubDu[iVar] = new su2double[nVar]; + } + + /*--- Initialize DubDu to unit matrix---*/ + for (iVar = 0; iVar < nVar; iVar++) + { + for (jVar = 0; jVar < nVar; jVar++) + DubDu[iVar][jVar]= 0; + + DubDu[iVar][iVar]= 1; + } + + /*--- Compute DubDu -= RNL---*/ + for (iVar=0; iVarGetInviscidProjJac(Velocity_b, &Enthalpy_b, &Chi_b, &Kappa_b, Normal, 1.0, Jacobian_b); + + /*--- Jacobian contribution due to grid motion ---*/ + if (grid_movement) + { + su2double projVelocity = 0.0; + gridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + projVelocity += gridVel[iDim]*Normal[iDim]; + for (iVar = 0; iVar < nVar; iVar++){ + Residual[iVar] -= projVelocity *(u_b[iVar]); + Jacobian_b[iVar][iVar] -= projVelocity; + } + + } + + /*--- initiate Jacobian_i to zero matrix ---*/ + for (iVar=0; iVarGetKind_Upwind() == TURKEL) + node[iPoint]->SetPreconditioner_Beta(conv_numerics->GetPrecond_Beta()); + + /*--- Viscous contribution ---*/ + if (viscous) { + + /*--- Primitive variables, using the derived quantities ---*/ + V_boundary[0] = Temperature_b; + for (iDim = 0; iDim < nDim; iDim++) + V_boundary[iDim+1] = Velocity_b[iDim]; + V_boundary[nDim+1] = Pressure_b; + V_boundary[nDim+2] = Density_b; + V_boundary[nDim+3] = Enthalpy_b; + + /*--- Set laminar and eddy viscosity at the infinity ---*/ + V_boundary[nDim+5] = FluidModel->GetLaminarViscosity(); + V_boundary[nDim+6] = node[iPoint]->GetEddyViscosity(); + V_boundary[nDim+7] = FluidModel->GetThermalConductivity(); + V_boundary[nDim+8] = FluidModel->GetCp(); + + /*--- Set the normal vector and the coordinates ---*/ + visc_numerics->SetNormal(Normal); + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + + /*--- Primitive variables, and gradient ---*/ + visc_numerics->SetPrimitive(V_domain, V_boundary); + visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); + + /*--- Secondary variables ---*/ + S_domain = node[iPoint]->GetSecondary(); + + /*--- Compute secondary thermodynamic properties (partial derivatives...) ---*/ + + S_boundary[0]= FluidModel->GetdPdrho_e(); + S_boundary[1]= FluidModel->GetdPde_rho(); + + S_boundary[2]= FluidModel->GetdTdrho_e(); + S_boundary[3]= FluidModel->GetdTde_rho(); + + /*--- Compute secondary thermo-physical properties (partial derivatives...) ---*/ + + S_boundary[4]= FluidModel->Getdmudrho_T(); + S_boundary[5]= FluidModel->GetdmudT_rho(); + + S_boundary[6]= FluidModel->Getdktdrho_T(); + S_boundary[7]= FluidModel->GetdktdT_rho(); + + visc_numerics->SetSecondary(S_domain, S_boundary); + + /*--- Turbulent kinetic energy ---*/ + if (config->GetKind_Turb_Model() == SST) + visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); + + /*--- Compute and update residual ---*/ + visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.SubtractBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + + } + } + + /*--- Free locally allocated memory ---*/ + delete [] Normal; + + delete [] Velocity_b; + delete [] Velocity_i; + + delete [] S_boundary; + delete [] Lambda_i; + delete [] u_b; + delete [] dw; + + + for (iVar = 0; iVar < nVar; iVar++) + { + delete [] P_Tensor[iVar]; + delete [] invP_Tensor[iVar]; + } + delete [] P_Tensor; + delete [] invP_Tensor; + + + delete [] delta_c; + delete [] deltaprim; + for (iVar = 0; iVar < nVar; iVar++) + { + delete [] R_Matrix[iVar]; + } + delete [] R_Matrix; + + +} + +void CEulerSolver::BC_Inlet(CGeometry *geometry, CSolver **solver_container, + CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + unsigned short iDim; + unsigned long iVertex, iPoint, Point_Normal; + su2double P_Total, T_Total, Velocity[3], Velocity2, H_Total, Temperature, Riemann, + Pressure, Density, Energy, *Flow_Dir, Mach2, SoundSpeed2, SoundSpeed_Total2, Vel_Mag, + alpha, aa, bb, cc, dd, Area, UnitNormal[3]; + su2double *V_inlet, *V_domain; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool grid_movement = config->GetGrid_Movement(); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + su2double Two_Gamma_M1 = 2.0/Gamma_Minus_One; + su2double Gas_Constant = config->GetGas_ConstantND(); + unsigned short Kind_Inlet = config->GetKind_Inlet(); + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + bool viscous = config->GetViscous(); + bool gravity = (config->GetGravityForce()); + bool tkeNeeded = (((config->GetKind_Solver() == RANS )|| (config->GetKind_Solver() == DISC_ADJ_RANS)) && + (config->GetKind_Turb_Model() == SST)); + su2double *Normal = new su2double[nDim]; + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + /*--- Allocate the value at the inlet ---*/ + + V_inlet = GetCharacPrimVar(val_marker, iVertex); + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Index of the closest interior node ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; + Area = sqrt (Area); + + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] = Normal[iDim]/Area; + + /*--- Retrieve solution at this boundary node ---*/ + + V_domain = node[iPoint]->GetPrimitive(); + + /*--- Build the fictitious intlet state based on characteristics ---*/ + + if (compressible) { + + /*--- Subsonic inflow: there is one outgoing characteristic (u-c), + therefore we can specify all but one state variable at the inlet. + The outgoing Riemann invariant provides the final piece of info. + Adapted from an original implementation in the Stanford University + multi-block (SUmb) solver in the routine bcSubsonicInflow.f90 + written by Edwin van der Weide, last modified 04-20-2009. ---*/ + + switch (Kind_Inlet) { + + /*--- Total properties have been specified at the inlet. ---*/ + + case TOTAL_CONDITIONS: + + /*--- Retrieve the specified total conditions for this inlet. ---*/ + + if (gravity) P_Total = config->GetInlet_Ptotal(Marker_Tag) - geometry->node[iPoint]->GetCoord(nDim-1)*STANDART_GRAVITY; + else P_Total = config->GetInlet_Ptotal(Marker_Tag); + T_Total = config->GetInlet_Ttotal(Marker_Tag); + Flow_Dir = config->GetInlet_FlowDir(Marker_Tag); + + /*--- Non-dim. the inputs if necessary. ---*/ + + P_Total /= config->GetPressure_Ref(); + T_Total /= config->GetTemperature_Ref(); + + /*--- Store primitives and set some variables for clarity. ---*/ + + Density = V_domain[nDim+2]; + Velocity2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity[iDim] = V_domain[iDim+1]; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + } + Energy = V_domain[nDim+3] - V_domain[nDim+1]/V_domain[nDim+2]; + Pressure = V_domain[nDim+1]; + H_Total = (Gamma*Gas_Constant/Gamma_Minus_One)*T_Total; + SoundSpeed2 = Gamma*Pressure/Density; + + /*--- Compute the acoustic Riemann invariant that is extrapolated + from the domain interior. ---*/ + + Riemann = 2.0*sqrt(SoundSpeed2)/Gamma_Minus_One; + for (iDim = 0; iDim < nDim; iDim++) + Riemann += Velocity[iDim]*UnitNormal[iDim]; + + /*--- Total speed of sound ---*/ + + SoundSpeed_Total2 = Gamma_Minus_One*(H_Total - (Energy + Pressure/Density)+0.5*Velocity2) + SoundSpeed2; + + /*--- Dot product of normal and flow direction. This should + be negative due to outward facing boundary normal convention. ---*/ + + alpha = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + alpha += UnitNormal[iDim]*Flow_Dir[iDim]; + + /*--- Coefficients in the quadratic equation for the velocity ---*/ + + aa = 1.0 + 0.5*Gamma_Minus_One*alpha*alpha; + bb = -1.0*Gamma_Minus_One*alpha*Riemann; + cc = 0.5*Gamma_Minus_One*Riemann*Riemann + -2.0*SoundSpeed_Total2/Gamma_Minus_One; + + /*--- Solve quadratic equation for velocity magnitude. Value must + be positive, so the choice of root is clear. ---*/ + + dd = bb*bb - 4.0*aa*cc; + dd = sqrt(max(0.0, dd)); + Vel_Mag = (-bb + dd)/(2.0*aa); + Vel_Mag = max(0.0, Vel_Mag); + Velocity2 = Vel_Mag*Vel_Mag; + + /*--- Compute speed of sound from total speed of sound eqn. ---*/ + + SoundSpeed2 = SoundSpeed_Total2 - 0.5*Gamma_Minus_One*Velocity2; + + /*--- Mach squared (cut between 0-1), use to adapt velocity ---*/ + + Mach2 = Velocity2/SoundSpeed2; + Mach2 = min(1.0, Mach2); + Velocity2 = Mach2*SoundSpeed2; + Vel_Mag = sqrt(Velocity2); + SoundSpeed2 = SoundSpeed_Total2 - 0.5*Gamma_Minus_One*Velocity2; + + /*--- Compute new velocity vector at the inlet ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + Velocity[iDim] = Vel_Mag*Flow_Dir[iDim]; + + /*--- Static temperature from the speed of sound relation ---*/ + + Temperature = SoundSpeed2/(Gamma*Gas_Constant); + + /*--- Static pressure using isentropic relation at a point ---*/ + + Pressure = P_Total*pow((Temperature/T_Total), Gamma/Gamma_Minus_One); + + /*--- Density at the inlet from the gas law ---*/ + + Density = Pressure/(Gas_Constant*Temperature); + + /*--- Using pressure, density, & velocity, compute the energy ---*/ + + Energy = Pressure/(Density*Gamma_Minus_One) + 0.5*Velocity2; + if (tkeNeeded) Energy += GetTke_Inf(); + + /*--- Primitive variables, using the derived quantities ---*/ + + V_inlet[0] = Temperature; + for (iDim = 0; iDim < nDim; iDim++) + V_inlet[iDim+1] = Velocity[iDim]; + V_inlet[nDim+1] = Pressure; + V_inlet[nDim+2] = Density; + V_inlet[nDim+3] = Energy + Pressure/Density; + + break; + + /*--- Mass flow has been specified at the inlet. ---*/ + + case MASS_FLOW: + + /*--- Retrieve the specified mass flow for the inlet. ---*/ + + Density = config->GetInlet_Ttotal(Marker_Tag); + Vel_Mag = config->GetInlet_Ptotal(Marker_Tag); + Flow_Dir = config->GetInlet_FlowDir(Marker_Tag); + + /*--- Non-dim. the inputs if necessary. ---*/ + + Density /= config->GetDensity_Ref(); + Vel_Mag /= config->GetVelocity_Ref(); + + /*--- Get primitives from current inlet state. ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + Velocity[iDim] = node[iPoint]->GetVelocity(iDim); + Pressure = node[iPoint]->GetPressure(); + SoundSpeed2 = Gamma*Pressure/V_domain[nDim+2]; + + /*--- Compute the acoustic Riemann invariant that is extrapolated + from the domain interior. ---*/ + + Riemann = Two_Gamma_M1*sqrt(SoundSpeed2); + for (iDim = 0; iDim < nDim; iDim++) + Riemann += Velocity[iDim]*UnitNormal[iDim]; + + /*--- Speed of sound squared for fictitious inlet state ---*/ + + SoundSpeed2 = Riemann; + for (iDim = 0; iDim < nDim; iDim++) + SoundSpeed2 -= Vel_Mag*Flow_Dir[iDim]*UnitNormal[iDim]; + + SoundSpeed2 = max(0.0,0.5*Gamma_Minus_One*SoundSpeed2); + SoundSpeed2 = SoundSpeed2*SoundSpeed2; + + /*--- Pressure for the fictitious inlet state ---*/ + + Pressure = SoundSpeed2*Density/Gamma; + + /*--- Energy for the fictitious inlet state ---*/ + + Energy = Pressure/(Density*Gamma_Minus_One) + 0.5*Vel_Mag*Vel_Mag; + if (tkeNeeded) Energy += GetTke_Inf(); + + /*--- Primitive variables, using the derived quantities ---*/ + + V_inlet[0] = Pressure / ( Gas_Constant * Density); + for (iDim = 0; iDim < nDim; iDim++) + V_inlet[iDim+1] = Vel_Mag*Flow_Dir[iDim]; + V_inlet[nDim+1] = Pressure; + V_inlet[nDim+2] = Density; + V_inlet[nDim+3] = Energy + Pressure/Density; + + break; + } + } + if (incompressible) { + + /*--- Retrieve the specified velocity for the inlet. ---*/ + + Vel_Mag = config->GetInlet_Ptotal(Marker_Tag)/config->GetVelocity_Ref(); + Flow_Dir = config->GetInlet_FlowDir(Marker_Tag); + + /*--- Store the velocity in the primitive variable vector ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + V_inlet[iDim+1] = Vel_Mag*Flow_Dir[iDim]; + + /*--- Neumann condition for pressure ---*/ + + V_inlet[0] = node[iPoint]->GetPressureInc(); + + /*--- Constant value of density ---*/ + + V_inlet[nDim+1] = GetDensity_Inf(); + + /*--- Beta coefficient from the config file ---*/ + + V_inlet[nDim+2] = config->GetArtComp_Factor(); + + } + if (freesurface) { + + /*--- Neumann condition for pressure, density, level set, and distance ---*/ + + V_inlet[0] = node[iPoint]->GetPressureInc(); + V_inlet[nDim+1] = node[iPoint]->GetDensityInc(); + V_inlet[nDim+5] = node[iPoint]->GetLevelSet(); + V_inlet[nDim+6] = node[iPoint]->GetDistance(); + + /*--- The velocity is computed from the infinity values ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + V_inlet[iDim+1] = GetVelocity_Inf(iDim); + } + + /*--- The y/z velocity is interpolated due to the + free surface effect on the pressure ---*/ + + V_inlet[nDim] = node[iPoint]->GetPrimitive(nDim); + + /*--- Neumann condition for artifical compresibility factor ---*/ + + V_inlet[nDim+2] = config->GetArtComp_Factor(); + + } + + /*--- Set various quantities in the solver class ---*/ + + conv_numerics->SetPrimitive(V_domain, V_inlet); + + if (grid_movement) + conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[iPoint]->GetGridVel()); + + /*--- Compute the residual using an upwind scheme ---*/ + + conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Update residual value ---*/ + + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + + if (implicit) + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + /*--- Roe Turkel preconditioning, set the value of beta ---*/ + + if (config->GetKind_Upwind() == TURKEL) + node[iPoint]->SetPreconditioner_Beta(conv_numerics->GetPrecond_Beta()); + + /*--- Viscous contribution ---*/ + + if (viscous) { + + /*--- Set laminar and eddy viscosity at the infinity ---*/ + + if (compressible) { + V_inlet[nDim+5] = node[iPoint]->GetLaminarViscosity(); + V_inlet[nDim+6] = node[iPoint]->GetEddyViscosity(); + } + if (incompressible || freesurface) { + V_inlet[nDim+3] = node[iPoint]->GetLaminarViscosityInc(); + V_inlet[nDim+4] = node[iPoint]->GetEddyViscosityInc(); + } + + /*--- Set the normal vector and the coordinates ---*/ + + visc_numerics->SetNormal(Normal); + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + + /*--- Primitive variables, and gradient ---*/ + + visc_numerics->SetPrimitive(V_domain, V_inlet); + visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); + + /*--- Turbulent kinetic energy ---*/ + + if (config->GetKind_Turb_Model() == SST) + visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); + + /*--- Compute and update residual ---*/ + + visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.SubtractBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + + } + } + + /*--- Free locally allocated memory ---*/ + + delete [] Normal; + +} + +void CEulerSolver::BC_Outlet(CGeometry *geometry, CSolver **solver_container, + CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + unsigned short iVar, iDim; + unsigned long iVertex, iPoint, Point_Normal; + su2double LevelSet, Density_Outlet = 0.0, Pressure, P_Exit, Velocity[3], + Velocity2, Entropy, Density, Energy, Riemann, Vn, SoundSpeed, Mach_Exit, Vn_Exit, + Area, UnitNormal[3], Height, yCoordRef, yCoord; + su2double *V_outlet, *V_domain; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + su2double Gas_Constant = config->GetGas_ConstantND(); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool grid_movement = config->GetGrid_Movement(); + su2double FreeSurface_Zero = config->GetFreeSurface_Zero(); + su2double epsilon = config->GetFreeSurface_Thickness(); + su2double RatioDensity = config->GetRatioDensity(); + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + bool viscous = config->GetViscous(); + bool gravity = (config->GetGravityForce()); + su2double PressFreeSurface = GetPressure_Inf(); + su2double Froude = config->GetFroude(); + bool tkeNeeded = (((config->GetKind_Solver() == RANS )|| (config->GetKind_Solver() == DISC_ADJ_RANS)) && + (config->GetKind_Turb_Model() == SST)); + su2double *Normal = new su2double[nDim]; + + /*--- Loop over all the vertices on this boundary marker ---*/ + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + /*--- Allocate the value at the outlet ---*/ + V_outlet = GetCharacPrimVar(val_marker, iVertex); + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Index of the closest interior node ---*/ + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; + Area = sqrt (Area); + + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] = Normal[iDim]/Area; + + /*--- Current solution at this boundary node ---*/ + V_domain = node[iPoint]->GetPrimitive(); + + /*--- Build the fictitious intlet state based on characteristics ---*/ + if (compressible) { + + /*--- Retrieve the specified back pressure for this outlet. ---*/ + if (gravity) P_Exit = config->GetOutlet_Pressure(Marker_Tag) - geometry->node[iPoint]->GetCoord(nDim-1)*STANDART_GRAVITY; + else P_Exit = config->GetOutlet_Pressure(Marker_Tag); + + /*--- Non-dim. the inputs if necessary. ---*/ + P_Exit = P_Exit/config->GetPressure_Ref(); + + /*--- Check whether the flow is supersonic at the exit. The type + of boundary update depends on this. ---*/ + Density = V_domain[nDim+2]; + Velocity2 = 0.0; Vn = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity[iDim] = V_domain[iDim+1]; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + Vn += Velocity[iDim]*UnitNormal[iDim]; + } + Pressure = V_domain[nDim+1]; + SoundSpeed = sqrt(Gamma*Pressure/Density); + Mach_Exit = sqrt(Velocity2)/SoundSpeed; + + if (Mach_Exit >= 1.0) { + + /*--- Supersonic exit flow: there are no incoming characteristics, + so no boundary condition is necessary. Set outlet state to current + state so that upwinding handles the direction of propagation. ---*/ + for (iVar = 0; iVar < nPrimVar; iVar++) V_outlet[iVar] = V_domain[iVar]; + + } else { + + /*--- Subsonic exit flow: there is one incoming characteristic, + therefore one variable can be specified (back pressure) and is used + to update the conservative variables. Compute the entropy and the + acoustic Riemann variable. These invariants, as well as the + tangential velocity components, are extrapolated. Adapted from an + original implementation in the Stanford University multi-block + (SUmb) solver in the routine bcSubsonicOutflow.f90 by Edwin van + der Weide, last modified 09-10-2007. ---*/ + + Entropy = Pressure*pow(1.0/Density, Gamma); + Riemann = Vn + 2.0*SoundSpeed/Gamma_Minus_One; + + /*--- Compute the new fictious state at the outlet ---*/ + Density = pow(P_Exit/Entropy,1.0/Gamma); + Pressure = P_Exit; + SoundSpeed = sqrt(Gamma*P_Exit/Density); + Vn_Exit = Riemann - 2.0*SoundSpeed/Gamma_Minus_One; + Velocity2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity[iDim] = Velocity[iDim] + (Vn_Exit-Vn)*UnitNormal[iDim]; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + } + Energy = P_Exit/(Density*Gamma_Minus_One) + 0.5*Velocity2; + if (tkeNeeded) Energy += GetTke_Inf(); + + /*--- Conservative variables, using the derived quantities ---*/ + V_outlet[0] = Pressure / ( Gas_Constant * Density); + for (iDim = 0; iDim < nDim; iDim++) + V_outlet[iDim+1] = Velocity[iDim]; + V_outlet[nDim+1] = Pressure; + V_outlet[nDim+2] = Density; + V_outlet[nDim+3] = Energy + Pressure/Density; + + } + } + if (incompressible) { + + /*--- The pressure is computed from the infinity values ---*/ + if (gravity) { + yCoordRef = 0.0; + yCoord = geometry->node[iPoint]->GetCoord(nDim-1); + V_outlet[0] = GetPressure_Inf() + GetDensity_Inf()*((yCoordRef-yCoord)/(config->GetFroude()*config->GetFroude())); + } + else { + V_outlet[0] = GetPressure_Inf(); + } + + /*--- Neumann condition for the velocity ---*/ + for (iDim = 0; iDim < nDim; iDim++) { + V_outlet[iDim+1] = node[Point_Normal]->GetPrimitive(iDim+1); + } + + /*--- Constant value of density ---*/ + V_outlet[nDim+1] = GetDensity_Inf(); + + /*--- Beta coefficient from the config file ---*/ + V_outlet[nDim+2] = config->GetArtComp_Factor(); + + } + if (freesurface) { + + /*--- Imposed pressure, density, level set and distance ---*/ + Height = geometry->node[iPoint]->GetCoord(nDim-1); + LevelSet = Height - FreeSurface_Zero; + if (LevelSet < -epsilon) Density_Outlet = config->GetDensity_FreeStreamND(); + if (LevelSet > epsilon) Density_Outlet = RatioDensity*config->GetDensity_FreeStreamND(); + V_outlet[0] = PressFreeSurface + Density_Outlet*((FreeSurface_Zero-Height)/(Froude*Froude)); + V_outlet[nDim+1] = Density_Outlet; + V_outlet[nDim+5] = LevelSet; + V_outlet[nDim+6] = LevelSet; + + /*--- Neumann condition in the interface for the pressure, density and level set and distance ---*/ + if (fabs(LevelSet) <= epsilon) { + V_outlet[0] = node[Point_Normal]->GetPressureInc(); + V_outlet[nDim+1] = node[Point_Normal]->GetDensityInc(); + V_outlet[nDim+5] = node[Point_Normal]->GetLevelSet(); + V_outlet[nDim+6] = node[Point_Normal]->GetDistance(); + } + + /*--- Neumann condition for the velocity ---*/ + for (iDim = 0; iDim < nDim; iDim++) { + V_outlet[iDim+1] = node[Point_Normal]->GetPrimitive(iDim+1); + } + + /*--- Neumann condition for artifical compresibility factor ---*/ + V_outlet[nDim+2] = config->GetArtComp_Factor(); + + } + + /*--- Set various quantities in the solver class ---*/ + conv_numerics->SetPrimitive(V_domain, V_outlet); + + if (grid_movement) + conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[iPoint]->GetGridVel()); + + /*--- Compute the residual using an upwind scheme ---*/ + conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Update residual value ---*/ + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + if (implicit) { + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + } + + /*--- Roe Turkel preconditioning, set the value of beta ---*/ + if (config->GetKind_Upwind() == TURKEL) + node[iPoint]->SetPreconditioner_Beta(conv_numerics->GetPrecond_Beta()); + + /*--- Viscous contribution ---*/ + if (viscous) { + + /*--- Set laminar and eddy viscosity at the infinity ---*/ + if (compressible) { + V_outlet[nDim+5] = node[iPoint]->GetLaminarViscosity(); + V_outlet[nDim+6] = node[iPoint]->GetEddyViscosity(); + } + if (incompressible || freesurface) { + V_outlet[nDim+3] = node[iPoint]->GetLaminarViscosityInc(); + V_outlet[nDim+4] = node[iPoint]->GetEddyViscosityInc(); + } + + /*--- Set the normal vector and the coordinates ---*/ + visc_numerics->SetNormal(Normal); + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + + /*--- Primitive variables, and gradient ---*/ + visc_numerics->SetPrimitive(V_domain, V_outlet); + visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); + + /*--- Turbulent kinetic energy ---*/ + if (config->GetKind_Turb_Model() == SST) + visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); + + /*--- Compute and update residual ---*/ + visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.SubtractBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + + } + } + + /*--- Free locally allocated memory ---*/ + delete [] Normal; + +} + +void CEulerSolver::BC_Supersonic_Inlet(CGeometry *geometry, CSolver **solver_container, + CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + unsigned short iDim; + unsigned long iVertex, iPoint, Point_Normal; + su2double *V_inlet, *V_domain; + + su2double Density, Pressure, Temperature, Energy, *Velocity, Velocity2; + su2double Gas_Constant = config->GetGas_ConstantND(); + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool grid_movement = config->GetGrid_Movement(); + bool viscous = config->GetViscous(); + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + bool tkeNeeded = (((config->GetKind_Solver() == RANS )|| (config->GetKind_Solver() == DISC_ADJ_RANS)) && + (config->GetKind_Turb_Model() == SST)); + su2double *Normal = new su2double[nDim]; + + /*--- Supersonic inlet flow: there are no outgoing characteristics, + so all flow variables can be imposed at the inlet. + First, retrieve the specified values for the primitive variables. ---*/ + + Temperature = config->GetInlet_Temperature(Marker_Tag); + Pressure = config->GetInlet_Pressure(Marker_Tag); + Velocity = config->GetInlet_Velocity(Marker_Tag); + + /*--- Density at the inlet from the gas law ---*/ + + Density = Pressure/(Gas_Constant*Temperature); + + /*--- Non-dim. the inputs if necessary. ---*/ + + Temperature = Temperature/config->GetTemperature_Ref(); + Pressure = Pressure/config->GetPressure_Ref(); + Density = Density/config->GetDensity_Ref(); + for (iDim = 0; iDim < nDim; iDim++) + Velocity[iDim] = Velocity[iDim]/config->GetVelocity_Ref(); + + /*--- Compute the energy from the specified state ---*/ + + Velocity2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Velocity2 += Velocity[iDim]*Velocity[iDim]; + Energy = Pressure/(Density*Gamma_Minus_One)+0.5*Velocity2; + if (tkeNeeded) Energy += GetTke_Inf(); + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + /*--- Allocate the value at the outlet ---*/ + + V_inlet = GetCharacPrimVar(val_marker, iVertex); + + /*--- Primitive variables, using the derived quantities ---*/ + + V_inlet[0] = Temperature; + for (iDim = 0; iDim < nDim; iDim++) + V_inlet[iDim+1] = Velocity[iDim]; + V_inlet[nDim+1] = Pressure; + V_inlet[nDim+2] = Density; + V_inlet[nDim+3] = Energy + Pressure/Density; + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Index of the closest interior node ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Current solution at this boundary node ---*/ + + V_domain = node[iPoint]->GetPrimitive(); + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + + /*--- Set various quantities in the solver class ---*/ + + conv_numerics->SetNormal(Normal); + conv_numerics->SetPrimitive(V_domain, V_inlet); + + if (grid_movement) + conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), + geometry->node[iPoint]->GetGridVel()); + + /*--- Compute the residual using an upwind scheme ---*/ + + conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + + if (implicit) + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + /*--- Viscous contribution ---*/ + + if (viscous) { + + /*--- Set laminar and eddy viscosity at the infinity ---*/ + + V_inlet[nDim+5] = node[iPoint]->GetLaminarViscosity(); + V_inlet[nDim+6] = node[iPoint]->GetEddyViscosity(); + + /*--- Set the normal vector and the coordinates ---*/ + + visc_numerics->SetNormal(Normal); + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + + /*--- Primitive variables, and gradient ---*/ + + visc_numerics->SetPrimitive(V_domain, V_inlet); + visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); + + /*--- Turbulent kinetic energy ---*/ + + if (config->GetKind_Turb_Model() == SST) + visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); + + /*--- Compute and update residual ---*/ + + visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.SubtractBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + } + + } + } + + /*--- Free locally allocated memory ---*/ + + delete [] Normal; + +} + +void CEulerSolver::BC_Supersonic_Outlet(CGeometry *geometry, CSolver **solver_container, + CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + unsigned short iDim; + unsigned long iVertex, iPoint, Point_Normal; + su2double *V_outlet, *V_domain; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool grid_movement = config->GetGrid_Movement(); + bool viscous = config->GetViscous(); + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + + su2double *Normal = new su2double[nDim]; + + /*--- Supersonic outlet flow: there are no ingoing characteristics, + so all flow variables can should be interpolated from the domain. ---*/ + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Index of the closest interior node ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Current solution at this boundary node ---*/ + + V_domain = node[iPoint]->GetPrimitive(); + + /*--- Allocate the value at the outlet ---*/ + + V_outlet = GetCharacPrimVar(val_marker, iVertex); + + /*--- Primitive variables, using the derived quantities ---*/ + + V_outlet[0] = V_domain[0]; + for (iDim = 0; iDim < nDim; iDim++) + V_outlet[iDim+1] = V_domain[iDim+1]; + V_outlet[nDim+1] = V_domain[nDim+1]; + V_outlet[nDim+2] = V_domain[nDim+2]; + V_outlet[nDim+3] = V_domain[nDim+3]; + + /*--- Current solution at this boundary node ---*/ + + V_domain = node[iPoint]->GetPrimitive(); + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + + /*--- Set various quantities in the solver class ---*/ + + conv_numerics->SetNormal(Normal); + conv_numerics->SetPrimitive(V_domain, V_outlet); + + if (grid_movement) + conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), + geometry->node[iPoint]->GetGridVel()); + + /*--- Compute the residual using an upwind scheme ---*/ + + conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + + if (implicit) + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + /*--- Viscous contribution ---*/ + + if (viscous) { + + /*--- Set laminar and eddy viscosity at the infinity ---*/ + + V_outlet[nDim+5] = node[iPoint]->GetLaminarViscosity(); + V_outlet[nDim+6] = node[iPoint]->GetEddyViscosity(); + + /*--- Set the normal vector and the coordinates ---*/ + + visc_numerics->SetNormal(Normal); + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + + /*--- Primitive variables, and gradient ---*/ + + visc_numerics->SetPrimitive(V_domain, V_outlet); + visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); + + /*--- Turbulent kinetic energy ---*/ + + if (config->GetKind_Turb_Model() == SST) + visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); + + /*--- Compute and update residual ---*/ + + visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.SubtractBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + } + + } + } + + /*--- Free locally allocated memory ---*/ + + delete [] Normal; + +} + +void CEulerSolver::BC_Engine_Inflow(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned short iDim; + unsigned long iVertex, iPoint, Point_Normal; + su2double Pressure, Inflow_Pressure, Velocity[3], Velocity2, Entropy, Target_Inflow_Mach = 0.0, Density, Energy, + Riemann, Area, UnitNormal[3], Vn, SoundSpeed, Vn_Exit, Inflow_Pressure_inc, Inflow_Pressure_old, Inflow_Mach_old; + su2double *V_inflow, *V_domain; + + su2double DampingFactor = config->GetDamp_Engine_Inflow(); + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool viscous = config->GetViscous(); + su2double Gas_Constant = config->GetGas_ConstantND(); + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + bool tkeNeeded = (((config->GetKind_Solver() == RANS )|| (config->GetKind_Solver() == DISC_ADJ_RANS)) && + (config->GetKind_Turb_Model() == SST)); + su2double Baseline_Press = 0.75 * config->GetPressure_FreeStreamND(); + + su2double *Normal = new su2double[nDim]; + + /*--- Retrieve the specified target fan face mach in the nacelle. ---*/ + + Target_Inflow_Mach = config->GetInflow_Mach_Target(Marker_Tag); + + /*--- Retrieve the old fan face pressure and mach number in the nacelle (this has been computed in a preprocessing). ---*/ + + Inflow_Pressure_old = config->GetInflow_Pressure(Marker_Tag); // Note that has been computed by the code (non-dimensional). + Inflow_Mach_old = config->GetInflow_Mach(Marker_Tag); + + /*--- Compute the pressure increment (note that increasing pressure decreases flow speed) ---*/ + + Inflow_Pressure_inc = - (1.0 - (Inflow_Mach_old/Target_Inflow_Mach)) * Baseline_Press; + + /*--- Estimate the new fan face pressure ---*/ + + Inflow_Pressure = (1.0 - DampingFactor)*Inflow_Pressure_old + DampingFactor * (Inflow_Pressure_old + Inflow_Pressure_inc); + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + /*--- Allocate the value at the outlet ---*/ + + V_inflow = GetCharacPrimVar(val_marker, iVertex); + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Index of the closest interior node ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Area += Normal[iDim]*Normal[iDim]; + Area = sqrt (Area); + + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] = Normal[iDim]/Area; + + /*--- Current solution at this boundary node ---*/ + + V_domain = node[iPoint]->GetPrimitive(); + + /*--- Subsonic nacelle inflow: there is one incoming characteristic, + therefore one variable can be specified (back pressure) and is used + to update the conservative variables. + + Compute the entropy and the acoustic variable. These + riemann invariants, as well as the tangential velocity components, + are extrapolated. ---*/ + + Density = V_domain[nDim+2]; + Velocity2 = 0.0; Vn = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity[iDim] = V_domain[iDim+1]; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + Vn += Velocity[iDim]*UnitNormal[iDim]; + } + Pressure = V_domain[nDim+1]; + SoundSpeed = sqrt(Gamma*Pressure/Density); + Entropy = Pressure*pow(1.0/Density, Gamma); + Riemann = Vn + 2.0*SoundSpeed/Gamma_Minus_One; + + /*--- Compute the new fictious state at the outlet ---*/ + + Density = pow(Inflow_Pressure/Entropy,1.0/Gamma); + Pressure = Inflow_Pressure; + SoundSpeed = sqrt(Gamma*Inflow_Pressure/Density); + Vn_Exit = Riemann - 2.0*SoundSpeed/Gamma_Minus_One; + Velocity2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity[iDim] = Velocity[iDim] + (Vn_Exit-Vn)*UnitNormal[iDim]; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + } + + Energy = Inflow_Pressure/(Density*Gamma_Minus_One) + 0.5*Velocity2; + if (tkeNeeded) Energy += GetTke_Inf(); + + /*--- Conservative variables, using the derived quantities ---*/ + + V_inflow[0] = Pressure / ( Gas_Constant * Density); + for (iDim = 0; iDim < nDim; iDim++) + V_inflow[iDim+1] = Velocity[iDim]; + V_inflow[nDim+1] = Pressure; + V_inflow[nDim+2] = Density; + V_inflow[nDim+3] = Energy + Pressure/Density; + + /*--- Set various quantities in the solver class ---*/ + + conv_numerics->SetNormal(Normal); + conv_numerics->SetPrimitive(V_domain, V_inflow); + + /*--- Compute the residual using an upwind scheme ---*/ + + conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + + if (implicit) + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + /*--- Viscous contribution ---*/ + + if (viscous) { + + /*--- Set laminar and eddy viscosity at the infinity ---*/ + + V_inflow[nDim+5] = node[iPoint]->GetLaminarViscosity(); + V_inflow[nDim+6] = node[iPoint]->GetEddyViscosity(); + + /*--- Set the normal vector and the coordinates ---*/ + + visc_numerics->SetNormal(Normal); + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + + /*--- Primitive variables, and gradient ---*/ + + visc_numerics->SetPrimitive(V_domain, V_inflow); + visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); + + /*--- Turbulent kinetic energy ---*/ + + if (config->GetKind_Turb_Model() == SST) + visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); + + /*--- Compute and update residual ---*/ + + visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.SubtractBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + + } + } + + delete [] Normal; + +} + +void CEulerSolver::BC_Engine_Exhaust(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned short iDim; + unsigned long iVertex, iPoint, Point_Normal; + su2double Exhaust_Pressure, Exhaust_Temperature, Velocity[3], Velocity2, H_Exhaust, Temperature, Riemann, Area, UnitNormal[3], Pressure, Density, Energy, Mach2, SoundSpeed2, SoundSpeed_Exhaust2, Vel_Mag, alpha, aa, bb, cc, dd, Flow_Dir[3]; + su2double *V_exhaust, *V_domain; + su2double Gas_Constant = config->GetGas_ConstantND(); + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool viscous = config->GetViscous(); + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + bool tkeNeeded = (((config->GetKind_Solver() == RANS )|| (config->GetKind_Solver() == DISC_ADJ_RANS)) && + (config->GetKind_Turb_Model() == SST)); + // su2double Target_Exhaust_Pressure, Exhaust_Pressure_old, Exhaust_Pressure_inc; + // su2double DampingFactor = config->GetDamp_Engine_Exhaust(); + // su2double Baseline_Press = 0.75 * config->GetPressure_FreeStreamND(); + + su2double *Normal = new su2double[nDim]; + + /*--- Retrieve the specified exhaust pressure in the engine (non-dimensional). ---*/ + + // Target_Exhaust_Pressure = config->GetExhaust_Pressure_Target(Marker_Tag) / config->GetPressure_Ref(); + + /*--- Retrieve the old exhaust pressure in the engine exhaust (this has been computed in a preprocessing). ---*/ + + // Exhaust_Pressure_old = config->GetExhaust_Pressure(Marker_Tag); + + /*--- Compute the Pressure increment ---*/ + + // Exhaust_Pressure_inc = (1.0 - (Exhaust_Pressure_old/Target_Exhaust_Pressure)) * Baseline_Press; + + /*--- Estimate the new exhaust pressure ---*/ + + // Exhaust_Pressure = (1.0 - DampingFactor) * Exhaust_Pressure_old + DampingFactor * (Exhaust_Pressure_old + Exhaust_Pressure_inc); + + /*--- The temperature is given (no iteration is required) ---*/ + + Exhaust_Temperature = config->GetExhaust_Temperature_Target(Marker_Tag); + Exhaust_Temperature /= config->GetTemperature_Ref(); + + /*--- The pressure is given (no iteration is required) ---*/ + /*--- CHECK: the above iterative process is overwritten on the next line. ---*/ + + Exhaust_Pressure = config->GetExhaust_Pressure_Target(Marker_Tag); + Exhaust_Pressure /= config->GetPressure_Ref(); + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + /*--- Allocate the value at the exhaust ---*/ + + V_exhaust = GetCharacPrimVar(val_marker, iVertex); + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Index of the closest interior node ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Area += Normal[iDim]*Normal[iDim]; + Area = sqrt (Area); + + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] = Normal[iDim]/Area; + + /*--- Current solution at this boundary node ---*/ + + V_domain = node[iPoint]->GetPrimitive(); + + /*--- Subsonic inflow: there is one outgoing characteristic (u-c), + therefore we can specify all but one state variable at the inlet. + The outgoing Riemann invariant provides the final piece of info. ---*/ + + /*--- Store primitives and set some variables for clarity. ---*/ + + Density = V_domain[nDim+2]; + Velocity2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity[iDim] = V_domain[iDim+1]; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + } + Energy = V_domain[nDim+3] - V_domain[nDim+1]/V_domain[nDim+2]; + Pressure = V_domain[nDim+1]; + H_Exhaust = (Gamma*Gas_Constant/Gamma_Minus_One)*Exhaust_Temperature; + SoundSpeed2 = Gamma*Pressure/Density; + + /*--- Compute the acoustic Riemann invariant that is extrapolated + from the domain interior. ---*/ + + Riemann = 2.0*sqrt(SoundSpeed2)/Gamma_Minus_One; + for (iDim = 0; iDim < nDim; iDim++) + Riemann += Velocity[iDim]*UnitNormal[iDim]; + + /*--- Total speed of sound ---*/ + + SoundSpeed_Exhaust2 = Gamma_Minus_One*(H_Exhaust - (Energy + Pressure/Density)+0.5*Velocity2) + SoundSpeed2; + + /*--- The flow direction is defined by the surface normal ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + Flow_Dir[iDim] = -UnitNormal[iDim]; + + /*--- Dot product of normal and flow direction. This should + be negative due to outward facing boundary normal convention. ---*/ + + alpha = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + alpha += UnitNormal[iDim]*Flow_Dir[iDim]; + + /*--- Coefficients in the quadratic equation for the velocity ---*/ + + aa = 1.0 + 0.5*Gamma_Minus_One*alpha*alpha; + bb = -1.0*Gamma_Minus_One*alpha*Riemann; + cc = 0.5*Gamma_Minus_One*Riemann*Riemann - 2.0*SoundSpeed_Exhaust2/Gamma_Minus_One; + + /*--- Solve quadratic equation for velocity magnitude. Value must + be positive, so the choice of root is clear. ---*/ + + dd = bb*bb - 4.0*aa*cc; + dd = sqrt(max(0.0, dd)); + Vel_Mag = (-bb + dd)/(2.0*aa); + + if (Vel_Mag >= 0.0) { + + Velocity2 = Vel_Mag*Vel_Mag; + + /*--- Compute speed of sound from total speed of sound eqn. ---*/ + + SoundSpeed2 = SoundSpeed_Exhaust2 - 0.5*Gamma_Minus_One*Velocity2; + Mach2 = Velocity2/SoundSpeed2; + Velocity2 = Mach2*SoundSpeed2; + Vel_Mag = sqrt(Velocity2); + SoundSpeed2 = SoundSpeed_Exhaust2 - 0.5*Gamma_Minus_One*Velocity2; + + /*--- Compute new velocity vector at the inlet ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + Velocity[iDim] = Vel_Mag*Flow_Dir[iDim]; + + /*--- Static temperature from the speed of sound relation ---*/ + + Temperature = SoundSpeed2/(Gamma*Gas_Constant); + + /*--- Static pressure using isentropic relation at a point ---*/ + + Pressure = Exhaust_Pressure*pow((Temperature/Exhaust_Temperature), Gamma/Gamma_Minus_One); + + /*--- Density at the exhaust from the gas law ---*/ + + Density = Pressure/(Gas_Constant*Temperature); + + /*--- Using pressure, density, & velocity, compute the energy ---*/ + + Energy = Pressure/(Density*Gamma_Minus_One) + 0.5*Velocity2; + if (tkeNeeded) Energy += GetTke_Inf(); + + /*--- Primitive variables, using the derived quantities ---*/ + + V_exhaust[0] = Temperature; + for (iDim = 0; iDim < nDim; iDim++) + V_exhaust[iDim+1] = Velocity[iDim]; + V_exhaust[nDim+1] = Pressure; + V_exhaust[nDim+2] = Density; + V_exhaust[nDim+3] = Energy + Pressure/Density; + + } + + /*--- The flow goes in the wrong direction ---*/ + + else { + + V_exhaust[0] = V_domain[0]; + for (iDim = 0; iDim < nDim; iDim++) + V_exhaust[iDim+1] = V_domain[iDim+1]; + V_exhaust[nDim+1] = V_domain[nDim+1]; + V_exhaust[nDim+2] = V_domain[nDim+2]; + V_exhaust[nDim+3] = V_domain[nDim+3]; + + } + + /*--- Set various quantities in the solver class ---*/ + + conv_numerics->SetNormal(Normal); + conv_numerics->SetPrimitive(V_domain, V_exhaust); + + /*--- Compute the residual using an upwind scheme ---*/ + + conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + + if (implicit) + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + /*--- Viscous contribution ---*/ + + if (viscous) { + + /*--- Set laminar and eddy viscosity at the infinity ---*/ + + V_exhaust[nDim+5] = node[iPoint]->GetLaminarViscosity(); + V_exhaust[nDim+6] = node[iPoint]->GetEddyViscosity(); + + /*--- Set the normal vector and the coordinates ---*/ + + visc_numerics->SetNormal(Normal); + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + + /*--- Primitive variables, and gradient ---*/ + + visc_numerics->SetPrimitive(V_domain, V_exhaust); + visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); + + /*--- Turbulent kinetic energy ---*/ + + if (config->GetKind_Turb_Model() == SST) + visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); + + /*--- Compute and update residual ---*/ + + visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.SubtractBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + + } + } + + delete [] Normal; + +} + +void CEulerSolver::BC_Engine_Bleed(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned short iDim; + unsigned long iVertex, iPoint, Point_Normal; + su2double Bleed_Pressure, Target_Bleed_MassFlow, Bleed_Pressure_old, Bleed_MassFlow_old, Bleed_Pressure_inc, Bleed_Temperature, Velocity[3], Velocity2, H_Bleed, Temperature, Riemann, Area, UnitNormal[3], Pressure, Density, Energy, Mach2, SoundSpeed2, SoundSpeed_Bleed2, Vel_Mag, alpha, aa, bb, cc, dd, Flow_Dir[3]; + su2double *V_bleed, *V_domain; + su2double Gas_Constant = config->GetGas_ConstantND(); + + su2double DampingFactor = config->GetDamp_Engine_Bleed(); + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool viscous = config->GetViscous(); + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + bool tkeNeeded = (((config->GetKind_Solver() == RANS )|| (config->GetKind_Solver() == DISC_ADJ_RANS)) && + (config->GetKind_Turb_Model() == SST)); + su2double Baseline_Press = 0.25 * config->GetPressure_FreeStreamND(); + + su2double *Normal = new su2double[nDim]; + + /*--- Retrieve the specified target bleed mass flow in the engine (non-dimensional). ---*/ + + Target_Bleed_MassFlow = config->GetBleed_MassFlow_Target(Marker_Tag) / (config->GetDensity_Ref() * config->GetVelocity_Ref()); + + /*--- Retrieve the old Bleed pressure and mass flow rate number in the engine bleed (this has been computed in a preprocessing). ---*/ + + Bleed_Pressure_old = config->GetBleed_Pressure(Marker_Tag); + Bleed_MassFlow_old = config->GetBleed_MassFlow(Marker_Tag); + + /*--- Compute the Pressure increment (note that increasing pressure also increases mass flow rate) ---*/ + + Bleed_Pressure_inc = (1.0 - (Bleed_MassFlow_old/Target_Bleed_MassFlow)) * Baseline_Press; + + /*--- Estimate the new bleed pressure ---*/ + + Bleed_Pressure = (1.0 - DampingFactor)*Bleed_Pressure_old + DampingFactor * (Bleed_Pressure_old + Bleed_Pressure_inc); + + /*--- The temperature is given (no iteration is required) ---*/ + + Bleed_Temperature = config->GetBleed_Temperature_Target(Marker_Tag); + Bleed_Temperature /= config->GetTemperature_Ref(); + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + /*--- Allocate the value at the exhaust ---*/ + + V_bleed = GetCharacPrimVar(val_marker, iVertex); + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Index of the closest interior node ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Area += Normal[iDim]*Normal[iDim]; + Area = sqrt (Area); + + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] = Normal[iDim]/Area; + + /*--- Current solution at this boundary node ---*/ + + V_domain = node[iPoint]->GetPrimitive(); + + /*--- Subsonic inflow: there is one outgoing characteristic (u-c), + therefore we can specify all but one state variable at the inlet. + The outgoing Riemann invariant provides the final piece of info. ---*/ + + /*--- Store primitives and set some variables for clarity. ---*/ + + Density = V_domain[nDim+2]; + Velocity2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Velocity[iDim] = V_domain[iDim+1]; + Velocity2 += Velocity[iDim]*Velocity[iDim]; + } + Energy = V_domain[nDim+3] - V_domain[nDim+1]/V_domain[nDim+2]; + Pressure = V_domain[nDim+1]; + H_Bleed = (Gamma*Gas_Constant/Gamma_Minus_One)*Bleed_Temperature; + SoundSpeed2 = Gamma*Pressure/Density; + + /*--- Compute the acoustic Riemann invariant that is extrapolated + from the domain interior. ---*/ + + Riemann = 2.0*sqrt(SoundSpeed2)/Gamma_Minus_One; + for (iDim = 0; iDim < nDim; iDim++) + Riemann += Velocity[iDim]*UnitNormal[iDim]; + + /*--- Total speed of sound ---*/ + + SoundSpeed_Bleed2 = Gamma_Minus_One*(H_Bleed - (Energy + Pressure/Density)+0.5*Velocity2) + SoundSpeed2; + + /*--- The flow direction is defined by the surface normal ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + Flow_Dir[iDim] = -UnitNormal[iDim]; + + /*--- Dot product of normal and flow direction. This should + be negative due to outward facing boundary normal convention. ---*/ + + alpha = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + alpha += UnitNormal[iDim]*Flow_Dir[iDim]; + + /*--- Coefficients in the quadratic equation for the velocity ---*/ + + aa = 1.0 + 0.5*Gamma_Minus_One*alpha*alpha; + bb = -1.0*Gamma_Minus_One*alpha*Riemann; + cc = 0.5*Gamma_Minus_One*Riemann*Riemann - 2.0*SoundSpeed_Bleed2/Gamma_Minus_One; + + /*--- Solve quadratic equation for velocity magnitude. Value must + be positive, so the choice of root is clear. ---*/ + + dd = bb*bb - 4.0*aa*cc; + dd = sqrt(max(0.0, dd)); + Vel_Mag = (-bb + dd)/(2.0*aa); + + if (Vel_Mag >= 0.0) { + + Velocity2 = Vel_Mag*Vel_Mag; + + /*--- Compute speed of sound from total speed of sound eqn. ---*/ + + SoundSpeed2 = SoundSpeed_Bleed2 - 0.5*Gamma_Minus_One*Velocity2; + + /*--- Mach squared (cut between 0-1), use to adapt velocity ---*/ + + Mach2 = Velocity2/SoundSpeed2; + Mach2 = min(1.0, Mach2); + Velocity2 = Mach2*SoundSpeed2; + Vel_Mag = sqrt(Velocity2); + SoundSpeed2 = SoundSpeed_Bleed2 - 0.5*Gamma_Minus_One*Velocity2; + + /*--- Compute new velocity vector at the inlet ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + Velocity[iDim] = Vel_Mag*Flow_Dir[iDim]; + + /*--- Static temperature from the speed of sound relation ---*/ + + Temperature = SoundSpeed2/(Gamma*Gas_Constant); + + /*--- Static pressure using isentropic relation at a point ---*/ + + Pressure = Bleed_Pressure*pow((Temperature/Bleed_Temperature), Gamma/Gamma_Minus_One); + + /*--- Density at the inlet from the gas law ---*/ + + Density = Pressure/(Gas_Constant*Temperature); + + /*--- Using pressure, density, & velocity, compute the energy ---*/ + + Energy = Pressure/(Density*Gamma_Minus_One) + 0.5*Velocity2; + if (tkeNeeded) Energy += GetTke_Inf(); + + /*--- Primitive variables, using the derived quantities ---*/ + + V_bleed[0] = Temperature; + for (iDim = 0; iDim < nDim; iDim++) + V_bleed[iDim+1] = Velocity[iDim]; + V_bleed[nDim+1] = Pressure; + V_bleed[nDim+2] = Density; + V_bleed[nDim+3] = Energy + Pressure/Density; + + } + + /*--- The flow goes in the wrong direction ---*/ + + else { + + V_bleed[0] = V_domain[0]; + for (iDim = 0; iDim < nDim; iDim++) + V_bleed[iDim+1] = V_domain[iDim+1]; + V_bleed[nDim+1] = V_domain[nDim+1]; + V_bleed[nDim+2] = V_domain[nDim+2]; + V_bleed[nDim+3] = V_domain[nDim+3]; + + } + + /*--- Set various quantities in the solver class ---*/ + + conv_numerics->SetNormal(Normal); + conv_numerics->SetPrimitive(V_domain, V_bleed); + + /*--- Compute the residual using an upwind scheme ---*/ + + conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + + if (implicit) + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + /*--- Viscous contribution ---*/ + + if (viscous) { + + /*--- Set laminar and eddy viscosity at the infinity ---*/ + + V_bleed[nDim+5] = node[iPoint]->GetLaminarViscosity(); + V_bleed[nDim+6] = node[iPoint]->GetEddyViscosity(); + + /*--- Set the normal vector and the coordinates ---*/ + + visc_numerics->SetNormal(Normal); + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + + /*--- Primitive variables, and gradient ---*/ + + visc_numerics->SetPrimitive(V_domain, V_bleed); + visc_numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[iPoint]->GetGradient_Primitive()); + + /*--- Turbulent kinetic energy ---*/ + + if (config->GetKind_Turb_Model() == SST) + visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), solver_container[TURB_SOL]->node[iPoint]->GetSolution(0)); + + /*--- Compute and update residual ---*/ + + visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.SubtractBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + + if (implicit) + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + + } + } + + delete [] Normal; + +} + +void CEulerSolver::BC_Sym_Plane(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, + CConfig *config, unsigned short val_marker) { + + /*--- Call the Euler residual ---*/ + + BC_Euler_Wall(geometry, solver_container, conv_numerics, config, val_marker); + +} + +void CEulerSolver::BC_Interface_Boundary(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config) { + + unsigned long iVertex, iPoint, jPoint; + unsigned short iDim, iVar, iMarker; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + + su2double *Normal = new su2double[nDim]; + su2double *PrimVar_i = new su2double[nPrimVar]; + su2double *PrimVar_j = new su2double[nPrimVar]; + +#ifndef HAVE_MPI + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) { + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Find the associate pair to the original node ---*/ + + jPoint = geometry->vertex[iMarker][iVertex]->GetDonorPoint(); + + if (iPoint != jPoint) { + + /*--- Store the solution for both points ---*/ + + for (iVar = 0; iVar < nPrimVar; iVar++) { + PrimVar_i[iVar] = node[iPoint]->GetPrimitive(iVar); + PrimVar_j[iVar] = node[jPoint]->GetPrimitive(iVar); + } + + /*--- Set primitive variables ---*/ + + numerics->SetPrimitive(PrimVar_i, PrimVar_j); + + /*--- Set the normal vector ---*/ + + geometry->vertex[iMarker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + numerics->SetNormal(Normal); + + /*--- Compute the convective residual using an upwind scheme ---*/ + + numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Add Residuals and Jacobians ---*/ + + LinSysRes.AddBlock(iPoint, Residual); + if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + } + + } + } + } + } + +#else + + int rank, jProcessor; + MPI_Status status; + //MPI_Status send_stat[1], recv_stat[1]; + //MPI_Request send_req[1], recv_req[1]; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + bool compute; + su2double *Buffer_Send_V = new su2double [nPrimVar]; + su2double *Buffer_Receive_V = new su2double [nPrimVar]; + + /*--- Do the send process, by the moment we are sending each + node individually, this must be changed ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) { + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Find the associate pair to the original node ---*/ + + jPoint = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; + jProcessor = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; + + if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; + else compute = true; + + /*--- We only send the information that belong to other boundary, -1 processor + means that the boundary condition is not applied ---*/ + + if (compute) { + + if (jProcessor != rank) { + + /*--- Copy the primitive variable ---*/ + + for (iVar = 0; iVar < nPrimVar; iVar++) + Buffer_Send_V[iVar] = node[iPoint]->GetPrimitive(iVar); + + SU2_MPI::Bsend(Buffer_Send_V, nPrimVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD); + + // SU2_MPI::Isend(Buffer_Send_V, nPrimVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD, &send_req[0]); + + // /*--- Wait for this set of non-blocking comm. to complete ---*/ + // + // SU2_MPI::Waitall(1, send_req, send_stat); + + } + + } + + } + } + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Find the associate pair to the original node ---*/ + + jPoint = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; + jProcessor = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; + + if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; + else compute = true; + + if (compute) { + + /*--- We only receive the information that belong to other boundary ---*/ + + if (jProcessor != rank) { + + SU2_MPI::Recv(Buffer_Receive_V, nPrimVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &status); + + // SU2_MPI::Irecv(Buffer_Receive_V, nPrimVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &recv_req[0]); + + /*--- Wait for the this set of non-blocking recv's to complete ---*/ + + // SU2_MPI::Waitall(1, recv_req, recv_stat); + + } + else { + for (iVar = 0; iVar < nPrimVar; iVar++) + Buffer_Receive_V[iVar] = node[jPoint]->GetPrimitive(iVar); + } + + /*--- Store the solution for both points ---*/ + + for (iVar = 0; iVar < nPrimVar; iVar++) { + PrimVar_i[iVar] = node[iPoint]->GetPrimitive(iVar); + PrimVar_j[iVar] = Buffer_Receive_V[iVar]; + } + + /*--- Set Conservative Variables ---*/ + + numerics->SetPrimitive(PrimVar_i, PrimVar_j); + + /*--- Set Normal ---*/ + + geometry->vertex[iMarker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + numerics->SetNormal(Normal); + + /*--- Compute the convective residual using an upwind scheme ---*/ + + numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Add Residuals and Jacobians ---*/ + + LinSysRes.AddBlock(iPoint, Residual); + if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + } + + } + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + + delete[] Buffer_Send_V; + delete[] Buffer_Receive_V; + +#endif + + /*--- Free locally allocated memory ---*/ + + delete [] Normal; + delete [] PrimVar_i; + delete [] PrimVar_j; + +} + +void CEulerSolver::BC_NearField_Boundary(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config) { + + unsigned long iVertex, iPoint, jPoint; + unsigned short iDim, iVar, iMarker; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + + su2double *Normal = new su2double[nDim]; + su2double *PrimVar_i = new su2double[nPrimVar]; + su2double *PrimVar_j = new su2double[nPrimVar]; + +#ifndef HAVE_MPI + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Find the associate pair to the original node ---*/ + + jPoint = geometry->vertex[iMarker][iVertex]->GetDonorPoint(); + + if (iPoint != jPoint) { + + /*--- Store the solution for both points ---*/ + + for (iVar = 0; iVar < nPrimVar; iVar++) { + PrimVar_i[iVar] = node[iPoint]->GetPrimitive(iVar); + PrimVar_j[iVar] = node[jPoint]->GetPrimitive(iVar); + } + + /*--- Set primitive variables ---*/ + + numerics->SetPrimitive(PrimVar_i, PrimVar_j); + + /*--- Set the normal vector ---*/ + + geometry->vertex[iMarker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + numerics->SetNormal(Normal); + + /*--- Compute the convective residual using an upwind scheme ---*/ + + numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Add Residuals and Jacobians ---*/ + + LinSysRes.AddBlock(iPoint, Residual); + if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + } + + } + } + } + } + +#else + + int rank, jProcessor; + MPI_Status status; + //MPI_Status send_stat[1], recv_stat[1]; + //MPI_Request send_req[1], recv_req[1]; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + bool compute; + su2double *Buffer_Send_V = new su2double [nPrimVar]; + su2double *Buffer_Receive_V = new su2double [nPrimVar]; + + /*--- Do the send process, by the moment we are sending each + node individually, this must be changed ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Find the associate pair to the original node ---*/ + + jPoint = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; + jProcessor = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; + + if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; + else compute = true; + + /*--- We only send the information that belong to other boundary, -1 processor + means that the boundary condition is not applied ---*/ + + if (compute) { + + if (jProcessor != rank) { + + /*--- Copy the primitive variable ---*/ + + for (iVar = 0; iVar < nPrimVar; iVar++) + Buffer_Send_V[iVar] = node[iPoint]->GetPrimitive(iVar); + + SU2_MPI::Bsend(Buffer_Send_V, nPrimVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD); + + // SU2_MPI::Isend(Buffer_Send_V, nPrimVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD, &send_req[0]); + + // /*--- Wait for this set of non-blocking comm. to complete ---*/ + // + // SU2_MPI::Waitall(1, send_req, send_stat); + + } + + } + + } + } + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Find the associate pair to the original node ---*/ + + jPoint = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; + jProcessor = geometry->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; + + if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; + else compute = true; + + if (compute) { + + /*--- We only receive the information that belong to other boundary ---*/ + + if (jProcessor != rank) { + + SU2_MPI::Recv(Buffer_Receive_V, nPrimVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &status); + + // SU2_MPI::Irecv(Buffer_Receive_V, nPrimVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &recv_req[0]); + + /*--- Wait for the this set of non-blocking recv's to complete ---*/ + + // SU2_MPI::Waitall(1, recv_req, recv_stat); + + } + else { + for (iVar = 0; iVar < nPrimVar; iVar++) + Buffer_Receive_V[iVar] = node[jPoint]->GetPrimitive(iVar); + } + + /*--- Store the solution for both points ---*/ + + for (iVar = 0; iVar < nPrimVar; iVar++) { + PrimVar_i[iVar] = node[iPoint]->GetPrimitive(iVar); + PrimVar_j[iVar] = Buffer_Receive_V[iVar]; + } + + /*--- Set Conservative Variables ---*/ + + numerics->SetPrimitive(PrimVar_i, PrimVar_j); + + /*--- Set Normal ---*/ + + geometry->vertex[iMarker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + numerics->SetNormal(Normal); + + /*--- Compute the convective residual using an upwind scheme ---*/ + + numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Add Residuals and Jacobians ---*/ + + LinSysRes.AddBlock(iPoint, Residual); + if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + } + + } + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + + delete[] Buffer_Send_V; + delete[] Buffer_Receive_V; + +#endif + + /*--- Free locally allocated memory ---*/ + + delete [] Normal; + delete [] PrimVar_i; + delete [] PrimVar_j; + +} + +void CEulerSolver::BC_ActDisk_Boundary(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config) { + + unsigned long iVertex, iPoint, jPoint, Pin = 0, Pout = 0, jProcessor; + unsigned short iDim, iVar, iMarker; + int iProcessor; + su2double *Coord, radius, DeltaP_avg, DeltaP_tip, DeltaT_avg, DeltaT_tip, + Radial[3] = {0.0,0.0,0.0}, Tangent[3] = {0.0,0.0,0.0}, Normal[3] = {0.0,0.0,0.0}, + UnitRadial[3] = {0.0,0.0,0.0}, UnitTangent[3] = {0.0,0.0,0.0}, UnitNormal[3] = {0.0,0.0,0.0}; + su2double H_in_ghost, P_in_ghost, Vel_Swirl_out_ghost, T_in_ghost, Rho_in_ghost, sos_in_ghost, Area, Vel_in_ghost; + su2double H_out_ghost, P_out_ghost, T_out_ghost, Rho_out_ghost, sos_out_ghost, Vel_Normal_in, Rho_in, Vel_Normal_out_ghost, Vel_out_ghost; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + unsigned short nMarker_ActDisk_Inlet = config->GetnMarker_ActDisk_Inlet(); + // su2double DampingFactor = 0.75; + + if (nMarker_ActDisk_Inlet != 0) { + + su2double *PrimVar_out = new su2double[nPrimVar]; + su2double *PrimVar_in = new su2double[nPrimVar]; + su2double *MeanPrimVar = new su2double[nPrimVar]; + su2double *PrimVar_out_ghost = new su2double[nPrimVar]; + su2double *PrimVar_in_ghost = new su2double[nPrimVar]; + su2double *ActDisk_Jump = new su2double[nPrimVar]; + su2double *Buffer_Send_V = new su2double [nPrimVar]; + su2double *Buffer_Receive_V = new su2double [nPrimVar]; + +#ifndef HAVE_MPI + iProcessor = MASTER_NODE; +#else + MPI_Status status; + //MPI_Status send_stat[1], recv_stat[1]; + //MPI_Request send_req[1], recv_req[1]; + MPI_Comm_rank(MPI_COMM_WORLD, &iProcessor); +#endif + + /*--- Identify the points that should be sended in a MPI implementation. + Do the send process, by the moment we are sending each node individually, this must be changed---*/ + +#ifdef HAVE_MPI + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == ACTDISK_INLET) || + (config->GetMarker_All_KindBC(iMarker) == ACTDISK_OUTLET)) { + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Find the associate pair to the original node ---*/ + + jPoint = geometry->vertex[iMarker][iVertex]->GetDonorPoint(); + jProcessor = geometry->vertex[iMarker][iVertex]->GetDonorProcessor(); + + /*--- We only send the information that belong to other boundary, using jPoint as the ID for the message ---*/ + + if ((int)jProcessor != iProcessor) { + + /*--- Copy the primitive variables ---*/ + + for (iVar = 0; iVar < nPrimVar; iVar++) + Buffer_Send_V[iVar] = node[iPoint]->GetPrimitive(iVar); + + SU2_MPI::Bsend(Buffer_Send_V, nPrimVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD); + + // SU2_MPI::Isend(Buffer_Send_V, nPrimVar, MPI_DOUBLE, jProcessor, iPoint, MPI_COMM_WORLD, &send_req[0]); + // SU2_MPI::Waitall(1, send_req, send_stat); + + } + + } + } + } + } + +#endif + + /*--- Evaluate the fluxes, the donor solution has been sended using MPI ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == ACTDISK_INLET) || + (config->GetMarker_All_KindBC(iMarker) == ACTDISK_OUTLET)) { + + unsigned short boundary = config->GetMarker_All_KindBC(iMarker); + su2double *Origin = config->GetActDisk_Origin(config->GetMarker_All_TagBound(iMarker)); + su2double R_root = config->GetActDisk_RootRadius(config->GetMarker_All_TagBound(iMarker)); + su2double R_tip = config->GetActDisk_TipRadius(config->GetMarker_All_TagBound(iMarker)); + su2double Target_Press_Jump = config->GetActDisk_PressJump(config->GetMarker_All_TagBound(iMarker))/ config->GetPressure_Ref(); + su2double Target_Temp_Jump = config->GetActDisk_TempJump(config->GetMarker_All_TagBound(iMarker))/ config->GetTemperature_Ref(); + su2double Omega = config->GetActDisk_Omega(config->GetMarker_All_TagBound(iMarker))*(PI_NUMBER/30.0); + unsigned short Distribution = config->GetActDisk_Distribution(config->GetMarker_All_TagBound(iMarker)); + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Find the associate pair to the original node ---*/ + + jPoint = geometry->vertex[iMarker][iVertex]->GetDonorPoint(); + jProcessor = geometry->vertex[iMarker][iVertex]->GetDonorProcessor(); + + /*--- Receive the information, using jPoint as the ID for the message ---*/ + + if ((int)jProcessor != iProcessor) { +#ifdef HAVE_MPI + + SU2_MPI::Recv(Buffer_Receive_V, nPrimVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &status); + + // SU2_MPI::Irecv(Buffer_Receive_V, nPrimVar, MPI_DOUBLE, jProcessor, jPoint, MPI_COMM_WORLD, &recv_req[0]); + // SU2_MPI::Waitall(1, send_req, send_stat); + +#endif + } + else { + + /*--- The point is in the same processor... no MPI required ---*/ + + for (iVar = 0; iVar < nPrimVar; iVar++) + Buffer_Receive_V[iVar] = node[jPoint]->GetPrimitive(iVar); + + } + + /*--- Identify the inner and the outer point (based on the normal direction) ---*/ + + if (boundary == ACTDISK_INLET) { + + Pin = iPoint; + + for (iVar = 0; iVar < nPrimVar; iVar++) { + PrimVar_out[iVar] = Buffer_Receive_V[iVar]; + PrimVar_in[iVar] = node[Pin]->GetPrimitive(iVar); + } + + } + if (boundary == ACTDISK_OUTLET) { + + Pout = iPoint; + + for (iVar = 0; iVar < nPrimVar; iVar++) { + PrimVar_out[iVar] = node[Pout]->GetPrimitive(iVar); + PrimVar_in[iVar] = Buffer_Receive_V[iVar]; + } + + } + + /*--- Set the jump in the actuator disk ---*/ + + for (iVar = 0; iVar < nPrimVar; iVar++) { + ActDisk_Jump[iVar] = 0.0; + } + + /*--- Compute the distance to the center of the rotor ---*/ + + Coord = geometry->node[iPoint]->GetCoord(); + radius = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + radius += (Coord[iDim]-Origin[iDim])*(Coord[iDim]-Origin[iDim]); + radius = sqrt(radius); + + /*--- Compute the pressure jump ---*/ + + // su2double Press_Jump = fabs(PrimVar_in[nDim+1]-PrimVar_in[nDim+1]); + // su2double Press_inc = (1.0 - (Press_Jump/Target_Press_Jump)) * 0.01 * config->GetPressure_FreeStreamND(); + // DeltaP_avg = (1.0 - DampingFactor)*Press_Jump + DampingFactor * (Press_Jump + Press_inc); + + DeltaP_avg = Target_Press_Jump; + if (Distribution == 1) { + DeltaP_tip = (3.0/2.0)*DeltaP_avg*R_tip*(R_tip*R_tip-R_root*R_root)/(R_tip*R_tip*R_tip-R_root*R_root*R_root); + ActDisk_Jump[nDim+1] = DeltaP_tip*radius/R_tip; + } + else + ActDisk_Jump[nDim+1] = DeltaP_avg; + + /*--- Compute the temperature jump ---*/ + + // su2double Temp_Jump = fabs(PrimVar_in[0]-PrimVar_in[0]); + // su2double Temp_inc = (1.0 - (Temp_Jump/Target_Temp_Jump)) * 0.01 * config->GetTemperature_FreeStreamND(); + // DeltaT_avg = (1.0 - DampingFactor)*Temp_Jump + DampingFactor * (Temp_Jump + Temp_inc); + + DeltaT_avg = Target_Temp_Jump; + if (Distribution == 1) { + DeltaT_tip = (3.0/2.0)*DeltaT_avg*R_tip*(R_tip*R_tip-R_root*R_root)/(R_tip*R_tip*R_tip-R_root*R_root*R_root); + ActDisk_Jump[0] = DeltaT_tip*radius/R_tip; + } + else + ActDisk_Jump[0] = DeltaT_avg; + + /*--- Inner point ---*/ + + if (boundary == ACTDISK_INLET) { + + for (iVar = 0; iVar < nPrimVar; iVar++) + PrimVar_in_ghost[iVar] = PrimVar_out[iVar] - ActDisk_Jump[iVar]; + + /*--- Check that this is a meaningful state ---*/ + + P_in_ghost = PrimVar_in_ghost[nDim+1]; + T_in_ghost = PrimVar_in_ghost[0]; + + FluidModel->SetTDState_PT(P_in_ghost, T_in_ghost); + Rho_in_ghost = FluidModel->GetDensity(); + sos_in_ghost = FluidModel->GetSoundSpeed(); + + /*--- Find unit normal to the actuator disk ---*/ + + geometry->vertex[iMarker][iVertex]->GetNormal(Normal); + + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); + for (iDim = 0; iDim < nDim; iDim++) { UnitNormal[iDim] = -Normal[iDim]/Area; } + + /*--- Impose only normal velocity on the disk inflow ---*/ + + Vel_in_ghost = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Vel_in_ghost += PrimVar_in[iDim+1]*UnitNormal[iDim]; + } + + /*--- COmpute the enthalpy ---*/ + + H_in_ghost = FluidModel->GetStaticEnergy() + 0.5*Vel_in_ghost*Vel_in_ghost + P_in_ghost/Rho_in_ghost; + + PrimVar_in_ghost[0] = T_in_ghost; + PrimVar_in_ghost[1] = Vel_in_ghost*UnitNormal[0]; + PrimVar_in_ghost[2] = Vel_in_ghost*UnitNormal[1]; + PrimVar_in_ghost[3] = Vel_in_ghost*UnitNormal[2]; + PrimVar_in_ghost[nDim+1]= P_in_ghost; + PrimVar_in_ghost[nDim+2]= Rho_in_ghost; + PrimVar_in_ghost[nDim+3]= H_in_ghost; + PrimVar_in_ghost[nDim+4]= sos_in_ghost; + + numerics->SetPrimitive(PrimVar_in, PrimVar_in_ghost); + + } + + /*--- Outer point ---*/ + + if (boundary == ACTDISK_OUTLET) { + + for (iVar = 0; iVar < nPrimVar; iVar++) + PrimVar_out_ghost[iVar] = PrimVar_in[iVar] + ActDisk_Jump[iVar]; + + /*--- Check that this is a meaningful state ---*/ + + P_out_ghost = PrimVar_out_ghost[nDim+1]; + T_out_ghost = PrimVar_out_ghost[0]; + + FluidModel->SetTDState_PT(P_out_ghost, T_out_ghost); + Rho_out_ghost = FluidModel->GetDensity(); + sos_out_ghost = FluidModel->GetSoundSpeed(); + + /*--- Find unit normal to the actuator disk ---*/ + + geometry->vertex[iMarker][iVertex]->GetNormal(Normal); + + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); + for (iDim = 0; iDim < nDim; iDim++) { UnitNormal[iDim] = Normal[iDim]/Area; } + + /*--- Find unit radial to the actuator disk ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + Radial[iDim] = Coord[iDim]-Origin[iDim]; + + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Radial[iDim]*Radial[iDim]; Area = sqrt(Area); + for (iDim = 0; iDim < nDim; iDim++) { UnitRadial[iDim] = Radial[iDim]/Area; } + + /*--- Find unit tangent to the actuator disk ---*/ + + Tangent[0] = UnitNormal[1]*UnitRadial[2] - UnitNormal[2]*UnitRadial[1]; + Tangent[1] = UnitNormal[2]*UnitRadial[0] - UnitNormal[0]*UnitRadial[2]; + Tangent[2] = UnitNormal[0]*UnitRadial[1] - UnitNormal[1]*UnitRadial[0]; + + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Tangent[iDim]*Tangent[iDim]; Area = sqrt(Area); + for (iDim = 0; iDim < nDim; iDim++) { UnitTangent[iDim] = Tangent[iDim]/Area; } + + /*--- Normal velocity to the disk and density at the inlet---*/ + + Vel_Normal_in = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Vel_Normal_in += PrimVar_in[iDim+1]*UnitNormal[iDim]; + } + + Rho_in = PrimVar_in[nDim+2]; + + /*--- Conservation of mass to evaluate velocity at the outlet ---*/ + + Vel_out_ghost = (Rho_in*Vel_Normal_in)/Rho_out_ghost; + + /*--- Compute the swirl velocity (check the formula) ---*/ + + if (Omega != 0.0) + Vel_Swirl_out_ghost = Omega*radius*(1.0-(1.0-sqrt(2.0*ActDisk_Jump[nDim+1]/(Rho_in*pow(Omega*radius, 2.0))))); + else + Vel_Swirl_out_ghost = 0.0; + + /*--- Compute normal component of the velocity ---*/ + + Vel_Normal_out_ghost = sqrt(Vel_out_ghost*Vel_out_ghost-Vel_Swirl_out_ghost*Vel_Swirl_out_ghost); + + /*--- Compute total entalphy ---*/ + + H_out_ghost = FluidModel->GetStaticEnergy() + 0.5*(Vel_Normal_out_ghost+Vel_Swirl_out_ghost)*(Vel_Normal_out_ghost+Vel_Swirl_out_ghost) + P_out_ghost/Rho_out_ghost; + + PrimVar_out_ghost[0] = T_out_ghost; + PrimVar_out_ghost[1] = Vel_Normal_out_ghost*UnitNormal[0] + Vel_Swirl_out_ghost*UnitTangent[0]; + PrimVar_out_ghost[2] = Vel_Normal_out_ghost*UnitNormal[1] + Vel_Swirl_out_ghost*UnitTangent[1]; + PrimVar_out_ghost[3] = Vel_Normal_out_ghost*UnitNormal[2] + Vel_Swirl_out_ghost*UnitTangent[2]; + PrimVar_out_ghost[nDim+1]= P_out_ghost; + PrimVar_out_ghost[nDim+2]= Rho_out_ghost; + PrimVar_out_ghost[nDim+3]= H_out_ghost; + PrimVar_out_ghost[nDim+4]= sos_out_ghost; + + numerics->SetPrimitive(PrimVar_out, PrimVar_out_ghost); + + } + + /*--- Set the normal vector ---*/ + + geometry->vertex[iMarker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + numerics->SetNormal(Normal); + + /*--- Compute the convective residual using an upwind scheme ---*/ + + numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Add Residuals and Jacobians ---*/ + + LinSysRes.AddBlock(iPoint, Residual); + if (implicit) Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + } + + } + + } + + } + + /*--- We are using non-blocking communications ---*/ + +#ifdef HAVE_MPI + + MPI_Barrier(MPI_COMM_WORLD); + +#endif + + /*--- Free locally allocated memory ---*/ + + delete [] PrimVar_out; + delete [] PrimVar_in; + delete [] MeanPrimVar; + delete [] PrimVar_out_ghost; + delete [] PrimVar_in_ghost; + delete [] ActDisk_Jump; + delete[] Buffer_Send_V; + delete[] Buffer_Receive_V; + + } + +} + +void CEulerSolver::BC_Dirichlet(CGeometry *geometry, CSolver **solver_container, + CConfig *config, unsigned short val_marker) { } + +void CEulerSolver::BC_Custom(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, unsigned short val_marker) { } + +void CEulerSolver::SetResidual_DualTime(CGeometry *geometry, CSolver **solver_container, CConfig *config, + unsigned short iRKStep, unsigned short iMesh, unsigned short RunTime_EqSystem) { + + /*--- Local variables ---*/ + + unsigned short iVar, jVar, iMarker, iDim; + unsigned long iPoint, jPoint, iEdge, iVertex; + + su2double *U_time_nM1, *U_time_n, *U_time_nP1; + su2double Volume_nM1, Volume_nP1, TimeStep; + su2double *Normal = NULL, *GridVel_i = NULL, *GridVel_j = NULL, Residual_GCL; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool FlowEq = (RunTime_EqSystem == RUNTIME_FLOW_SYS); + bool AdjEq = (RunTime_EqSystem == RUNTIME_ADJFLOW_SYS); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool grid_movement = config->GetGrid_Movement(); + + /*--- Store the physical time step ---*/ + + TimeStep = config->GetDelta_UnstTimeND(); + + /*--- Compute the dual time-stepping source term for static meshes ---*/ + + if (!grid_movement) { + + /*--- Loop over all nodes (excluding halos) ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Retrieve the solution at time levels n-1, n, and n+1. Note that + we are currently iterating on U^n+1 and that U^n & U^n-1 are fixed, + previous solutions that are stored in memory. ---*/ + + U_time_nM1 = node[iPoint]->GetSolution_time_n1(); + U_time_n = node[iPoint]->GetSolution_time_n(); + U_time_nP1 = node[iPoint]->GetSolution(); + + /*--- CV volume at time n+1. As we are on a static mesh, the volume + of the CV will remained fixed for all time steps. ---*/ + + Volume_nP1 = geometry->node[iPoint]->GetVolume(); + + /*--- Compute the dual time-stepping source term based on the chosen + time discretization scheme (1st- or 2nd-order).---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Residual[iVar] = (U_time_nP1[iVar] - U_time_n[iVar])*Volume_nP1 / TimeStep; + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + Residual[iVar] = ( 3.0*U_time_nP1[iVar] - 4.0*U_time_n[iVar] + +1.0*U_time_nM1[iVar])*Volume_nP1 / (2.0*TimeStep); + } + if ((incompressible || freesurface) && (FlowEq || AdjEq)) Residual[0] = 0.0; + + /*--- Store the residual and compute the Jacobian contribution due + to the dual time source term. ---*/ + + LinSysRes.AddBlock(iPoint, Residual); + if (implicit) { + for (iVar = 0; iVar < nVar; iVar++) { + for (jVar = 0; jVar < nVar; jVar++) Jacobian_i[iVar][jVar] = 0.0; + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Jacobian_i[iVar][iVar] = Volume_nP1 / TimeStep; + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + Jacobian_i[iVar][iVar] = (Volume_nP1*3.0)/(2.0*TimeStep); + } + if ((incompressible || freesurface) && (FlowEq || AdjEq)) Jacobian_i[0][0] = 0.0; + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + } + } + + } + + else { + + /*--- For unsteady flows on dynamic meshes (rigidly transforming or + dynamically deforming), the Geometric Conservation Law (GCL) should be + satisfied in conjunction with the ALE formulation of the governing + equations. The GCL prevents accuracy issues caused by grid motion, i.e. + a uniform free-stream should be preserved through a moving grid. First, + we will loop over the edges and boundaries to compute the GCL component + of the dual time source term that depends on grid velocities. ---*/ + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Get indices for nodes i & j plus the face normal ---*/ + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + Normal = geometry->edge[iEdge]->GetNormal(); + + /*--- Grid velocities stored at nodes i & j ---*/ + + GridVel_i = geometry->node[iPoint]->GetGridVel(); + GridVel_j = geometry->node[jPoint]->GetGridVel(); + + /*--- Compute the GCL term by averaging the grid velocities at the + edge mid-point and dotting with the face normal. ---*/ + + Residual_GCL = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Residual_GCL += 0.5*(GridVel_i[iDim]+GridVel_j[iDim])*Normal[iDim]; + + /*--- Compute the GCL component of the source term for node i ---*/ + + U_time_n = node[iPoint]->GetSolution_time_n(); + for (iVar = 0; iVar < nVar; iVar++) + Residual[iVar] = U_time_n[iVar]*Residual_GCL; + if ((incompressible || freesurface) && (FlowEq || AdjEq)) Residual[0] = 0.0; + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Compute the GCL component of the source term for node j ---*/ + + U_time_n = node[jPoint]->GetSolution_time_n(); + for (iVar = 0; iVar < nVar; iVar++) + Residual[iVar] = U_time_n[iVar]*Residual_GCL; + if ((incompressible || freesurface) && (FlowEq || AdjEq)) Residual[0] = 0.0; + LinSysRes.SubtractBlock(jPoint, Residual); + + } + + /*--- Loop over the boundary edges ---*/ + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + + /*--- Get the index for node i plus the boundary face normal ---*/ + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + + /*--- Grid velocities stored at boundary node i ---*/ + + GridVel_i = geometry->node[iPoint]->GetGridVel(); + + /*--- Compute the GCL term by dotting the grid velocity with the face + normal. The normal is negated to match the boundary convention. ---*/ + + Residual_GCL = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Residual_GCL -= 0.5*(GridVel_i[iDim]+GridVel_i[iDim])*Normal[iDim]; + + /*--- Compute the GCL component of the source term for node i ---*/ + + U_time_n = node[iPoint]->GetSolution_time_n(); + for (iVar = 0; iVar < nVar; iVar++) + Residual[iVar] = U_time_n[iVar]*Residual_GCL; + if ((incompressible || freesurface) && (FlowEq || AdjEq)) Residual[0] = 0.0; + LinSysRes.AddBlock(iPoint, Residual); + + } + } + + /*--- Loop over all nodes (excluding halos) to compute the remainder + of the dual time-stepping source term. ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Retrieve the solution at time levels n-1, n, and n+1. Note that + we are currently iterating on U^n+1 and that U^n & U^n-1 are fixed, + previous solutions that are stored in memory. ---*/ + + U_time_nM1 = node[iPoint]->GetSolution_time_n1(); + U_time_n = node[iPoint]->GetSolution_time_n(); + U_time_nP1 = node[iPoint]->GetSolution(); + + /*--- CV volume at time n-1 and n+1. In the case of dynamically deforming + grids, the volumes will change. On rigidly transforming grids, the + volumes will remain constant. ---*/ + + Volume_nM1 = geometry->node[iPoint]->GetVolume_nM1(); + Volume_nP1 = geometry->node[iPoint]->GetVolume(); + + /*--- Compute the dual time-stepping source residual. Due to the + introduction of the GCL term above, the remainder of the source residual + due to the time discretization has a new form.---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Residual[iVar] = (U_time_nP1[iVar] - U_time_n[iVar])*(Volume_nP1/TimeStep); + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + Residual[iVar] = (U_time_nP1[iVar] - U_time_n[iVar])*(3.0*Volume_nP1/(2.0*TimeStep)) + + (U_time_nM1[iVar] - U_time_n[iVar])*(Volume_nM1/(2.0*TimeStep)); + } + if ((incompressible || freesurface) && (FlowEq || AdjEq)) Residual[0] = 0.0; + + /*--- Store the residual and compute the Jacobian contribution due + to the dual time source term. ---*/ + + LinSysRes.AddBlock(iPoint, Residual); + if (implicit) { + for (iVar = 0; iVar < nVar; iVar++) { + for (jVar = 0; jVar < nVar; jVar++) Jacobian_i[iVar][jVar] = 0.0; + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Jacobian_i[iVar][iVar] = Volume_nP1/TimeStep; + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + Jacobian_i[iVar][iVar] = (3.0*Volume_nP1)/(2.0*TimeStep); + } + if ((incompressible || freesurface) && (FlowEq || AdjEq)) Jacobian_i[0][0] = 0.0; + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + } + } + } + +} + +void CEulerSolver::SetFlow_Displacement(CGeometry **flow_geometry, CVolumetricMovement *flow_grid_movement, + CConfig *flow_config, CConfig *fea_config, CGeometry **fea_geometry, CSolver ***fea_solution) { + unsigned short iMarker, iDim; + unsigned long iVertex, iPoint; + su2double *Coord, VarCoord[3]; + + //#ifndef HAVE_MPI + unsigned long iPoint_Donor; + su2double *CoordDonor, *DisplacementDonor; + + for (iMarker = 0; iMarker < flow_config->GetnMarker_All(); iMarker++) { + + if (flow_config->GetMarker_All_FSIinterface(iMarker) != 0) { + + for(iVertex = 0; iVertex < flow_geometry[MESH_0]->nVertex[iMarker]; iVertex++) { + + iPoint = flow_geometry[MESH_0]->vertex[iMarker][iVertex]->GetNode(); + + iPoint_Donor = flow_geometry[MESH_0]->vertex[iMarker][iVertex]->GetDonorPoint(); + + Coord = flow_geometry[MESH_0]->node[iPoint]->GetCoord(); + + CoordDonor = fea_geometry[MESH_0]->node[iPoint_Donor]->GetCoord(); + + /*--- The displacements come from the predicted solution ---*/ + DisplacementDonor = fea_solution[MESH_0][FEA_SOL]->node[iPoint_Donor]->GetSolution_Pred(); + + for (iDim = 0; iDim < nDim; iDim++) + + VarCoord[iDim] = (CoordDonor[iDim]+DisplacementDonor[iDim])-Coord[iDim]; + + flow_geometry[MESH_0]->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + } + } + } + flow_grid_movement->SetVolume_Deformation(flow_geometry[MESH_0], flow_config, true); + + + //#else + // + // int rank = MPI::COMM_WORLD.Get_rank(), jProcessor; + // su2double *Buffer_Send_Coord = new su2double [nDim]; + // su2double *Buffer_Receive_Coord = new su2double [nDim]; + // unsigned long jPoint; + // + // /*--- Do the send process, by the moment we are sending each + // node individually, this must be changed ---*/ + // for (iMarker = 0; iMarker < fea_config->GetnMarker_All(); iMarker++) { + // if (fea_config->GetMarker_All_KindBC(iMarker) == LOAD_BOUNDARY) { + // for (iVertex = 0; iVertex < fea_geometry[MESH_0]->nVertex[iMarker]; iVertex++) { + // iPoint = fea_geometry[MESH_0]->vertex[iMarker][iVertex]->GetNode(); + // + // if (fea_geometry[MESH_0]->node[iPoint]->GetDomain()) { + // + // /*--- Find the associate pair to the original node (index and processor) ---*/ + // jPoint = fea_geometry[MESH_0]->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; + // jProcessor = fea_geometry[MESH_0]->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; + // + // /*--- We only send the pressure that belong to other boundary ---*/ + // if (jProcessor != rank) { + // for (iDim = 0; iDim < nDim; iDim++) + // Buffer_Send_Coord[iDim] = fea_geometry[MESH_0]->node[iPoint]->GetCoord(iDim); + // + // MPI::COMM_WORLD.Bsend(Buffer_Send_Coord, nDim, MPI::DOUBLE, jProcessor, iPoint); + // } + // + // } + // } + // } + // } + // + // /*--- Now the loop is over the fea points ---*/ + // for (iMarker = 0; iMarker < flow_config->GetnMarker_All(); iMarker++) { + // if ((flow_config->GetMarker_All_KindBC(iMarker) == EULER_WALL) && + // (flow_config->GetMarker_All_Moving(iMarker) == YES)) { + // for (iVertex = 0; iVertex < flow_geometry[MESH_0]->nVertex[iMarker]; iVertex++) { + // iPoint = flow_geometry[MESH_0]->vertex[iMarker][iVertex]->GetNode(); + // if (flow_geometry[MESH_0]->node[iPoint]->GetDomain()) { + // + // /*--- Find the associate pair to the original node ---*/ + // jPoint = flow_geometry[MESH_0]->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[0]; + // jProcessor = flow_geometry[MESH_0]->vertex[iMarker][iVertex]->GetPeriodicPointDomain()[1]; + // + // /*--- We only receive the information that belong to other boundary ---*/ + // if (jProcessor != rank) + // MPI::COMM_WORLD.Recv(Buffer_Receive_Coord, nDim, MPI::DOUBLE, jProcessor, jPoint); + // else { + // for (iDim = 0; iDim < nDim; iDim++) + // Buffer_Send_Coord[iDim] = fea_geometry[MESH_0]->node[jPoint]->GetCoord(iDim); + // } + // + // /*--- Store the solution for both points ---*/ + // Coord = flow_geometry[MESH_0]->node[iPoint]->GetCoord(); + // + // for (iDim = 0; iDim < nDim; iDim++) + // VarCoord[iDim] = Buffer_Send_Coord[iDim]-Coord[iDim]; + // + // flow_geometry[MESH_0]->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + // + // + // } + // } + // } + // } + // delete[] Buffer_Send_Coord; + // delete[] Buffer_Receive_Coord; + // + //#endif + // +} + +void CEulerSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig *config, int val_iter) { + + /*--- Restart the solution from file information ---*/ + unsigned short iDim, iVar, iMesh, iMeshFine; + unsigned long iPoint, index, iChildren, Point_Fine; + unsigned short turb_model = config->GetKind_Turb_Model(); + su2double Area_Children, Area_Parent, *Coord, *Solution_Fine, dull_val; + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool grid_movement = config->GetGrid_Movement(); + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + string UnstExt, text_line; + ifstream restart_file; + + string restart_filename = config->GetSolution_FlowFileName(); + + Coord = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Coord[iDim] = 0.0; + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Modify file name for an unsteady restart ---*/ + + if (dual_time) + restart_filename = config->GetUnsteady_FileName(restart_filename, val_iter); + + /*--- Open the restart file, and throw an error if this fails. ---*/ + + restart_file.open(restart_filename.data(), ios::in); + if (restart_file.fail()) { + if (rank == MASTER_NODE) + cout << "There is no flow restart file!! " << restart_filename.data() << "."<< endl; + exit(EXIT_FAILURE); + } + + /*--- In case this is a parallel simulation, we need to perform the + Global2Local index transformation first. ---*/ + + long *Global2Local = NULL; + Global2Local = new long[geometry[MESH_0]->GetGlobal_nPointDomain()]; + /*--- First, set all indices to a negative value by default ---*/ + for (iPoint = 0; iPoint < geometry[MESH_0]->GetGlobal_nPointDomain(); iPoint++) { + Global2Local[iPoint] = -1; + } + + /*--- Now fill array with the transform values only for local points ---*/ + + for (iPoint = 0; iPoint < geometry[MESH_0]->GetnPointDomain(); iPoint++) { + Global2Local[geometry[MESH_0]->node[iPoint]->GetGlobalIndex()] = iPoint; + } + + /*--- Read all lines in the restart file ---*/ + + long iPoint_Local = 0; unsigned long iPoint_Global = 0; + + /*--- The first line is the header ---*/ + + getline (restart_file, text_line); + + while (getline (restart_file, text_line)) { + istringstream point_line(text_line); + + /*--- Retrieve local index. If this node from the restart file lives + on a different processor, the value of iPoint_Local will be -1, as + initialized above. Otherwise, the local index for this node on the + current processor will be returned and used to instantiate the vars. ---*/ + + iPoint_Local = Global2Local[iPoint_Global]; + if (iPoint_Local >= 0) { + + if (compressible) { + if (nDim == 2) point_line >> index >> Coord[0] >> Coord[1] >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; + if (nDim == 3) point_line >> index >> Coord[0] >> Coord[1] >> Coord[2] >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3] >> Solution[4]; + } + if (incompressible) { + if (nDim == 2) point_line >> index >> Coord[0] >> Coord[1] >> Solution[0] >> Solution[1] >> Solution[2]; + if (nDim == 3) point_line >> index >> Coord[0] >> Coord[1] >> Coord[2] >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; + } + if (freesurface) { + if (nDim == 2) point_line >> index >> Coord[0] >> Coord[1] >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; + if (nDim == 3) point_line >> index >> Coord[0] >> Coord[1] >> Coord[2] >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3] >> Solution[4]; + } + + node[iPoint_Local]->SetSolution(Solution); + + /*--- For dynamic meshes, read in and store the + grid coordinates and grid velocities for each node. ---*/ + + if (grid_movement) { + + /*--- First, remove any variables for the turbulence model that + appear in the restart file before the grid velocities. ---*/ + + if (turb_model == SA || turb_model == SA_NEG) { + point_line >> dull_val; + } else if (turb_model == SST) { + point_line >> dull_val >> dull_val; + } + + /*--- Read in the next 2 or 3 variables which are the grid velocities ---*/ + + su2double GridVel[3] = {0.0,0.0,0.0}; + if (nDim == 2) point_line >> GridVel[0] >> GridVel[1]; + else point_line >> GridVel[0] >> GridVel[1] >> GridVel[2]; + + for (iDim = 0; iDim < nDim; iDim++) { + geometry[MESH_0]->node[iPoint_Local]->SetCoord(iDim, Coord[iDim]); + geometry[MESH_0]->node[iPoint_Local]->SetGridVel(iDim, GridVel[iDim]); + } + + } + + } + iPoint_Global++; + } + + /*--- Close the restart file ---*/ + + restart_file.close(); + + /*--- Free memory needed for the transformation ---*/ + + delete [] Global2Local; + + /*--- MPI solution ---*/ + + solver[MESH_0][FLOW_SOL]->Set_MPI_Solution(geometry[MESH_0], config); + + /*--- Interpolate the solution down to the coarse multigrid levels ---*/ + + for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++) { + for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { + Area_Parent = geometry[iMesh]->node[iPoint]->GetVolume(); + for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; + for (iChildren = 0; iChildren < geometry[iMesh]->node[iPoint]->GetnChildren_CV(); iChildren++) { + Point_Fine = geometry[iMesh]->node[iPoint]->GetChildren_CV(iChildren); + Area_Children = geometry[iMesh-1]->node[Point_Fine]->GetVolume(); + Solution_Fine = solver[iMesh-1][FLOW_SOL]->node[Point_Fine]->GetSolution(); + for (iVar = 0; iVar < nVar; iVar++) { + Solution[iVar] += Solution_Fine[iVar]*Area_Children/Area_Parent; + } + } + solver[iMesh][FLOW_SOL]->node[iPoint]->SetSolution(Solution); + } + solver[iMesh][FLOW_SOL]->Set_MPI_Solution(geometry[iMesh], config); + } + + /*--- Update the geometry for flows on dynamic meshes ---*/ + + if (grid_movement) { + + /*--- Communicate the new coordinates and grid velocities at the halos ---*/ + + geometry[MESH_0]->Set_MPI_Coord(config); + geometry[MESH_0]->Set_MPI_GridVel(config); + + /*--- Recompute the edges and dual mesh control volumes in the + domain and on the boundaries. ---*/ + + geometry[MESH_0]->SetCoord_CG(); + geometry[MESH_0]->SetControlVolume(config, UPDATE); + geometry[MESH_0]->SetBoundControlVolume(config, UPDATE); + + /*--- 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]); + geometry[iMesh]->SetRestricted_GridVelocity(geometry[iMeshFine], config); + } + } + + delete [] Coord; + +} + +void CEulerSolver::SetFreeSurface_Distance(CGeometry *geometry, CConfig *config) { + su2double *coord = NULL, dist2, *iCoord = NULL, *jCoord = NULL, LevelSet_i, LevelSet_j, + **Coord_LevelSet = NULL, *xCoord = NULL, *yCoord = NULL, *zCoord = NULL, auxCoordx, auxCoordy, + auxCoordz, FreeSurface, volume, LevelSetDiff_Squared, LevelSetDiff, dist, Min_dist; + unsigned short iDim; + unsigned long iPoint, jPoint, iVertex, jVertex, nVertex_LevelSet, iEdge; + ifstream index_file; + ofstream LevelSet_file; + string text_line; + int rank = MASTER_NODE; + char cstr[200], buffer[50]; + + unsigned short nDim = geometry->GetnDim(); + unsigned long iExtIter = config->GetExtIter(); + +#ifndef HAVE_MPI + + /*--- Identification of the 0 level set points and coordinates ---*/ + nVertex_LevelSet = 0; + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + iPoint = geometry->edge[iEdge]->GetNode(0); LevelSet_i = node[iPoint]->GetSolution(nDim+1); + jPoint = geometry->edge[iEdge]->GetNode(1); LevelSet_j = node[jPoint]->GetSolution(nDim+1); + if (LevelSet_i*LevelSet_j < 0.0) nVertex_LevelSet ++; + } + + /*--- Allocate vector of boundary coordinates ---*/ + Coord_LevelSet = new su2double* [nVertex_LevelSet]; + for (iVertex = 0; iVertex < nVertex_LevelSet; iVertex++) + Coord_LevelSet[iVertex] = new su2double [nDim]; + + /*--- Get coordinates of the points of the surface ---*/ + nVertex_LevelSet = 0; + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + iPoint = geometry->edge[iEdge]->GetNode(0); LevelSet_i = node[iPoint]->GetSolution(nDim+1); iCoord = geometry->node[iPoint]->GetCoord(); + jPoint = geometry->edge[iEdge]->GetNode(1); LevelSet_j = node[jPoint]->GetSolution(nDim+1); jCoord = geometry->node[jPoint]->GetCoord(); + if (LevelSet_i*LevelSet_j < 0.0) { + for (iDim = 0; iDim < nDim; iDim++) + Coord_LevelSet[nVertex_LevelSet][iDim] = iCoord[iDim]-LevelSet_i*(jCoord[iDim]-iCoord[iDim])/(LevelSet_j-LevelSet_i); + nVertex_LevelSet++; + } + } + +#else + + int nProcessor, iProcessor; + unsigned long *Buffer_Send_nVertex = NULL, *Buffer_Receive_nVertex = NULL, + nLocalVertex_LevelSet = 0, nGlobalVertex_LevelSet = 0, MaxLocalVertex_LevelSet = 0, nBuffer; + su2double *Buffer_Send_Coord = NULL, *Buffer_Receive_Coord = NULL; + + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + Buffer_Send_nVertex = new unsigned long [1]; + Buffer_Receive_nVertex = new unsigned long [nProcessor]; + + nLocalVertex_LevelSet = 0; + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + iPoint = geometry->edge[iEdge]->GetNode(0); LevelSet_i = node[iPoint]->GetSolution(nDim+1); + jPoint = geometry->edge[iEdge]->GetNode(1); LevelSet_j = node[jPoint]->GetSolution(nDim+1); + if (LevelSet_i*LevelSet_j < 0.0) nLocalVertex_LevelSet ++; + } + + Buffer_Send_nVertex[0] = nLocalVertex_LevelSet; + + SU2_MPI::Allreduce(&nLocalVertex_LevelSet, &nGlobalVertex_LevelSet, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&nLocalVertex_LevelSet, &MaxLocalVertex_LevelSet, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + nBuffer = MaxLocalVertex_LevelSet*nDim; + Buffer_Send_Coord = new su2double [nBuffer]; + Buffer_Receive_Coord = new su2double [nProcessor*nBuffer]; + + for (iVertex = 0; iVertex < MaxLocalVertex_LevelSet; iVertex++) + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; + + nLocalVertex_LevelSet = 0; + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + iPoint = geometry->edge[iEdge]->GetNode(0); LevelSet_i = node[iPoint]->GetSolution(nDim+1); iCoord = geometry->node[iPoint]->GetCoord(); + jPoint = geometry->edge[iEdge]->GetNode(1); LevelSet_j = node[jPoint]->GetSolution(nDim+1); jCoord = geometry->node[jPoint]->GetCoord(); + + if (LevelSet_i*LevelSet_j < 0.0) { + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[nLocalVertex_LevelSet*nDim+iDim] = iCoord[iDim]-LevelSet_i*(jCoord[iDim]-iCoord[iDim])/(LevelSet_j-LevelSet_i); + nLocalVertex_LevelSet++; + } + } + + SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer, MPI_DOUBLE, MPI_COMM_WORLD); + + /*--- Identification of the 0 level set points and coordinates ---*/ + nVertex_LevelSet = 0; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) + nVertex_LevelSet += Buffer_Receive_nVertex[iProcessor]; + + /*--- Allocate vector of boundary coordinates ---*/ + Coord_LevelSet = new su2double* [nVertex_LevelSet]; + for (iVertex = 0; iVertex < nVertex_LevelSet; iVertex++) + Coord_LevelSet[iVertex] = new su2double [nDim]; + + /*--- Set the value of the coordinates at the level set zero ---*/ + nVertex_LevelSet = 0; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) + for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { + for (iDim = 0; iDim < nDim; iDim++) + Coord_LevelSet[nVertex_LevelSet][iDim] = Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_LevelSet+iVertex)*nDim+iDim]; + nVertex_LevelSet++; + } + + delete [] Buffer_Send_Coord; + delete [] Buffer_Receive_Coord; + delete [] Buffer_Send_nVertex; + delete [] Buffer_Receive_nVertex; + +#endif + + /*--- Get coordinates of the points and compute distances to the surface ---*/ + for (iPoint = 0; iPoint < nPoint; iPoint++) { + coord = geometry->node[iPoint]->GetCoord(); + + /*--- Compute the min distance ---*/ + Min_dist = 1E20; + for (iVertex = 0; iVertex < nVertex_LevelSet; iVertex++) { + + dist2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + dist2 += (coord[iDim] - Coord_LevelSet[iVertex][iDim])*(coord[iDim]-Coord_LevelSet[iVertex][iDim]); + dist = sqrt(dist2); + if (dist < Min_dist) { Min_dist = dist; } + + } + + /*--- Compute the sign using the current solution ---*/ + su2double NumberSign = 1.0; + if (node[iPoint]->GetSolution(0) != 0.0) + NumberSign = node[iPoint]->GetSolution(nDim+1)/fabs(node[iPoint]->GetSolution(nDim+1)); + + /*--- Store the value of the Level Set and the Distance (primitive variables) ---*/ + node[iPoint]->SetPrimitive(nDim+5, node[iPoint]->GetSolution(nDim+1)); + node[iPoint]->SetPrimitive(nDim+6, Min_dist*NumberSign); + + } + + if (config->GetIntIter() == 0) { + + /*--- Order the arrays (x Coordinate, y Coordinate, z Coordiante) ---*/ + for (iVertex = 0; iVertex < nVertex_LevelSet; iVertex++) { + for (jVertex = 0; jVertex < nVertex_LevelSet - 1 - iVertex; jVertex++) { + if (Coord_LevelSet[jVertex][0] > Coord_LevelSet[jVertex+1][0]) { + auxCoordx = Coord_LevelSet[jVertex][0]; Coord_LevelSet[jVertex][0] = Coord_LevelSet[jVertex+1][0]; Coord_LevelSet[jVertex+1][0] = auxCoordx; + auxCoordy = Coord_LevelSet[jVertex][1]; Coord_LevelSet[jVertex][1] = Coord_LevelSet[jVertex+1][1]; Coord_LevelSet[jVertex+1][1] = auxCoordy; + if (nDim == 3) { auxCoordz = Coord_LevelSet[jVertex][2]; Coord_LevelSet[jVertex][2] = Coord_LevelSet[jVertex+1][2]; Coord_LevelSet[jVertex+1][2] = auxCoordz; } + } + } + } + + /*--- Get coordinates of the points and compute distances to the surface ---*/ + FreeSurface = 0.0; + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + coord = geometry->node[iPoint]->GetCoord(); + volume = geometry->node[iPoint]->GetVolume(); + LevelSetDiff = (node[iPoint]->GetSolution(nDim+1) - coord[nDim-1]); + LevelSetDiff_Squared = LevelSetDiff*LevelSetDiff; + FreeSurface += 0.5*LevelSetDiff_Squared*volume; + + node[iPoint]->SetDiffLevelSet(LevelSetDiff); + + } + + if ((rank == MASTER_NODE) && (iExtIter % config->GetWrt_Sol_Freq_DualTime() == 0)) { + + /*--- Write the Level Set distribution, the target level set---*/ + LevelSet_file.precision(15); + + /*--- Write file name with extension ---*/ + strcpy (cstr, "LevelSet"); + if (config->GetUnsteady_Simulation()) { + if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(iExtIter)); + if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(iExtIter)); + if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(iExtIter)); + } + else { + SPRINTF (buffer, ".dat"); + } + + strcat(cstr, buffer); + + LevelSet_file.open(cstr, ios::out); + LevelSet_file << "TITLE = \"SU2 Free surface simulation\"" << endl; + if (nDim == 2) LevelSet_file << "VARIABLES = \"x coord\",\"y coord\"" << endl; + if (nDim == 3) LevelSet_file << "VARIABLES = \"x coord\",\"y coord\",\"z coord\"" << endl; + LevelSet_file << "ZONE T= \"Free Surface\"" << endl; + + for (iVertex = 0; iVertex < nVertex_LevelSet; iVertex++) { + if (nDim == 2) LevelSet_file << scientific << Coord_LevelSet[iVertex][0] << ", " << Coord_LevelSet[iVertex][1] << endl; + if (nDim == 3) LevelSet_file << scientific << Coord_LevelSet[iVertex][0] << ", " << Coord_LevelSet[iVertex][1] << ", " << Coord_LevelSet[iVertex][2] << endl; + } + LevelSet_file.close(); + + } + + /*--- Store the value of the free surface coefficient ---*/ + SetTotal_CFreeSurface(FreeSurface); + + delete [] xCoord; + delete [] yCoord; + if (nDim == 3) delete [] zCoord; + + } + + /*--- Deallocate vector of boundary coordinates ---*/ + for (iVertex = 0; iVertex < nVertex_LevelSet; iVertex++) + delete Coord_LevelSet[iVertex]; + delete [] Coord_LevelSet; + +} + +CNSSolver::CNSSolver(void) : CEulerSolver() { + + /*--- Basic array initialization ---*/ + + CDrag_Visc = NULL; CLift_Visc = NULL; CSideForce_Visc = NULL; CEff_Visc = NULL; + CMx_Visc = NULL; CMy_Visc = NULL; CMz_Visc = NULL; + CFx_Visc = NULL; CFy_Visc = NULL; CFz_Visc = NULL; + + ForceViscous = NULL; MomentViscous = NULL; CSkinFriction = NULL; + + /*--- Surface based array initialization ---*/ + + Surface_CLift_Visc = NULL; Surface_CDrag_Visc = NULL; Surface_CSideForce_Visc = NULL; Surface_CEff_Visc = NULL; + Surface_CFx_Visc = NULL; Surface_CFy_Visc = NULL; Surface_CFz_Visc = NULL; + Surface_CMx_Visc = NULL; Surface_CMy_Visc = NULL; Surface_CMz_Visc = NULL; + + /*--- Rotorcraft simulation array initialization ---*/ + + CMerit_Visc = NULL; CT_Visc = NULL; CQ_Visc = NULL; + +} + +CNSSolver::CNSSolver(CGeometry *geometry, CConfig *config, unsigned short iMesh) : CEulerSolver() { + + unsigned long iPoint, index, counter_local = 0, counter_global = 0, iVertex; + unsigned short iVar, iDim, iMarker, nLineLets; + su2double Density, Velocity2, Pressure, Temperature, dull_val, StaticEnergy; + int Unst_RestartIter; + ifstream restart_file; + unsigned short iZone = config->GetiZone(); + unsigned short nZone = geometry->GetnZone(); + bool restart = (config->GetRestart() || config->GetRestart_Flow()); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + bool roe_turkel = (config->GetKind_Upwind_Flow() == TURKEL); + bool adjoint = config->GetAdjoint(); + string filename = config->GetSolution_FlowFileName(); + + unsigned short direct_diff = config->GetDirectDiff(); + unsigned short nMarkerTurboPerf = config->Get_nMarkerTurboPerf(); + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Array initialization ---*/ + + CDrag_Visc = NULL; CLift_Visc = NULL; CSideForce_Visc = NULL; CEff_Visc = NULL; + CMx_Visc = NULL; CMy_Visc = NULL; CMz_Visc = NULL; + CFx_Visc = NULL; CFy_Visc = NULL; CFz_Visc = NULL; + + Surface_CLift_Visc = NULL; Surface_CDrag_Visc = NULL; Surface_CSideForce_Visc = NULL; Surface_CEff_Visc = NULL; + Surface_CFx_Visc = NULL; Surface_CFy_Visc = NULL; Surface_CFz_Visc = NULL; + Surface_CMx_Visc = NULL; Surface_CMy_Visc = NULL; Surface_CMz_Visc = NULL; + + CMerit_Visc = NULL; CT_Visc = NULL; CQ_Visc = NULL; + MaxHeatFlux_Visc = NULL; ForceViscous = NULL; MomentViscous = NULL; + CSkinFriction = NULL; Cauchy_Serie = NULL; Heat_Visc = NULL; + + /*--- Set the gamma value ---*/ + + Gamma = config->GetGamma(); + Gamma_Minus_One = Gamma - 1.0; + + /*--- Define geometry constants in the solver structure + Compressible flow, primitive variables (T, vx, vy, vz, P, rho, h, c, lamMu, EddyMu, ThCond, Cp) + Incompressible flow, primitive variables (P, vx, vy, vz, rho, beta, lamMu, EddyMu), + FreeSurface Incompressible flow, primitive variables (P, vx, vy, vz, rho, beta, lamMu, EddyMu, LevelSet, Dist), + ---*/ + + nDim = geometry->GetnDim(); + + if (incompressible) { nVar = nDim+1; nPrimVar = nDim+5; nPrimVarGrad = nDim+3; } + if (freesurface) { nVar = nDim+2; nPrimVar = nDim+7; nPrimVarGrad = nDim+6; } + if (compressible) { nVar = nDim+2; + nPrimVar = nDim+9; nPrimVarGrad = nDim+4; + nSecondaryVar = 8; nSecondaryVarGrad = 2; + } + + nMarker = config->GetnMarker_All(); + nPoint = geometry->GetnPoint(); + nPointDomain = geometry->GetnPointDomain(); + + /*--- Perform the non-dimensionalization for the flow equations using the + specified reference values. ---*/ + + SetNondimensionalization(geometry, config, iMesh); + + /*--- Allocate the node variables ---*/ + node = new CVariable*[nPoint]; + + /*--- Define some auxiliar vector related with the residual ---*/ + + Residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; + Residual_RMS = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_RMS[iVar] = 0.0; + Residual_Max = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_Max[iVar] = 0.0; + Residual_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_i[iVar] = 0.0; + Residual_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_j[iVar] = 0.0; + Res_Conv = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Conv[iVar] = 0.0; + Res_Visc = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Visc[iVar] = 0.0; + Res_Sour = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Res_Sour[iVar] = 0.0; + + /*--- Define some structures for locating max residuals ---*/ + + Point_Max = new unsigned long[nVar]; for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; + Point_Max_Coord = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Point_Max_Coord[iVar] = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; + } + + /*--- Define some auxiliary vectors related to the solution ---*/ + + Solution = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; + Solution_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_i[iVar] = 0.0; + Solution_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Solution_j[iVar] = 0.0; + + /*--- Define some auxiliary vectors related to the geometry ---*/ + + Vector = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = 0.0; + Vector_i = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_i[iDim] = 0.0; + Vector_j = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Vector_j[iDim] = 0.0; + + /*--- Define some auxiliary vectors related to the primitive solution ---*/ + + Primitive = new su2double[nPrimVar]; for (iVar = 0; iVar < nPrimVar; iVar++) Primitive[iVar] = 0.0; + Primitive_i = new su2double[nPrimVar]; for (iVar = 0; iVar < nPrimVar; iVar++) Primitive_i[iVar] = 0.0; + Primitive_j = new su2double[nPrimVar]; for (iVar = 0; iVar < nPrimVar; iVar++) Primitive_j[iVar] = 0.0; + + /*--- Define some auxiliary vectors related to the Secondary solution ---*/ + + if (compressible){ + Secondary = new su2double[nSecondaryVar]; for (iVar = 0; iVar < nSecondaryVar; iVar++) Secondary[iVar] = 0.0; + Secondary_i = new su2double[nSecondaryVar]; for (iVar = 0; iVar < nSecondaryVar; iVar++) Secondary_i[iVar] = 0.0; + Secondary_j = new su2double[nSecondaryVar]; for (iVar = 0; iVar < nSecondaryVar; iVar++) Secondary_j[iVar] = 0.0; + } + + /*--- Define some auxiliar vector related with the undivided lapalacian computation ---*/ + + if (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED) { + iPoint_UndLapl = new su2double [nPoint]; + jPoint_UndLapl = new su2double [nPoint]; + } + + /*--- Define some auxiliary vectors related to low-speed preconditioning ---*/ + + if (roe_turkel) { + LowMach_Precontioner = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar ++) + LowMach_Precontioner[iVar] = new su2double[nVar]; + } + + /*--- Initialize the solution and right hand side vectors for storing + the residuals and updating the solution (always needed even for + explicit schemes). ---*/ + + LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); + LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); + + /*--- Jacobians and vector structures for implicit computations ---*/ + + if (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT) { + + Jacobian_i = new su2double* [nVar]; + Jacobian_j = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Jacobian_i[iVar] = new su2double [nVar]; + Jacobian_j[iVar] = new su2double [nVar]; + } + + if (rank == MASTER_NODE) cout << "Initialize Jacobian structure (Navier-Stokes). MG level: " << iMesh <<"." << endl; + Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); + + if ((config->GetKind_Linear_Solver_Prec() == LINELET) || + (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { + nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); + if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; + } + + } + + else { + if (rank == MASTER_NODE) + cout << "Explicit scheme. No Jacobian structure (Navier-Stokes). MG level: " << iMesh <<"." << endl; + } + + /*--- Define some auxiliary vectors for computing flow variable + gradients by least squares, S matrix := inv(R)*traspose(inv(R)), + c vector := transpose(WA)*(Wb) ---*/ + + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { + + Smatrix = new su2double* [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Smatrix[iDim] = new su2double [nDim]; + + cvector = new su2double* [nPrimVarGrad]; + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + cvector[iVar] = new su2double [nDim]; + } + + /*--- Store the value of the characteristic primitive variables at the boundaries ---*/ + + CharacPrimVar = new su2double** [nMarker]; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + CharacPrimVar[iMarker] = new su2double* [geometry->nVertex[iMarker]]; + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + CharacPrimVar[iMarker][iVertex] = new su2double [nPrimVar]; + for (iVar = 0; iVar < nPrimVar; iVar++) { + CharacPrimVar[iMarker][iVertex][iVar] = 0.0; + } + } + } + + /*--- Inviscid force definition and coefficient in all the markers ---*/ + + CPressure = new su2double* [nMarker]; + CPressureTarget = new su2double* [nMarker]; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + CPressure[iMarker] = new su2double [geometry->nVertex[iMarker]]; + CPressureTarget[iMarker] = new su2double [geometry->nVertex[iMarker]]; + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + CPressure[iMarker][iVertex] = 0.0; + CPressureTarget[iMarker][iVertex] = 0.0; + } + } + + /*--- Heat flux in all the markers ---*/ + + HeatFlux = new su2double* [nMarker]; + HeatFluxTarget = new su2double* [nMarker]; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + HeatFlux[iMarker] = new su2double [geometry->nVertex[iMarker]]; + HeatFluxTarget[iMarker] = new su2double [geometry->nVertex[iMarker]]; + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + HeatFlux[iMarker][iVertex] = 0.0; + HeatFluxTarget[iMarker][iVertex] = 0.0; + } + } + + /*--- Y plus in all the markers ---*/ + + YPlus = new su2double* [nMarker]; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + YPlus[iMarker] = new su2double [geometry->nVertex[iMarker]]; + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + YPlus[iMarker][iVertex] = 0.0; + } + } + + /*--- Skin friction in all the markers ---*/ + + CSkinFriction = new su2double* [nMarker]; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + CSkinFriction[iMarker] = new su2double [geometry->nVertex[iMarker]]; + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + CSkinFriction[iMarker][iVertex] = 0.0; + } + } + + /*--- Non dimensional coefficients ---*/ + + ForceInviscid = new su2double[3]; + MomentInviscid = new su2double[3]; + CDrag_Inv = new su2double[nMarker]; + CLift_Inv = new su2double[nMarker]; + CSideForce_Inv = new su2double[nMarker]; + CMx_Inv = new su2double[nMarker]; + CMy_Inv = new su2double[nMarker]; + CMz_Inv = new su2double[nMarker]; + CEff_Inv = new su2double[nMarker]; + CFx_Inv = new su2double[nMarker]; + CFy_Inv = new su2double[nMarker]; + CFz_Inv = new su2double[nMarker]; + + ForceViscous = new su2double[3]; + MomentViscous = new su2double[3]; + CDrag_Visc = new su2double[nMarker]; + CLift_Visc = new su2double[nMarker]; + CSideForce_Visc = new su2double[nMarker]; + CMx_Visc = new su2double[nMarker]; + CMy_Visc = new su2double[nMarker]; + CMz_Visc = new su2double[nMarker]; + CEff_Visc = new su2double[nMarker]; + CFx_Visc = new su2double[nMarker]; + CFy_Visc = new su2double[nMarker]; + CFz_Visc = new su2double[nMarker]; + + Surface_CLift_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CDrag_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CSideForce_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CEff_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CFx_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CFy_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CFz_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CMx_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CMy_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CMz_Inv = new su2double[config->GetnMarker_Monitoring()]; + Surface_CLift = new su2double[config->GetnMarker_Monitoring()]; + Surface_CDrag = new su2double[config->GetnMarker_Monitoring()]; + Surface_CSideForce = new su2double[config->GetnMarker_Monitoring()]; + Surface_CEff = new su2double[config->GetnMarker_Monitoring()]; + Surface_CFx = new su2double[config->GetnMarker_Monitoring()]; + Surface_CFy = new su2double[config->GetnMarker_Monitoring()]; + Surface_CFz = new su2double[config->GetnMarker_Monitoring()]; + Surface_CMx = new su2double[config->GetnMarker_Monitoring()]; + Surface_CMy = new su2double[config->GetnMarker_Monitoring()]; + Surface_CMz = new su2double[config->GetnMarker_Monitoring()]; + + Surface_CLift_Visc = new su2double[config->GetnMarker_Monitoring()]; + Surface_CDrag_Visc = new su2double[config->GetnMarker_Monitoring()]; + Surface_CSideForce_Visc = new su2double[config->GetnMarker_Monitoring()]; + Surface_CEff_Visc = new su2double[config->GetnMarker_Monitoring()]; + Surface_CFx_Visc = new su2double[config->GetnMarker_Monitoring()]; + Surface_CFy_Visc = new su2double[config->GetnMarker_Monitoring()]; + Surface_CFz_Visc = new su2double[config->GetnMarker_Monitoring()]; + Surface_CMx_Visc = new su2double[config->GetnMarker_Monitoring()]; + Surface_CMy_Visc = new su2double[config->GetnMarker_Monitoring()]; + Surface_CMz_Visc = new su2double[config->GetnMarker_Monitoring()]; + + /*--- Rotational coefficients ---*/ + + CMerit_Inv = new su2double[nMarker]; + CT_Inv = new su2double[nMarker]; + CQ_Inv = new su2double[nMarker]; + + CMerit_Visc = new su2double[nMarker]; + CT_Visc = new su2double[nMarker]; + CQ_Visc = new su2double[nMarker]; + + /*--- Heat based coefficients ---*/ + + Heat_Visc = new su2double[nMarker]; + MaxHeatFlux_Visc = new su2double[nMarker]; + + /*--- Supersonic coefficients ---*/ + + CEquivArea_Inv = new su2double[nMarker]; + CNearFieldOF_Inv = new su2double[nMarker]; + + /*--- Engine simulation ---*/ + + Inflow_MassFlow = new su2double[nMarker]; + Inflow_Pressure = new su2double[nMarker]; + Inflow_Mach = new su2double[nMarker]; + Inflow_Area = new su2double[nMarker]; + + Exhaust_MassFlow = new su2double[nMarker]; + Exhaust_Pressure = new su2double[nMarker]; + Exhaust_Temperature = new su2double[nMarker]; + Exhaust_Area = new su2double[nMarker]; + + Bleed_MassFlow = new su2double[nMarker]; + Bleed_Pressure = new su2double[nMarker]; + Bleed_Temperature = new su2double[nMarker]; + Bleed_Area = new su2double[nMarker]; + + /*--- Init total coefficients ---*/ + + Total_CDrag = 0.0; Total_CLift = 0.0; Total_CSideForce = 0.0; + Total_CMx = 0.0; Total_CMy = 0.0; Total_CMz = 0.0; + Total_CEff = 0.0; Total_CEquivArea = 0.0; Total_CNearFieldOF = 0.0; + Total_CFx = 0.0; Total_CFy = 0.0; Total_CFz = 0.0; + Total_CT = 0.0; Total_CQ = 0.0; Total_CMerit = 0.0; + Total_MaxHeat = 0.0; Total_Heat = 0.0; + Total_CpDiff = 0.0; Total_HeatFluxDiff = 0.0; + + /*--- Read farfield conditions from config ---*/ + + Density_Inf = config->GetDensity_FreeStreamND(); + Pressure_Inf = config->GetPressure_FreeStreamND(); + Velocity_Inf = config->GetVelocity_FreeStreamND(); + Energy_Inf = config->GetEnergy_FreeStreamND(); + Temperature_Inf = config->GetTemperature_FreeStreamND(); + Viscosity_Inf = config->GetViscosity_FreeStreamND(); + Mach_Inf = config->GetMach(); + Prandtl_Lam = config->GetPrandtl_Lam(); + Prandtl_Turb = config->GetPrandtl_Turb(); + Tke_Inf = config->GetTke_FreeStreamND(); + + /*--- Initialize the secondary values for direct derivative approxiations ---*/ + + switch(direct_diff){ + case NO_DERIVATIVE: + break; + case D_DENSITY: + SU2_TYPE::SetDerivative(Density_Inf, 1.0); + break; + case D_PRESSURE: + SU2_TYPE::SetDerivative(Pressure_Inf, 1.0); + break; + case D_TEMPERATURE: + SU2_TYPE::SetDerivative(Temperature_Inf, 1.0); + break; + case D_VISCOSITY: + SU2_TYPE::SetDerivative(Viscosity_Inf, 1.0); + break; + case D_MACH: case D_AOA: + case D_SIDESLIP: case D_REYNOLDS: + case D_TURB2LAM: case D_DESIGN: + /*--- Already done in postprocessing of config ---*/ + break; + default: + break; + } + + /*--- Initializate fan face pressure, fan face mach number, and mass flow rate ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + Inflow_MassFlow[iMarker] = 0.0; + Inflow_Mach[iMarker] = Mach_Inf; + Inflow_Pressure[iMarker] = Pressure_Inf; + Inflow_Area[iMarker] = 0.0; + + Exhaust_MassFlow[iMarker] = 0.0; + Exhaust_Temperature[iMarker] = Temperature_Inf; + Exhaust_Pressure[iMarker] = Pressure_Inf; + Exhaust_Area[iMarker] = 0.0; + + Bleed_MassFlow[iMarker] = 0.0; + Bleed_Temperature[iMarker] = Temperature_Inf; + Bleed_Pressure[iMarker] = Pressure_Inf; + Bleed_Area[iMarker] = 0.0; + } + + /*--- Initializate quantities for the mixing process*/ + + AveragedVelocity = new su2double* [nMarker]; + AveragedNormal = new su2double* [nMarker]; + AveragedGridVel = new su2double* [nMarker]; + AveragedFlux = new su2double* [nMarker]; + TotalFlux = new su2double* [nMarker]; + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + AveragedVelocity[iMarker] = new su2double [nDim]; + AveragedNormal[iMarker] = new su2double [nDim]; + AveragedGridVel[iMarker] = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) { + AveragedVelocity[iMarker][iDim] = 0.0; + AveragedNormal[iMarker][iDim] = 0.0; + AveragedGridVel[iMarker][iDim] = 0.0; + } + } + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + AveragedFlux[iMarker] = new su2double [nVar]; + TotalFlux[iMarker] = new su2double [nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + AveragedFlux[iMarker][iVar] = 0.0; + TotalFlux[iMarker][iVar] = 0.0; + } + } + + AveragedNormalVelocity = new su2double[nMarker]; + AveragedTangVelocity = new su2double[nMarker]; + ExtAveragedNormalVelocity = new su2double[nMarker]; + ExtAveragedTangVelocity = new su2double[nMarker]; + MassFlow= new su2double[nMarker]; + FlowAngle= new su2double[nMarker]; + AveragedEnthalpy = new su2double[nMarker]; + AveragedPressure = new su2double[nMarker]; + AveragedTotPressure = new su2double[nMarker]; + AveragedTotTemperature = new su2double[nMarker]; + ExtAveragedTotPressure = new su2double[nMarker]; + ExtAveragedTotTemperature = new su2double[nMarker]; + ExtAveragedPressure = new su2double[nMarker]; + AveragedDensity = new su2double[nMarker]; + ExtAveragedDensity = new su2double[nMarker]; + AveragedSoundSpeed= new su2double[nMarker]; + AveragedEntropy = new su2double[nMarker]; + AveragedTangGridVelocity = new su2double[nMarker]; + AveragedMach = new su2double[nMarker]; + AveragedNormalMach = new su2double[nMarker]; + AveragedTangMach = new su2double[nMarker]; + + + /*--- Initializate quantities for turboperformace ---*/ + + TotalStaticEfficiency = new su2double[nMarkerTurboPerf]; + TotalTotalEfficiency = new su2double[nMarkerTurboPerf]; + KineticEnergyLoss= new su2double[nMarkerTurboPerf]; + TotalPressureLoss= new su2double[nMarkerTurboPerf]; + MassFlowIn= new su2double[nMarkerTurboPerf]; + MassFlowOut= new su2double[nMarkerTurboPerf]; + FlowAngleIn= new su2double[nMarkerTurboPerf]; + FlowAngleOut= new su2double[nMarkerTurboPerf]; + EulerianWork= new su2double[nMarkerTurboPerf]; + TotalEnthalpyIn= new su2double[nMarkerTurboPerf]; + PressureRatio= new su2double[nMarkerTurboPerf]; + PressureOut= new su2double[nMarkerTurboPerf]; + EnthalpyOut= new su2double[nMarkerTurboPerf]; + MachIn= new su2double[nMarkerTurboPerf]; + MachOut= new su2double[nMarkerTurboPerf]; + NormalMachIn= new su2double[nMarkerTurboPerf]; + NormalMachOut= new su2double[nMarkerTurboPerf]; + VelocityOutIs= new su2double[nMarkerTurboPerf]; + + for (iMarker = 0; iMarker < nMarkerTurboPerf; iMarker++){ + TotalStaticEfficiency[iMarker]= 0.0; + TotalTotalEfficiency[iMarker]= 0.0; + KineticEnergyLoss[iMarker]= 0.0; + TotalPressureLoss[iMarker]= 0.0; + MassFlowIn[iMarker]= 0.0; + MassFlowOut[iMarker]= 0.0; + FlowAngleIn[iMarker]= 0.0; + FlowAngleOut[iMarker]= 0.0; + EulerianWork[iMarker]= 0.0; + TotalEnthalpyIn[iMarker]= 0.0; + PressureRatio[iMarker]= 0.0; + PressureOut[iMarker]= 0.0; + EnthalpyOut[iMarker]= 0.0; + MachIn[iMarker]= 0.0; + MachOut[iMarker]= 0.0; + NormalMachIn[iMarker]= 0.0; + NormalMachOut[iMarker]= 0.0; + VelocityOutIs[iMarker]= 0.0; + } + + + /*--- Initialize the cauchy critera array for fixed CL mode ---*/ + + if (config->GetFixed_CL_Mode()) + + Cauchy_Serie = new su2double [config->GetCauchy_Elems()+1]; + + /*--- Check for a restart and set up the variables at each node + appropriately. Coarse multigrid levels will be intitially set to + the farfield values bc the solver will immediately interpolate + the solution from the finest mesh to the coarser levels. ---*/ + + if (!restart || (iMesh != MESH_0)) { + + /*--- Restart the solution from the free-stream state ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint++) + node[iPoint] = new CNSVariable(Density_Inf, Velocity_Inf, Energy_Inf, nDim, nVar, config); + + } + + else { + + /*--- Modify file name for an unsteady restart ---*/ + + if (dual_time) { + + if (adjoint) { + Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_AdjointIter()) - 1; + } else if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_RestartIter())-1; + else + Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_RestartIter())-2; + + filename = config->GetUnsteady_FileName(filename, Unst_RestartIter); + + } + + if (nZone >1) + filename= config->GetRestart_FlowFileName(filename, iZone); + + /*--- Open the restart file, throw an error if this fails. ---*/ + + restart_file.open(filename.data(), ios::in); + if (restart_file.fail()) { + if (rank == MASTER_NODE) + cout << "There is no flow restart file!! " << filename.data() << "."<< endl; + exit(EXIT_FAILURE); + } + + /*--- In case this is a parallel simulation, we need to perform the + Global2Local index transformation first. ---*/ + + long *Global2Local = new long[geometry->GetGlobal_nPointDomain()]; + + /*--- First, set all indices to a negative value by default ---*/ + + for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) + Global2Local[iPoint] = -1; + + /*--- Now fill array with the transform values only for local points ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) + Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; + + /*--- Read all lines in the restart file ---*/ + + long iPoint_Local; + unsigned long iPoint_Global_Local = 0, iPoint_Global = 0; string text_line; + unsigned short rbuf_NotMatching = 0, sbuf_NotMatching = 0; + + /*--- The first line is the header ---*/ + + getline (restart_file, text_line); + + while (getline (restart_file, text_line)) { + istringstream point_line(text_line); + + /*--- Retrieve local index. If this node from the restart file lives + on a different processor, the value of iPoint_Local will be -1. + Otherwise, the local index for this node on the current processor + will be returned and used to instantiate the vars. ---*/ + + if (iPoint_Global >= geometry->GetGlobal_nPointDomain()) { sbuf_NotMatching = 1; break; } + + iPoint_Local = Global2Local[iPoint_Global]; + + /*--- Load the solution for this node. Note that the first entry + on the restart file line is the global index, followed by the + node coordinates, and then the conservative variables. ---*/ + + if (iPoint_Local >= 0) { + if (compressible) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3] >> Solution[4]; + } + if (incompressible) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; + } + if (freesurface) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1] >> Solution[2] >> Solution[3] >> Solution[4]; + } + node[iPoint_Local] = new CNSVariable(Solution, nDim, nVar, config); + iPoint_Global_Local++; + } + iPoint_Global++; + } + + /*--- Detect a wrong solution file ---*/ + + if (iPoint_Global_Local < nPointDomain) { sbuf_NotMatching = 1; } + +#ifndef HAVE_MPI + rbuf_NotMatching = sbuf_NotMatching; +#else + SU2_MPI::Allreduce(&sbuf_NotMatching, &rbuf_NotMatching, 1, MPI_UNSIGNED_SHORT, MPI_SUM, MPI_COMM_WORLD); +#endif + + if (rbuf_NotMatching != 0) { + if (rank == MASTER_NODE) { + cout << endl << "The solution file " << filename.data() << " doesn't match with the mesh file!" << endl; + cout << "It could be empty lines at the end of the file." << endl << endl; + } +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Barrier(MPI_COMM_WORLD); + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + } + + /*--- Instantiate the variable class with an arbitrary solution + at any halo/periodic nodes. The initial solution can be arbitrary, + because a send/recv is performed immediately in the solver. ---*/ + + for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) + node[iPoint] = new CNSVariable(Solution, nDim, nVar, config); + + /*--- Close the restart file ---*/ + + restart_file.close(); + + /*--- Free memory needed for the transformation ---*/ + + delete [] Global2Local; + + } + + /*--- Check that the initial solution is physical, report any non-physical nodes ---*/ + + if (compressible) { + + counter_local = 0; + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + + Density = node[iPoint]->GetSolution(0); + + Velocity2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Velocity2 += (node[iPoint]->GetSolution(iDim+1)/Density)*(node[iPoint]->GetSolution(iDim+1)/Density); + + StaticEnergy= node[iPoint]->GetSolution(nDim+1)/Density - 0.5*Velocity2; + + FluidModel->SetTDState_rhoe(Density, StaticEnergy); + Pressure= FluidModel->GetPressure(); + Temperature= FluidModel->GetTemperature(); + + /*--- Use the values at the infinity ---*/ + + if ((Pressure < 0.0) || (Density < 0.0) || (Temperature < 0.0)) { + Solution[0] = Density_Inf; + for (iDim = 0; iDim < nDim; iDim++) + Solution[iDim+1] = Velocity_Inf[iDim]*Density_Inf; + Solution[nDim+1] = Energy_Inf*Density_Inf; + node[iPoint]->SetSolution(Solution); + node[iPoint]->SetSolution_Old(Solution); + counter_local++; + } + + } + + /*--- Warning message about non-physical points ---*/ + + if (config->GetConsole_Output_Verb() == VERB_HIGH) { +#ifdef HAVE_MPI + SU2_MPI::Reduce(&counter_local, &counter_global, 1, MPI_UNSIGNED_LONG, MPI_SUM, MASTER_NODE, MPI_COMM_WORLD); +#else + counter_global = counter_local; +#endif + if ((rank == MASTER_NODE) && (counter_global != 0)) + cout << "Warning. The original solution contains "<< counter_global << " points that are not physical." << endl; + } + + } + + /*--- For incompressible solver set the initial values for the density and viscosity, + unless a freesurface problem, this must be constant during the computation ---*/ + + if (incompressible || freesurface) { + for (iPoint = 0; iPoint < nPoint; iPoint++) { + node[iPoint]->SetDensityInc(Density_Inf); + node[iPoint]->SetLaminarViscosityInc(Viscosity_Inf); + } + } + + /*--- Define solver parameters needed for execution of destructor ---*/ + + if (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED) space_centered = true; + else space_centered = false; + + if (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT) euler_implicit = true; + else euler_implicit = false; + + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) least_squares = true; + else least_squares = false; + + /*--- Perform the MPI communication of the solution ---*/ + + Set_MPI_Solution(geometry, config); + +} + +CNSSolver::~CNSSolver(void) { + unsigned short iMarker; + + if (CDrag_Visc != NULL) delete [] CDrag_Visc; + if (CLift_Visc != NULL) delete [] CLift_Visc; + if (CSideForce_Visc != NULL) delete [] CSideForce_Visc; + if (CMx_Visc != NULL) delete [] CMx_Visc; + if (CMy_Visc != NULL) delete [] CMy_Visc; + if (CMz_Visc != NULL) delete [] CMz_Visc; + if (CFx_Visc != NULL) delete [] CFx_Visc; + if (CFy_Visc != NULL) delete [] CFy_Visc; + if (CFz_Visc != NULL) delete [] CFz_Visc; + if (CEff_Visc != NULL) delete [] CEff_Visc; + if (CMerit_Visc != NULL) delete [] CMerit_Visc; + if (CT_Visc != NULL) delete [] CT_Visc; + if (CQ_Visc != NULL) delete [] CQ_Visc; + if (Heat_Visc != NULL) delete [] Heat_Visc; + if (MaxHeatFlux_Visc != NULL) delete [] MaxHeatFlux_Visc; + if (ForceViscous != NULL) delete [] ForceViscous; + if (MomentViscous != NULL) delete [] MomentViscous; + + + if (Surface_CLift_Visc != NULL) delete [] Surface_CLift_Visc; + if (Surface_CDrag_Visc != NULL) delete [] Surface_CDrag_Visc; + if (Surface_CSideForce_Visc != NULL) delete [] Surface_CSideForce_Visc; + if (Surface_CEff_Visc != NULL) delete [] Surface_CEff_Visc; + if (Surface_CFx_Visc != NULL) delete [] Surface_CFx_Visc; + if (Surface_CFy_Visc != NULL) delete [] Surface_CFy_Visc; + if (Surface_CFz_Visc != NULL) delete [] Surface_CFz_Visc; + if (Surface_CMx_Visc != NULL) delete [] Surface_CMx_Visc; + if (Surface_CMy_Visc != NULL) delete [] Surface_CMy_Visc; + if (Surface_CMz_Visc != NULL) delete [] Surface_CMz_Visc; + + if (Cauchy_Serie != NULL) delete [] Cauchy_Serie; + + if (CSkinFriction != NULL) { + for (iMarker = 0; iMarker < nMarker; iMarker++) { + delete CSkinFriction[iMarker]; + } + delete [] CSkinFriction; + } + +} + +void CNSSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { + + unsigned long iPoint, ErrorCounter = 0; + su2double StrainMag = 0.0, Omega = 0.0, *Vorticity; + +#ifdef HAVE_MPI + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + unsigned long ExtIter = config->GetExtIter(); + bool adjoint = config->GetAdjoint(); + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool center = (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED) || (adjoint && config->GetKind_ConvNumScheme_AdjFlow() == SPACE_CENTERED); + bool center_jst = center && config->GetKind_Centered_Flow() == JST; + bool limiter_flow = ((config->GetSpatialOrder_Flow() == SECOND_ORDER_LIMITER) && (ExtIter <= config->GetLimiterIter())); + bool limiter_turb = ((config->GetSpatialOrder_Turb() == SECOND_ORDER_LIMITER) && (ExtIter <= config->GetLimiterIter())); + bool limiter_adjflow = ((config->GetSpatialOrder_AdjFlow() == SECOND_ORDER_LIMITER) && (ExtIter <= config->GetLimiterIter())); + bool limiter_visc = config->GetViscous_Limiter_Flow(); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool fixed_cl = config->GetFixed_CL_Mode(); + bool engine = ((config->GetnMarker_EngineInflow() != 0) || (config->GetnMarker_EngineBleed() != 0) || (config->GetnMarker_EngineExhaust() != 0)); + bool actuator_disk = ((config->GetnMarker_ActDisk_Inlet() != 0) || (config->GetnMarker_ActDisk_Outlet() != 0)); + + /*--- Compute the engine properties ---*/ + + if (engine) { GetEngine_Properties(geometry, config, iMesh, Output); } + + /*--- Compute the actuator disk properties ---*/ + + if (actuator_disk) { GetActuatorDisk_Properties(geometry, config, iMesh, Output); } + + /*--- Update the angle of attack at the far-field for fixed CL calculations. ---*/ + + if (fixed_cl) { SetFarfield_AoA(geometry, solver_container, config, iMesh, Output); } + + /*--- Compute distance function to zero level set ---*/ + + if (freesurface) { SetFreeSurface_Distance(geometry, config); } + + /*--- Set the primitive variables ---*/ + + ErrorCounter = SetPrimitive_Variables(solver_container, config, Output); + + /*--- Artificial dissipation ---*/ + + if (center && !Output) { + SetMax_Eigenvalue(geometry, config); + if ((center_jst) && (iMesh == MESH_0)) { + SetDissipation_Switch(geometry, config); + SetUndivided_Laplacian(geometry, config); + } + } + + /*--- Compute gradient of the primitive variables ---*/ + + if (config->GetKind_Gradient_Method() == GREEN_GAUSS) { + SetPrimitive_Gradient_GG(geometry, config); + // if (compressible && !ideal_gas) SetSecondary_Gradient_GG(geometry, config); + } + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { + SetPrimitive_Gradient_LS(geometry, config); + // if (compressible && !ideal_gas) SetSecondary_Gradient_LS(geometry, config); + } + + /*--- Compute the limiter in case we need it in the turbulence model + or to limit the viscous terms (check this logic with JST and 2nd order turbulence model) ---*/ + + if ((iMesh == MESH_0) && (limiter_flow || limiter_turb || limiter_adjflow || limiter_visc) && !Output) { SetPrimitive_Limiter(geometry, config); + // if (compressible && !ideal_gas) SetSecondary_Limiter(geometry, config); + } + + /*--- Evaluate the vorticity and strain rate magnitude ---*/ + + StrainMag_Max = 0.0, Omega_Max = 0.0; + for (iPoint = 0; iPoint < nPoint; iPoint++) { + + solver_container[FLOW_SOL]->node[iPoint]->SetVorticity(limiter_visc); + solver_container[FLOW_SOL]->node[iPoint]->SetStrainMag(limiter_visc); + + StrainMag = solver_container[FLOW_SOL]->node[iPoint]->GetStrainMag(); + Vorticity = solver_container[FLOW_SOL]->node[iPoint]->GetVorticity(); + Omega = sqrt(Vorticity[0]*Vorticity[0]+ Vorticity[1]*Vorticity[1]+ Vorticity[2]*Vorticity[2]); + + StrainMag_Max = max(StrainMag_Max, StrainMag); + Omega_Max = max(Omega_Max, Omega); + + } + + /*--- Initialize the Jacobian matrices ---*/ + + if (implicit && !config->GetDiscrete_Adjoint()) Jacobian.SetValZero(); + + /*--- Error message ---*/ + + if (config->GetConsole_Output_Verb() == VERB_HIGH) { + +#ifdef HAVE_MPI + unsigned long MyErrorCounter = ErrorCounter; ErrorCounter = 0; + su2double MyOmega_Max = Omega_Max; Omega_Max = 0.0; + su2double MyStrainMag_Max = StrainMag_Max; StrainMag_Max = 0.0; + + SU2_MPI::Allreduce(&MyErrorCounter, &ErrorCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyStrainMag_Max, &StrainMag_Max, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyOmega_Max, &Omega_Max, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); +#endif + + if (iMesh == MESH_0) { + config->SetNonphysical_Points(ErrorCounter); + solver_container[FLOW_SOL]->SetStrainMag_Max(StrainMag_Max); + solver_container[FLOW_SOL]->SetOmega_Max(Omega_Max); + } + + } + +} + +unsigned long CNSSolver::SetPrimitive_Variables(CSolver **solver_container, CConfig *config, bool Output) { + + unsigned long iPoint, ErrorCounter = 0; + su2double eddy_visc = 0.0, turb_ke = 0.0; + unsigned short turb_model = config->GetKind_Turb_Model(); + bool RightSol = true; + + bool tkeNeeded = (turb_model == SST); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + + for (iPoint = 0; iPoint < nPoint; iPoint ++) { + + /*--- Retrieve the value of the kinetic energy (if need it) ---*/ + + if (turb_model != NONE) { + eddy_visc = solver_container[TURB_SOL]->node[iPoint]->GetmuT(); + if (tkeNeeded) turb_ke = solver_container[TURB_SOL]->node[iPoint]->GetSolution(0); + } + + /*--- Initialize the non-physical points vector ---*/ + + node[iPoint]->SetNon_Physical(false); + + /*--- Incompressible flow, primitive variables nDim+3, (P, vx, vy, vz, rho, beta), + FreeSurface Incompressible flow, primitive variables nDim+4, (P, vx, vy, vz, rho, beta, dist), + Compressible flow, primitive variables nDim+5, (T, vx, vy, vz, P, rho, h, c, lamMu, eddyMu, ThCond, Cp) ---*/ + + if (compressible) { + RightSol = node[iPoint]->SetPrimVar_Compressible(eddy_visc, turb_ke, FluidModel); + node[iPoint]->SetSecondaryVar_Compressible(FluidModel); + } + + if (incompressible){ + RightSol = node[iPoint]->SetPrimVar_Incompressible(Density_Inf, Viscosity_Inf, eddy_visc, turb_ke, config); + } + + if (freesurface){ + RightSol = node[iPoint]->SetPrimVar_FreeSurface(eddy_visc, turb_ke, config); + } + + if (!RightSol) { node[iPoint]->SetNon_Physical(true); ErrorCounter++; } + + /*--- Initialize the convective, source and viscous residual vector ---*/ + + if (!Output) LinSysRes.SetBlock_Zero(iPoint); + + } + + return ErrorCounter; +} + +void CNSSolver::SetTime_Step(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned long Iteration) { + + su2double Mean_BetaInc2, *Normal, Area, Vol, Mean_SoundSpeed = 0.0, Mean_ProjVel = 0.0, Lambda, Local_Delta_Time, Local_Delta_Time_Visc, Mean_DensityInc, + Global_Delta_Time = 1E6, Mean_LaminarVisc = 0.0, Mean_EddyVisc = 0.0, Mean_Density = 0.0, Lambda_1, Lambda_2, K_v = 0.25, Global_Delta_UnstTimeND; + unsigned long iEdge, iVertex, iPoint = 0, jPoint = 0; + unsigned short iDim, iMarker; + su2double ProjVel, ProjVel_i, ProjVel_j; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool grid_movement = config->GetGrid_Movement(); + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + + Min_Delta_Time = 1.E6; Max_Delta_Time = 0.0; + + /*--- Set maximum inviscid eigenvalue to zero, and compute sound speed and viscosity ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + node[iPoint]->SetMax_Lambda_Inv(0.0); + node[iPoint]->SetMax_Lambda_Visc(0.0); + } + + /*--- Loop interior edges ---*/ + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Point identification, Normal vector and area ---*/ + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + + Normal = geometry->edge[iEdge]->GetNormal(); + Area = 0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); + + /*--- Mean Values ---*/ + + if (compressible) { + Mean_ProjVel = 0.5 * (node[iPoint]->GetProjVel(Normal) + node[jPoint]->GetProjVel(Normal)); + Mean_SoundSpeed = 0.5 * (node[iPoint]->GetSoundSpeed() + node[jPoint]->GetSoundSpeed()) * Area; + } + if (incompressible || freesurface) { + Mean_ProjVel = 0.5 * (node[iPoint]->GetProjVel(Normal) + node[jPoint]->GetProjVel(Normal)); + Mean_BetaInc2 = 0.5 * (node[iPoint]->GetBetaInc2() + node[jPoint]->GetBetaInc2()); + Mean_DensityInc = 0.5 * (node[iPoint]->GetDensityInc() + node[jPoint]->GetDensityInc()); + Mean_SoundSpeed = sqrt(Mean_ProjVel*Mean_ProjVel + (Mean_BetaInc2/Mean_DensityInc)*Area*Area); + } + + /*--- Adjustment for grid movement ---*/ + + if (grid_movement) { + su2double *GridVel_i = geometry->node[iPoint]->GetGridVel(); + su2double *GridVel_j = geometry->node[jPoint]->GetGridVel(); + ProjVel_i = 0.0; ProjVel_j =0.0; + for (iDim = 0; iDim < nDim; iDim++) { + ProjVel_i += GridVel_i[iDim]*Normal[iDim]; + ProjVel_j += GridVel_j[iDim]*Normal[iDim]; + } + Mean_ProjVel -= 0.5 * (ProjVel_i + ProjVel_j) ; + } + + /*--- Inviscid contribution ---*/ + + Lambda = fabs(Mean_ProjVel) + Mean_SoundSpeed ; + if (geometry->node[iPoint]->GetDomain()) node[iPoint]->AddMax_Lambda_Inv(Lambda); + if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddMax_Lambda_Inv(Lambda); + + /*--- Viscous contribution ---*/ + + if (compressible) { + Mean_LaminarVisc = 0.5*(node[iPoint]->GetLaminarViscosity() + node[jPoint]->GetLaminarViscosity()); + Mean_EddyVisc = 0.5*(node[iPoint]->GetEddyViscosity() + node[jPoint]->GetEddyViscosity()); + Mean_Density = 0.5*(node[iPoint]->GetSolution(0) + node[jPoint]->GetSolution(0)); + } + if (incompressible || freesurface) { + Mean_LaminarVisc = 0.5*(node[iPoint]->GetLaminarViscosityInc() + node[jPoint]->GetLaminarViscosityInc()); + Mean_EddyVisc = 0.5*(node[iPoint]->GetEddyViscosityInc() + node[jPoint]->GetEddyViscosityInc()); + Mean_Density = 0.5*(node[iPoint]->GetDensityInc() + node[jPoint]->GetDensityInc()); + } + + Lambda_1 = (4.0/3.0)*(Mean_LaminarVisc + Mean_EddyVisc); + //TODO (REAL_GAS) removing Gamma it cannot work with FLUIDPROP + Lambda_2 = (1.0 + (Prandtl_Lam/Prandtl_Turb)*(Mean_EddyVisc/Mean_LaminarVisc))*(Gamma*Mean_LaminarVisc/Prandtl_Lam); + Lambda = (Lambda_1 + Lambda_2)*Area*Area/Mean_Density; + + if (geometry->node[iPoint]->GetDomain()) node[iPoint]->AddMax_Lambda_Visc(Lambda); + if (geometry->node[jPoint]->GetDomain()) node[jPoint]->AddMax_Lambda_Visc(Lambda); + + } + + /*--- Loop boundary edges ---*/ + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + + /*--- Point identification, Normal vector and area ---*/ + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); + + /*--- Mean Values ---*/ + + if (compressible) { + Mean_ProjVel = node[iPoint]->GetProjVel(Normal); + Mean_SoundSpeed = node[iPoint]->GetSoundSpeed() * Area; + } + if (incompressible || freesurface) { + Mean_ProjVel = node[iPoint]->GetProjVel(Normal); + Mean_BetaInc2 = node[iPoint]->GetBetaInc2(); + Mean_DensityInc = node[iPoint]->GetDensityInc(); + Mean_SoundSpeed = sqrt(Mean_ProjVel*Mean_ProjVel + (Mean_BetaInc2/Mean_DensityInc)*Area*Area); + } + + /*--- Adjustment for grid movement ---*/ + + if (grid_movement) { + su2double *GridVel = geometry->node[iPoint]->GetGridVel(); + ProjVel = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + ProjVel += GridVel[iDim]*Normal[iDim]; + Mean_ProjVel -= ProjVel; + } + + /*--- Inviscid contribution ---*/ + + Lambda = fabs(Mean_ProjVel) + Mean_SoundSpeed; + if (geometry->node[iPoint]->GetDomain()) { + node[iPoint]->AddMax_Lambda_Inv(Lambda); + } + + /*--- Viscous contribution ---*/ + + if (compressible) { + Mean_LaminarVisc = node[iPoint]->GetLaminarViscosity(); + Mean_EddyVisc = node[iPoint]->GetEddyViscosity(); + Mean_Density = node[iPoint]->GetSolution(0); + } + if (incompressible || freesurface) { + Mean_LaminarVisc = 0.5*(node[iPoint]->GetLaminarViscosityInc() + node[jPoint]->GetLaminarViscosityInc()); + Mean_EddyVisc = 0.5*(node[iPoint]->GetEddyViscosityInc() + node[jPoint]->GetEddyViscosityInc()); + Mean_Density = 0.5*(node[iPoint]->GetDensityInc() + node[jPoint]->GetDensityInc()); + } + + Lambda_1 = (4.0/3.0)*(Mean_LaminarVisc + Mean_EddyVisc); + Lambda_2 = (1.0 + (Prandtl_Lam/Prandtl_Turb)*(Mean_EddyVisc/Mean_LaminarVisc))*(Gamma*Mean_LaminarVisc/Prandtl_Lam); + Lambda = (Lambda_1 + Lambda_2)*Area*Area/Mean_Density; + + if (geometry->node[iPoint]->GetDomain()) node[iPoint]->AddMax_Lambda_Visc(Lambda); + + } + } + + /*--- Each element uses their own speed, steady state simulation ---*/ + + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + Vol = geometry->node[iPoint]->GetVolume(); + + if (Vol != 0.0) { + Local_Delta_Time = config->GetCFL(iMesh)*Vol / node[iPoint]->GetMax_Lambda_Inv(); + Local_Delta_Time_Visc = config->GetCFL(iMesh)*K_v*Vol*Vol/ node[iPoint]->GetMax_Lambda_Visc(); + Local_Delta_Time = min(Local_Delta_Time, Local_Delta_Time_Visc); + Global_Delta_Time = min(Global_Delta_Time, Local_Delta_Time); + Min_Delta_Time = min(Min_Delta_Time, Local_Delta_Time); + Max_Delta_Time = max(Max_Delta_Time, Local_Delta_Time); + if (Local_Delta_Time > config->GetMax_DeltaTime()) + Local_Delta_Time = config->GetMax_DeltaTime(); + node[iPoint]->SetDelta_Time(Local_Delta_Time); + } + else { + node[iPoint]->SetDelta_Time(0.0); + } + + } + + + /*--- Compute the max and the min dt (in parallel) ---*/ + if (config->GetConsole_Output_Verb() == VERB_HIGH) { +#ifdef HAVE_MPI + su2double rbuf_time, sbuf_time; + sbuf_time = Min_Delta_Time; + SU2_MPI::Reduce(&sbuf_time, &rbuf_time, 1, MPI_DOUBLE, MPI_MIN, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Bcast(&rbuf_time, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + Min_Delta_Time = rbuf_time; + + sbuf_time = Max_Delta_Time; + SU2_MPI::Reduce(&sbuf_time, &rbuf_time, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Bcast(&rbuf_time, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + Max_Delta_Time = rbuf_time; +#endif + } + + /*--- For exact time solution use the minimum delta time of the whole mesh ---*/ + if (config->GetUnsteady_Simulation() == TIME_STEPPING) { +#ifdef HAVE_MPI + su2double rbuf_time, sbuf_time; + sbuf_time = Global_Delta_Time; + SU2_MPI::Reduce(&sbuf_time, &rbuf_time, 1, MPI_DOUBLE, MPI_MIN, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Bcast(&rbuf_time, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + Global_Delta_Time = rbuf_time; +#endif + for (iPoint = 0; iPoint < nPointDomain; iPoint++) + node[iPoint]->SetDelta_Time(Global_Delta_Time); + } + + /*--- Recompute the unsteady time step for the dual time strategy + if the unsteady CFL is diferent from 0 ---*/ + if ((dual_time) && (Iteration == 0) && (config->GetUnst_CFL() != 0.0) && (iMesh == MESH_0)) { + Global_Delta_UnstTimeND = config->GetUnst_CFL()*Global_Delta_Time/config->GetCFL(iMesh); + +#ifdef HAVE_MPI + su2double rbuf_time, sbuf_time; + sbuf_time = Global_Delta_UnstTimeND; + SU2_MPI::Reduce(&sbuf_time, &rbuf_time, 1, MPI_DOUBLE, MPI_MIN, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Bcast(&rbuf_time, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + Global_Delta_UnstTimeND = rbuf_time; +#endif + config->SetDelta_UnstTimeND(Global_Delta_UnstTimeND); + } + + /*--- The pseudo local time (explicit integration) cannot be greater than the physical time ---*/ + if (dual_time) + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + if (!implicit) { + Local_Delta_Time = min((2.0/3.0)*config->GetDelta_UnstTimeND(), node[iPoint]->GetDelta_Time()); + node[iPoint]->SetDelta_Time(Local_Delta_Time); + } + } + +} + +void CNSSolver::Viscous_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config, unsigned short iMesh, unsigned short iRKStep) { + + unsigned long iPoint, jPoint, iEdge; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Points, coordinates and normal vector in edge ---*/ + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[jPoint]->GetCoord()); + numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); + + /*--- Primitive and secondary variables ---*/ + + numerics->SetPrimitive(node[iPoint]->GetPrimitive(), node[jPoint]->GetPrimitive()); + numerics->SetSecondary(node[iPoint]->GetSecondary(), node[jPoint]->GetSecondary()); + + /*--- Gradient and limiters ---*/ + + numerics->SetPrimVarGradient(node[iPoint]->GetGradient_Primitive(), node[jPoint]->GetGradient_Primitive()); + numerics->SetPrimVarLimiter(node[iPoint]->GetLimiter_Primitive(), node[jPoint]->GetLimiter_Primitive()); + + /*--- Turbulent kinetic energy ---*/ + + if (config->GetKind_Turb_Model() == SST) + numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->node[iPoint]->GetSolution(0), + solver_container[TURB_SOL]->node[jPoint]->GetSolution(0)); + + /*--- Compute and update residual ---*/ + + numerics->ComputeResidual(Res_Visc, Jacobian_i, Jacobian_j, config); + + LinSysRes.SubtractBlock(iPoint, Res_Visc); + LinSysRes.AddBlock(jPoint, Res_Visc); + + /*--- Implicit part ---*/ + + if (implicit) { + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + Jacobian.SubtractBlock(iPoint, jPoint, Jacobian_j); + Jacobian.AddBlock(jPoint, iPoint, Jacobian_i); + Jacobian.AddBlock(jPoint, jPoint, Jacobian_j); + } + + } + +} + +void CNSSolver::Viscous_Forces(CGeometry *geometry, CConfig *config) { + + unsigned long iVertex, iPoint, iPointNormal; + unsigned short Boundary, Monitoring, iMarker, iMarker_Monitoring, iDim, jDim; + su2double Viscosity = 0.0, div_vel, *Normal, MomentDist[3] = {0.0, 0.0, 0.0}, WallDist[3] = {0.0, 0.0, 0.0}, + *Coord, *Coord_Normal, Area, WallShearStress, TauNormal, factor, RefTemp, RefVel2, + RefDensity, GradTemperature, Density = 0.0, WallDistMod, FrictionVel, + Mach2Vel, Mach_Motion, UnitNormal[3] = {0.0, 0.0, 0.0}, TauElem[3] = {0.0, 0.0, 0.0}, TauTangent[3] = {0.0, 0.0, 0.0}, + Tau[3][3] = {{0.0, 0.0, 0.0},{0.0, 0.0, 0.0},{0.0, 0.0, 0.0}}, Force[3] = {0.0, 0.0, 0.0}, Cp, thermal_conductivity, MaxNorm = 8.0, + Grad_Vel[3][3] = {{0.0, 0.0, 0.0},{0.0, 0.0, 0.0},{0.0, 0.0, 0.0}}, Grad_Temp[3] = {0.0, 0.0, 0.0}, + delta[3][3] = {{1.0, 0.0, 0.0},{0.0,1.0,0.0},{0.0,0.0,1.0}}; + +#ifdef HAVE_MPI + su2double MyAllBound_CDrag_Visc, MyAllBound_CLift_Visc, MyAllBound_CSideForce_Visc, MyAllBound_CMx_Visc, MyAllBound_CMy_Visc, MyAllBound_CMz_Visc, MyAllBound_CFx_Visc, MyAllBound_CFy_Visc, MyAllBound_CFz_Visc, MyAllBound_CT_Visc, MyAllBound_CQ_Visc, MyAllBound_HeatFlux_Visc, MyAllBound_MaxHeatFlux_Visc, *MySurface_CLift_Visc = NULL, *MySurface_CDrag_Visc = NULL, *MySurface_CSideForce_Visc = NULL, *MySurface_CEff_Visc = NULL, *MySurface_CFx_Visc = NULL, *MySurface_CFy_Visc = NULL, *MySurface_CFz_Visc = NULL, *MySurface_CMx_Visc = NULL, *MySurface_CMy_Visc = NULL, *MySurface_CMz_Visc = NULL; +#endif + + string Marker_Tag, Monitoring_Tag; + + su2double Alpha = config->GetAoA()*PI_NUMBER/180.0; + su2double Beta = config->GetAoS()*PI_NUMBER/180.0; + su2double RefAreaCoeff = config->GetRefAreaCoeff(); + su2double RefLengthMoment = config->GetRefLengthMoment(); + su2double Gas_Constant = config->GetGas_ConstantND(); + su2double *Origin = config->GetRefOriginMoment(0); + bool grid_movement = config->GetGrid_Movement(); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + su2double Prandtl_Lam = config->GetPrandtl_Lam(); + + /*--- 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 (grid_movement) { + 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]; + } + + factor = 1.0 / (0.5*RefDensity*RefAreaCoeff*RefVel2); + + /*--- Variables initialization ---*/ + + AllBound_CDrag_Visc = 0.0; AllBound_CLift_Visc = 0.0; AllBound_CSideForce_Visc = 0.0; + AllBound_CMx_Visc = 0.0; AllBound_CMy_Visc = 0.0; AllBound_CMz_Visc = 0.0; + AllBound_CFx_Visc = 0.0; AllBound_CFy_Visc = 0.0; AllBound_CFz_Visc = 0.0; + AllBound_CT_Visc = 0.0; AllBound_CQ_Visc = 0.0; AllBound_CMerit_Visc = 0.0; + AllBound_HeatFlux_Visc = 0.0; AllBound_MaxHeatFlux_Visc = 0.0; AllBound_CEff_Visc = 0.0; + + for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { + Surface_CLift_Visc[iMarker_Monitoring] = 0.0; Surface_CDrag_Visc[iMarker_Monitoring] = 0.0; + Surface_CSideForce_Visc[iMarker_Monitoring] = 0.0; Surface_CEff_Visc[iMarker_Monitoring] = 0.0; + Surface_CFx_Visc[iMarker_Monitoring] = 0.0; Surface_CFy_Visc[iMarker_Monitoring] = 0.0; + Surface_CFz_Visc[iMarker_Monitoring] = 0.0; Surface_CMx_Visc[iMarker_Monitoring] = 0.0; + Surface_CMy_Visc[iMarker_Monitoring] = 0.0; Surface_CMz_Visc[iMarker_Monitoring] = 0.0; + } + + /*--- Loop over the Navier-Stokes markers ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + Boundary = config->GetMarker_All_KindBC(iMarker); + Monitoring = config->GetMarker_All_Monitoring(iMarker); + + /*--- Obtain the origin for the moment computation for a particular marker ---*/ + + if (Monitoring == YES) { + for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { + Monitoring_Tag = config->GetMarker_Monitoring(iMarker_Monitoring); + Marker_Tag = config->GetMarker_All_TagBound(iMarker); + if (Marker_Tag == Monitoring_Tag) + Origin = config->GetRefOriginMoment(iMarker_Monitoring); + } + } + + if ((Boundary == HEAT_FLUX) || (Boundary == ISOTHERMAL)) { + + /*--- Forces initialization at each Marker ---*/ + + CDrag_Visc[iMarker] = 0.0; CLift_Visc[iMarker] = 0.0; CSideForce_Visc[iMarker] = 0.0; + CMx_Visc[iMarker] = 0.0; CMy_Visc[iMarker] = 0.0; CMz_Visc[iMarker] = 0.0; + CFx_Visc[iMarker] = 0.0; CFy_Visc[iMarker] = 0.0; CFz_Visc[iMarker] = 0.0; + CT_Visc[iMarker] = 0.0; CQ_Visc[iMarker] = 0.0; CMerit_Visc[iMarker] = 0.0; + Heat_Visc[iMarker] = 0.0; MaxHeatFlux_Visc[iMarker] = 0.0; CEff_Visc[iMarker] = 0.0; + + for (iDim = 0; iDim < nDim; iDim++) ForceViscous[iDim] = 0.0; + MomentViscous[0] = 0.0; MomentViscous[1] = 0.0; MomentViscous[2] = 0.0; + + /*--- Loop over the vertices to compute the forces ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + iPointNormal = geometry->vertex[iMarker][iVertex]->GetNormal_Neighbor(); + + Coord = geometry->node[iPoint]->GetCoord(); + Coord_Normal = geometry->node[iPointNormal]->GetCoord(); + + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + + for (iDim = 0; iDim < nDim; iDim++) { + for (jDim = 0 ; jDim < nDim; jDim++) { + Grad_Vel[iDim][jDim] = node[iPoint]->GetGradient_Primitive(iDim+1, jDim); + } + Grad_Temp[iDim] = node[iPoint]->GetGradient_Primitive(0, iDim); + } + + if (compressible) { + Viscosity = node[iPoint]->GetLaminarViscosity(); + Density = node[iPoint]->GetDensity(); + } + if (incompressible || freesurface) { + Viscosity = node[iPoint]->GetLaminarViscosityInc(); + Density = node[iPoint]->GetDensityInc(); + } + + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); + for (iDim = 0; iDim < nDim; iDim++) { + UnitNormal[iDim] = Normal[iDim]/Area; + MomentDist[iDim] = Coord[iDim] - Origin[iDim]; + } + + /*--- Evaluate Tau ---*/ + + div_vel = 0.0; for (iDim = 0; iDim < nDim; iDim++) div_vel += Grad_Vel[iDim][iDim]; + + for (iDim = 0; iDim < nDim; iDim++) { + for (jDim = 0 ; jDim < nDim; jDim++) { + Tau[iDim][jDim] = Viscosity*(Grad_Vel[jDim][iDim] + Grad_Vel[iDim][jDim]) - TWO3*Viscosity*div_vel*delta[iDim][jDim]; + } + } + + /*--- Project Tau in each surface element ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + TauElem[iDim] = 0.0; + for (jDim = 0; jDim < nDim; jDim++) { + TauElem[iDim] += Tau[iDim][jDim]*UnitNormal[jDim]; + } + } + + /*--- Compute wall shear stress (using the stress tensor) ---*/ + + 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); + + for (iDim = 0; iDim < nDim; iDim++) WallDist[iDim] = (Coord[iDim] - Coord_Normal[iDim]); + WallDistMod = 0.0; for (iDim = 0; iDim < nDim; iDim++) WallDistMod += WallDist[iDim]*WallDist[iDim]; WallDistMod = sqrt(WallDistMod); + + /*--- Compute wall skin friction coefficient, and heat flux on the wall ---*/ + + CSkinFriction[iMarker][iVertex] = WallShearStress / (0.5*RefDensity*RefVel2); + + /*--- Compute y+ and non-dimensional velocity ---*/ + + FrictionVel = sqrt(fabs(WallShearStress)/Density); + YPlus[iMarker][iVertex] = WallDistMod*FrictionVel/(Viscosity/Density); + + /*--- Compute total and maximum heat flux on the wall ---*/ + + if (compressible) { + + GradTemperature = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + GradTemperature -= Grad_Temp[iDim]*UnitNormal[iDim]; + + Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; + thermal_conductivity = Cp * Viscosity/Prandtl_Lam; + HeatFlux[iMarker][iVertex] = -thermal_conductivity*GradTemperature; + Heat_Visc[iMarker] += HeatFlux[iMarker][iVertex]*Area; + MaxHeatFlux_Visc[iMarker] += pow(HeatFlux[iMarker][iVertex], MaxNorm); + + } + + /*--- Note that y+, and heat are computed at the + halo cells (for visualization purposes), but not the forces ---*/ + + if ((geometry->node[iPoint]->GetDomain()) && (Monitoring == YES)) { + + /*--- Force computation ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + Force[iDim] = TauElem[iDim]*Area*factor; + ForceViscous[iDim] += Force[iDim]; + } + + /*--- Moment with respect to the reference axis ---*/ + + if (iDim == 3) { + MomentViscous[0] += (Force[2]*MomentDist[1] - Force[1]*MomentDist[2])/RefLengthMoment; + MomentViscous[1] += (Force[0]*MomentDist[2] - Force[2]*MomentDist[0])/RefLengthMoment; + } + MomentViscous[2] += (Force[1]*MomentDist[0] - Force[0]*MomentDist[1])/RefLengthMoment; + + } + + } + + /*--- Project forces and store the non-dimensional coefficients ---*/ + + if (Monitoring == YES) { + if (nDim == 2) { + CDrag_Visc[iMarker] = ForceViscous[0]*cos(Alpha) + ForceViscous[1]*sin(Alpha); + CLift_Visc[iMarker] = -ForceViscous[0]*sin(Alpha) + ForceViscous[1]*cos(Alpha); + CEff_Visc[iMarker] = CLift_Visc[iMarker] / (CDrag_Visc[iMarker]+EPS); + CMz_Visc[iMarker] = MomentViscous[2]; + CFx_Visc[iMarker] = ForceViscous[0]; + CFy_Visc[iMarker] = ForceViscous[1]; + CT_Visc[iMarker] = -CFx_Visc[iMarker]; + CQ_Visc[iMarker] = -CMz_Visc[iMarker]; + CMerit_Visc[iMarker] = CT_Visc[iMarker] / (CQ_Visc[iMarker]+EPS); + MaxHeatFlux_Visc[iMarker] = pow(MaxHeatFlux_Visc[iMarker], 1.0/MaxNorm); + } + if (nDim == 3) { + CDrag_Visc[iMarker] = ForceViscous[0]*cos(Alpha)*cos(Beta) + ForceViscous[1]*sin(Beta) + ForceViscous[2]*sin(Alpha)*cos(Beta); + CLift_Visc[iMarker] = -ForceViscous[0]*sin(Alpha) + ForceViscous[2]*cos(Alpha); + CSideForce_Visc[iMarker] = -ForceViscous[0]*sin(Beta)*cos(Alpha) + ForceViscous[1]*cos(Beta) - ForceViscous[2]*sin(Beta)*sin(Alpha); + CEff_Visc[iMarker] = CLift_Visc[iMarker]/(CDrag_Visc[iMarker] + EPS); + CMx_Visc[iMarker] = MomentViscous[0]; + CMy_Visc[iMarker] = MomentViscous[1]; + CMz_Visc[iMarker] = MomentViscous[2]; + CFx_Visc[iMarker] = ForceViscous[0]; + CFy_Visc[iMarker] = ForceViscous[1]; + CFz_Visc[iMarker] = ForceViscous[2]; + CT_Visc[iMarker] = -CFz_Visc[iMarker]; + CQ_Visc[iMarker] = -CMz_Visc[iMarker]; + CMerit_Visc[iMarker] = CT_Visc[iMarker] / (CQ_Visc[iMarker] + EPS); + MaxHeatFlux_Visc[iMarker] = pow(MaxHeatFlux_Visc[iMarker], 1.0/MaxNorm); + } + + AllBound_CDrag_Visc += CDrag_Visc[iMarker]; + AllBound_CLift_Visc += CLift_Visc[iMarker]; + AllBound_CSideForce_Visc += CSideForce_Visc[iMarker]; + AllBound_CMx_Visc += CMx_Visc[iMarker]; + AllBound_CMy_Visc += CMy_Visc[iMarker]; + AllBound_CMz_Visc += CMz_Visc[iMarker]; + AllBound_CFx_Visc += CFx_Visc[iMarker]; + AllBound_CFy_Visc += CFy_Visc[iMarker]; + AllBound_CFz_Visc += CFz_Visc[iMarker]; + AllBound_CT_Visc += CT_Visc[iMarker]; + AllBound_CQ_Visc += CQ_Visc[iMarker]; + AllBound_HeatFlux_Visc += Heat_Visc[iMarker]; + AllBound_MaxHeatFlux_Visc += pow(MaxHeatFlux_Visc[iMarker], MaxNorm); + + /*--- Compute the coefficients per surface ---*/ + + for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { + Monitoring_Tag = config->GetMarker_Monitoring(iMarker_Monitoring); + Marker_Tag = config->GetMarker_All_TagBound(iMarker); + if (Marker_Tag == Monitoring_Tag) { + Surface_CLift_Visc[iMarker_Monitoring] += CLift_Visc[iMarker]; + Surface_CDrag_Visc[iMarker_Monitoring] += CDrag_Visc[iMarker]; + Surface_CSideForce_Visc[iMarker_Monitoring] += CSideForce_Visc[iMarker]; + Surface_CEff_Visc[iMarker_Monitoring] += CEff_Visc[iMarker]; + Surface_CFx_Visc[iMarker_Monitoring] += CFx_Visc[iMarker]; + Surface_CFy_Visc[iMarker_Monitoring] += CFy_Visc[iMarker]; + Surface_CFz_Visc[iMarker_Monitoring] += CFz_Visc[iMarker]; + Surface_CMx_Visc[iMarker_Monitoring] += CMx_Visc[iMarker]; + Surface_CMy_Visc[iMarker_Monitoring] += CMy_Visc[iMarker]; + Surface_CMz_Visc[iMarker_Monitoring] += CMz_Visc[iMarker]; + } + } + + } + + } + } + + /*--- Update some global coeffients ---*/ + + AllBound_CEff_Visc = AllBound_CLift_Visc / (AllBound_CDrag_Visc + EPS); + AllBound_CMerit_Visc = AllBound_CT_Visc / (AllBound_CQ_Visc + EPS); + AllBound_MaxHeatFlux_Visc = pow(AllBound_MaxHeatFlux_Visc, 1.0/MaxNorm); + + +#ifdef HAVE_MPI + + /*--- Add AllBound information using all the nodes ---*/ + + MyAllBound_CDrag_Visc = AllBound_CDrag_Visc; AllBound_CDrag_Visc = 0.0; + MyAllBound_CLift_Visc = AllBound_CLift_Visc; AllBound_CLift_Visc = 0.0; + MyAllBound_CSideForce_Visc = AllBound_CSideForce_Visc; AllBound_CSideForce_Visc = 0.0; + AllBound_CEff_Visc = 0.0; + MyAllBound_CMx_Visc = AllBound_CMx_Visc; AllBound_CMx_Visc = 0.0; + MyAllBound_CMy_Visc = AllBound_CMy_Visc; AllBound_CMy_Visc = 0.0; + MyAllBound_CMz_Visc = AllBound_CMz_Visc; AllBound_CMz_Visc = 0.0; + MyAllBound_CFx_Visc = AllBound_CFx_Visc; AllBound_CFx_Visc = 0.0; + MyAllBound_CFy_Visc = AllBound_CFy_Visc; AllBound_CFy_Visc = 0.0; + MyAllBound_CFz_Visc = AllBound_CFz_Visc; AllBound_CFz_Visc = 0.0; + MyAllBound_CT_Visc = AllBound_CT_Visc; AllBound_CT_Visc = 0.0; + MyAllBound_CQ_Visc = AllBound_CQ_Visc; AllBound_CQ_Visc = 0.0; + AllBound_CMerit_Visc = 0.0; + MyAllBound_HeatFlux_Visc = AllBound_HeatFlux_Visc; AllBound_HeatFlux_Visc = 0.0; + MyAllBound_MaxHeatFlux_Visc = pow(AllBound_MaxHeatFlux_Visc, MaxNorm); AllBound_MaxHeatFlux_Visc = 0.0; + + SU2_MPI::Allreduce(&MyAllBound_CDrag_Visc, &AllBound_CDrag_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CLift_Visc, &AllBound_CLift_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CSideForce_Visc, &AllBound_CSideForce_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + AllBound_CEff_Visc = AllBound_CLift_Visc / (AllBound_CDrag_Visc + EPS); + SU2_MPI::Allreduce(&MyAllBound_CMx_Visc, &AllBound_CMx_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CMy_Visc, &AllBound_CMy_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CMz_Visc, &AllBound_CMz_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CFx_Visc, &AllBound_CFx_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CFy_Visc, &AllBound_CFy_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CFz_Visc, &AllBound_CFz_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CT_Visc, &AllBound_CT_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_CQ_Visc, &AllBound_CQ_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + AllBound_CMerit_Visc = AllBound_CT_Visc / (AllBound_CQ_Visc + EPS); + SU2_MPI::Allreduce(&MyAllBound_HeatFlux_Visc, &AllBound_HeatFlux_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyAllBound_MaxHeatFlux_Visc, &AllBound_MaxHeatFlux_Visc, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + AllBound_MaxHeatFlux_Visc = pow(AllBound_MaxHeatFlux_Visc, 1.0/MaxNorm); + + /*--- Add the forces on the surfaces using all the nodes ---*/ + + MySurface_CLift_Visc = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CDrag_Visc = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CSideForce_Visc = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CEff_Visc = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CFx_Visc = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CFy_Visc = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CFz_Visc = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CMx_Visc = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CMy_Visc = new su2double[config->GetnMarker_Monitoring()]; + MySurface_CMz_Visc = new su2double[config->GetnMarker_Monitoring()]; + + for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { + + MySurface_CLift_Visc[iMarker_Monitoring] = Surface_CLift_Visc[iMarker_Monitoring]; + MySurface_CDrag_Visc[iMarker_Monitoring] = Surface_CDrag_Visc[iMarker_Monitoring]; + MySurface_CSideForce_Visc[iMarker_Monitoring] = Surface_CSideForce_Visc[iMarker_Monitoring]; + MySurface_CEff_Visc[iMarker_Monitoring] = Surface_CEff_Visc[iMarker_Monitoring]; + MySurface_CFx_Visc[iMarker_Monitoring] = Surface_CFx_Visc[iMarker_Monitoring]; + MySurface_CFy_Visc[iMarker_Monitoring] = Surface_CFy_Visc[iMarker_Monitoring]; + MySurface_CFz_Visc[iMarker_Monitoring] = Surface_CFz_Visc[iMarker_Monitoring]; + MySurface_CMx_Visc[iMarker_Monitoring] = Surface_CMx_Visc[iMarker_Monitoring]; + MySurface_CMy_Visc[iMarker_Monitoring] = Surface_CMy_Visc[iMarker_Monitoring]; + MySurface_CMz_Visc[iMarker_Monitoring] = Surface_CMz_Visc[iMarker_Monitoring]; + + Surface_CLift_Visc[iMarker_Monitoring] = 0.0; + Surface_CDrag_Visc[iMarker_Monitoring] = 0.0; + Surface_CSideForce_Visc[iMarker_Monitoring] = 0.0; + Surface_CEff_Visc[iMarker_Monitoring] = 0.0; + Surface_CFx_Visc[iMarker_Monitoring] = 0.0; + Surface_CFy_Visc[iMarker_Monitoring] = 0.0; + Surface_CFz_Visc[iMarker_Monitoring] = 0.0; + Surface_CMx_Visc[iMarker_Monitoring] = 0.0; + Surface_CMy_Visc[iMarker_Monitoring] = 0.0; + Surface_CMz_Visc[iMarker_Monitoring] = 0.0; + } + + SU2_MPI::Allreduce(MySurface_CLift_Visc, Surface_CLift_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(MySurface_CDrag_Visc, Surface_CDrag_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(MySurface_CSideForce_Visc, Surface_CSideForce_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) + Surface_CEff_Visc[iMarker_Monitoring] = Surface_CLift_Visc[iMarker_Monitoring] / (Surface_CDrag_Visc[iMarker_Monitoring] + EPS); + SU2_MPI::Allreduce(MySurface_CFx_Visc, Surface_CFx_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(MySurface_CFy_Visc, Surface_CFy_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(MySurface_CFz_Visc, Surface_CFz_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(MySurface_CMx_Visc, Surface_CMx_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(MySurface_CMy_Visc, Surface_CMy_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(MySurface_CMz_Visc, Surface_CMz_Visc, config->GetnMarker_Monitoring(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + + delete [] MySurface_CLift_Visc; delete [] MySurface_CDrag_Visc; delete [] MySurface_CSideForce_Visc; + delete [] MySurface_CEff_Visc; delete [] MySurface_CFx_Visc; delete [] MySurface_CFy_Visc; + delete [] MySurface_CFz_Visc; delete [] MySurface_CMx_Visc; delete [] MySurface_CMy_Visc; + delete [] MySurface_CMz_Visc; + +#endif + + /*--- Update the total coefficients (note that all the nodes have the same value)---*/ + + Total_CDrag += AllBound_CDrag_Visc; + Total_CLift += AllBound_CLift_Visc; + Total_CSideForce += AllBound_CSideForce_Visc; + Total_CEff = Total_CLift / (Total_CDrag + EPS); + Total_CMx += AllBound_CMx_Visc; + Total_CMy += AllBound_CMy_Visc; + Total_CMz += AllBound_CMz_Visc; + Total_CFx += AllBound_CFx_Visc; + Total_CFy += AllBound_CFy_Visc; + Total_CFz += AllBound_CFz_Visc; + Total_CT += AllBound_CT_Visc; + Total_CQ += AllBound_CQ_Visc; + Total_CMerit = AllBound_CT_Visc / (AllBound_CQ_Visc + EPS); + Total_Heat = AllBound_HeatFlux_Visc; + Total_MaxHeat = AllBound_MaxHeatFlux_Visc; + + /*--- Update the total coefficients per surface (note that all the nodes have the same value)---*/ + + for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { + Surface_CLift[iMarker_Monitoring] += Surface_CLift_Visc[iMarker_Monitoring]; + Surface_CDrag[iMarker_Monitoring] += Surface_CDrag_Visc[iMarker_Monitoring]; + Surface_CSideForce[iMarker_Monitoring] += Surface_CSideForce_Visc[iMarker_Monitoring]; + Surface_CEff[iMarker_Monitoring] = Surface_CLift[iMarker_Monitoring] / (Surface_CDrag[iMarker_Monitoring] + EPS); + Surface_CFx[iMarker_Monitoring] += Surface_CFx_Visc[iMarker_Monitoring]; + Surface_CFy[iMarker_Monitoring] += Surface_CFy_Visc[iMarker_Monitoring]; + Surface_CFz[iMarker_Monitoring] += Surface_CFz_Visc[iMarker_Monitoring]; + Surface_CMx[iMarker_Monitoring] += Surface_CMx_Visc[iMarker_Monitoring]; + Surface_CMy[iMarker_Monitoring] += Surface_CMy_Visc[iMarker_Monitoring]; + Surface_CMz[iMarker_Monitoring] += Surface_CMz_Visc[iMarker_Monitoring]; + } + +} + +void CNSSolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned short iDim, jDim, iVar, jVar; + unsigned long iVertex, iPoint, Point_Normal, total_index; + + su2double Wall_HeatFlux, dist_ij, *Coord_i, *Coord_j, theta2; + su2double thetax, thetay, thetaz, etax, etay, etaz, pix, piy, piz, factor; + su2double ProjGridVel, *GridVel, GridVel2, *Normal, Area, Pressure = 0.0; + su2double total_viscosity, div_vel, Density, tau_vel[3] = {0.0, 0.0, 0.0}, UnitNormal[3] = {0.0, 0.0, 0.0}; + su2double laminar_viscosity = 0.0, eddy_viscosity = 0.0, Grad_Vel[3][3] = {{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}}, + tau[3][3] = {{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}}; + su2double delta[3][3] = {{1.0, 0.0, 0.0},{0.0,1.0,0.0},{0.0,0.0,1.0}}; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool grid_movement = config->GetGrid_Movement(); + + /*--- Identify the boundary by string name ---*/ + + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + + /*--- Get the specified wall heat flux from config ---*/ + + Wall_HeatFlux = config->GetWall_HeatFlux(Marker_Tag); + + /*--- Loop over all of the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Compute dual-grid area and boundary normal ---*/ + + Normal = geometry->vertex[val_marker][iVertex]->GetNormal(); + + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Area += Normal[iDim]*Normal[iDim]; + Area = sqrt (Area); + + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] = -Normal[iDim]/Area; + + /*--- Initialize the convective & viscous residuals to zero ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + Res_Conv[iVar] = 0.0; + Res_Visc[iVar] = 0.0; + } + + /*--- Store the corrected velocity at the wall which will + be zero (v = 0), unless there are moving walls (v = u_wall)---*/ + + if (grid_movement) { + GridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = GridVel[iDim]; + } else { + for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = 0.0; + } + + /*--- Impose the value of the velocity as a strong boundary + condition (Dirichlet). Fix the velocity and remove any + contribution to the residual at this node. ---*/ + + if (compressible) node[iPoint]->SetVelocity_Old(Vector); + if (incompressible || freesurface) node[iPoint]->SetVelocityInc_Old(Vector); + + for (iDim = 0; iDim < nDim; iDim++) + LinSysRes.SetBlock_Zero(iPoint, iDim+1); + node[iPoint]->SetVel_ResTruncError_Zero(); + + /*--- Apply a weak boundary condition for the energy equation. + Compute the residual due to the prescribed heat flux. ---*/ + + if (compressible) Res_Visc[nDim+1] = Wall_HeatFlux * Area; + + /*--- If the wall is moving, there are additional residual contributions + due to pressure (p v_wall.n) and shear stress (tau.v_wall.n). ---*/ + + if (grid_movement) { + + /*--- Get the grid velocity at the current boundary node ---*/ + + GridVel = geometry->node[iPoint]->GetGridVel(); + ProjGridVel = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + ProjGridVel += GridVel[iDim]*UnitNormal[iDim]*Area; + + /*--- Retrieve other primitive quantities and viscosities ---*/ + + Density = node[iPoint]->GetSolution(0); + if (compressible) { + Pressure = node[iPoint]->GetPressure(); + laminar_viscosity = node[iPoint]->GetLaminarViscosity(); + eddy_viscosity = node[iPoint]->GetEddyViscosity(); + } + if (incompressible || freesurface) { + Pressure = node[iPoint]->GetPressureInc(); + laminar_viscosity = node[iPoint]->GetLaminarViscosityInc(); + eddy_viscosity = node[iPoint]->GetEddyViscosityInc(); + } + total_viscosity = laminar_viscosity + eddy_viscosity; + + for (iDim = 0; iDim < nDim; iDim++) { + for (jDim = 0 ; jDim < nDim; jDim++) { + Grad_Vel[iDim][jDim] = node[iPoint]->GetGradient_Primitive(iDim+1, jDim); + } + } + + /*--- Divergence of the velocity ---*/ + + div_vel = 0.0; for (iDim = 0 ; iDim < nDim; iDim++) div_vel += Grad_Vel[iDim][iDim]; + + /*--- Compute the viscous stress tensor ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + for (jDim = 0; jDim < nDim; jDim++) { + tau[iDim][jDim] = total_viscosity*( Grad_Vel[jDim][iDim]+Grad_Vel[iDim][jDim] ) - TWO3*total_viscosity*div_vel*delta[iDim][jDim]; + } + } + + /*--- Dot product of the stress tensor with the grid velocity ---*/ + + for (iDim = 0 ; iDim < nDim; iDim++) { + tau_vel[iDim] = 0.0; + for (jDim = 0 ; jDim < nDim; jDim++) + tau_vel[iDim] += tau[iDim][jDim]*GridVel[jDim]; + } + + /*--- Compute the convective and viscous residuals (energy eqn.) ---*/ + + Res_Conv[nDim+1] = Pressure*ProjGridVel; + for (iDim = 0 ; iDim < nDim; iDim++) + Res_Visc[nDim+1] += tau_vel[iDim]*UnitNormal[iDim]*Area; + + /*--- Implicit Jacobian contributions due to moving walls ---*/ + + if (implicit) { + + /*--- Jacobian contribution related to the pressure term ---*/ + + GridVel2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + GridVel2 += GridVel[iDim]*GridVel[iDim]; + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + Jacobian_i[iVar][jVar] = 0.0; + Jacobian_i[nDim+1][0] = 0.5*(Gamma-1.0)*GridVel2*ProjGridVel; + for (jDim = 0; jDim < nDim; jDim++) + Jacobian_i[nDim+1][jDim+1] = -(Gamma-1.0)*GridVel[jDim]*ProjGridVel; + Jacobian_i[nDim+1][nDim+1] = (Gamma-1.0)*ProjGridVel; + + /*--- Add the block to the Global Jacobian structure ---*/ + + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + /*--- Now the Jacobian contribution related to the shear stress ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + Jacobian_i[iVar][jVar] = 0.0; + + /*--- Compute closest normal neighbor ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Get coordinates of i & nearest normal and compute distance ---*/ + + Coord_i = geometry->node[iPoint]->GetCoord(); + Coord_j = geometry->node[Point_Normal]->GetCoord(); + + dist_ij = 0; + for (iDim = 0; iDim < nDim; iDim++) + dist_ij += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); + dist_ij = sqrt(dist_ij); + + theta2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + theta2 += UnitNormal[iDim]*UnitNormal[iDim]; + + factor = total_viscosity*Area/(Density*dist_ij); + + if (nDim == 2) { + thetax = theta2 + UnitNormal[0]*UnitNormal[0]/3.0; + thetay = theta2 + UnitNormal[1]*UnitNormal[1]/3.0; + + etaz = UnitNormal[0]*UnitNormal[1]/3.0; + + pix = GridVel[0]*thetax + GridVel[1]*etaz; + piy = GridVel[0]*etaz + GridVel[1]*thetay; + + Jacobian_i[nDim+1][0] -= factor*(-pix*GridVel[0]+piy*GridVel[1]); + Jacobian_i[nDim+1][1] -= factor*pix; + Jacobian_i[nDim+1][2] -= factor*piy; + } else { + thetax = theta2 + UnitNormal[0]*UnitNormal[0]/3.0; + thetay = theta2 + UnitNormal[1]*UnitNormal[1]/3.0; + thetaz = theta2 + UnitNormal[2]*UnitNormal[2]/3.0; + + etaz = UnitNormal[0]*UnitNormal[1]/3.0; + etax = UnitNormal[1]*UnitNormal[2]/3.0; + etay = UnitNormal[0]*UnitNormal[2]/3.0; + + pix = GridVel[0]*thetax + GridVel[1]*etaz + GridVel[2]*etay; + piy = GridVel[0]*etaz + GridVel[1]*thetay + GridVel[2]*etax; + piz = GridVel[0]*etay + GridVel[1]*etax + GridVel[2]*thetaz; + + Jacobian_i[nDim+1][0] -= factor*(-pix*GridVel[0]+piy*GridVel[1]+piz*GridVel[2]); + Jacobian_i[nDim+1][1] -= factor*pix; + Jacobian_i[nDim+1][2] -= factor*piy; + Jacobian_i[nDim+1][3] -= factor*piz; + } + + /*--- Subtract the block from the Global Jacobian structure ---*/ + + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + } + + /*--- Convective contribution to the residual at the wall ---*/ + + LinSysRes.AddBlock(iPoint, Res_Conv); + + /*--- Viscous contribution to the residual at the wall ---*/ + + LinSysRes.SubtractBlock(iPoint, Res_Visc); + + /*--- Enforce the no-slip boundary condition in a strong way by + modifying the velocity-rows of the Jacobian (1 on the diagonal). ---*/ + + if (implicit) { + for (iVar = 1; iVar <= nDim; iVar++) { + total_index = iPoint*nVar+iVar; + Jacobian.DeleteValsRowi(total_index); + } + } + + } + } +} + +void CNSSolver::BC_Isothermal_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned short iVar, jVar, iDim, jDim; + unsigned long iVertex, iPoint, Point_Normal, total_index; + + su2double *Normal, *Coord_i, *Coord_j, Area, dist_ij, theta2; + su2double Twall, dTdn, dTdrho, thermal_conductivity; + su2double thetax, thetay, thetaz, etax, etay, etaz, pix, piy, piz, factor; + su2double ProjGridVel, *GridVel, GridVel2, Pressure = 0.0, Density, Vel2; + su2double total_viscosity, div_vel, tau_vel[3] = {0.0,0.0,0.0}, UnitNormal[3] = {0.0,0.0,0.0}; + su2double laminar_viscosity, eddy_viscosity, Grad_Vel[3][3] = {{1.0, 0.0, 0.0},{0.0,1.0,0.0},{0.0,0.0,1.0}}, + tau[3][3] = {{0.0, 0.0, 0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}}, delta[3][3] = {{1.0, 0.0, 0.0},{0.0,1.0,0.0},{0.0,0.0,1.0}}; + + su2double Prandtl_Lam = config->GetPrandtl_Lam(); + su2double Prandtl_Turb = config->GetPrandtl_Turb(); + su2double Gas_Constant = config->GetGas_ConstantND(); + su2double Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; + + bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool grid_movement = config->GetGrid_Movement(); + + /*--- Identify the boundary ---*/ + + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + + /*--- Retrieve the specified wall temperature ---*/ + + Twall = config->GetIsothermal_Temperature(Marker_Tag)/config->GetTemperature_Ref(); + + /*--- Loop over boundary points ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Compute dual-grid area and boundary normal ---*/ + + Normal = geometry->vertex[val_marker][iVertex]->GetNormal(); + + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt (Area); + + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] = -Normal[iDim]/Area; + + /*--- Calculate useful quantities ---*/ + + theta2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + theta2 += UnitNormal[iDim]*UnitNormal[iDim]; + + /*--- Compute closest normal neighbor ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Get coordinates of i & nearest normal and compute distance ---*/ + + Coord_i = geometry->node[iPoint]->GetCoord(); + Coord_j = geometry->node[Point_Normal]->GetCoord(); + dist_ij = 0; + for (iDim = 0; iDim < nDim; iDim++) + dist_ij += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); + dist_ij = sqrt(dist_ij); + + /*--- Store the corrected velocity at the wall which will + be zero (v = 0), unless there is grid motion (v = u_wall)---*/ + + if (grid_movement) { + GridVel = geometry->node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = GridVel[iDim]; + } + else { + for (iDim = 0; iDim < nDim; iDim++) Vector[iDim] = 0.0; + } + + /*--- Initialize the convective & viscous residuals to zero ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + Res_Conv[iVar] = 0.0; + Res_Visc[iVar] = 0.0; + } + + /*--- Set the residual, truncation error and velocity value on the boundary ---*/ + + if (compressible) node[iPoint]->SetVelocity_Old(Vector); + if (incompressible || freesurface) node[iPoint]->SetVelocityInc_Old(Vector); + + for (iDim = 0; iDim < nDim; iDim++) + LinSysRes.SetBlock_Zero(iPoint, iDim+1); + node[iPoint]->SetVel_ResTruncError_Zero(); + + /*--- Compute the normal gradient in temperature using Twall ---*/ + + dTdn = -(node[Point_Normal]->GetPrimitive(0) - Twall)/dist_ij; + + /*--- Get transport coefficients ---*/ + + laminar_viscosity = node[iPoint]->GetLaminarViscosity(); + eddy_viscosity = node[iPoint]->GetEddyViscosity(); + thermal_conductivity = Cp * ( laminar_viscosity/Prandtl_Lam + eddy_viscosity/Prandtl_Turb); + + // work in progress on real-gases... + //thermal_conductivity = node[iPoint]->GetThermalConductivity(); + //Cp = node[iPoint]->GetSpecificHeatCp(); + //thermal_conductivity += Cp*eddy_viscosity/Prandtl_Turb; + + /*--- Apply a weak boundary condition for the energy equation. + Compute the residual due to the prescribed heat flux. ---*/ + + Res_Visc[nDim+1] = thermal_conductivity * dTdn * Area; + + /*--- Calculate Jacobian for implicit time stepping ---*/ + + if (implicit) { + + for (iVar = 0; iVar < nVar; iVar ++) + for (jVar = 0; jVar < nVar; jVar ++) + Jacobian_i[iVar][jVar] = 0.0; + + /*--- Calculate useful quantities ---*/ + + Density = node[iPoint]->GetPrimitive(nDim+2); + Vel2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Vel2 += node[iPoint]->GetPrimitive(iDim+1) * node[iPoint]->GetPrimitive(iDim+1); + dTdrho = 1.0/Density * ( -Twall + (Gamma-1.0)/Gas_Constant*(Vel2/2.0) ); + + /*--- Enforce the no-slip boundary condition in a strong way ---*/ + + for (iVar = 1; iVar <= nDim; iVar++) { + total_index = iPoint*nVar+iVar; + Jacobian.DeleteValsRowi(total_index); + } + + /*--- Add contributions to the Jacobian from the weak enforcement of the energy equations ---*/ + + Jacobian_i[nDim+1][0] = -thermal_conductivity*theta2/dist_ij * dTdrho * Area; + Jacobian_i[nDim+1][nDim+1] = -thermal_conductivity*theta2/dist_ij * (Gamma-1.0)/(Gas_Constant*Density) * Area; + + /*--- Subtract the block from the Global Jacobian structure ---*/ + + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + + /*--- If the wall is moving, there are additional residual contributions + due to pressure (p v_wall.n) and shear stress (tau.v_wall.n). ---*/ + + if (grid_movement) { + + /*--- Get the grid velocity at the current boundary node ---*/ + + GridVel = geometry->node[iPoint]->GetGridVel(); + ProjGridVel = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + ProjGridVel += GridVel[iDim]*UnitNormal[iDim]*Area; + + /*--- Retrieve other primitive quantities and viscosities ---*/ + + Density = node[iPoint]->GetSolution(0); + if (compressible) { + Pressure = node[iPoint]->GetPressure(); + laminar_viscosity = node[iPoint]->GetLaminarViscosity(); + eddy_viscosity = node[iPoint]->GetEddyViscosity(); + } + if (incompressible || freesurface) { + Pressure = node[iPoint]->GetPressureInc(); + laminar_viscosity = node[iPoint]->GetLaminarViscosityInc(); + eddy_viscosity = node[iPoint]->GetEddyViscosityInc(); + } + + total_viscosity = laminar_viscosity + eddy_viscosity; + + for (iDim = 0; iDim < nDim; iDim++) { + for (jDim = 0 ; jDim < nDim; jDim++) { + Grad_Vel[iDim][jDim] = node[iPoint]->GetGradient_Primitive(iDim+1, jDim); + } + } + + /*--- Divergence of the velocity ---*/ + + div_vel = 0.0; for (iDim = 0 ; iDim < nDim; iDim++) div_vel += Grad_Vel[iDim][iDim]; + + /*--- Compute the viscous stress tensor ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + for (jDim = 0; jDim < nDim; jDim++) { + tau[iDim][jDim] = total_viscosity*( Grad_Vel[jDim][iDim] + Grad_Vel[iDim][jDim] ) - TWO3*total_viscosity*div_vel*delta[iDim][jDim]; + } + + /*--- Dot product of the stress tensor with the grid velocity ---*/ + + for (iDim = 0 ; iDim < nDim; iDim++) { + tau_vel[iDim] = 0.0; + for (jDim = 0 ; jDim < nDim; jDim++) + tau_vel[iDim] += tau[iDim][jDim]*GridVel[jDim]; + } + + /*--- Compute the convective and viscous residuals (energy eqn.) ---*/ + + Res_Conv[nDim+1] = Pressure*ProjGridVel; + for (iDim = 0 ; iDim < nDim; iDim++) + Res_Visc[nDim+1] += tau_vel[iDim]*UnitNormal[iDim]*Area; + + /*--- Implicit Jacobian contributions due to moving walls ---*/ + + if (implicit) { + + /*--- Jacobian contribution related to the pressure term ---*/ + + GridVel2 = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + GridVel2 += GridVel[iDim]*GridVel[iDim]; + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + Jacobian_i[iVar][jVar] = 0.0; + + Jacobian_i[nDim+1][0] = 0.5*(Gamma-1.0)*GridVel2*ProjGridVel; + for (jDim = 0; jDim < nDim; jDim++) + Jacobian_i[nDim+1][jDim+1] = -(Gamma-1.0)*GridVel[jDim]*ProjGridVel; + Jacobian_i[nDim+1][nDim+1] = (Gamma-1.0)*ProjGridVel; + + /*--- Add the block to the Global Jacobian structure ---*/ + + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + /*--- Now the Jacobian contribution related to the shear stress ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + Jacobian_i[iVar][jVar] = 0.0; + + factor = total_viscosity*Area/(Density*dist_ij); + + if (nDim == 2) { + thetax = theta2 + UnitNormal[0]*UnitNormal[0]/3.0; + thetay = theta2 + UnitNormal[1]*UnitNormal[1]/3.0; + + etaz = UnitNormal[0]*UnitNormal[1]/3.0; + + pix = GridVel[0]*thetax + GridVel[1]*etaz; + piy = GridVel[0]*etaz + GridVel[1]*thetay; + + Jacobian_i[nDim+1][0] -= factor*(-pix*GridVel[0]+piy*GridVel[1]); + Jacobian_i[nDim+1][1] -= factor*pix; + Jacobian_i[nDim+1][2] -= factor*piy; + } + else { + thetax = theta2 + UnitNormal[0]*UnitNormal[0]/3.0; + thetay = theta2 + UnitNormal[1]*UnitNormal[1]/3.0; + thetaz = theta2 + UnitNormal[2]*UnitNormal[2]/3.0; + + etaz = UnitNormal[0]*UnitNormal[1]/3.0; + etax = UnitNormal[1]*UnitNormal[2]/3.0; + etay = UnitNormal[0]*UnitNormal[2]/3.0; + + pix = GridVel[0]*thetax + GridVel[1]*etaz + GridVel[2]*etay; + piy = GridVel[0]*etaz + GridVel[1]*thetay + GridVel[2]*etax; + piz = GridVel[0]*etay + GridVel[1]*etax + GridVel[2]*thetaz; + + Jacobian_i[nDim+1][0] -= factor*(-pix*GridVel[0]+piy*GridVel[1]+piz*GridVel[2]); + Jacobian_i[nDim+1][1] -= factor*pix; + Jacobian_i[nDim+1][2] -= factor*piy; + Jacobian_i[nDim+1][3] -= factor*piz; + } + + /*--- Subtract the block from the Global Jacobian structure ---*/ + + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + } + + } + + /*--- Convective contribution to the residual at the wall ---*/ + + LinSysRes.AddBlock(iPoint, Res_Conv); + + /*--- Viscous contribution to the residual at the wall ---*/ + + LinSysRes.SubtractBlock(iPoint, Res_Visc); + + /*--- Enforce the no-slip boundary condition in a strong way by + modifying the velocity-rows of the Jacobian (1 on the diagonal). ---*/ + + if (implicit) { + for (iVar = 1; iVar <= nDim; iVar++) { + total_index = iPoint*nVar+iVar; + Jacobian.DeleteValsRowi(total_index); + } + } + + } + } +} diff --git a/SU2_CFD/src/solver_direct_poisson.cpp b/SU2_CFD/src/solver_direct_poisson.cpp index cad6707d54e..085f5e3a839 100644 --- a/SU2_CFD/src/solver_direct_poisson.cpp +++ b/SU2_CFD/src/solver_direct_poisson.cpp @@ -1,538 +1,538 @@ -/*! - * \file solution_direct_poisson.cpp - * \brief Main subrotuines for solving direct problems - * \author F. Palacios - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/solver_structure.hpp" - -CPoissonSolver::CPoissonSolver(void) : CSolver() { } - -CPoissonSolver::CPoissonSolver(CGeometry *geometry, CConfig *config) : CSolver() { - - unsigned long nPoint, iPoint; - unsigned short iVar, iDim; - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - nDim = geometry->GetnDim(); - nPoint = geometry->GetnPoint(); - nPointDomain = geometry->GetnPointDomain(); - nVar = 1; - node = new CVariable*[nPoint]; - - Residual = new su2double[nVar]; Residual_RMS = new su2double[nVar]; - Solution = new su2double[nVar]; - Residual_Max = new su2double[nVar]; - - /*--- Define some structures for locating max residuals ---*/ - - Point_Max = new unsigned long[nVar]; - for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; - Point_Max_Coord = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Point_Max_Coord[iVar] = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; - } - - /*--- Point to point stiffness matrix ---*/ - - if (nDim == 2) { - StiffMatrix_Elem = new su2double* [3]; - Source_Vector = new su2double [3]; - for (unsigned short iVar = 0; iVar < 3; iVar++) { - StiffMatrix_Elem[iVar] = new su2double [3]; - } - } - - if (nDim == 3) { - StiffMatrix_Elem = new su2double* [4]; - Source_Vector = new su2double [4]; - for (unsigned short iVar = 0; iVar < 4; iVar++) { - StiffMatrix_Elem[iVar] = new su2double [4]; - } - } - - StiffMatrix_Node = new su2double* [1]; - for (unsigned short iVar = 0; iVar < 1; iVar++) { - StiffMatrix_Node[iVar] = new su2double [1]; - } - - /*--- Initialization of the structure of the whole Jacobian ---*/ - if (rank == MASTER_NODE) cout << "Initialize Jacobian structure (Poisson equation)." << endl; - StiffMatrix.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); - - /*--- Solution and residual vectors ---*/ - - LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysAux.Initialize(nPoint, nPointDomain, nVar, 0.0); - - /*--- Computation of gradients by least squares ---*/ - - Smatrix = new su2double* [nDim]; // S matrix := inv(R)*traspose(inv(R)) - for (iDim = 0; iDim < nDim; iDim++) - Smatrix[iDim] = new su2double [nDim]; - - cvector = new su2double* [nVar]; // c vector := transpose(WA)*(Wb) - for (iVar = 0; iVar < nVar; iVar++) - cvector[iVar] = new su2double [nDim]; - - /*--- Always instantiate and initialize the variable to a zero value. ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) - node[iPoint] = new CPotentialVariable(0.0, nDim, nVar, config); - -} - -CPoissonSolver::~CPoissonSolver(void) { - - unsigned short iVar, iDim; - - delete [] Residual; - delete [] Residual_Max; - delete [] Solution; - delete [] Source_Vector; - - if (nDim == 2) { - for (iVar = 0; iVar < 3; iVar++) - delete [] StiffMatrix_Elem[iVar]; - } - - if (nDim == 3) { - for (iVar = 0; iVar < 4; iVar++) - delete [] StiffMatrix_Elem[iVar]; - } - - for (iVar = 0; iVar < 1; iVar++) - delete [] StiffMatrix_Node[iVar]; - - delete [] StiffMatrix_Elem; - delete [] StiffMatrix_Node; - - /*--- Computation of gradients by least-squares ---*/ - for (iDim = 0; iDim < this->nDim; iDim++) - delete [] Smatrix[iDim]; - delete [] Smatrix; - - for (iVar = 0; iVar < nVar; iVar++) - delete [] cvector[iVar]; - delete [] cvector; -} - -void CPoissonSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, - CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { - unsigned long iPoint; - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) - LinSysRes.SetBlock_Zero(iPoint); - - StiffMatrix.SetValZero(); - -} - -void CPoissonSolver::Compute_Residual(CGeometry *geometry, CSolver **solver_container, CConfig *config, - unsigned short iMesh) { - - unsigned long iPoint; - unsigned short iVar = 0; - - /*--- Build linear system ---*/ - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { - LinSysRes[iPoint] = LinSysRes.GetBlock(iPoint, iVar); - LinSysSol[iPoint] = node[iPoint]->GetSolution(iVar); - } - - StiffMatrix.MatrixVectorProduct(LinSysSol, LinSysRes); - - /*--- Update residual ---*/ - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { - LinSysRes.SetBlock(iPoint, 0, LinSysRes[iPoint]); - } -} - -/*! - * \method Source_Residual - * \brief Source terms of the poisson solver - * \author A. Lonkar - */ -void CPoissonSolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, - CConfig *config, unsigned short iMesh) { -// -// unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, Point_3 = 0; -// su2double a[3], b[3], c[3], d[3], Area_Local, Volume_Local; -// // su2double Local_Delta_Time; -// su2double **Gradient_0, **Gradient_1, **Gradient_2, **Gradient_3; -// su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, *Coord_3= NULL;; -// unsigned short iDim; -// su2double dt; -// // su2double dx, u, c; -// bool MacCormack_relaxation = (config->GetMacCormackRelaxation()); -// -// if (nDim == 2) { -// if (config->GetPoissonSolver()) { -// -// for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { -// -// Point_0 = geometry->elem[iElem]->GetNode(0); -// Point_1 = geometry->elem[iElem]->GetNode(1); -// Point_2 = geometry->elem[iElem]->GetNode(2); -// -// Coord_0 = geometry->node[Point_0]->GetCoord(); -// Coord_1 = geometry->node[Point_1]->GetCoord(); -// Coord_2 = geometry->node[Point_2]->GetCoord(); -// -// for (iDim = 0; iDim < nDim; iDim++) { -// a[iDim] = Coord_0[iDim]-Coord_2[iDim]; -// b[iDim] = Coord_1[iDim]-Coord_2[iDim]; -// } -// -// Area_Local = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); -// -// Gradient_0 = node[Point_0]->GetPlasmaRhoUGradient(); -// Gradient_1 = node[Point_1]->GetPlasmaRhoUGradient(); -// Gradient_2 = node[Point_2]->GetPlasmaRhoUGradient(); -// -// numerics->SetVolume(Area_Local); -// -// dt = node[Point_0]->GetPlasmaTimeStep(); -// -// /* u = 4800; -// c = 87110; -// c = 800; -// dx = 0.004/81; -// Local_Delta_Time = config->GetCFL(iMesh) * dx/(u+c); -// numerics->SetTimeStep(Local_Delta_Time); -// */ -// -// numerics->SetCoord(Coord_0, Coord_1, Coord_2); -// numerics->SetTimeStep(dt); -// numerics->SetChargeDensity(node[Point_0]->GetChargeDensity(), node[Point_1]->GetChargeDensity(), node[Point_2]->GetChargeDensity(), node[Point_3]->GetChargeDensity()); -// numerics->SetConsVarGradient(Gradient_0, Gradient_1, Gradient_2 ); -// numerics->ComputeResidual_MacCormack(Source_Vector, config); -// -// LinSysRes.AddBlock(Point_0, &Source_Vector[0]); -// LinSysRes.AddBlock(Point_1, &Source_Vector[1]); -// LinSysRes.AddBlock(Point_2, &Source_Vector[2]); -// -// if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { -// -// Point_0 = geometry->elem[iElem]->GetNode(3); -// Point_1 = geometry->elem[iElem]->GetNode(0); -// Point_2 = geometry->elem[iElem]->GetNode(2); -// -// Coord_0 = geometry->node[Point_0]->GetCoord(); -// Coord_1 = geometry->node[Point_1]->GetCoord(); -// Coord_2 = geometry->node[Point_2]->GetCoord(); -// -// for (iDim = 0; iDim < nDim; iDim++) { -// a[iDim] = Coord_0[iDim]-Coord_2[iDim]; -// b[iDim] = Coord_1[iDim]-Coord_2[iDim]; -// } -// -// Area_Local = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); -// -// Gradient_0 = node[Point_0]->GetPlasmaRhoUGradient(); -// Gradient_1 = node[Point_1]->GetPlasmaRhoUGradient(); -// Gradient_2 = node[Point_2]->GetPlasmaRhoUGradient(); -// -// numerics->SetVolume(Area_Local); -// -// /* u = 4800; -// c = 87110; -// c = 732.0; -// dx = 0.004/81; -// Local_Delta_Time = config->GetCFL(iMesh) * dx/(u+c); -// numerics->SetTimeStep(Local_Delta_Time); -// */ -// -// dt = node[Point_0]->GetPlasmaTimeStep(); -// numerics->SetCoord(Coord_0, Coord_1, Coord_2); -// numerics->SetTimeStep(dt); -// numerics->SetChargeDensity(node[Point_0]->GetChargeDensity(), node[Point_1]->GetChargeDensity(), node[Point_2]->GetChargeDensity(), node[Point_3]->GetChargeDensity()); -// numerics->SetConsVarGradient(Gradient_0, Gradient_1, Gradient_2 ); -// numerics->ComputeResidual_MacCormack(Source_Vector, config); -// LinSysRes.AddBlock(Point_0, &Source_Vector[0]); -// LinSysRes.AddBlock(Point_1, &Source_Vector[1]); -// LinSysRes.AddBlock(Point_2, &Source_Vector[2]); -// } -// } -// } -// } -// if (nDim == 3) { -// if (config->GetPoissonSolver()) { -// for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { -// Point_0 = geometry->elem[iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); -// Point_1 = geometry->elem[iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); -// Point_2 = geometry->elem[iElem]->GetNode(2); Coord_2 = geometry->node[Point_2]->GetCoord(); -// Point_3 = geometry->elem[iElem]->GetNode(3); Coord_3 = geometry->node[Point_3]->GetCoord(); -// -// for (iDim = 0; iDim < nDim; iDim++) { -// a[iDim] = Coord_0[iDim]-Coord_2[iDim]; -// b[iDim] = Coord_1[iDim]-Coord_2[iDim]; -// c[iDim] = Coord_3[iDim]-Coord_2[iDim]; -// } -// -// d[0] = a[1]*b[2]-a[2]*b[1]; -// d[1] = -(a[0]*b[2]-a[2]*b[0]); -// d[2] = a[0]*b[1]-a[1]*b[0]; -// -// /*--- Compute element volume ---*/ -// Volume_Local = fabs(c[0]*d[0] + c[1]*d[1] + c[2]*d[2])/6.0; -// numerics->SetVolume(Volume_Local); -// numerics->SetChargeDensity(node[Point_0]->GetChargeDensity(), node[Point_1]->GetChargeDensity(), node[Point_2]->GetChargeDensity(), node[Point_3]->GetChargeDensity()); -// -// if (MacCormack_relaxation) { -// -// Gradient_0 = node[Point_0]->GetPlasmaRhoUGradient(); -// Gradient_1 = node[Point_1]->GetPlasmaRhoUGradient(); -// Gradient_2 = node[Point_2]->GetPlasmaRhoUGradient(); -// Gradient_3 = node[Point_3]->GetPlasmaRhoUGradient(); -// numerics->SetCoord(Coord_0, Coord_1, Coord_2, Coord_3); -// numerics->SetConsVarGradient(Gradient_0, Gradient_1, Gradient_2, Gradient_3 ); -// numerics->ComputeResidual_MacCormack(Source_Vector, config); -// } -// else numerics->ComputeResidual(Source_Vector, config); -// -// LinSysRes.AddBlock(Point_0, &Source_Vector[0]); -// LinSysRes.AddBlock(Point_1, &Source_Vector[1]); -// LinSysRes.AddBlock(Point_2, &Source_Vector[2]); -// LinSysRes.AddBlock(Point_3, &Source_Vector[3]); -// } -// } -// } -} - -void CPoissonSolver::Source_Template(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config, unsigned short iMesh) { -} - - -/*! - * \method Copy_Zone_Solution - * \brief Copy solution from solver 1 into solver 2 - * \author A. Lonkar - */ -void CPoissonSolver::Copy_Zone_Solution(CSolver ***solver1_solution, - CGeometry **solver1_geometry, - CConfig *solver1_config, - CSolver ***solver2_solution, - CGeometry **solver2_geometry, - CConfig *solver2_config) { - unsigned long iPoint; - unsigned short iDim; - su2double neg_EFvalue; - su2double *E_field = new su2double [nDim]; - - for (iPoint = 0; iPoint < solver1_geometry[MESH_0]->GetnPointDomain(); iPoint++) { - for (iDim =0; iDim < nDim; iDim ++) { - neg_EFvalue = solver1_solution[MESH_0][POISSON_SOL]->node[iPoint]->GetGradient(0, iDim); - E_field[iDim] = -1.0*neg_EFvalue; - } - } -}; - -/*! - * \method Galerkin_Method - * \brief calculate the element stiffness matrix - * \author A. Lonkar - */ -void CPoissonSolver::Viscous_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config, unsigned short iMesh, unsigned short iRKStep) { - - unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, Point_3 = 0; - su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, *Coord_3 = NULL; - - if (nDim == 2 ) { - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - Point_0 = geometry->elem[iElem]->GetNode(0); - Point_1 = geometry->elem[iElem]->GetNode(1); - Point_2 = geometry->elem[iElem]->GetNode(2); - - Coord_0 = geometry->node[Point_0]->GetCoord(); - Coord_1 = geometry->node[Point_1]->GetCoord(); - Coord_2 = geometry->node[Point_2]->GetCoord(); - - numerics->SetCoord(Coord_0, Coord_1, Coord_2); - numerics->ComputeResidual(StiffMatrix_Elem, config); - AddStiffMatrix(StiffMatrix_Elem, Point_0, Point_1, Point_2, Point_3); - } - } - - if (nDim == 3 ) { - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - Point_0 = geometry->elem[iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); - Point_1 = geometry->elem[iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); - Point_2 = geometry->elem[iElem]->GetNode(2); Coord_2 = geometry->node[Point_2]->GetCoord(); - Point_3 = geometry->elem[iElem]->GetNode(3); Coord_3 = geometry->node[Point_3]->GetCoord(); - - numerics->SetCoord(Coord_0, Coord_1, Coord_2, Coord_3); - numerics->ComputeResidual(StiffMatrix_Elem, config); - AddStiffMatrix(StiffMatrix_Elem, Point_0, Point_1, Point_2, Point_3); - - } - } -} - -/*! - * \method AddStiffMatrix - * \brief Assemble the Global stiffness matrix - * \author A. Lonkar - */ -void CPoissonSolver::AddStiffMatrix(su2double **StiffMatrix_Elem, unsigned long Point_0, unsigned long Point_1, unsigned long Point_2, unsigned long Point_3) { - - if (nDim == 2 ) { - StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][0]; StiffMatrix.AddBlock(Point_0, Point_0, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][1]; StiffMatrix.AddBlock(Point_0, Point_1, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][2]; StiffMatrix.AddBlock(Point_0, Point_2, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][0]; StiffMatrix.AddBlock(Point_1, Point_0, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][1]; StiffMatrix.AddBlock(Point_1, Point_1, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][2]; StiffMatrix.AddBlock(Point_1, Point_2, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][0]; StiffMatrix.AddBlock(Point_2, Point_0, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][1]; StiffMatrix.AddBlock(Point_2, Point_1, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][2]; StiffMatrix.AddBlock(Point_2, Point_2, StiffMatrix_Node); - } - if (nDim == 3) { - - StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][0]; StiffMatrix.AddBlock(Point_0, Point_0, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][1]; StiffMatrix.AddBlock(Point_0, Point_1, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][2]; StiffMatrix.AddBlock(Point_0, Point_2, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][3]; StiffMatrix.AddBlock(Point_0, Point_3, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][0]; StiffMatrix.AddBlock(Point_1, Point_0, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][1]; StiffMatrix.AddBlock(Point_1, Point_1, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][2]; StiffMatrix.AddBlock(Point_1, Point_2, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][3]; StiffMatrix.AddBlock(Point_1, Point_3, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][0]; StiffMatrix.AddBlock(Point_2, Point_0, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][1]; StiffMatrix.AddBlock(Point_2, Point_1, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][2]; StiffMatrix.AddBlock(Point_2, Point_2, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][3]; StiffMatrix.AddBlock(Point_2, Point_3, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[3][0]; StiffMatrix.AddBlock(Point_3, Point_0, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[3][1]; StiffMatrix.AddBlock(Point_3, Point_1, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[3][2]; StiffMatrix.AddBlock(Point_3, Point_2, StiffMatrix_Node); - StiffMatrix_Node[0][0] = StiffMatrix_Elem[3][3]; StiffMatrix.AddBlock(Point_3, Point_3, StiffMatrix_Node); - - } -} - -void CPoissonSolver::BC_Dirichlet(CGeometry *geometry, CSolver **solver_container, - CConfig *config, unsigned short val_marker) { - unsigned long Point, iVertex; - - /*--- Identify if a boundary is Dirichlet or Neumman ---*/ - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - Point = geometry->vertex[val_marker][iVertex]->GetNode(); - Solution[0]= 10.0; - node[Point]->SetSolution(Solution); - - LinSysRes.SetBlock(Point, Solution); - LinSysSol.SetBlock(Point, Solution); - - StiffMatrix.DeleteValsRowi(Point); // & includes 1 in the diagonal - } - -} - -void CPoissonSolver::BC_Neumann(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, - unsigned short val_marker) { } - -void CPoissonSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { - - unsigned long iPoint, total_index; - unsigned short iVar; - - /*--- Build implicit system ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - LinSysSol[total_index] = 0.0; - } - - } - - /*--- Initialize residual and solution at the ghost points ---*/ - - for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar + iVar; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - } - } - - /*--- Solve or smooth the linear system ---*/ - - CSysSolve system; - system.Solve(StiffMatrix, LinSysRes, LinSysSol, geometry, config); - - /*--- Update solution (system written in terms of increments) ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - node[iPoint]->SetSolution(iVar, LinSysSol[iPoint*nVar+iVar]); - } - } - - /*--- MPI solution ---*/ - - Set_MPI_Solution(geometry, config); - - /*--- Compute the residual Ax-f ---*/ - - StiffMatrix.ComputeResidual(LinSysSol, LinSysRes, LinSysAux); - - /*--- Set maximum residual to zero ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - SetRes_RMS(iVar, 0.0); - SetRes_Max(iVar, 0.0, 0); - } - - /*--- Compute the residual ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - AddRes_RMS(iVar, LinSysAux[total_index]*LinSysAux[total_index]); - AddRes_Max(iVar, fabs(LinSysAux[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); - } - } - - /*--- Compute the root mean square residual ---*/ - - SetResidual_RMS(geometry, config); - -} +/*! + * \file solution_direct_poisson.cpp + * \brief Main subrotuines for solving direct problems + * \author F. Palacios + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/solver_structure.hpp" + +CPoissonSolver::CPoissonSolver(void) : CSolver() { } + +CPoissonSolver::CPoissonSolver(CGeometry *geometry, CConfig *config) : CSolver() { + + unsigned long nPoint, iPoint; + unsigned short iVar, iDim; + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + nDim = geometry->GetnDim(); + nPoint = geometry->GetnPoint(); + nPointDomain = geometry->GetnPointDomain(); + nVar = 1; + node = new CVariable*[nPoint]; + + Residual = new su2double[nVar]; Residual_RMS = new su2double[nVar]; + Solution = new su2double[nVar]; + Residual_Max = new su2double[nVar]; + + /*--- Define some structures for locating max residuals ---*/ + + Point_Max = new unsigned long[nVar]; + for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; + Point_Max_Coord = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Point_Max_Coord[iVar] = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; + } + + /*--- Point to point stiffness matrix ---*/ + + if (nDim == 2) { + StiffMatrix_Elem = new su2double* [3]; + Source_Vector = new su2double [3]; + for (unsigned short iVar = 0; iVar < 3; iVar++) { + StiffMatrix_Elem[iVar] = new su2double [3]; + } + } + + if (nDim == 3) { + StiffMatrix_Elem = new su2double* [4]; + Source_Vector = new su2double [4]; + for (unsigned short iVar = 0; iVar < 4; iVar++) { + StiffMatrix_Elem[iVar] = new su2double [4]; + } + } + + StiffMatrix_Node = new su2double* [1]; + for (unsigned short iVar = 0; iVar < 1; iVar++) { + StiffMatrix_Node[iVar] = new su2double [1]; + } + + /*--- Initialization of the structure of the whole Jacobian ---*/ + if (rank == MASTER_NODE) cout << "Initialize Jacobian structure (Poisson equation)." << endl; + StiffMatrix.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); + + /*--- Solution and residual vectors ---*/ + + LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); + LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); + LinSysAux.Initialize(nPoint, nPointDomain, nVar, 0.0); + + /*--- Computation of gradients by least squares ---*/ + + Smatrix = new su2double* [nDim]; // S matrix := inv(R)*traspose(inv(R)) + for (iDim = 0; iDim < nDim; iDim++) + Smatrix[iDim] = new su2double [nDim]; + + cvector = new su2double* [nVar]; // c vector := transpose(WA)*(Wb) + for (iVar = 0; iVar < nVar; iVar++) + cvector[iVar] = new su2double [nDim]; + + /*--- Always instantiate and initialize the variable to a zero value. ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint++) + node[iPoint] = new CPotentialVariable(0.0, nDim, nVar, config); + +} + +CPoissonSolver::~CPoissonSolver(void) { + + unsigned short iVar, iDim; + + delete [] Residual; + delete [] Residual_Max; + delete [] Solution; + delete [] Source_Vector; + + if (nDim == 2) { + for (iVar = 0; iVar < 3; iVar++) + delete [] StiffMatrix_Elem[iVar]; + } + + if (nDim == 3) { + for (iVar = 0; iVar < 4; iVar++) + delete [] StiffMatrix_Elem[iVar]; + } + + for (iVar = 0; iVar < 1; iVar++) + delete [] StiffMatrix_Node[iVar]; + + delete [] StiffMatrix_Elem; + delete [] StiffMatrix_Node; + + /*--- Computation of gradients by least-squares ---*/ + for (iDim = 0; iDim < this->nDim; iDim++) + delete [] Smatrix[iDim]; + delete [] Smatrix; + + for (iVar = 0; iVar < nVar; iVar++) + delete [] cvector[iVar]; + delete [] cvector; +} + +void CPoissonSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, + CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { + unsigned long iPoint; + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) + LinSysRes.SetBlock_Zero(iPoint); + + StiffMatrix.SetValZero(); + +} + +void CPoissonSolver::Compute_Residual(CGeometry *geometry, CSolver **solver_container, CConfig *config, + unsigned short iMesh) { + + unsigned long iPoint; + unsigned short iVar = 0; + + /*--- Build linear system ---*/ + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { + LinSysRes[iPoint] = LinSysRes.GetBlock(iPoint, iVar); + LinSysSol[iPoint] = node[iPoint]->GetSolution(iVar); + } + + StiffMatrix.MatrixVectorProduct(LinSysSol, LinSysRes); + + /*--- Update residual ---*/ + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { + LinSysRes.SetBlock(iPoint, 0, LinSysRes[iPoint]); + } +} + +/*! + * \method Source_Residual + * \brief Source terms of the poisson solver + * \author A. Lonkar + */ +void CPoissonSolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, + CConfig *config, unsigned short iMesh) { +// +// unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, Point_3 = 0; +// su2double a[3], b[3], c[3], d[3], Area_Local, Volume_Local; +// // su2double Local_Delta_Time; +// su2double **Gradient_0, **Gradient_1, **Gradient_2, **Gradient_3; +// su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, *Coord_3= NULL;; +// unsigned short iDim; +// su2double dt; +// // su2double dx, u, c; +// bool MacCormack_relaxation = (config->GetMacCormackRelaxation()); +// +// if (nDim == 2) { +// if (config->GetPoissonSolver()) { +// +// for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { +// +// Point_0 = geometry->elem[iElem]->GetNode(0); +// Point_1 = geometry->elem[iElem]->GetNode(1); +// Point_2 = geometry->elem[iElem]->GetNode(2); +// +// Coord_0 = geometry->node[Point_0]->GetCoord(); +// Coord_1 = geometry->node[Point_1]->GetCoord(); +// Coord_2 = geometry->node[Point_2]->GetCoord(); +// +// for (iDim = 0; iDim < nDim; iDim++) { +// a[iDim] = Coord_0[iDim]-Coord_2[iDim]; +// b[iDim] = Coord_1[iDim]-Coord_2[iDim]; +// } +// +// Area_Local = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); +// +// Gradient_0 = node[Point_0]->GetPlasmaRhoUGradient(); +// Gradient_1 = node[Point_1]->GetPlasmaRhoUGradient(); +// Gradient_2 = node[Point_2]->GetPlasmaRhoUGradient(); +// +// numerics->SetVolume(Area_Local); +// +// dt = node[Point_0]->GetPlasmaTimeStep(); +// +// /* u = 4800; +// c = 87110; +// c = 800; +// dx = 0.004/81; +// Local_Delta_Time = config->GetCFL(iMesh) * dx/(u+c); +// numerics->SetTimeStep(Local_Delta_Time); +// */ +// +// numerics->SetCoord(Coord_0, Coord_1, Coord_2); +// numerics->SetTimeStep(dt); +// numerics->SetChargeDensity(node[Point_0]->GetChargeDensity(), node[Point_1]->GetChargeDensity(), node[Point_2]->GetChargeDensity(), node[Point_3]->GetChargeDensity()); +// numerics->SetConsVarGradient(Gradient_0, Gradient_1, Gradient_2 ); +// numerics->ComputeResidual_MacCormack(Source_Vector, config); +// +// LinSysRes.AddBlock(Point_0, &Source_Vector[0]); +// LinSysRes.AddBlock(Point_1, &Source_Vector[1]); +// LinSysRes.AddBlock(Point_2, &Source_Vector[2]); +// +// if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) { +// +// Point_0 = geometry->elem[iElem]->GetNode(3); +// Point_1 = geometry->elem[iElem]->GetNode(0); +// Point_2 = geometry->elem[iElem]->GetNode(2); +// +// Coord_0 = geometry->node[Point_0]->GetCoord(); +// Coord_1 = geometry->node[Point_1]->GetCoord(); +// Coord_2 = geometry->node[Point_2]->GetCoord(); +// +// for (iDim = 0; iDim < nDim; iDim++) { +// a[iDim] = Coord_0[iDim]-Coord_2[iDim]; +// b[iDim] = Coord_1[iDim]-Coord_2[iDim]; +// } +// +// Area_Local = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); +// +// Gradient_0 = node[Point_0]->GetPlasmaRhoUGradient(); +// Gradient_1 = node[Point_1]->GetPlasmaRhoUGradient(); +// Gradient_2 = node[Point_2]->GetPlasmaRhoUGradient(); +// +// numerics->SetVolume(Area_Local); +// +// /* u = 4800; +// c = 87110; +// c = 732.0; +// dx = 0.004/81; +// Local_Delta_Time = config->GetCFL(iMesh) * dx/(u+c); +// numerics->SetTimeStep(Local_Delta_Time); +// */ +// +// dt = node[Point_0]->GetPlasmaTimeStep(); +// numerics->SetCoord(Coord_0, Coord_1, Coord_2); +// numerics->SetTimeStep(dt); +// numerics->SetChargeDensity(node[Point_0]->GetChargeDensity(), node[Point_1]->GetChargeDensity(), node[Point_2]->GetChargeDensity(), node[Point_3]->GetChargeDensity()); +// numerics->SetConsVarGradient(Gradient_0, Gradient_1, Gradient_2 ); +// numerics->ComputeResidual_MacCormack(Source_Vector, config); +// LinSysRes.AddBlock(Point_0, &Source_Vector[0]); +// LinSysRes.AddBlock(Point_1, &Source_Vector[1]); +// LinSysRes.AddBlock(Point_2, &Source_Vector[2]); +// } +// } +// } +// } +// if (nDim == 3) { +// if (config->GetPoissonSolver()) { +// for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { +// Point_0 = geometry->elem[iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); +// Point_1 = geometry->elem[iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); +// Point_2 = geometry->elem[iElem]->GetNode(2); Coord_2 = geometry->node[Point_2]->GetCoord(); +// Point_3 = geometry->elem[iElem]->GetNode(3); Coord_3 = geometry->node[Point_3]->GetCoord(); +// +// for (iDim = 0; iDim < nDim; iDim++) { +// a[iDim] = Coord_0[iDim]-Coord_2[iDim]; +// b[iDim] = Coord_1[iDim]-Coord_2[iDim]; +// c[iDim] = Coord_3[iDim]-Coord_2[iDim]; +// } +// +// d[0] = a[1]*b[2]-a[2]*b[1]; +// d[1] = -(a[0]*b[2]-a[2]*b[0]); +// d[2] = a[0]*b[1]-a[1]*b[0]; +// +// /*--- Compute element volume ---*/ +// Volume_Local = fabs(c[0]*d[0] + c[1]*d[1] + c[2]*d[2])/6.0; +// numerics->SetVolume(Volume_Local); +// numerics->SetChargeDensity(node[Point_0]->GetChargeDensity(), node[Point_1]->GetChargeDensity(), node[Point_2]->GetChargeDensity(), node[Point_3]->GetChargeDensity()); +// +// if (MacCormack_relaxation) { +// +// Gradient_0 = node[Point_0]->GetPlasmaRhoUGradient(); +// Gradient_1 = node[Point_1]->GetPlasmaRhoUGradient(); +// Gradient_2 = node[Point_2]->GetPlasmaRhoUGradient(); +// Gradient_3 = node[Point_3]->GetPlasmaRhoUGradient(); +// numerics->SetCoord(Coord_0, Coord_1, Coord_2, Coord_3); +// numerics->SetConsVarGradient(Gradient_0, Gradient_1, Gradient_2, Gradient_3 ); +// numerics->ComputeResidual_MacCormack(Source_Vector, config); +// } +// else numerics->ComputeResidual(Source_Vector, config); +// +// LinSysRes.AddBlock(Point_0, &Source_Vector[0]); +// LinSysRes.AddBlock(Point_1, &Source_Vector[1]); +// LinSysRes.AddBlock(Point_2, &Source_Vector[2]); +// LinSysRes.AddBlock(Point_3, &Source_Vector[3]); +// } +// } +// } +} + +void CPoissonSolver::Source_Template(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config, unsigned short iMesh) { +} + + +/*! + * \method Copy_Zone_Solution + * \brief Copy solution from solver 1 into solver 2 + * \author A. Lonkar + */ +void CPoissonSolver::Copy_Zone_Solution(CSolver ***solver1_solution, + CGeometry **solver1_geometry, + CConfig *solver1_config, + CSolver ***solver2_solution, + CGeometry **solver2_geometry, + CConfig *solver2_config) { + unsigned long iPoint; + unsigned short iDim; + su2double neg_EFvalue; + su2double *E_field = new su2double [nDim]; + + for (iPoint = 0; iPoint < solver1_geometry[MESH_0]->GetnPointDomain(); iPoint++) { + for (iDim =0; iDim < nDim; iDim ++) { + neg_EFvalue = solver1_solution[MESH_0][POISSON_SOL]->node[iPoint]->GetGradient(0, iDim); + E_field[iDim] = -1.0*neg_EFvalue; + } + } +}; + +/*! + * \method Galerkin_Method + * \brief calculate the element stiffness matrix + * \author A. Lonkar + */ +void CPoissonSolver::Viscous_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config, unsigned short iMesh, unsigned short iRKStep) { + + unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, Point_3 = 0; + su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, *Coord_3 = NULL; + + if (nDim == 2 ) { + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + Point_0 = geometry->elem[iElem]->GetNode(0); + Point_1 = geometry->elem[iElem]->GetNode(1); + Point_2 = geometry->elem[iElem]->GetNode(2); + + Coord_0 = geometry->node[Point_0]->GetCoord(); + Coord_1 = geometry->node[Point_1]->GetCoord(); + Coord_2 = geometry->node[Point_2]->GetCoord(); + + numerics->SetCoord(Coord_0, Coord_1, Coord_2); + numerics->ComputeResidual(StiffMatrix_Elem, config); + AddStiffMatrix(StiffMatrix_Elem, Point_0, Point_1, Point_2, Point_3); + } + } + + if (nDim == 3 ) { + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + Point_0 = geometry->elem[iElem]->GetNode(0); Coord_0 = geometry->node[Point_0]->GetCoord(); + Point_1 = geometry->elem[iElem]->GetNode(1); Coord_1 = geometry->node[Point_1]->GetCoord(); + Point_2 = geometry->elem[iElem]->GetNode(2); Coord_2 = geometry->node[Point_2]->GetCoord(); + Point_3 = geometry->elem[iElem]->GetNode(3); Coord_3 = geometry->node[Point_3]->GetCoord(); + + numerics->SetCoord(Coord_0, Coord_1, Coord_2, Coord_3); + numerics->ComputeResidual(StiffMatrix_Elem, config); + AddStiffMatrix(StiffMatrix_Elem, Point_0, Point_1, Point_2, Point_3); + + } + } +} + +/*! + * \method AddStiffMatrix + * \brief Assemble the Global stiffness matrix + * \author A. Lonkar + */ +void CPoissonSolver::AddStiffMatrix(su2double **StiffMatrix_Elem, unsigned long Point_0, unsigned long Point_1, unsigned long Point_2, unsigned long Point_3) { + + if (nDim == 2 ) { + StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][0]; StiffMatrix.AddBlock(Point_0, Point_0, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][1]; StiffMatrix.AddBlock(Point_0, Point_1, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][2]; StiffMatrix.AddBlock(Point_0, Point_2, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][0]; StiffMatrix.AddBlock(Point_1, Point_0, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][1]; StiffMatrix.AddBlock(Point_1, Point_1, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][2]; StiffMatrix.AddBlock(Point_1, Point_2, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][0]; StiffMatrix.AddBlock(Point_2, Point_0, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][1]; StiffMatrix.AddBlock(Point_2, Point_1, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][2]; StiffMatrix.AddBlock(Point_2, Point_2, StiffMatrix_Node); + } + if (nDim == 3) { + + StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][0]; StiffMatrix.AddBlock(Point_0, Point_0, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][1]; StiffMatrix.AddBlock(Point_0, Point_1, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][2]; StiffMatrix.AddBlock(Point_0, Point_2, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[0][3]; StiffMatrix.AddBlock(Point_0, Point_3, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][0]; StiffMatrix.AddBlock(Point_1, Point_0, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][1]; StiffMatrix.AddBlock(Point_1, Point_1, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][2]; StiffMatrix.AddBlock(Point_1, Point_2, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[1][3]; StiffMatrix.AddBlock(Point_1, Point_3, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][0]; StiffMatrix.AddBlock(Point_2, Point_0, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][1]; StiffMatrix.AddBlock(Point_2, Point_1, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][2]; StiffMatrix.AddBlock(Point_2, Point_2, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[2][3]; StiffMatrix.AddBlock(Point_2, Point_3, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[3][0]; StiffMatrix.AddBlock(Point_3, Point_0, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[3][1]; StiffMatrix.AddBlock(Point_3, Point_1, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[3][2]; StiffMatrix.AddBlock(Point_3, Point_2, StiffMatrix_Node); + StiffMatrix_Node[0][0] = StiffMatrix_Elem[3][3]; StiffMatrix.AddBlock(Point_3, Point_3, StiffMatrix_Node); + + } +} + +void CPoissonSolver::BC_Dirichlet(CGeometry *geometry, CSolver **solver_container, + CConfig *config, unsigned short val_marker) { + unsigned long Point, iVertex; + + /*--- Identify if a boundary is Dirichlet or Neumman ---*/ + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + Point = geometry->vertex[val_marker][iVertex]->GetNode(); + Solution[0]= 10.0; + node[Point]->SetSolution(Solution); + + LinSysRes.SetBlock(Point, Solution); + LinSysSol.SetBlock(Point, Solution); + + StiffMatrix.DeleteValsRowi(Point); // & includes 1 in the diagonal + } + +} + +void CPoissonSolver::BC_Neumann(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, + unsigned short val_marker) { } + +void CPoissonSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { + + unsigned long iPoint, total_index; + unsigned short iVar; + + /*--- Build implicit system ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + LinSysSol[total_index] = 0.0; + } + + } + + /*--- Initialize residual and solution at the ghost points ---*/ + + for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar + iVar; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + } + } + + /*--- Solve or smooth the linear system ---*/ + + CSysSolve system; + system.Solve(StiffMatrix, LinSysRes, LinSysSol, geometry, config); + + /*--- Update solution (system written in terms of increments) ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + node[iPoint]->SetSolution(iVar, LinSysSol[iPoint*nVar+iVar]); + } + } + + /*--- MPI solution ---*/ + + Set_MPI_Solution(geometry, config); + + /*--- Compute the residual Ax-f ---*/ + + StiffMatrix.ComputeResidual(LinSysSol, LinSysRes, LinSysAux); + + /*--- Set maximum residual to zero ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + SetRes_RMS(iVar, 0.0); + SetRes_Max(iVar, 0.0, 0); + } + + /*--- Compute the residual ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + AddRes_RMS(iVar, LinSysAux[total_index]*LinSysAux[total_index]); + AddRes_Max(iVar, fabs(LinSysAux[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); + } + } + + /*--- Compute the root mean square residual ---*/ + + SetResidual_RMS(geometry, config); + +} diff --git a/SU2_CFD/src/solver_direct_turbulent.cpp b/SU2_CFD/src/solver_direct_turbulent.cpp index fdec52a2650..942ed278a5e 100644 --- a/SU2_CFD/src/solver_direct_turbulent.cpp +++ b/SU2_CFD/src/solver_direct_turbulent.cpp @@ -1,3221 +1,3221 @@ -/*! - * \file solution_direct_turbulent.cpp - * \brief Main subrotuines for solving direct problems - * \author F. Palacios, A. Bueno - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/solver_structure.hpp" - -CTurbSolver::CTurbSolver(void) : CSolver() { - - FlowPrimVar_i = NULL; - FlowPrimVar_j = NULL; - lowerlimit = NULL; - upperlimit = NULL; - -} - -CTurbSolver::CTurbSolver(CConfig *config) : CSolver() { - - Gamma = config->GetGamma(); - Gamma_Minus_One = Gamma - 1.0; - - FlowPrimVar_i = NULL; - FlowPrimVar_j = NULL; - lowerlimit = NULL; - upperlimit = NULL; - -} - -CTurbSolver::~CTurbSolver(void) { - - if (FlowPrimVar_i != NULL) delete [] FlowPrimVar_i; - if (FlowPrimVar_j != NULL) delete [] FlowPrimVar_j; - if (lowerlimit != NULL) delete [] lowerlimit; - if (upperlimit != NULL) delete [] upperlimit; - -} - -void CTurbSolver::Set_MPI_Solution(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iMarker, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector, nBufferS_Scalar, nBufferR_Scalar; - su2double *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL, *Buffer_Receive_muT = NULL, *Buffer_Send_muT = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - nBufferS_Scalar = nVertexS; nBufferR_Scalar = nVertexR; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_U = new su2double [nBufferR_Vector]; - Buffer_Send_U = new su2double[nBufferS_Vector]; - - Buffer_Receive_muT = new su2double [nBufferR_Scalar]; - Buffer_Send_muT = new su2double[nBufferS_Scalar]; - - /*--- Copy the solution that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - Buffer_Send_muT[iVertex] = node[iPoint]->GetmuT(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution(iVar); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); - SU2_MPI::Sendrecv(Buffer_Send_muT, nBufferS_Scalar, MPI_DOUBLE, send_to, 1, - Buffer_Receive_muT, nBufferR_Scalar, MPI_DOUBLE, receive_from, 1, MPI_COMM_WORLD, &status); -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - Buffer_Receive_muT[iVertex] = node[iPoint]->GetmuT(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_U; - delete [] Buffer_Send_muT; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - - /*--- Copy conservative variables. ---*/ - node[iPoint]->SetmuT(Buffer_Receive_muT[iVertex]); - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetSolution(iVar, Buffer_Receive_U[iVar*nVertexR+iVertex]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_muT; - delete [] Buffer_Receive_U; - - } - - } - -} - -void CTurbSolver::Set_MPI_Solution_Old(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iMarker, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_U = new su2double [nBufferR_Vector]; - Buffer_Send_U = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution_Old(iVar); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_U; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - - /*--- Copy transformed conserved variables back into buffer. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetSolution_Old(iVar, Buffer_Receive_U[iVar*nVertexR+iVertex]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_U; - - } - - } -} - -void CTurbSolver::Set_MPI_Solution_Gradient(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, - *Buffer_Receive_Gradient = NULL, *Buffer_Send_Gradient = NULL; - - su2double **Gradient = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - Gradient[iVar] = new su2double[nDim]; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar*nDim; nBufferR_Vector = nVertexR*nVar*nDim; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_Gradient = new su2double [nBufferR_Vector]; - Buffer_Send_Gradient = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Gradient[iDim*nVar*nVertexS+iVar*nVertexS+iVertex] = node[iPoint]->GetGradient(iVar, iDim); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Gradient, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_Gradient, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex] = Buffer_Send_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_Gradient; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Gradient[iVar][iDim] = Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; - - /*--- Need to rotate the gradients for all conserved variables. ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - if (nDim == 2) { - Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; - } - else { - Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; - Gradient[iVar][2] = rotMatrix[2][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; - } - } - - /*--- Store the received information ---*/ - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - node[iPoint]->SetGradient(iVar, iDim, Gradient[iVar][iDim]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_Gradient; - - } - - } - - for (iVar = 0; iVar < nVar; iVar++) - delete [] Gradient[iVar]; - delete [] Gradient; - -} - -void CTurbSolver::Set_MPI_Solution_Limiter(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iMarker, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double *Buffer_Receive_Limit = NULL, *Buffer_Send_Limit = NULL; - - su2double *Limiter = new su2double [nVar]; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - - /*--- Allocate Receive and send buffers ---*/ - Buffer_Receive_Limit = new su2double [nBufferR_Vector]; - Buffer_Send_Limit = new su2double[nBufferS_Vector]; - - /*--- Copy the solution old that should be sended ---*/ - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_Limit[iVar*nVertexS+iVertex] = node[iPoint]->GetLimiter(iVar); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Limit, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_Limit, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); -#else - - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_Limit[iVar*nVertexR+iVertex] = Buffer_Send_Limit[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - delete [] Buffer_Send_Limit; - - /*--- Do the coordinate transformation ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - - /*--- Copy transformed conserved variables back into buffer. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetLimiter(iVar, Buffer_Receive_Limit[iVar*nVertexR+iVertex]); - - } - - /*--- Deallocate receive buffer ---*/ - delete [] Buffer_Receive_Limit; - - } - - } - - delete [] Limiter; - -} - - -void CTurbSolver::Upwind_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, unsigned short iMesh) { - - su2double *Turb_i, *Turb_j, *Limiter_i = NULL, *Limiter_j = NULL, *V_i, *V_j, **Gradient_i, **Gradient_j, Project_Grad_i, Project_Grad_j; - unsigned long iEdge, iPoint, jPoint; - unsigned short iDim, iVar; - - bool second_order = ((config->GetSpatialOrder() == SECOND_ORDER) || (config->GetSpatialOrder() == SECOND_ORDER_LIMITER)); - bool limiter = (config->GetSpatialOrder() == SECOND_ORDER_LIMITER); - bool grid_movement = config->GetGrid_Movement(); - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Points in edge and normal vectors ---*/ - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); - - /*--- Primitive variables w/o reconstruction ---*/ - - V_i = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - V_j = solver_container[FLOW_SOL]->node[jPoint]->GetPrimitive(); - numerics->SetPrimitive(V_i, V_j); - - /*--- Turbulent variables w/o reconstruction ---*/ - - Turb_i = node[iPoint]->GetSolution(); - Turb_j = node[jPoint]->GetSolution(); - numerics->SetTurbVar(Turb_i, Turb_j); - - /*--- Grid Movement ---*/ - - if (grid_movement) - numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[jPoint]->GetGridVel()); - - if (second_order) { - - for (iDim = 0; iDim < nDim; iDim++) { - Vector_i[iDim] = 0.5*(geometry->node[jPoint]->GetCoord(iDim) - geometry->node[iPoint]->GetCoord(iDim)); - Vector_j[iDim] = 0.5*(geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim)); - } - - /*--- Mean flow primitive variables using gradient reconstruction and limiters ---*/ - - Gradient_i = solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(); - Gradient_j = solver_container[FLOW_SOL]->node[jPoint]->GetGradient_Primitive(); - if (limiter) { - Limiter_i = solver_container[FLOW_SOL]->node[iPoint]->GetLimiter_Primitive(); - Limiter_j = solver_container[FLOW_SOL]->node[jPoint]->GetLimiter_Primitive(); - } - - for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnPrimVarGrad(); iVar++) { - Project_Grad_i = 0.0; Project_Grad_j = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Project_Grad_i += Vector_i[iDim]*Gradient_i[iVar][iDim]; - Project_Grad_j += Vector_j[iDim]*Gradient_j[iVar][iDim]; - } - if (limiter) { - FlowPrimVar_i[iVar] = V_i[iVar] + Limiter_i[iVar]*Project_Grad_i; - FlowPrimVar_j[iVar] = V_j[iVar] + Limiter_j[iVar]*Project_Grad_j; - } - else { - FlowPrimVar_i[iVar] = V_i[iVar] + Project_Grad_i; - FlowPrimVar_j[iVar] = V_j[iVar] + Project_Grad_j; - } - } - - numerics->SetPrimitive(FlowPrimVar_i, FlowPrimVar_j); - - /*--- Turbulent variables using gradient reconstruction and limiters ---*/ - - Gradient_i = node[iPoint]->GetGradient(); - Gradient_j = node[jPoint]->GetGradient(); - if (limiter) { - Limiter_i = node[iPoint]->GetLimiter(); - Limiter_j = node[jPoint]->GetLimiter(); - } - - for (iVar = 0; iVar < nVar; iVar++) { - Project_Grad_i = 0.0; Project_Grad_j = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Project_Grad_i += Vector_i[iDim]*Gradient_i[iVar][iDim]; - Project_Grad_j += Vector_j[iDim]*Gradient_j[iVar][iDim]; - } - if (limiter) { - Solution_i[iVar] = Turb_i[iVar] + Limiter_i[iVar]*Project_Grad_i; - Solution_j[iVar] = Turb_j[iVar] + Limiter_j[iVar]*Project_Grad_j; - } - else { - Solution_i[iVar] = Turb_i[iVar] + Project_Grad_i; - Solution_j[iVar] = Turb_j[iVar] + Project_Grad_j; - } - } - - numerics->SetTurbVar(Solution_i, Solution_j); - - } - - /*--- Add and subtract residual ---*/ - - numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - LinSysRes.AddBlock(iPoint, Residual); - LinSysRes.SubtractBlock(jPoint, Residual); - - /*--- Implicit part ---*/ - - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - Jacobian.AddBlock(iPoint, jPoint, Jacobian_j); - Jacobian.SubtractBlock(jPoint, iPoint, Jacobian_i); - Jacobian.SubtractBlock(jPoint, jPoint, Jacobian_j); - - } - -} - -void CTurbSolver::Viscous_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config, unsigned short iMesh, unsigned short iRKStep) { - unsigned long iEdge, iPoint, jPoint; - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Points in edge ---*/ - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - - /*--- Points coordinates, and normal vector ---*/ - - numerics->SetCoord(geometry->node[iPoint]->GetCoord(), - geometry->node[jPoint]->GetCoord()); - numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); - - /*--- Conservative variables w/o reconstruction ---*/ - - numerics->SetPrimitive(solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(), - solver_container[FLOW_SOL]->node[jPoint]->GetPrimitive()); - - /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ - - numerics->SetTurbVar(node[iPoint]->GetSolution(), node[jPoint]->GetSolution()); - numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), node[jPoint]->GetGradient()); - - /*--- Menter's first blending function (only SST)---*/ - if (config->GetKind_Turb_Model() == SST) - numerics->SetF1blending(node[iPoint]->GetF1blending(), node[jPoint]->GetF1blending()); - - /*--- Compute residual, and Jacobians ---*/ - - numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Add and subtract residual, and update Jacobians ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual); - LinSysRes.AddBlock(jPoint, Residual); - - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - Jacobian.SubtractBlock(iPoint, jPoint, Jacobian_j); - Jacobian.AddBlock(jPoint, iPoint, Jacobian_i); - Jacobian.AddBlock(jPoint, jPoint, Jacobian_j); - - } - -} - -void CTurbSolver::BC_Sym_Plane(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - /*--- Convective fluxes across symmetry plane are equal to zero. ---*/ - -} - -void CTurbSolver::BC_Euler_Wall(CGeometry *geometry, CSolver **solver_container, - CNumerics *numerics, CConfig *config, unsigned short val_marker) { - - /*--- Convective fluxes across euler wall are equal to zero. ---*/ - -} - -void CTurbSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { - - unsigned short iVar; - unsigned long iPoint, total_index; - su2double Delta, Vol, density_old = 0.0, density = 0.0; - - bool adjoint = config->GetAdjoint(); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - - /*--- Set maximum residual to zero ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - SetRes_RMS(iVar, 0.0); - SetRes_Max(iVar, 0.0, 0); - } - - /*--- Build implicit system ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Read the volume ---*/ - - Vol = geometry->node[iPoint]->GetVolume(); - - /*--- Modify matrix diagonal to assure diagonal dominance ---*/ - - Delta = Vol / (config->GetCFLRedCoeff_Turb()*solver_container[FLOW_SOL]->node[iPoint]->GetDelta_Time()); - Jacobian.AddVal2Diag(iPoint, Delta); - - /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - LinSysRes[total_index] = - LinSysRes[total_index]; - LinSysSol[total_index] = 0.0; - AddRes_RMS(iVar, LinSysRes[total_index]*LinSysRes[total_index]); - AddRes_Max(iVar, fabs(LinSysRes[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); - } - } - - /*--- Initialize residual and solution at the ghost points ---*/ - - for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar + iVar; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - } - } - - /*--- Solve or smooth the linear system ---*/ - - CSysSolve system; - system.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); - - /*--- Update solution (system written in terms of increments) ---*/ - - if (!adjoint) { - - /*--- Update and clip trubulent solution ---*/ - - switch (config->GetKind_Turb_Model()) { - - case SA: - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - node[iPoint]->AddClippedSolution(0, config->GetRelaxation_Factor_Turb()*LinSysSol[iPoint], lowerlimit[0], upperlimit[0]); - } - - break; - - case SA_NEG: - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - node[iPoint]->AddSolution(0, config->GetRelaxation_Factor_Turb()*LinSysSol[iPoint]); - } - - break; - - case SST: - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - if (compressible) { - density_old = solver_container[FLOW_SOL]->node[iPoint]->GetSolution_Old(0); - density = solver_container[FLOW_SOL]->node[iPoint]->GetDensity(); - } - if (incompressible || freesurface) { - density_old = solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); - density = solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); - } - - for (iVar = 0; iVar < nVar; iVar++) { - node[iPoint]->AddConservativeSolution(iVar, config->GetRelaxation_Factor_Turb()*LinSysSol[iPoint*nVar+iVar], density, density_old, lowerlimit[iVar], upperlimit[iVar]); - } - - } - - break; - - } - } - - - /*--- MPI solution ---*/ - - Set_MPI_Solution(geometry, config); - - /*--- Compute the root mean square residual ---*/ - - SetResidual_RMS(geometry, config); - -} - -void CTurbSolver::SetResidual_DualTime(CGeometry *geometry, CSolver **solver_container, CConfig *config, - unsigned short iRKStep, unsigned short iMesh, unsigned short RunTime_EqSystem) { - - /*--- Local variables ---*/ - - unsigned short iVar, jVar, iMarker, iDim; - unsigned long iPoint, jPoint, iEdge, iVertex; - - su2double *U_time_nM1, *U_time_n, *U_time_nP1; - su2double Volume_nM1, Volume_nP1, TimeStep; - su2double Density_nM1, Density_n, Density_nP1; - su2double *Normal = NULL, *GridVel_i = NULL, *GridVel_j = NULL, Residual_GCL; - - bool implicit = (config->GetKind_TimeIntScheme_Turb() == EULER_IMPLICIT); - bool grid_movement = config->GetGrid_Movement(); - - /*--- Store the physical time step ---*/ - - TimeStep = config->GetDelta_UnstTimeND(); - - /*--- Compute the dual time-stepping source term for static meshes ---*/ - - if (!grid_movement) { - - /*--- Loop over all nodes (excluding halos) ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Retrieve the solution at time levels n-1, n, and n+1. Note that - we are currently iterating on U^n+1 and that U^n & U^n-1 are fixed, - previous solutions that are stored in memory. ---*/ - - U_time_nM1 = node[iPoint]->GetSolution_time_n1(); - U_time_n = node[iPoint]->GetSolution_time_n(); - U_time_nP1 = node[iPoint]->GetSolution(); - - /*--- CV volume at time n+1. As we are on a static mesh, the volume - of the CV will remained fixed for all time steps. ---*/ - - Volume_nP1 = geometry->node[iPoint]->GetVolume(); - - /*--- Compute the dual time-stepping source term based on the chosen - time discretization scheme (1st- or 2nd-order).---*/ - - if (config->GetKind_Turb_Model() == SST) { - - /*--- If this is the SST model, we need to multiply by the density - in order to get the conservative variables ---*/ - Density_nM1 = solver_container[FLOW_SOL]->node[iPoint]->GetSolution_time_n1()[0]; - Density_n = solver_container[FLOW_SOL]->node[iPoint]->GetSolution_time_n()[0]; - Density_nP1 = solver_container[FLOW_SOL]->node[iPoint]->GetSolution()[0]; - - for (iVar = 0; iVar < nVar; iVar++) { - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Residual[iVar] = ( Density_nP1*U_time_nP1[iVar] - Density_n*U_time_n[iVar])*Volume_nP1 / TimeStep; - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - Residual[iVar] = ( 3.0*Density_nP1*U_time_nP1[iVar] - 4.0*Density_n*U_time_n[iVar] - +1.0*Density_nM1*U_time_nM1[iVar])*Volume_nP1 / (2.0*TimeStep); - } - - } else { - - for (iVar = 0; iVar < nVar; iVar++) { - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Residual[iVar] = (U_time_nP1[iVar] - U_time_n[iVar])*Volume_nP1 / TimeStep; - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - Residual[iVar] = ( 3.0*U_time_nP1[iVar] - 4.0*U_time_n[iVar] - +1.0*U_time_nM1[iVar])*Volume_nP1 / (2.0*TimeStep); - } - } - - /*--- Store the residual and compute the Jacobian contribution due - to the dual time source term. ---*/ - - LinSysRes.AddBlock(iPoint, Residual); - if (implicit) { - for (iVar = 0; iVar < nVar; iVar++) { - for (jVar = 0; jVar < nVar; jVar++) Jacobian_i[iVar][jVar] = 0.0; - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Jacobian_i[iVar][iVar] = Volume_nP1 / TimeStep; - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - Jacobian_i[iVar][iVar] = (Volume_nP1*3.0)/(2.0*TimeStep); - } - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - } - } - - } else { - - /*--- For unsteady flows on dynamic meshes (rigidly transforming or - dynamically deforming), the Geometric Conservation Law (GCL) should be - satisfied in conjunction with the ALE formulation of the governing - equations. The GCL prevents accuracy issues caused by grid motion, i.e. - a uniform free-stream should be preserved through a moving grid. First, - we will loop over the edges and boundaries to compute the GCL component - of the dual time source term that depends on grid velocities. ---*/ - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Get indices for nodes i & j plus the face normal ---*/ - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - Normal = geometry->edge[iEdge]->GetNormal(); - - /*--- Grid velocities stored at nodes i & j ---*/ - - GridVel_i = geometry->node[iPoint]->GetGridVel(); - GridVel_j = geometry->node[jPoint]->GetGridVel(); - - /*--- Compute the GCL term by averaging the grid velocities at the - edge mid-point and dotting with the face normal. ---*/ - - Residual_GCL = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Residual_GCL += 0.5*(GridVel_i[iDim]+GridVel_j[iDim])*Normal[iDim]; - - /*--- Compute the GCL component of the source term for node i ---*/ - - U_time_n = node[iPoint]->GetSolution_time_n(); - - /*--- Multiply by density at node i for the SST model ---*/ - - if (config->GetKind_Turb_Model() == SST) { - Density_n = solver_container[FLOW_SOL]->node[iPoint]->GetSolution_time_n()[0]; - for (iVar = 0; iVar < nVar; iVar++) - Residual[iVar] = Density_n*U_time_n[iVar]*Residual_GCL; - } else { - for (iVar = 0; iVar < nVar; iVar++) - Residual[iVar] = U_time_n[iVar]*Residual_GCL; - } - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Compute the GCL component of the source term for node j ---*/ - - U_time_n = node[jPoint]->GetSolution_time_n(); - - /*--- Multiply by density at node j for the SST model ---*/ - - if (config->GetKind_Turb_Model() == SST) { - Density_n = solver_container[FLOW_SOL]->node[jPoint]->GetSolution_time_n()[0]; - for (iVar = 0; iVar < nVar; iVar++) - Residual[iVar] = Density_n*U_time_n[iVar]*Residual_GCL; - } else { - for (iVar = 0; iVar < nVar; iVar++) - Residual[iVar] = U_time_n[iVar]*Residual_GCL; - } - LinSysRes.SubtractBlock(jPoint, Residual); - - } - - /*--- Loop over the boundary edges ---*/ - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - - /*--- Get the index for node i plus the boundary face normal ---*/ - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - - /*--- Grid velocities stored at boundary node i ---*/ - - GridVel_i = geometry->node[iPoint]->GetGridVel(); - - /*--- Compute the GCL term by dotting the grid velocity with the face - normal. The normal is negated to match the boundary convention. ---*/ - - Residual_GCL = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Residual_GCL -= 0.5*(GridVel_i[iDim]+GridVel_i[iDim])*Normal[iDim]; - - /*--- Compute the GCL component of the source term for node i ---*/ - - U_time_n = node[iPoint]->GetSolution_time_n(); - - /*--- Multiply by density at node i for the SST model ---*/ - - if (config->GetKind_Turb_Model() == SST) { - Density_n = solver_container[FLOW_SOL]->node[iPoint]->GetSolution_time_n()[0]; - for (iVar = 0; iVar < nVar; iVar++) - Residual[iVar] = Density_n*U_time_n[iVar]*Residual_GCL; - } else { - for (iVar = 0; iVar < nVar; iVar++) - Residual[iVar] = U_time_n[iVar]*Residual_GCL; - } - LinSysRes.AddBlock(iPoint, Residual); - } - } - - /*--- Loop over all nodes (excluding halos) to compute the remainder - of the dual time-stepping source term. ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Retrieve the solution at time levels n-1, n, and n+1. Note that - we are currently iterating on U^n+1 and that U^n & U^n-1 are fixed, - previous solutions that are stored in memory. ---*/ - - U_time_nM1 = node[iPoint]->GetSolution_time_n1(); - U_time_n = node[iPoint]->GetSolution_time_n(); - U_time_nP1 = node[iPoint]->GetSolution(); - - /*--- CV volume at time n-1 and n+1. In the case of dynamically deforming - grids, the volumes will change. On rigidly transforming grids, the - volumes will remain constant. ---*/ - - Volume_nM1 = geometry->node[iPoint]->GetVolume_nM1(); - Volume_nP1 = geometry->node[iPoint]->GetVolume(); - - /*--- Compute the dual time-stepping source residual. Due to the - introduction of the GCL term above, the remainder of the source residual - due to the time discretization has a new form.---*/ - - if (config->GetKind_Turb_Model() == SST) { - - /*--- If this is the SST model, we need to multiply by the density - in order to get the conservative variables ---*/ - Density_nM1 = solver_container[FLOW_SOL]->node[iPoint]->GetSolution_time_n1()[0]; - Density_n = solver_container[FLOW_SOL]->node[iPoint]->GetSolution_time_n()[0]; - Density_nP1 = solver_container[FLOW_SOL]->node[iPoint]->GetSolution()[0]; - - for (iVar = 0; iVar < nVar; iVar++) { - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Residual[iVar] = (Density_nP1*U_time_nP1[iVar] - Density_n*U_time_n[iVar])*(Volume_nP1/TimeStep); - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - Residual[iVar] = (Density_nP1*U_time_nP1[iVar] - Density_n*U_time_n[iVar])*(3.0*Volume_nP1/(2.0*TimeStep)) - + (Density_nM1*U_time_nM1[iVar] - Density_n*U_time_n[iVar])*(Volume_nM1/(2.0*TimeStep)); - } - - } else { - - for (iVar = 0; iVar < nVar; iVar++) { - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Residual[iVar] = (U_time_nP1[iVar] - U_time_n[iVar])*(Volume_nP1/TimeStep); - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - Residual[iVar] = (U_time_nP1[iVar] - U_time_n[iVar])*(3.0*Volume_nP1/(2.0*TimeStep)) - + (U_time_nM1[iVar] - U_time_n[iVar])*(Volume_nM1/(2.0*TimeStep)); - } - } - - /*--- Store the residual and compute the Jacobian contribution due - to the dual time source term. ---*/ - - LinSysRes.AddBlock(iPoint, Residual); - if (implicit) { - for (iVar = 0; iVar < nVar; iVar++) { - for (jVar = 0; jVar < nVar; jVar++) Jacobian_i[iVar][jVar] = 0.0; - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Jacobian_i[iVar][iVar] = Volume_nP1/TimeStep; - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - Jacobian_i[iVar][iVar] = (3.0*Volume_nP1)/(2.0*TimeStep); - } - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - } - } - } - -} - -CTurbSASolver::CTurbSASolver(void) : CTurbSolver() { } - -CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned short iMesh, CFluidModel* FluidModel) : CTurbSolver() { - unsigned short iVar, iDim, nLineLets; - unsigned long iPoint, index; - su2double Density_Inf, Viscosity_Inf, Factor_nu_Inf, Factor_nu_Engine, dull_val; - - unsigned short iZone = config->GetiZone(); - unsigned short nZone = geometry->GetnZone(); - bool restart = (config->GetRestart() || config->GetRestart_Flow()); - bool adjoint = config->GetAdjoint(); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - Gamma = config->GetGamma(); - Gamma_Minus_One = Gamma - 1.0; - - /*--- Dimension of the problem --> dependent of the turbulent model ---*/ - - nVar = 1; - nPoint = geometry->GetnPoint(); - nPointDomain = geometry->GetnPointDomain(); - - /*--- Define geometry constants in the solver structure ---*/ - - nDim = geometry->GetnDim(); - node = new CVariable*[nPoint]; - - /*--- Single grid simulation ---*/ - - if (iMesh == MESH_0 || config->GetMGCycle() == FULLMG_CYCLE) { - - /*--- Define some auxiliar vector related with the residual ---*/ - - Residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; - Residual_RMS = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_RMS[iVar] = 0.0; - Residual_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_i[iVar] = 0.0; - Residual_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_j[iVar] = 0.0; - Residual_Max = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_Max[iVar] = 0.0; - - /*--- Define some structures for locating max residuals ---*/ - - Point_Max = new unsigned long[nVar]; - for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; - Point_Max_Coord = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Point_Max_Coord[iVar] = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; - } - - /*--- Define some auxiliar vector related with the solution ---*/ - - Solution = new su2double[nVar]; - Solution_i = new su2double[nVar]; Solution_j = new su2double[nVar]; - - /*--- Define some auxiliar vector related with the geometry ---*/ - - Vector_i = new su2double[nDim]; Vector_j = new su2double[nDim]; - - /*--- Define some auxiliar vector related with the flow solution ---*/ - - FlowPrimVar_i = new su2double [nDim+7]; FlowPrimVar_j = new su2double [nDim+7]; - - /*--- Jacobians and vector structures for implicit computations ---*/ - - Jacobian_i = new su2double* [nVar]; - Jacobian_j = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Jacobian_i[iVar] = new su2double [nVar]; - Jacobian_j[iVar] = new su2double [nVar]; - } - - /*--- Initialization of the structure of the whole Jacobian ---*/ - - if (rank == MASTER_NODE) cout << "Initialize Jacobian structure (SA model)." << endl; - Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); - - if ((config->GetKind_Linear_Solver_Prec() == LINELET) || - (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { - nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); - if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; - } - - LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); - - if (config->GetExtraOutput()) { - if (nDim == 2) { nOutputVariables = 13; } - else if (nDim == 3) { nOutputVariables = 19; } - OutputVariables.Initialize(nPoint, nPointDomain, nOutputVariables, 0.0); - OutputHeadingNames = new string[nOutputVariables]; - } - - /*--- Computation of gradients by least squares ---*/ - - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { - /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ - Smatrix = new su2double* [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Smatrix[iDim] = new su2double [nDim]; - - /*--- c vector := transpose(WA)*(Wb) ---*/ - - cvector = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - cvector[iVar] = new su2double [nDim]; - } - - } - - /*--- Initialize lower and upper limits---*/ - - lowerlimit = new su2double[nVar]; - upperlimit = new su2double[nVar]; - - lowerlimit[0] = 1.0e-10; - upperlimit[0] = 1.0; - - - /*--- Read farfield conditions from config ---*/ - - Density_Inf = config->GetDensity_FreeStreamND(); - Viscosity_Inf = config->GetViscosity_FreeStreamND(); - - /*--- Factor_nu_Inf in [3.0, 5.0] ---*/ - - Factor_nu_Inf = config->GetNuFactor_FreeStream(); - nu_tilde_Inf = Factor_nu_Inf*Viscosity_Inf/Density_Inf; - - /*--- Factor_nu_Engine ---*/ - Factor_nu_Engine = config->GetNuFactor_Engine(); - nu_tilde_Engine = Factor_nu_Engine*Viscosity_Inf/Density_Inf; - - /*--- Eddy viscosity at infinity ---*/ - su2double Ji, Ji_3, fv1, cv1_3 = 7.1*7.1*7.1; - su2double muT_Inf; - Ji = nu_tilde_Inf/Viscosity_Inf*Density_Inf; - Ji_3 = Ji*Ji*Ji; - fv1 = Ji_3/(Ji_3+cv1_3); - muT_Inf = Density_Inf*fv1*nu_tilde_Inf; - - /*--- Restart the solution from file information ---*/ - if (!restart || (iMesh != MESH_0)) { - for (iPoint = 0; iPoint < nPoint; iPoint++) - node[iPoint] = new CTurbSAVariable(nu_tilde_Inf, muT_Inf, nDim, nVar, config); - } - else { - - /*--- Restart the solution from file information ---*/ - ifstream restart_file; - string filename = config->GetSolution_FlowFileName(); - su2double Density, StaticEnergy, Laminar_Viscosity, nu, nu_hat, muT = 0.0, U[5]; - - /*--- Modify file name for an unsteady restart ---*/ - if (dual_time) { - int Unst_RestartIter; - if (adjoint) { - Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_AdjointIter()) - 1; - } else if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_RestartIter())-1; - else - Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_RestartIter())-2; - filename = config->GetUnsteady_FileName(filename, Unst_RestartIter); - } - if (nZone >1) - filename= config->GetRestart_FlowFileName(filename, iZone); - - - /*--- Open the restart file, throw an error if this fails. ---*/ - restart_file.open(filename.data(), ios::in); - if (restart_file.fail()) { - cout << "There is no turbulent restart file!!" << endl; - exit(EXIT_FAILURE); - } - - /*--- In case this is a parallel simulation, we need to perform the - Global2Local index transformation first. ---*/ - long *Global2Local; - Global2Local = new long[geometry->GetGlobal_nPointDomain()]; - /*--- First, set all indices to a negative value by default ---*/ - for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) { - Global2Local[iPoint] = -1; - } - /*--- Now fill array with the transform values only for local points ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; - } - - /*--- Read all lines in the restart file ---*/ - long iPoint_Local; unsigned long iPoint_Global = 0; string text_line; - - /*--- The first line is the header ---*/ - getline (restart_file, text_line); - - while (getline (restart_file, text_line)) { - istringstream point_line(text_line); - - /*--- Retrieve local index. If this node from the restart file lives - on a different processor, the value of iPoint_Local will be -1. - Otherwise, the local index for this node on the current processor - will be returned and used to instantiate the vars. ---*/ - iPoint_Local = Global2Local[iPoint_Global]; - if (iPoint_Local >= 0) { - if (compressible) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> U[0] >> U[1] >> U[2] >> U[3] >> Solution[0]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> U[0] >> U[1] >> U[2] >> U[3] >> U[4] >> Solution[0]; - - Density = U[0]; - if (nDim == 2) - StaticEnergy = U[3]/U[0] - (U[1]*U[1] + U[2]*U[2])/(2.0*U[0]*U[0]); -// Pressure = Gamma_Minus_One*(U[3] - (U[1]*U[1] + U[2]*U[2])/(2.0*U[0])); - else - StaticEnergy = U[4]/U[0] - (U[1]*U[1] + U[2]*U[2] + U[3]*U[3] )/(2.0*U[0]*U[0]); -// Pressure = Gamma_Minus_One*(U[4] - (U[1]*U[1] + U[2]*U[2] + U[3]*U[3])/(2.0*U[0])); - -// Temperature = Pressure/(Gas_Constant*Density); -// -// -// Temperature_Dim = Temperature*Temperature_Ref; -// -// if (config->GetSystemMeasurements() == SI) { T_ref = 273.15; S = 110.4; Mu_ref = 1.716E-5; } -// if (config->GetSystemMeasurements() == US) { T_ref = 518.7; S = 198.72; Mu_ref = 3.62E-7; } -// -// /*--- Calculate viscosity from a non-dim. Sutherland's Law ---*/ -// -// Laminar_Viscosity = Mu_ref*(pow(Temperature_Dim/T_ref, 1.5) * (T_ref+S)/(Temperature_Dim+S)); -// Laminar_Viscosity = Laminar_Viscosity/Viscosity_Ref; - - FluidModel->SetTDState_rhoe(Density, StaticEnergy); - Laminar_Viscosity = FluidModel->GetLaminarViscosity(); - nu = Laminar_Viscosity/Density; - nu_hat = Solution[0]; - Ji = nu_hat/nu; - Ji_3 = Ji*Ji*Ji; - fv1 = Ji_3/(Ji_3+cv1_3); - muT = Density*fv1*nu_hat; - - } - if (incompressible) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; - muT = muT_Inf; - } - - if (freesurface) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; - muT = muT_Inf; - } - - /*--- Instantiate the solution at this node, note that the eddy viscosity should be recomputed ---*/ - node[iPoint_Local] = new CTurbSAVariable(Solution[0], muT, nDim, nVar, config); - } - iPoint_Global++; - } - - /*--- Instantiate the variable class with an arbitrary solution - at any halo/periodic nodes. The initial solution can be arbitrary, - because a send/recv is performed immediately in the solver. ---*/ - for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { - node[iPoint] = new CTurbSAVariable(Solution[0], muT_Inf, nDim, nVar, config); - } - - /*--- Close the restart file ---*/ - restart_file.close(); - - /*--- Free memory needed for the transformation ---*/ - delete [] Global2Local; - } - - /*--- MPI solution ---*/ - Set_MPI_Solution(geometry, config); - -} - -CTurbSASolver::~CTurbSASolver(void) { - -} - -void CTurbSASolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { - - unsigned long iPoint; - - unsigned long ExtIter = config->GetExtIter(); - bool limiter_flow = ((config->GetSpatialOrder_Flow() == SECOND_ORDER_LIMITER) && (ExtIter <= config->GetLimiterIter())); - - for (iPoint = 0; iPoint < nPoint; iPoint ++) { - - /*--- Initialize the residual vector ---*/ - - LinSysRes.SetBlock_Zero(iPoint); - - } - - /*--- Initialize the Jacobian matrices ---*/ - - Jacobian.SetValZero(); - - if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); - - /*--- Upwind second order reconstruction ---*/ - - if (config->GetSpatialOrder() == SECOND_ORDER_LIMITER) SetSolution_Limiter(geometry, config); - - if (limiter_flow) solver_container[FLOW_SOL]->SetPrimitive_Limiter(geometry, config); - -} - -void CTurbSASolver::Postprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh) { - - su2double rho = 0.0, mu = 0.0, nu, *nu_hat, muT, Ji, Ji_3, fv1; - su2double cv1_3 = 7.1*7.1*7.1; - unsigned long iPoint; - - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool neg_spalart_allmaras = (config->GetKind_Turb_Model() == SA_NEG); - - - /*--- Compute eddy viscosity ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint ++) { - - if (compressible) { - rho = solver_container[FLOW_SOL]->node[iPoint]->GetDensity(); - mu = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); - } - if (incompressible || freesurface) { - rho = solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); - mu = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosityInc(); - } - - nu = mu/rho; - nu_hat = node[iPoint]->GetSolution(); - - Ji = nu_hat[0]/nu; - Ji_3 = Ji*Ji*Ji; - fv1 = Ji_3/(Ji_3+cv1_3); - - muT = rho*fv1*nu_hat[0]; - - if (neg_spalart_allmaras && (muT < 0.0)) muT = 0.0; - - node[iPoint]->SetmuT(muT); - - } - -} - -void CTurbSASolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, - CConfig *config, unsigned short iMesh) { - unsigned long iPoint; - su2double LevelSet; - unsigned short iVar; - - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool time_spectral = (config->GetUnsteady_Simulation() == TIME_SPECTRAL); - bool transition = (config->GetKind_Trans_Model() == LM); - su2double epsilon = config->GetFreeSurface_Thickness(); - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Conservative variables w/o reconstruction ---*/ - - numerics->SetPrimitive(solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(), NULL); - - /*--- Gradient of the primitive and conservative variables ---*/ - - numerics->SetPrimVarGradient(solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(), NULL); - - /*--- Set vorticity and strain rate magnitude ---*/ - - numerics->SetVorticity(solver_container[FLOW_SOL]->node[iPoint]->GetVorticity(), NULL); - - numerics->SetStrainMag(solver_container[FLOW_SOL]->node[iPoint]->GetStrainMag(), 0.0); - - /*--- Set intermittency ---*/ - - if (transition) { - numerics->SetIntermittency(solver_container[TRANS_SOL]->node[iPoint]->GetIntermittency()); - } - - /*--- Turbulent variables w/o reconstruction, and its gradient ---*/ - - numerics->SetTurbVar(node[iPoint]->GetSolution(), NULL); - numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), NULL); - - /*--- Set volume ---*/ - - numerics->SetVolume(geometry->node[iPoint]->GetVolume()); - - /*--- Set distance to the surface ---*/ - - numerics->SetDistance(geometry->node[iPoint]->GetWall_Distance(), 0.0); - - /*--- Compute the source term ---*/ - - numerics->ComputeResidual(Residual, Jacobian_i, NULL, config); - - /*--- Don't add source term in the interface or air ---*/ - - if (freesurface) { - LevelSet = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(nDim+1); - if (LevelSet > -epsilon) for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; - } - - /*--- Subtract residual and the Jacobian ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual); - - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - - if (time_spectral) { - - su2double Volume, Source; - unsigned short nVar_Turb = solver_container[TURB_SOL]->GetnVar(); - - /*--- Loop over points ---*/ - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Get control volume ---*/ - - Volume = geometry->node[iPoint]->GetVolume(); - - /*--- Access stored time spectral source term ---*/ - - for (unsigned short iVar = 0; iVar < nVar_Turb; iVar++) { - Source = node[iPoint]->GetTimeSpectral_Source(iVar); - Residual[iVar] = Source*Volume; - } - - /*--- Add Residual ---*/ - - LinSysRes.AddBlock(iPoint, Residual); - - } - } - -} - -void CTurbSASolver::Source_Template(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config, unsigned short iMesh) { - -} - -void CTurbSASolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - unsigned long iPoint, iVertex; - unsigned short iVar; - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Get the velocity vector ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = 0.0; - - node[iPoint]->SetSolution_Old(Solution); - LinSysRes.SetBlock_Zero(iPoint); - - /*--- includes 1 in the diagonal ---*/ - - Jacobian.DeleteValsRowi(iPoint); - } - } - -} - -void CTurbSASolver::BC_Isothermal_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, - unsigned short val_marker) { - unsigned long iPoint, iVertex; - unsigned short iVar; - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Get the velocity vector ---*/ - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = 0.0; - - node[iPoint]->SetSolution_Old(Solution); - LinSysRes.SetBlock_Zero(iPoint); - - /*--- Includes 1 in the diagonal ---*/ - - Jacobian.DeleteValsRowi(iPoint); - } - } - -} - -void CTurbSASolver::BC_Far_Field(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned long iPoint, iVertex; - unsigned short iVar, iDim; - su2double *Normal, *V_infty, *V_domain; - - bool grid_movement = config->GetGrid_Movement(); - - Normal = new su2double[nDim]; - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Allocate the value at the infinity ---*/ - - V_infty = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); - - /*--- Retrieve solution at the farfield boundary node ---*/ - - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - /*--- Grid Movement ---*/ - - if (grid_movement) - conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[iPoint]->GetGridVel()); - - conv_numerics->SetPrimitive(V_domain, V_infty); - - /*--- Set turbulent variable at the wall, and at infinity ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Solution_i[iVar] = node[iPoint]->GetSolution(iVar); - Solution_j[0] = nu_tilde_Inf; - conv_numerics->SetTurbVar(Solution_i, Solution_j); - - /*--- Set Normal (it is necessary to change the sign) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) - Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - /*--- Compute residuals and Jacobians ---*/ - - conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Add residuals and Jacobians ---*/ - - LinSysRes.AddBlock(iPoint, Residual); - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - } - } - - delete [] Normal; - -} - -void CTurbSASolver::BC_Inlet(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned short iDim; - unsigned long iVertex, iPoint, Point_Normal; - su2double *V_inlet, *V_domain, *Normal; - - Normal = new su2double[nDim]; - - bool grid_movement = config->GetGrid_Movement(); - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Index of the closest interior node ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - - /*--- Allocate the value at the inlet ---*/ - - V_inlet = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); - - /*--- Retrieve solution at the farfield boundary node ---*/ - - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - /*--- Set various quantities in the solver class ---*/ - - conv_numerics->SetPrimitive(V_domain, V_inlet); - - /*--- Set the turbulent variable states (prescribed for an inflow) ---*/ - - Solution_i[0] = node[iPoint]->GetSolution(0); - Solution_j[0] = nu_tilde_Inf; - - conv_numerics->SetTurbVar(Solution_i, Solution_j); - - /*--- Set various other quantities in the conv_numerics class ---*/ - - conv_numerics->SetNormal(Normal); - - if (grid_movement) - conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), - geometry->node[iPoint]->GetGridVel()); - - /*--- Compute the residual using an upwind scheme ---*/ - - conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - /*--- Viscous contribution ---*/ - - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - visc_numerics->SetNormal(Normal); - - /*--- Conservative variables w/o reconstruction ---*/ - - visc_numerics->SetPrimitive(V_domain, V_inlet); - - /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ - - visc_numerics->SetTurbVar(Solution_i, Solution_j); - visc_numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); - - /*--- Compute residual, and Jacobians ---*/ - - visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Subtract residual, and update Jacobians ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual); - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - } - - /*--- Free locally allocated memory ---*/ - delete[] Normal; - -} - -void CTurbSASolver::BC_Outlet(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, - CConfig *config, unsigned short val_marker) { - unsigned long iPoint, iVertex, Point_Normal; - unsigned short iVar, iDim; - su2double *V_outlet, *V_domain, *Normal; - - bool grid_movement = config->GetGrid_Movement(); - - Normal = new su2double[nDim]; - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Index of the closest interior node ---*/ - - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Allocate the value at the outlet ---*/ - - V_outlet = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); - - /*--- Retrieve solution at the farfield boundary node ---*/ - - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - /*--- Set various quantities in the solver class ---*/ - - conv_numerics->SetPrimitive(V_domain, V_outlet); - - /*--- Set the turbulent variables. Here we use a Neumann BC such - that the turbulent variable is copied from the interior of the - domain to the outlet before computing the residual. - Solution_i --> TurbVar_internal, - Solution_j --> TurbVar_outlet ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - Solution_i[iVar] = node[iPoint]->GetSolution(iVar); - Solution_j[iVar] = node[iPoint]->GetSolution(iVar); - } - conv_numerics->SetTurbVar(Solution_i, Solution_j); - - /*--- Set Normal (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) - Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - if (grid_movement) - conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), - geometry->node[iPoint]->GetGridVel()); - - /*--- Compute the residual using an upwind scheme ---*/ - - conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - /*--- Viscous contribution ---*/ - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - visc_numerics->SetNormal(Normal); - - /*--- Conservative variables w/o reconstruction ---*/ - - visc_numerics->SetPrimitive(V_domain, V_outlet); - - /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ - - visc_numerics->SetTurbVar(Solution_i, Solution_j); - visc_numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); - - /*--- Compute residual, and Jacobians ---*/ - - visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Subtract residual, and update Jacobians ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual); - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - } - - /*--- Free locally allocated memory ---*/ - - delete[] Normal; - -} - -void CTurbSASolver::BC_Engine_Inflow(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned long iPoint, iVertex; - unsigned short iDim; - su2double *V_inflow, *V_domain, *Normal; - - Normal = new su2double[nDim]; - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Allocate the value at the infinity ---*/ - - V_inflow = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); - - /*--- Retrieve solution at the farfield boundary node ---*/ - - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - /*--- Set various quantities in the solver class ---*/ - - conv_numerics->SetPrimitive(V_domain, V_inflow); - - /*--- Set the turbulent variables. Here we use a Neumann BC such - that the turbulent variable is copied from the interior of the - domain to the outlet before computing the residual. ---*/ - - conv_numerics->SetTurbVar(node[iPoint]->GetSolution(), node[iPoint]->GetSolution()); - - /*--- Set Normal (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) - Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - /*--- Compute the residual using an upwind scheme ---*/ - - conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - /*--- Viscous contribution ---*/ - - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[iPoint]->GetCoord()); - visc_numerics->SetNormal(Normal); - - /*--- Conservative variables w/o reconstruction ---*/ - - visc_numerics->SetPrimitive(V_domain, V_inflow); - - /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ - - visc_numerics->SetTurbVar(node[iPoint]->GetSolution(), node[iPoint]->GetSolution()); - visc_numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); - - /*--- Compute residual, and Jacobians ---*/ - - visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Subtract residual, and update Jacobians ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual); - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - } - - /*--- Free locally allocated memory ---*/ - - delete[] Normal; - -} - -void CTurbSASolver::BC_Engine_Exhaust(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned short iDim; - unsigned long iVertex, iPoint; - su2double *V_exhaust, *V_domain, *Normal; - - Normal = new su2double[nDim]; - - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - - /*--- Allocate the value at the infinity ---*/ - - V_exhaust = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); - - /*--- Retrieve solution at the farfield boundary node ---*/ - - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - /*--- Set various quantities in the solver class ---*/ - - conv_numerics->SetPrimitive(V_domain, V_exhaust); - - /*--- Set the turbulent variable states (prescribed for an inflow) ---*/ - - Solution_i[0] = node[iPoint]->GetSolution(0); - Solution_j[0] = nu_tilde_Engine; - - conv_numerics->SetTurbVar(Solution_i, Solution_j); - - /*--- Set various other quantities in the conv_numerics class ---*/ - - conv_numerics->SetNormal(Normal); - - /*--- Compute the residual using an upwind scheme ---*/ - - conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - /*--- Viscous contribution ---*/ - - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[iPoint]->GetCoord()); - visc_numerics->SetNormal(Normal); - - /*--- Conservative variables w/o reconstruction ---*/ - - visc_numerics->SetPrimitive(V_domain, V_exhaust); - - /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ - - visc_numerics->SetTurbVar(Solution_i, Solution_j); - visc_numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); - - /*--- Compute residual, and Jacobians ---*/ - - visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Subtract residual, and update Jacobians ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual); - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - } - - /*--- Free locally allocated memory ---*/ - - delete[] Normal; - -} - -void CTurbSASolver::BC_Engine_Bleed(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned short iDim; - unsigned long iVertex, iPoint; - su2double *V_bleed, *V_domain, *Normal; - - Normal = new su2double[nDim]; - - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - - /*--- Loop over all the vertices on this boundary marker ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - - /*--- Allocate the value at the infinity ---*/ - - V_bleed = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); - - /*--- Retrieve solution at the farfield boundary node ---*/ - - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - /*--- Set various quantities in the solver class ---*/ - - conv_numerics->SetPrimitive(V_domain, V_bleed); - - /*--- Set the turbulent variable states (prescribed for an inflow) ---*/ - - Solution_i[0] = node[iPoint]->GetSolution(0); - Solution_j[0] = nu_tilde_Engine; - - conv_numerics->SetTurbVar(Solution_i, Solution_j); - - /*--- Set various other quantities in the conv_numerics class ---*/ - - conv_numerics->SetNormal(Normal); - - /*--- Compute the residual using an upwind scheme ---*/ - - conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - /*--- Viscous contribution ---*/ - - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[iPoint]->GetCoord()); - visc_numerics->SetNormal(Normal); - - /*--- Conservative variables w/o reconstruction ---*/ - - visc_numerics->SetPrimitive(V_domain, V_bleed); - - /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ - - visc_numerics->SetTurbVar(Solution_i, Solution_j); - visc_numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); - - /*--- Compute residual, and Jacobians ---*/ - - visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Subtract residual, and update Jacobians ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual); - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - } - - /*--- Free locally allocated memory ---*/ - - delete[] Normal; - -} - -void CTurbSASolver::BC_Interface_Boundary(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config) { - // unsigned long iVertex, iPoint, jPoint; - // unsigned short iVar, iDim; - // - // su2double *Vector = new su2double[nDim]; - // - //#ifndef HAVE_MPI - // - // for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - // iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - // - // if (geometry->node[iPoint]->GetDomain()) { - // - // /*--- Find the associate pair to the original node ---*/ - // jPoint = geometry->vertex[val_marker][iVertex]->GetDonorPoint(); - // - // if (iPoint != jPoint) { - // - // /*--- Store the solution for both points ---*/ - // for (iVar = 0; iVar < nVar; iVar++) { - // Solution_i[iVar] = node[iPoint]->GetSolution(iVar); - // Solution_j[iVar] = node[jPoint]->GetSolution(iVar); - // } - // - // /*--- Set Conservative Variables ---*/ - // numerics->SetTurbVar(Solution_i, Solution_j); - // - // /*--- Retrieve flow solution for both points ---*/ - // for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { - // FlowPrimVar_i[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); - // FlowPrimVar_j[iVar] = solver_container[FLOW_SOL]->node[jPoint]->GetSolution(iVar); - // } - // - // /*--- Set Flow Variables ---*/ - // numerics->SetConservative(FlowPrimVar_i, FlowPrimVar_j); - // - // /*--- Set the normal vector ---*/ - // geometry->vertex[val_marker][iVertex]->GetNormal(Vector); - // for (iDim = 0; iDim < nDim; iDim++) - // Vector[iDim] = -Vector[iDim]; - // numerics->SetNormal(Vector); - // - // /*--- Add Residuals and Jacobians ---*/ - // numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - // LinSysRes.AddBlock(iPoint, Residual); - // Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - // - // } - // } - // } - // - //#else - // - // int rank = MPI::COMM_WORLD.Get_rank(), jProcessor; - // su2double *Conserv_Var, *Flow_Var; - // bool compute; - // - // unsigned short Buffer_Size = nVar+solver_container[FLOW_SOL]->GetnVar(); - // su2double *Buffer_Send_U = new su2double [Buffer_Size]; - // su2double *Buffer_Receive_U = new su2double [Buffer_Size]; - // - // /*--- Do the send process, by the moment we are sending each - // node individually, this must be changed ---*/ - // for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - // iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - // if (geometry->node[iPoint]->GetDomain()) { - // - // /*--- Find the associate pair to the original node ---*/ - // jPoint = geometry->vertex[val_marker][iVertex]->GetPeriodicPointDomain()[0]; - // jProcessor = geometry->vertex[val_marker][iVertex]->GetPeriodicPointDomain()[1]; - // - // if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; - // else compute = true; - // - // /*--- We only send the information that belong to other boundary ---*/ - // if ((jProcessor != rank) && compute) { - // - // Conserv_Var = node[iPoint]->GetSolution(); - // Flow_Var = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); - // - // for (iVar = 0; iVar < nVar; iVar++) - // Buffer_Send_U[iVar] = Conserv_Var[iVar]; - // - // for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) - // Buffer_Send_U[nVar+iVar] = Flow_Var[iVar]; - // - // MPI::COMM_WORLD.Bsend(Buffer_Send_U, Buffer_Size, MPI::DOUBLE, jProcessor, iPoint); - // - // } - // } - // } - // - // for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - // - // iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - // - // if (geometry->node[iPoint]->GetDomain()) { - // - // /*--- Find the associate pair to the original node ---*/ - // jPoint = geometry->vertex[val_marker][iVertex]->GetPeriodicPointDomain()[0]; - // jProcessor = geometry->vertex[val_marker][iVertex]->GetPeriodicPointDomain()[1]; - // - // if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; - // else compute = true; - // - // if (compute) { - // - // /*--- We only receive the information that belong to other boundary ---*/ - // if (jProcessor != rank) { - // MPI::COMM_WORLD.Recv(Buffer_Receive_U, Buffer_Size, MPI::DOUBLE, jProcessor, jPoint); - // } - // else { - // - // for (iVar = 0; iVar < nVar; iVar++) - // Buffer_Receive_U[iVar] = node[jPoint]->GetSolution(iVar); - // - // for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) - // Buffer_Send_U[nVar+iVar] = solver_container[FLOW_SOL]->node[jPoint]->GetSolution(iVar); - // - // } - // - // /*--- Store the solution for both points ---*/ - // for (iVar = 0; iVar < nVar; iVar++) { - // Solution_i[iVar] = node[iPoint]->GetSolution(iVar); - // Solution_j[iVar] = Buffer_Receive_U[iVar]; - // } - // - // /*--- Set Turbulent Variables ---*/ - // numerics->SetTurbVar(Solution_i, Solution_j); - // - // /*--- Retrieve flow solution for both points ---*/ - // for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { - // FlowPrimVar_i[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); - // FlowPrimVar_j[iVar] = Buffer_Receive_U[nVar + iVar]; - // } - // - // /*--- Set Flow Variables ---*/ - // numerics->SetConservative(FlowPrimVar_i, FlowPrimVar_j); - // - // geometry->vertex[val_marker][iVertex]->GetNormal(Vector); - // for (iDim = 0; iDim < nDim; iDim++) - // Vector[iDim] = -Vector[iDim]; - // numerics->SetNormal(Vector); - // - // numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - // LinSysRes.AddBlock(iPoint, Residual); - // Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - // - // } - // } - // } - // - // delete[] Buffer_Send_U; - // delete[] Buffer_Receive_U; - // - //#endif - // - // delete[] Vector; - // -} - -void CTurbSASolver::BC_NearField_Boundary(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config) { - // unsigned long iVertex, iPoint, jPoint; - // unsigned short iVar, iDim; - // - // su2double *Vector = new su2double[nDim]; - // - //#ifndef HAVE_MPI - // - // for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - // iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - // - // if (geometry->node[iPoint]->GetDomain()) { - // - // /*--- Find the associate pair to the original node ---*/ - // jPoint = geometry->vertex[val_marker][iVertex]->GetDonorPoint(); - // - // if (iPoint != jPoint) { - // - // /*--- Store the solution for both points ---*/ - // for (iVar = 0; iVar < nVar; iVar++) { - // Solution_i[iVar] = node[iPoint]->GetSolution(iVar); - // Solution_j[iVar] = node[jPoint]->GetSolution(iVar); - // } - // - // /*--- Set Conservative Variables ---*/ - // numerics->SetTurbVar(Solution_i, Solution_j); - // - // /*--- Retrieve flow solution for both points ---*/ - // for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { - // FlowPrimVar_i[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); - // FlowPrimVar_j[iVar] = solver_container[FLOW_SOL]->node[jPoint]->GetSolution(iVar); - // } - // - // /*--- Set Flow Variables ---*/ - // numerics->SetConservative(FlowPrimVar_i, FlowPrimVar_j); - // - // /*--- Set the normal vector ---*/ - // geometry->vertex[val_marker][iVertex]->GetNormal(Vector); - // for (iDim = 0; iDim < nDim; iDim++) - // Vector[iDim] = -Vector[iDim]; - // numerics->SetNormal(Vector); - // - // /*--- Add Residuals and Jacobians ---*/ - // numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - // LinSysRes.AddBlock(iPoint, Residual); - // Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - // - // } - // } - // } - // - //#else - // - // int rank = MPI::COMM_WORLD.Get_rank(), jProcessor; - // su2double *Conserv_Var, *Flow_Var; - // bool compute; - // - // unsigned short Buffer_Size = nVar+solver_container[FLOW_SOL]->GetnVar(); - // su2double *Buffer_Send_U = new su2double [Buffer_Size]; - // su2double *Buffer_Receive_U = new su2double [Buffer_Size]; - // - // /*--- Do the send process, by the moment we are sending each - // node individually, this must be changed ---*/ - // for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - // iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - // if (geometry->node[iPoint]->GetDomain()) { - // - // /*--- Find the associate pair to the original node ---*/ - // jPoint = geometry->vertex[val_marker][iVertex]->GetPeriodicPointDomain()[0]; - // jProcessor = geometry->vertex[val_marker][iVertex]->GetPeriodicPointDomain()[1]; - // - // if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; - // else compute = true; - // - // /*--- We only send the information that belong to other boundary ---*/ - // if ((jProcessor != rank) && compute) { - // - // Conserv_Var = node[iPoint]->GetSolution(); - // Flow_Var = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); - // - // for (iVar = 0; iVar < nVar; iVar++) - // Buffer_Send_U[iVar] = Conserv_Var[iVar]; - // - // for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) - // Buffer_Send_U[nVar+iVar] = Flow_Var[iVar]; - // - // MPI::COMM_WORLD.Bsend(Buffer_Send_U, Buffer_Size, MPI::DOUBLE, jProcessor, iPoint); - // - // } - // } - // } - // - // for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - // - // iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - // - // if (geometry->node[iPoint]->GetDomain()) { - // - // /*--- Find the associate pair to the original node ---*/ - // jPoint = geometry->vertex[val_marker][iVertex]->GetPeriodicPointDomain()[0]; - // jProcessor = geometry->vertex[val_marker][iVertex]->GetPeriodicPointDomain()[1]; - // - // if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; - // else compute = true; - // - // if (compute) { - // - // /*--- We only receive the information that belong to other boundary ---*/ - // if (jProcessor != rank) { - // MPI::COMM_WORLD.Recv(Buffer_Receive_U, Buffer_Size, MPI::DOUBLE, jProcessor, jPoint); - // } - // else { - // - // for (iVar = 0; iVar < nVar; iVar++) - // Buffer_Receive_U[iVar] = node[jPoint]->GetSolution(iVar); - // - // for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) - // Buffer_Send_U[nVar+iVar] = solver_container[FLOW_SOL]->node[jPoint]->GetSolution(iVar); - // - // } - // - // /*--- Store the solution for both points ---*/ - // for (iVar = 0; iVar < nVar; iVar++) { - // Solution_i[iVar] = node[iPoint]->GetSolution(iVar); - // Solution_j[iVar] = Buffer_Receive_U[iVar]; - // } - // - // /*--- Set Turbulent Variables ---*/ - // numerics->SetTurbVar(Solution_i, Solution_j); - // - // /*--- Retrieve flow solution for both points ---*/ - // for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { - // FlowPrimVar_i[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); - // FlowPrimVar_j[iVar] = Buffer_Receive_U[nVar + iVar]; - // } - // - // /*--- Set Flow Variables ---*/ - // numerics->SetConservative(FlowPrimVar_i, FlowPrimVar_j); - // - // geometry->vertex[val_marker][iVertex]->GetNormal(Vector); - // for (iDim = 0; iDim < nDim; iDim++) - // Vector[iDim] = -Vector[iDim]; - // numerics->SetNormal(Vector); - // - // numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - // LinSysRes.AddBlock(iPoint, Residual); - // Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - // - // } - // } - // } - // - // delete[] Buffer_Send_U; - // delete[] Buffer_Receive_U; - // - //#endif - // - // delete[] Vector; - // -} - -void CTurbSASolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig *config, int val_iter) { - - /*--- Restart the solution from file information ---*/ - unsigned short iVar, iMesh; - unsigned long iPoint, index, iChildren, Point_Fine; - su2double dull_val, Area_Children, Area_Parent, *Solution_Fine; - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - string UnstExt, text_line; - ifstream restart_file; - string restart_filename = config->GetSolution_FlowFileName(); - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Modify file name for an unsteady restart ---*/ - if (dual_time) - restart_filename = config->GetUnsteady_FileName(restart_filename, val_iter); - - /*--- Open the restart file, throw an error if this fails. ---*/ - restart_file.open(restart_filename.data(), ios::in); - if (restart_file.fail()) { - if (rank == MASTER_NODE) - cout << "There is no flow restart file!! " << restart_filename.data() << "."<< endl; - exit(EXIT_FAILURE); - } - - /*--- In case this is a parallel simulation, we need to perform the - Global2Local index transformation first. ---*/ - long *Global2Local = NULL; - Global2Local = new long[geometry[MESH_0]->GetGlobal_nPointDomain()]; - /*--- First, set all indices to a negative value by default ---*/ - for (iPoint = 0; iPoint < geometry[MESH_0]->GetGlobal_nPointDomain(); iPoint++) { - Global2Local[iPoint] = -1; - } - - /*--- Now fill array with the transform values only for local points ---*/ - for (iPoint = 0; iPoint < geometry[MESH_0]->GetnPointDomain(); iPoint++) { - Global2Local[geometry[MESH_0]->node[iPoint]->GetGlobalIndex()] = iPoint; - } - - /*--- Read all lines in the restart file ---*/ - long iPoint_Local = 0; unsigned long iPoint_Global = 0; - - /*--- The first line is the header ---*/ - getline (restart_file, text_line); - - while (getline (restart_file, text_line)) { - istringstream point_line(text_line); - - /*--- Retrieve local index. If this node from the restart file lives - on a different processor, the value of iPoint_Local will be -1, as - initialized above. Otherwise, the local index for this node on the - current processor will be returned and used to instantiate the vars. ---*/ - iPoint_Local = Global2Local[iPoint_Global]; - if (iPoint_Local >= 0) { - - if (compressible) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; - } - if (incompressible) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; - } - if (freesurface) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; - } - - - node[iPoint_Local]->SetSolution(Solution); - - } - iPoint_Global++; - } - - /*--- Close the restart file ---*/ - restart_file.close(); - - /*--- Free memory needed for the transformation ---*/ - delete [] Global2Local; - - /*--- MPI solution and compute the eddy viscosity ---*/ - solver[MESH_0][TURB_SOL]->Set_MPI_Solution(geometry[MESH_0], config); - solver[MESH_0][TURB_SOL]->Postprocessing(geometry[MESH_0], solver[MESH_0], config, MESH_0); - - /*--- Interpolate the solution down to the coarse multigrid levels ---*/ - for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++) { - for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { - Area_Parent = geometry[iMesh]->node[iPoint]->GetVolume(); - for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; - for (iChildren = 0; iChildren < geometry[iMesh]->node[iPoint]->GetnChildren_CV(); iChildren++) { - Point_Fine = geometry[iMesh]->node[iPoint]->GetChildren_CV(iChildren); - Area_Children = geometry[iMesh-1]->node[Point_Fine]->GetVolume(); - Solution_Fine = solver[iMesh-1][TURB_SOL]->node[Point_Fine]->GetSolution(); - for (iVar = 0; iVar < nVar; iVar++) { - Solution[iVar] += Solution_Fine[iVar]*Area_Children/Area_Parent; - } - } - solver[iMesh][TURB_SOL]->node[iPoint]->SetSolution(Solution); - } - solver[iMesh][TURB_SOL]->Set_MPI_Solution(geometry[iMesh], config); - solver[iMesh][TURB_SOL]->Postprocessing(geometry[iMesh], solver[iMesh], config, iMesh); - } - -} - -CTurbSSTSolver::CTurbSSTSolver(void) : CTurbSolver() { - - /*--- Array initialization ---*/ - constants = NULL; - -} - -CTurbSSTSolver::CTurbSSTSolver(CGeometry *geometry, CConfig *config, unsigned short iMesh) : CTurbSolver() { - unsigned short iVar, iDim, nLineLets; - unsigned long iPoint, index; - su2double dull_val; - ifstream restart_file; - string text_line; - - unsigned short iZone = config->GetiZone(); - unsigned short nZone = geometry->GetnZone(); - bool restart = (config->GetRestart() || config->GetRestart_Flow()); - bool adjoint = config->GetAdjoint(); - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Array initialization ---*/ - - constants = NULL; - - Gamma = config->GetGamma(); - Gamma_Minus_One = Gamma - 1.0; - - /*--- Dimension of the problem --> dependent of the turbulent model ---*/ - - nVar = 2; - nPoint = geometry->GetnPoint(); - nPointDomain = geometry->GetnPointDomain(); - - /*--- Define geometry constants in the solver structure ---*/ - - nDim = geometry->GetnDim(); - node = new CVariable*[nPoint]; - - /*--- Single grid simulation ---*/ - - if (iMesh == MESH_0) { - - /*--- Define some auxiliary vector related with the residual ---*/ - - Residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; - Residual_RMS = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_RMS[iVar] = 0.0; - Residual_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_i[iVar] = 0.0; - Residual_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_j[iVar] = 0.0; - Residual_Max = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_Max[iVar] = 0.0; - - /*--- Define some structures for locating max residuals ---*/ - - Point_Max = new unsigned long[nVar]; - for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; - Point_Max_Coord = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Point_Max_Coord[iVar] = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; - } - - /*--- Define some auxiliary vector related with the solution ---*/ - - Solution = new su2double[nVar]; - Solution_i = new su2double[nVar]; Solution_j = new su2double[nVar]; - - /*--- Define some auxiliary vector related with the geometry ---*/ - - Vector_i = new su2double[nDim]; Vector_j = new su2double[nDim]; - - /*--- Define some auxiliary vector related with the flow solution ---*/ - - FlowPrimVar_i = new su2double [nDim+7]; FlowPrimVar_j = new su2double [nDim+7]; - - /*--- Jacobians and vector structures for implicit computations ---*/ - - Jacobian_i = new su2double* [nVar]; - Jacobian_j = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Jacobian_i[iVar] = new su2double [nVar]; - Jacobian_j[iVar] = new su2double [nVar]; - } - - /*--- Initialization of the structure of the whole Jacobian ---*/ - - if (rank == MASTER_NODE) cout << "Initialize Jacobian structure (SST model)." << endl; - Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); - - if ((config->GetKind_Linear_Solver_Prec() == LINELET) || - (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { - nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); - if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; - } - - LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); - } - - /*--- Computation of gradients by least squares ---*/ - - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { - /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ - Smatrix = new su2double* [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Smatrix[iDim] = new su2double [nDim]; - /*--- c vector := transpose(WA)*(Wb) ---*/ - cvector = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - cvector[iVar] = new su2double [nDim]; - } - - /*--- Initialize value for model constants ---*/ - constants = new su2double[10]; - constants[0] = 0.85; //sigma_k1 - constants[1] = 1.0; //sigma_k2 - constants[2] = 0.5; //sigma_om1 - constants[3] = 0.856; //sigma_om2 - constants[4] = 0.075; //beta_1 - constants[5] = 0.0828; //beta_2 - constants[6] = 0.09; //betaStar - constants[7] = 0.31; //a1 - constants[8] = constants[4]/constants[6] - constants[2]*0.41*0.41/sqrt(constants[6]); //alfa_1 - constants[9] = constants[5]/constants[6] - constants[3]*0.41*0.41/sqrt(constants[6]); //alfa_2 - - /*--- Initialize lower and upper limits---*/ - lowerlimit = new su2double[nVar]; - upperlimit = new su2double[nVar]; - - lowerlimit[0] = 1.0e-10; - upperlimit[0] = 1.0e10; - - lowerlimit[1] = 1.0e-4; - upperlimit[1] = 1.0e15; - - /*--- Flow infinity initialization stuff ---*/ - su2double rhoInf, *VelInf, muLamInf, Intensity, viscRatio, muT_Inf; - - rhoInf = config->GetDensity_FreeStreamND(); - VelInf = config->GetVelocity_FreeStreamND(); - muLamInf = config->GetViscosity_FreeStreamND(); - Intensity = config->GetTurbulenceIntensity_FreeStream(); - viscRatio = config->GetTurb2LamViscRatio_FreeStream(); - - su2double VelMag = 0; - for (iDim = 0; iDim < nDim; iDim++) - VelMag += VelInf[iDim]*VelInf[iDim]; - VelMag = sqrt(VelMag); - - kine_Inf = 3.0/2.0*(VelMag*VelMag*Intensity*Intensity); - omega_Inf = rhoInf*kine_Inf/(muLamInf*viscRatio); - - /*--- Eddy viscosity, initialized without stress limiter at the infinity ---*/ - muT_Inf = rhoInf*kine_Inf/omega_Inf; - - /*--- Restart the solution from file information ---*/ - if (!restart || (iMesh != MESH_0)) { - for (iPoint = 0; iPoint < nPoint; iPoint++) - node[iPoint] = new CTurbSSTVariable(kine_Inf, omega_Inf, muT_Inf, nDim, nVar, constants, config); - } - else { - - /*--- Restart the solution from file information ---*/ - ifstream restart_file; - string filename = config->GetSolution_FlowFileName(); - - /*--- Modify file name for an unsteady restart ---*/ - if (dual_time) { - int Unst_RestartIter; - if (adjoint) { - Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_AdjointIter()) - 1; - } else if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_RestartIter())-1; - else - Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_RestartIter())-2; - filename = config->GetUnsteady_FileName(filename, Unst_RestartIter); - } - if (nZone >1) - filename= config->GetRestart_FlowFileName(filename, iZone); - - - /*--- Open the restart file, throw an error if this fails. ---*/ - restart_file.open(filename.data(), ios::in); - if (restart_file.fail()) { - cout << "There is no turbulent restart file!!" << endl; - exit(EXIT_FAILURE); - } - - /*--- In case this is a parallel simulation, we need to perform the - Global2Local index transformation first. ---*/ - long *Global2Local; - Global2Local = new long[geometry->GetGlobal_nPointDomain()]; - /*--- First, set all indices to a negative value by default ---*/ - for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) { - Global2Local[iPoint] = -1; - } - /*--- Now fill array with the transform values only for local points ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; - } - - /*--- Read all lines in the restart file ---*/ - long iPoint_Local; unsigned long iPoint_Global = 0; string text_line; - - /*--- The first line is the header ---*/ - getline (restart_file, text_line); - - - while (getline (restart_file, text_line)) { - istringstream point_line(text_line); - - /*--- Retrieve local index. If this node from the restart file lives - on a different processor, the value of iPoint_Local will be -1. - Otherwise, the local index for this node on the current processor - will be returned and used to instantiate the vars. ---*/ - iPoint_Local = Global2Local[iPoint_Global]; - if (iPoint_Local >= 0) { - - if (compressible) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1]; - } - if (incompressible) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1]; - } - if (freesurface) { - if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1]; - if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1]; - } - - /*--- Instantiate the solution at this node, note that the muT_Inf should recomputed ---*/ - node[iPoint_Local] = new CTurbSSTVariable(Solution[0], Solution[1], muT_Inf, nDim, nVar, constants, config); - } - iPoint_Global++; - } - - /*--- Instantiate the variable class with an arbitrary solution - at any halo/periodic nodes. The initial solution can be arbitrary, - because a send/recv is performed immediately in the solver. ---*/ - for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { - node[iPoint] = new CTurbSSTVariable(Solution[0], Solution[1], muT_Inf, nDim, nVar, constants, config); - } - - /*--- Close the restart file ---*/ - restart_file.close(); - - /*--- Free memory needed for the transformation ---*/ - delete [] Global2Local; - } - - /*--- MPI solution ---*/ - Set_MPI_Solution(geometry, config); - -} - -CTurbSSTSolver::~CTurbSSTSolver(void) { - - if (constants != NULL) delete [] constants; - -} - -void CTurbSSTSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { - - unsigned long iPoint; - - unsigned long ExtIter = config->GetExtIter(); - bool limiter_flow = ((config->GetSpatialOrder_Flow() == SECOND_ORDER_LIMITER) && (ExtIter <= config->GetLimiterIter())); - - for (iPoint = 0; iPoint < nPoint; iPoint ++) { - - /*--- Initialize the residual vector ---*/ - - LinSysRes.SetBlock_Zero(iPoint); - - } - - /*--- Initialize the Jacobian matrices ---*/ - - Jacobian.SetValZero(); - - /*--- Upwind second order reconstruction ---*/ - - if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); - - if (config->GetSpatialOrder() == SECOND_ORDER_LIMITER) SetSolution_Limiter(geometry, config); - - if (limiter_flow) solver_container[FLOW_SOL]->SetPrimitive_Limiter(geometry, config); - -} - -void CTurbSSTSolver::Postprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh) { - su2double rho = 0.0, mu = 0.0, dist, omega, kine, strMag, F2, muT, zeta; - su2double a1 = constants[7]; - unsigned long iPoint; - - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - - /*--- Compute mean flow and turbulence gradients ---*/ - - if (config->GetKind_Gradient_Method() == GREEN_GAUSS) { -// solver_container[FLOW_SOL]->SetPrimitive_Gradient_GG(geometry, config); - SetSolution_Gradient_GG(geometry, config); - } - if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { -// solver_container[FLOW_SOL]->SetPrimitive_Gradient_LS(geometry, config); - SetSolution_Gradient_LS(geometry, config); - } - - for (iPoint = 0; iPoint < nPoint; iPoint ++) { - - /*--- Compute blending functions and cross diffusion ---*/ - - if (compressible) { - rho = solver_container[FLOW_SOL]->node[iPoint]->GetDensity(); - mu = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); - } - if (incompressible || freesurface) { - rho = solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); - mu = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosityInc(); - } - - dist = geometry->node[iPoint]->GetWall_Distance(); - - strMag = solver_container[FLOW_SOL]->node[iPoint]->GetStrainMag(); - - node[iPoint]->SetBlendingFunc(mu, dist, rho); - - F2 = node[iPoint]->GetF2blending(); - - /*--- Compute the eddy viscosity ---*/ - - kine = node[iPoint]->GetSolution(0); - omega = node[iPoint]->GetSolution(1); - zeta = min(1.0/omega, a1/(strMag*F2)); - muT = min(max(rho*kine*zeta,0.0),1.0); - node[iPoint]->SetmuT(muT); - - } - -} - -void CTurbSSTSolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, CConfig *config, unsigned short iMesh) { - - unsigned long iPoint; - - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - - /*--- Conservative variables w/o reconstruction ---*/ - - numerics->SetPrimitive(solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(), NULL); - - /*--- Gradient of the primitive and conservative variables ---*/ - - numerics->SetPrimVarGradient(solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(), NULL); - - /*--- Turbulent variables w/o reconstruction, and its gradient ---*/ - - numerics->SetTurbVar(node[iPoint]->GetSolution(), NULL); - numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), NULL); - - /*--- Set volume ---*/ - - numerics->SetVolume(geometry->node[iPoint]->GetVolume()); - - /*--- Set distance to the surface ---*/ - - numerics->SetDistance(geometry->node[iPoint]->GetWall_Distance(), 0.0); - - /*--- Menter's first blending function ---*/ - - numerics->SetF1blending(node[iPoint]->GetF1blending(),0.0); - - /*--- Menter's second blending function ---*/ - - numerics->SetF2blending(node[iPoint]->GetF2blending(),0.0); - - /*--- Set vorticity and strain rate magnitude ---*/ - - numerics->SetVorticity(solver_container[FLOW_SOL]->node[iPoint]->GetVorticity(), NULL); - - numerics->SetStrainMag(solver_container[FLOW_SOL]->node[iPoint]->GetStrainMag(), 0.0); - - /*--- Cross diffusion ---*/ - - numerics->SetCrossDiff(node[iPoint]->GetCrossDiff(),0.0); - - /*--- Compute the source term ---*/ - - numerics->ComputeResidual(Residual, Jacobian_i, NULL, config); - - /*--- Subtract residual and the Jacobian ---*/ - - LinSysRes.SubtractBlock(iPoint, Residual); - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - -} - -void CTurbSSTSolver::Source_Template(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, - CConfig *config, unsigned short iMesh) { - -} - -void CTurbSSTSolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned long iPoint, jPoint, iVertex, total_index; - unsigned short iDim, iVar; - su2double distance, density = 0.0, laminar_viscosity = 0.0, beta_1; - - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - if (geometry->node[iPoint]->GetDomain()) { - - /*--- distance to closest neighbor ---*/ - jPoint = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - distance = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - distance += (geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim))* - (geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim)); - } - distance = sqrt(distance); - - /*--- Set wall values ---*/ - if (compressible) { - density = solver_container[FLOW_SOL]->node[jPoint]->GetDensity(); - laminar_viscosity = solver_container[FLOW_SOL]->node[jPoint]->GetLaminarViscosity(); - } - if (incompressible || freesurface) { - density = solver_container[FLOW_SOL]->node[jPoint]->GetDensityInc(); - laminar_viscosity = solver_container[FLOW_SOL]->node[jPoint]->GetLaminarViscosityInc(); - } - - beta_1 = constants[4]; - - Solution[0] = 0.0; - Solution[1] = 60.0*laminar_viscosity/(density*beta_1*distance*distance); - - /*--- Set the solution values and zero the residual ---*/ - node[iPoint]->SetSolution_Old(Solution); - node[iPoint]->SetSolution(Solution); - LinSysRes.SetBlock_Zero(iPoint); - - /*--- Change rows of the Jacobian (includes 1 in the diagonal) ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - Jacobian.DeleteValsRowi(total_index); - } - - } - } - -} - -void CTurbSSTSolver::BC_Isothermal_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, - unsigned short val_marker) { - - unsigned long iPoint, jPoint, iVertex, total_index; - unsigned short iDim, iVar; - su2double distance, density = 0.0, laminar_viscosity = 0.0, beta_1; - - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - if (geometry->node[iPoint]->GetDomain()) { - - /*--- distance to closest neighbor ---*/ - jPoint = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - distance = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - distance += (geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim))* - (geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim)); - } - distance = sqrt(distance); - - /*--- Set wall values ---*/ - if (compressible) { - density = solver_container[FLOW_SOL]->node[jPoint]->GetDensity(); - laminar_viscosity = solver_container[FLOW_SOL]->node[jPoint]->GetLaminarViscosity(); - } - if (incompressible || freesurface) { - density = solver_container[FLOW_SOL]->node[jPoint]->GetDensityInc(); - laminar_viscosity = solver_container[FLOW_SOL]->node[jPoint]->GetLaminarViscosityInc(); - } - - beta_1 = constants[4]; - - Solution[0] = 0.0; - Solution[1] = 60.0*laminar_viscosity/(density*beta_1*distance*distance); - - /*--- Set the solution values and zero the residual ---*/ - node[iPoint]->SetSolution_Old(Solution); - node[iPoint]->SetSolution(Solution); - LinSysRes.SetBlock_Zero(iPoint); - - /*--- Change rows of the Jacobian (includes 1 in the diagonal) ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - Jacobian.DeleteValsRowi(total_index); - } - - } - } - -} - -void CTurbSSTSolver::BC_Far_Field(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned long iPoint, iVertex; - su2double *Normal, *V_infty, *V_domain; - unsigned short iVar, iDim; - - bool grid_movement = config->GetGrid_Movement(); - - Normal = new su2double[nDim]; - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Allocate the value at the infinity ---*/ - - V_infty = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); - - /*--- Retrieve solution at the farfield boundary node ---*/ - - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - conv_numerics->SetPrimitive(V_domain, V_infty); - - /*--- Set turbulent variable at the wall, and at infinity ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Solution_i[iVar] = node[iPoint]->GetSolution(iVar); - - Solution_j[0] = kine_Inf; - Solution_j[1] = omega_Inf; - - conv_numerics->SetTurbVar(Solution_i, Solution_j); - - /*--- Set Normal (it is necessary to change the sign) ---*/ - - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) - Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - /*--- Grid Movement ---*/ - - if (grid_movement) - conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[iPoint]->GetGridVel()); - - /*--- Compute residuals and Jacobians ---*/ - - conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Add residuals and Jacobians ---*/ - - LinSysRes.AddBlock(iPoint, Residual); - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - } - } - - delete [] Normal; - -} - -void CTurbSSTSolver::BC_Inlet(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, - unsigned short val_marker) { - - unsigned short iVar, iDim; - unsigned long iVertex, iPoint, Point_Normal; - su2double *V_inlet, *V_domain, *Normal; - - Normal = new su2double[nDim]; - - bool grid_movement = config->GetGrid_Movement(); - - string Marker_Tag = config->GetMarker_All_TagBound(val_marker); - - /*--- Loop over all the vertices on this boundary marker ---*/ - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Index of the closest interior node ---*/ - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Normal vector for this vertex (negate for outward convention) ---*/ - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - - /*--- Allocate the value at the inlet ---*/ - V_inlet = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); - - /*--- Retrieve solution at the farfield boundary node ---*/ - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - /*--- Set various quantities in the solver class ---*/ - conv_numerics->SetPrimitive(V_domain, V_inlet); - - /*--- Set the turbulent variable states. Use free-stream SST - values for the turbulent state at the inflow. ---*/ - for (iVar = 0; iVar < nVar; iVar++) - Solution_i[iVar] = node[iPoint]->GetSolution(iVar); - - Solution_j[0]= kine_Inf; - Solution_j[1]= omega_Inf; - - conv_numerics->SetTurbVar(Solution_i, Solution_j); - - /*--- Set various other quantities in the solver class ---*/ - conv_numerics->SetNormal(Normal); - - if (grid_movement) - conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), - geometry->node[iPoint]->GetGridVel()); - - /*--- Compute the residual using an upwind scheme ---*/ - conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - /*--- Viscous contribution ---*/ - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - visc_numerics->SetNormal(Normal); - - /*--- Conservative variables w/o reconstruction ---*/ - visc_numerics->SetPrimitive(V_domain, V_inlet); - - /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ - visc_numerics->SetTurbVar(Solution_i, Solution_j); - visc_numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); - - /*--- Menter's first blending function ---*/ - visc_numerics->SetF1blending(node[iPoint]->GetF1blending(), node[iPoint]->GetF1blending()); - - /*--- Compute residual, and Jacobians ---*/ - visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Subtract residual, and update Jacobians ---*/ - LinSysRes.SubtractBlock(iPoint, Residual); - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - } - - /*--- Free locally allocated memory ---*/ - delete[] Normal; - -} - -void CTurbSSTSolver::BC_Outlet(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - - unsigned long iPoint, iVertex, Point_Normal; - unsigned short iVar, iDim; - su2double *V_outlet, *V_domain, *Normal; - - bool grid_movement = config->GetGrid_Movement(); - - Normal = new su2double[nDim]; - - /*--- Loop over all the vertices on this boundary marker ---*/ - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Index of the closest interior node ---*/ - Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - /*--- Allocate the value at the outlet ---*/ - V_outlet = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); - - /*--- Retrieve solution at the farfield boundary node ---*/ - V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); - - /*--- Set various quantities in the solver class ---*/ - conv_numerics->SetPrimitive(V_domain, V_outlet); - - /*--- Set the turbulent variables. Here we use a Neumann BC such - that the turbulent variable is copied from the interior of the - domain to the outlet before computing the residual. - Solution_i --> TurbVar_internal, - Solution_j --> TurbVar_outlet ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - Solution_i[iVar] = node[iPoint]->GetSolution(iVar); - Solution_j[iVar] = node[iPoint]->GetSolution(iVar); - } - conv_numerics->SetTurbVar(Solution_i, Solution_j); - - /*--- Set Normal (negate for outward convention) ---*/ - geometry->vertex[val_marker][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) - Normal[iDim] = -Normal[iDim]; - conv_numerics->SetNormal(Normal); - - if (grid_movement) - conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), - geometry->node[iPoint]->GetGridVel()); - - /*--- Compute the residual using an upwind scheme ---*/ - conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - LinSysRes.AddBlock(iPoint, Residual); - - /*--- Jacobian contribution for implicit integration ---*/ - Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); - - /*--- Viscous contribution ---*/ - visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); - visc_numerics->SetNormal(Normal); - - /*--- Conservative variables w/o reconstruction ---*/ - visc_numerics->SetPrimitive(V_domain, V_outlet); - - /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ - visc_numerics->SetTurbVar(Solution_i, Solution_j); - visc_numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); - - /*--- Menter's first blending function ---*/ - visc_numerics->SetF1blending(node[iPoint]->GetF1blending(), node[iPoint]->GetF1blending()); - - /*--- Compute residual, and Jacobians ---*/ - visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); - - /*--- Subtract residual, and update Jacobians ---*/ - LinSysRes.SubtractBlock(iPoint, Residual); - Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); - - } - } - - /*--- Free locally allocated memory ---*/ - delete[] Normal; - -} - -su2double* CTurbSSTSolver::GetConstants() { - return constants; -} +/*! + * \file solution_direct_turbulent.cpp + * \brief Main subrotuines for solving direct problems + * \author F. Palacios, A. Bueno + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/solver_structure.hpp" + +CTurbSolver::CTurbSolver(void) : CSolver() { + + FlowPrimVar_i = NULL; + FlowPrimVar_j = NULL; + lowerlimit = NULL; + upperlimit = NULL; + +} + +CTurbSolver::CTurbSolver(CConfig *config) : CSolver() { + + Gamma = config->GetGamma(); + Gamma_Minus_One = Gamma - 1.0; + + FlowPrimVar_i = NULL; + FlowPrimVar_j = NULL; + lowerlimit = NULL; + upperlimit = NULL; + +} + +CTurbSolver::~CTurbSolver(void) { + + if (FlowPrimVar_i != NULL) delete [] FlowPrimVar_i; + if (FlowPrimVar_j != NULL) delete [] FlowPrimVar_j; + if (lowerlimit != NULL) delete [] lowerlimit; + if (upperlimit != NULL) delete [] upperlimit; + +} + +void CTurbSolver::Set_MPI_Solution(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iMarker, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector, nBufferS_Scalar, nBufferR_Scalar; + su2double *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL, *Buffer_Receive_muT = NULL, *Buffer_Send_muT = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + nBufferS_Scalar = nVertexS; nBufferR_Scalar = nVertexR; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_U = new su2double [nBufferR_Vector]; + Buffer_Send_U = new su2double[nBufferS_Vector]; + + Buffer_Receive_muT = new su2double [nBufferR_Scalar]; + Buffer_Send_muT = new su2double[nBufferS_Scalar]; + + /*--- Copy the solution that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + Buffer_Send_muT[iVertex] = node[iPoint]->GetmuT(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution(iVar); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); + SU2_MPI::Sendrecv(Buffer_Send_muT, nBufferS_Scalar, MPI_DOUBLE, send_to, 1, + Buffer_Receive_muT, nBufferR_Scalar, MPI_DOUBLE, receive_from, 1, MPI_COMM_WORLD, &status); +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + Buffer_Receive_muT[iVertex] = node[iPoint]->GetmuT(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_U; + delete [] Buffer_Send_muT; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + + /*--- Copy conservative variables. ---*/ + node[iPoint]->SetmuT(Buffer_Receive_muT[iVertex]); + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetSolution(iVar, Buffer_Receive_U[iVar*nVertexR+iVertex]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_muT; + delete [] Buffer_Receive_U; + + } + + } + +} + +void CTurbSolver::Set_MPI_Solution_Old(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iMarker, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_U = new su2double [nBufferR_Vector]; + Buffer_Send_U = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution_Old(iVar); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_U; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + + /*--- Copy transformed conserved variables back into buffer. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetSolution_Old(iVar, Buffer_Receive_U[iVar*nVertexR+iVertex]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_U; + + } + + } +} + +void CTurbSolver::Set_MPI_Solution_Gradient(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, + *Buffer_Receive_Gradient = NULL, *Buffer_Send_Gradient = NULL; + + su2double **Gradient = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + Gradient[iVar] = new su2double[nDim]; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar*nDim; nBufferR_Vector = nVertexR*nVar*nDim; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_Gradient = new su2double [nBufferR_Vector]; + Buffer_Send_Gradient = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Gradient[iDim*nVar*nVertexS+iVar*nVertexS+iVertex] = node[iPoint]->GetGradient(iVar, iDim); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Gradient, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_Gradient, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex] = Buffer_Send_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_Gradient; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Gradient[iVar][iDim] = Buffer_Receive_Gradient[iDim*nVar*nVertexR+iVar*nVertexR+iVertex]; + + /*--- Need to rotate the gradients for all conserved variables. ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + if (nDim == 2) { + Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex]; + } + else { + Gradient[iVar][0] = rotMatrix[0][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[0][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][1] = rotMatrix[1][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[1][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; + Gradient[iVar][2] = rotMatrix[2][0]*Buffer_Receive_Gradient[0*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][1]*Buffer_Receive_Gradient[1*nVar*nVertexR+iVar*nVertexR+iVertex] + rotMatrix[2][2]*Buffer_Receive_Gradient[2*nVar*nVertexR+iVar*nVertexR+iVertex]; + } + } + + /*--- Store the received information ---*/ + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + node[iPoint]->SetGradient(iVar, iDim, Gradient[iVar][iDim]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_Gradient; + + } + + } + + for (iVar = 0; iVar < nVar; iVar++) + delete [] Gradient[iVar]; + delete [] Gradient; + +} + +void CTurbSolver::Set_MPI_Solution_Limiter(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iMarker, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double *Buffer_Receive_Limit = NULL, *Buffer_Send_Limit = NULL; + + su2double *Limiter = new su2double [nVar]; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + + /*--- Allocate Receive and send buffers ---*/ + Buffer_Receive_Limit = new su2double [nBufferR_Vector]; + Buffer_Send_Limit = new su2double[nBufferS_Vector]; + + /*--- Copy the solution old that should be sended ---*/ + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_Limit[iVar*nVertexS+iVertex] = node[iPoint]->GetLimiter(iVar); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Limit, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_Limit, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); +#else + + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_Limit[iVar*nVertexR+iVertex] = Buffer_Send_Limit[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + delete [] Buffer_Send_Limit; + + /*--- Do the coordinate transformation ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + + /*--- Copy transformed conserved variables back into buffer. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetLimiter(iVar, Buffer_Receive_Limit[iVar*nVertexR+iVertex]); + + } + + /*--- Deallocate receive buffer ---*/ + delete [] Buffer_Receive_Limit; + + } + + } + + delete [] Limiter; + +} + + +void CTurbSolver::Upwind_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config, unsigned short iMesh) { + + su2double *Turb_i, *Turb_j, *Limiter_i = NULL, *Limiter_j = NULL, *V_i, *V_j, **Gradient_i, **Gradient_j, Project_Grad_i, Project_Grad_j; + unsigned long iEdge, iPoint, jPoint; + unsigned short iDim, iVar; + + bool second_order = ((config->GetSpatialOrder() == SECOND_ORDER) || (config->GetSpatialOrder() == SECOND_ORDER_LIMITER)); + bool limiter = (config->GetSpatialOrder() == SECOND_ORDER_LIMITER); + bool grid_movement = config->GetGrid_Movement(); + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Points in edge and normal vectors ---*/ + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); + + /*--- Primitive variables w/o reconstruction ---*/ + + V_i = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + V_j = solver_container[FLOW_SOL]->node[jPoint]->GetPrimitive(); + numerics->SetPrimitive(V_i, V_j); + + /*--- Turbulent variables w/o reconstruction ---*/ + + Turb_i = node[iPoint]->GetSolution(); + Turb_j = node[jPoint]->GetSolution(); + numerics->SetTurbVar(Turb_i, Turb_j); + + /*--- Grid Movement ---*/ + + if (grid_movement) + numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[jPoint]->GetGridVel()); + + if (second_order) { + + for (iDim = 0; iDim < nDim; iDim++) { + Vector_i[iDim] = 0.5*(geometry->node[jPoint]->GetCoord(iDim) - geometry->node[iPoint]->GetCoord(iDim)); + Vector_j[iDim] = 0.5*(geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim)); + } + + /*--- Mean flow primitive variables using gradient reconstruction and limiters ---*/ + + Gradient_i = solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(); + Gradient_j = solver_container[FLOW_SOL]->node[jPoint]->GetGradient_Primitive(); + if (limiter) { + Limiter_i = solver_container[FLOW_SOL]->node[iPoint]->GetLimiter_Primitive(); + Limiter_j = solver_container[FLOW_SOL]->node[jPoint]->GetLimiter_Primitive(); + } + + for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnPrimVarGrad(); iVar++) { + Project_Grad_i = 0.0; Project_Grad_j = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Project_Grad_i += Vector_i[iDim]*Gradient_i[iVar][iDim]; + Project_Grad_j += Vector_j[iDim]*Gradient_j[iVar][iDim]; + } + if (limiter) { + FlowPrimVar_i[iVar] = V_i[iVar] + Limiter_i[iVar]*Project_Grad_i; + FlowPrimVar_j[iVar] = V_j[iVar] + Limiter_j[iVar]*Project_Grad_j; + } + else { + FlowPrimVar_i[iVar] = V_i[iVar] + Project_Grad_i; + FlowPrimVar_j[iVar] = V_j[iVar] + Project_Grad_j; + } + } + + numerics->SetPrimitive(FlowPrimVar_i, FlowPrimVar_j); + + /*--- Turbulent variables using gradient reconstruction and limiters ---*/ + + Gradient_i = node[iPoint]->GetGradient(); + Gradient_j = node[jPoint]->GetGradient(); + if (limiter) { + Limiter_i = node[iPoint]->GetLimiter(); + Limiter_j = node[jPoint]->GetLimiter(); + } + + for (iVar = 0; iVar < nVar; iVar++) { + Project_Grad_i = 0.0; Project_Grad_j = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Project_Grad_i += Vector_i[iDim]*Gradient_i[iVar][iDim]; + Project_Grad_j += Vector_j[iDim]*Gradient_j[iVar][iDim]; + } + if (limiter) { + Solution_i[iVar] = Turb_i[iVar] + Limiter_i[iVar]*Project_Grad_i; + Solution_j[iVar] = Turb_j[iVar] + Limiter_j[iVar]*Project_Grad_j; + } + else { + Solution_i[iVar] = Turb_i[iVar] + Project_Grad_i; + Solution_j[iVar] = Turb_j[iVar] + Project_Grad_j; + } + } + + numerics->SetTurbVar(Solution_i, Solution_j); + + } + + /*--- Add and subtract residual ---*/ + + numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + LinSysRes.AddBlock(iPoint, Residual); + LinSysRes.SubtractBlock(jPoint, Residual); + + /*--- Implicit part ---*/ + + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + Jacobian.AddBlock(iPoint, jPoint, Jacobian_j); + Jacobian.SubtractBlock(jPoint, iPoint, Jacobian_i); + Jacobian.SubtractBlock(jPoint, jPoint, Jacobian_j); + + } + +} + +void CTurbSolver::Viscous_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config, unsigned short iMesh, unsigned short iRKStep) { + unsigned long iEdge, iPoint, jPoint; + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Points in edge ---*/ + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + + /*--- Points coordinates, and normal vector ---*/ + + numerics->SetCoord(geometry->node[iPoint]->GetCoord(), + geometry->node[jPoint]->GetCoord()); + numerics->SetNormal(geometry->edge[iEdge]->GetNormal()); + + /*--- Conservative variables w/o reconstruction ---*/ + + numerics->SetPrimitive(solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(), + solver_container[FLOW_SOL]->node[jPoint]->GetPrimitive()); + + /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ + + numerics->SetTurbVar(node[iPoint]->GetSolution(), node[jPoint]->GetSolution()); + numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), node[jPoint]->GetGradient()); + + /*--- Menter's first blending function (only SST)---*/ + if (config->GetKind_Turb_Model() == SST) + numerics->SetF1blending(node[iPoint]->GetF1blending(), node[jPoint]->GetF1blending()); + + /*--- Compute residual, and Jacobians ---*/ + + numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Add and subtract residual, and update Jacobians ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual); + LinSysRes.AddBlock(jPoint, Residual); + + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + Jacobian.SubtractBlock(iPoint, jPoint, Jacobian_j); + Jacobian.AddBlock(jPoint, iPoint, Jacobian_i); + Jacobian.AddBlock(jPoint, jPoint, Jacobian_j); + + } + +} + +void CTurbSolver::BC_Sym_Plane(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + /*--- Convective fluxes across symmetry plane are equal to zero. ---*/ + +} + +void CTurbSolver::BC_Euler_Wall(CGeometry *geometry, CSolver **solver_container, + CNumerics *numerics, CConfig *config, unsigned short val_marker) { + + /*--- Convective fluxes across euler wall are equal to zero. ---*/ + +} + +void CTurbSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { + + unsigned short iVar; + unsigned long iPoint, total_index; + su2double Delta, Vol, density_old = 0.0, density = 0.0; + + bool adjoint = config->GetAdjoint(); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + + /*--- Set maximum residual to zero ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + SetRes_RMS(iVar, 0.0); + SetRes_Max(iVar, 0.0, 0); + } + + /*--- Build implicit system ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Read the volume ---*/ + + Vol = geometry->node[iPoint]->GetVolume(); + + /*--- Modify matrix diagonal to assure diagonal dominance ---*/ + + Delta = Vol / (config->GetCFLRedCoeff_Turb()*solver_container[FLOW_SOL]->node[iPoint]->GetDelta_Time()); + Jacobian.AddVal2Diag(iPoint, Delta); + + /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + LinSysRes[total_index] = - LinSysRes[total_index]; + LinSysSol[total_index] = 0.0; + AddRes_RMS(iVar, LinSysRes[total_index]*LinSysRes[total_index]); + AddRes_Max(iVar, fabs(LinSysRes[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); + } + } + + /*--- Initialize residual and solution at the ghost points ---*/ + + for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar + iVar; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + } + } + + /*--- Solve or smooth the linear system ---*/ + + CSysSolve system; + system.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); + + /*--- Update solution (system written in terms of increments) ---*/ + + if (!adjoint) { + + /*--- Update and clip trubulent solution ---*/ + + switch (config->GetKind_Turb_Model()) { + + case SA: + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + node[iPoint]->AddClippedSolution(0, config->GetRelaxation_Factor_Turb()*LinSysSol[iPoint], lowerlimit[0], upperlimit[0]); + } + + break; + + case SA_NEG: + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + node[iPoint]->AddSolution(0, config->GetRelaxation_Factor_Turb()*LinSysSol[iPoint]); + } + + break; + + case SST: + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + if (compressible) { + density_old = solver_container[FLOW_SOL]->node[iPoint]->GetSolution_Old(0); + density = solver_container[FLOW_SOL]->node[iPoint]->GetDensity(); + } + if (incompressible || freesurface) { + density_old = solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); + density = solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); + } + + for (iVar = 0; iVar < nVar; iVar++) { + node[iPoint]->AddConservativeSolution(iVar, config->GetRelaxation_Factor_Turb()*LinSysSol[iPoint*nVar+iVar], density, density_old, lowerlimit[iVar], upperlimit[iVar]); + } + + } + + break; + + } + } + + + /*--- MPI solution ---*/ + + Set_MPI_Solution(geometry, config); + + /*--- Compute the root mean square residual ---*/ + + SetResidual_RMS(geometry, config); + +} + +void CTurbSolver::SetResidual_DualTime(CGeometry *geometry, CSolver **solver_container, CConfig *config, + unsigned short iRKStep, unsigned short iMesh, unsigned short RunTime_EqSystem) { + + /*--- Local variables ---*/ + + unsigned short iVar, jVar, iMarker, iDim; + unsigned long iPoint, jPoint, iEdge, iVertex; + + su2double *U_time_nM1, *U_time_n, *U_time_nP1; + su2double Volume_nM1, Volume_nP1, TimeStep; + su2double Density_nM1, Density_n, Density_nP1; + su2double *Normal = NULL, *GridVel_i = NULL, *GridVel_j = NULL, Residual_GCL; + + bool implicit = (config->GetKind_TimeIntScheme_Turb() == EULER_IMPLICIT); + bool grid_movement = config->GetGrid_Movement(); + + /*--- Store the physical time step ---*/ + + TimeStep = config->GetDelta_UnstTimeND(); + + /*--- Compute the dual time-stepping source term for static meshes ---*/ + + if (!grid_movement) { + + /*--- Loop over all nodes (excluding halos) ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Retrieve the solution at time levels n-1, n, and n+1. Note that + we are currently iterating on U^n+1 and that U^n & U^n-1 are fixed, + previous solutions that are stored in memory. ---*/ + + U_time_nM1 = node[iPoint]->GetSolution_time_n1(); + U_time_n = node[iPoint]->GetSolution_time_n(); + U_time_nP1 = node[iPoint]->GetSolution(); + + /*--- CV volume at time n+1. As we are on a static mesh, the volume + of the CV will remained fixed for all time steps. ---*/ + + Volume_nP1 = geometry->node[iPoint]->GetVolume(); + + /*--- Compute the dual time-stepping source term based on the chosen + time discretization scheme (1st- or 2nd-order).---*/ + + if (config->GetKind_Turb_Model() == SST) { + + /*--- If this is the SST model, we need to multiply by the density + in order to get the conservative variables ---*/ + Density_nM1 = solver_container[FLOW_SOL]->node[iPoint]->GetSolution_time_n1()[0]; + Density_n = solver_container[FLOW_SOL]->node[iPoint]->GetSolution_time_n()[0]; + Density_nP1 = solver_container[FLOW_SOL]->node[iPoint]->GetSolution()[0]; + + for (iVar = 0; iVar < nVar; iVar++) { + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Residual[iVar] = ( Density_nP1*U_time_nP1[iVar] - Density_n*U_time_n[iVar])*Volume_nP1 / TimeStep; + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + Residual[iVar] = ( 3.0*Density_nP1*U_time_nP1[iVar] - 4.0*Density_n*U_time_n[iVar] + +1.0*Density_nM1*U_time_nM1[iVar])*Volume_nP1 / (2.0*TimeStep); + } + + } else { + + for (iVar = 0; iVar < nVar; iVar++) { + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Residual[iVar] = (U_time_nP1[iVar] - U_time_n[iVar])*Volume_nP1 / TimeStep; + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + Residual[iVar] = ( 3.0*U_time_nP1[iVar] - 4.0*U_time_n[iVar] + +1.0*U_time_nM1[iVar])*Volume_nP1 / (2.0*TimeStep); + } + } + + /*--- Store the residual and compute the Jacobian contribution due + to the dual time source term. ---*/ + + LinSysRes.AddBlock(iPoint, Residual); + if (implicit) { + for (iVar = 0; iVar < nVar; iVar++) { + for (jVar = 0; jVar < nVar; jVar++) Jacobian_i[iVar][jVar] = 0.0; + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Jacobian_i[iVar][iVar] = Volume_nP1 / TimeStep; + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + Jacobian_i[iVar][iVar] = (Volume_nP1*3.0)/(2.0*TimeStep); + } + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + } + } + + } else { + + /*--- For unsteady flows on dynamic meshes (rigidly transforming or + dynamically deforming), the Geometric Conservation Law (GCL) should be + satisfied in conjunction with the ALE formulation of the governing + equations. The GCL prevents accuracy issues caused by grid motion, i.e. + a uniform free-stream should be preserved through a moving grid. First, + we will loop over the edges and boundaries to compute the GCL component + of the dual time source term that depends on grid velocities. ---*/ + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Get indices for nodes i & j plus the face normal ---*/ + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + Normal = geometry->edge[iEdge]->GetNormal(); + + /*--- Grid velocities stored at nodes i & j ---*/ + + GridVel_i = geometry->node[iPoint]->GetGridVel(); + GridVel_j = geometry->node[jPoint]->GetGridVel(); + + /*--- Compute the GCL term by averaging the grid velocities at the + edge mid-point and dotting with the face normal. ---*/ + + Residual_GCL = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Residual_GCL += 0.5*(GridVel_i[iDim]+GridVel_j[iDim])*Normal[iDim]; + + /*--- Compute the GCL component of the source term for node i ---*/ + + U_time_n = node[iPoint]->GetSolution_time_n(); + + /*--- Multiply by density at node i for the SST model ---*/ + + if (config->GetKind_Turb_Model() == SST) { + Density_n = solver_container[FLOW_SOL]->node[iPoint]->GetSolution_time_n()[0]; + for (iVar = 0; iVar < nVar; iVar++) + Residual[iVar] = Density_n*U_time_n[iVar]*Residual_GCL; + } else { + for (iVar = 0; iVar < nVar; iVar++) + Residual[iVar] = U_time_n[iVar]*Residual_GCL; + } + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Compute the GCL component of the source term for node j ---*/ + + U_time_n = node[jPoint]->GetSolution_time_n(); + + /*--- Multiply by density at node j for the SST model ---*/ + + if (config->GetKind_Turb_Model() == SST) { + Density_n = solver_container[FLOW_SOL]->node[jPoint]->GetSolution_time_n()[0]; + for (iVar = 0; iVar < nVar; iVar++) + Residual[iVar] = Density_n*U_time_n[iVar]*Residual_GCL; + } else { + for (iVar = 0; iVar < nVar; iVar++) + Residual[iVar] = U_time_n[iVar]*Residual_GCL; + } + LinSysRes.SubtractBlock(jPoint, Residual); + + } + + /*--- Loop over the boundary edges ---*/ + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + + /*--- Get the index for node i plus the boundary face normal ---*/ + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + + /*--- Grid velocities stored at boundary node i ---*/ + + GridVel_i = geometry->node[iPoint]->GetGridVel(); + + /*--- Compute the GCL term by dotting the grid velocity with the face + normal. The normal is negated to match the boundary convention. ---*/ + + Residual_GCL = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Residual_GCL -= 0.5*(GridVel_i[iDim]+GridVel_i[iDim])*Normal[iDim]; + + /*--- Compute the GCL component of the source term for node i ---*/ + + U_time_n = node[iPoint]->GetSolution_time_n(); + + /*--- Multiply by density at node i for the SST model ---*/ + + if (config->GetKind_Turb_Model() == SST) { + Density_n = solver_container[FLOW_SOL]->node[iPoint]->GetSolution_time_n()[0]; + for (iVar = 0; iVar < nVar; iVar++) + Residual[iVar] = Density_n*U_time_n[iVar]*Residual_GCL; + } else { + for (iVar = 0; iVar < nVar; iVar++) + Residual[iVar] = U_time_n[iVar]*Residual_GCL; + } + LinSysRes.AddBlock(iPoint, Residual); + } + } + + /*--- Loop over all nodes (excluding halos) to compute the remainder + of the dual time-stepping source term. ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Retrieve the solution at time levels n-1, n, and n+1. Note that + we are currently iterating on U^n+1 and that U^n & U^n-1 are fixed, + previous solutions that are stored in memory. ---*/ + + U_time_nM1 = node[iPoint]->GetSolution_time_n1(); + U_time_n = node[iPoint]->GetSolution_time_n(); + U_time_nP1 = node[iPoint]->GetSolution(); + + /*--- CV volume at time n-1 and n+1. In the case of dynamically deforming + grids, the volumes will change. On rigidly transforming grids, the + volumes will remain constant. ---*/ + + Volume_nM1 = geometry->node[iPoint]->GetVolume_nM1(); + Volume_nP1 = geometry->node[iPoint]->GetVolume(); + + /*--- Compute the dual time-stepping source residual. Due to the + introduction of the GCL term above, the remainder of the source residual + due to the time discretization has a new form.---*/ + + if (config->GetKind_Turb_Model() == SST) { + + /*--- If this is the SST model, we need to multiply by the density + in order to get the conservative variables ---*/ + Density_nM1 = solver_container[FLOW_SOL]->node[iPoint]->GetSolution_time_n1()[0]; + Density_n = solver_container[FLOW_SOL]->node[iPoint]->GetSolution_time_n()[0]; + Density_nP1 = solver_container[FLOW_SOL]->node[iPoint]->GetSolution()[0]; + + for (iVar = 0; iVar < nVar; iVar++) { + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Residual[iVar] = (Density_nP1*U_time_nP1[iVar] - Density_n*U_time_n[iVar])*(Volume_nP1/TimeStep); + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + Residual[iVar] = (Density_nP1*U_time_nP1[iVar] - Density_n*U_time_n[iVar])*(3.0*Volume_nP1/(2.0*TimeStep)) + + (Density_nM1*U_time_nM1[iVar] - Density_n*U_time_n[iVar])*(Volume_nM1/(2.0*TimeStep)); + } + + } else { + + for (iVar = 0; iVar < nVar; iVar++) { + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Residual[iVar] = (U_time_nP1[iVar] - U_time_n[iVar])*(Volume_nP1/TimeStep); + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + Residual[iVar] = (U_time_nP1[iVar] - U_time_n[iVar])*(3.0*Volume_nP1/(2.0*TimeStep)) + + (U_time_nM1[iVar] - U_time_n[iVar])*(Volume_nM1/(2.0*TimeStep)); + } + } + + /*--- Store the residual and compute the Jacobian contribution due + to the dual time source term. ---*/ + + LinSysRes.AddBlock(iPoint, Residual); + if (implicit) { + for (iVar = 0; iVar < nVar; iVar++) { + for (jVar = 0; jVar < nVar; jVar++) Jacobian_i[iVar][jVar] = 0.0; + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Jacobian_i[iVar][iVar] = Volume_nP1/TimeStep; + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + Jacobian_i[iVar][iVar] = (3.0*Volume_nP1)/(2.0*TimeStep); + } + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + } + } + } + +} + +CTurbSASolver::CTurbSASolver(void) : CTurbSolver() { } + +CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned short iMesh, CFluidModel* FluidModel) : CTurbSolver() { + unsigned short iVar, iDim, nLineLets; + unsigned long iPoint, index; + su2double Density_Inf, Viscosity_Inf, Factor_nu_Inf, Factor_nu_Engine, dull_val; + + unsigned short iZone = config->GetiZone(); + unsigned short nZone = geometry->GetnZone(); + bool restart = (config->GetRestart() || config->GetRestart_Flow()); + bool adjoint = config->GetAdjoint(); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + Gamma = config->GetGamma(); + Gamma_Minus_One = Gamma - 1.0; + + /*--- Dimension of the problem --> dependent of the turbulent model ---*/ + + nVar = 1; + nPoint = geometry->GetnPoint(); + nPointDomain = geometry->GetnPointDomain(); + + /*--- Define geometry constants in the solver structure ---*/ + + nDim = geometry->GetnDim(); + node = new CVariable*[nPoint]; + + /*--- Single grid simulation ---*/ + + if (iMesh == MESH_0 || config->GetMGCycle() == FULLMG_CYCLE) { + + /*--- Define some auxiliar vector related with the residual ---*/ + + Residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; + Residual_RMS = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_RMS[iVar] = 0.0; + Residual_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_i[iVar] = 0.0; + Residual_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_j[iVar] = 0.0; + Residual_Max = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_Max[iVar] = 0.0; + + /*--- Define some structures for locating max residuals ---*/ + + Point_Max = new unsigned long[nVar]; + for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; + Point_Max_Coord = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Point_Max_Coord[iVar] = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; + } + + /*--- Define some auxiliar vector related with the solution ---*/ + + Solution = new su2double[nVar]; + Solution_i = new su2double[nVar]; Solution_j = new su2double[nVar]; + + /*--- Define some auxiliar vector related with the geometry ---*/ + + Vector_i = new su2double[nDim]; Vector_j = new su2double[nDim]; + + /*--- Define some auxiliar vector related with the flow solution ---*/ + + FlowPrimVar_i = new su2double [nDim+7]; FlowPrimVar_j = new su2double [nDim+7]; + + /*--- Jacobians and vector structures for implicit computations ---*/ + + Jacobian_i = new su2double* [nVar]; + Jacobian_j = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Jacobian_i[iVar] = new su2double [nVar]; + Jacobian_j[iVar] = new su2double [nVar]; + } + + /*--- Initialization of the structure of the whole Jacobian ---*/ + + if (rank == MASTER_NODE) cout << "Initialize Jacobian structure (SA model)." << endl; + Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); + + if ((config->GetKind_Linear_Solver_Prec() == LINELET) || + (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { + nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); + if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; + } + + LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); + LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); + + if (config->GetExtraOutput()) { + if (nDim == 2) { nOutputVariables = 13; } + else if (nDim == 3) { nOutputVariables = 19; } + OutputVariables.Initialize(nPoint, nPointDomain, nOutputVariables, 0.0); + OutputHeadingNames = new string[nOutputVariables]; + } + + /*--- Computation of gradients by least squares ---*/ + + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { + /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ + Smatrix = new su2double* [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Smatrix[iDim] = new su2double [nDim]; + + /*--- c vector := transpose(WA)*(Wb) ---*/ + + cvector = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + cvector[iVar] = new su2double [nDim]; + } + + } + + /*--- Initialize lower and upper limits---*/ + + lowerlimit = new su2double[nVar]; + upperlimit = new su2double[nVar]; + + lowerlimit[0] = 1.0e-10; + upperlimit[0] = 1.0; + + + /*--- Read farfield conditions from config ---*/ + + Density_Inf = config->GetDensity_FreeStreamND(); + Viscosity_Inf = config->GetViscosity_FreeStreamND(); + + /*--- Factor_nu_Inf in [3.0, 5.0] ---*/ + + Factor_nu_Inf = config->GetNuFactor_FreeStream(); + nu_tilde_Inf = Factor_nu_Inf*Viscosity_Inf/Density_Inf; + + /*--- Factor_nu_Engine ---*/ + Factor_nu_Engine = config->GetNuFactor_Engine(); + nu_tilde_Engine = Factor_nu_Engine*Viscosity_Inf/Density_Inf; + + /*--- Eddy viscosity at infinity ---*/ + su2double Ji, Ji_3, fv1, cv1_3 = 7.1*7.1*7.1; + su2double muT_Inf; + Ji = nu_tilde_Inf/Viscosity_Inf*Density_Inf; + Ji_3 = Ji*Ji*Ji; + fv1 = Ji_3/(Ji_3+cv1_3); + muT_Inf = Density_Inf*fv1*nu_tilde_Inf; + + /*--- Restart the solution from file information ---*/ + if (!restart || (iMesh != MESH_0)) { + for (iPoint = 0; iPoint < nPoint; iPoint++) + node[iPoint] = new CTurbSAVariable(nu_tilde_Inf, muT_Inf, nDim, nVar, config); + } + else { + + /*--- Restart the solution from file information ---*/ + ifstream restart_file; + string filename = config->GetSolution_FlowFileName(); + su2double Density, StaticEnergy, Laminar_Viscosity, nu, nu_hat, muT = 0.0, U[5]; + + /*--- Modify file name for an unsteady restart ---*/ + if (dual_time) { + int Unst_RestartIter; + if (adjoint) { + Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_AdjointIter()) - 1; + } else if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_RestartIter())-1; + else + Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_RestartIter())-2; + filename = config->GetUnsteady_FileName(filename, Unst_RestartIter); + } + if (nZone >1) + filename= config->GetRestart_FlowFileName(filename, iZone); + + + /*--- Open the restart file, throw an error if this fails. ---*/ + restart_file.open(filename.data(), ios::in); + if (restart_file.fail()) { + cout << "There is no turbulent restart file!!" << endl; + exit(EXIT_FAILURE); + } + + /*--- In case this is a parallel simulation, we need to perform the + Global2Local index transformation first. ---*/ + long *Global2Local; + Global2Local = new long[geometry->GetGlobal_nPointDomain()]; + /*--- First, set all indices to a negative value by default ---*/ + for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) { + Global2Local[iPoint] = -1; + } + /*--- Now fill array with the transform values only for local points ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; + } + + /*--- Read all lines in the restart file ---*/ + long iPoint_Local; unsigned long iPoint_Global = 0; string text_line; + + /*--- The first line is the header ---*/ + getline (restart_file, text_line); + + while (getline (restart_file, text_line)) { + istringstream point_line(text_line); + + /*--- Retrieve local index. If this node from the restart file lives + on a different processor, the value of iPoint_Local will be -1. + Otherwise, the local index for this node on the current processor + will be returned and used to instantiate the vars. ---*/ + iPoint_Local = Global2Local[iPoint_Global]; + if (iPoint_Local >= 0) { + if (compressible) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> U[0] >> U[1] >> U[2] >> U[3] >> Solution[0]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> U[0] >> U[1] >> U[2] >> U[3] >> U[4] >> Solution[0]; + + Density = U[0]; + if (nDim == 2) + StaticEnergy = U[3]/U[0] - (U[1]*U[1] + U[2]*U[2])/(2.0*U[0]*U[0]); +// Pressure = Gamma_Minus_One*(U[3] - (U[1]*U[1] + U[2]*U[2])/(2.0*U[0])); + else + StaticEnergy = U[4]/U[0] - (U[1]*U[1] + U[2]*U[2] + U[3]*U[3] )/(2.0*U[0]*U[0]); +// Pressure = Gamma_Minus_One*(U[4] - (U[1]*U[1] + U[2]*U[2] + U[3]*U[3])/(2.0*U[0])); + +// Temperature = Pressure/(Gas_Constant*Density); +// +// +// Temperature_Dim = Temperature*Temperature_Ref; +// +// if (config->GetSystemMeasurements() == SI) { T_ref = 273.15; S = 110.4; Mu_ref = 1.716E-5; } +// if (config->GetSystemMeasurements() == US) { T_ref = 518.7; S = 198.72; Mu_ref = 3.62E-7; } +// +// /*--- Calculate viscosity from a non-dim. Sutherland's Law ---*/ +// +// Laminar_Viscosity = Mu_ref*(pow(Temperature_Dim/T_ref, 1.5) * (T_ref+S)/(Temperature_Dim+S)); +// Laminar_Viscosity = Laminar_Viscosity/Viscosity_Ref; + + FluidModel->SetTDState_rhoe(Density, StaticEnergy); + Laminar_Viscosity = FluidModel->GetLaminarViscosity(); + nu = Laminar_Viscosity/Density; + nu_hat = Solution[0]; + Ji = nu_hat/nu; + Ji_3 = Ji*Ji*Ji; + fv1 = Ji_3/(Ji_3+cv1_3); + muT = Density*fv1*nu_hat; + + } + if (incompressible) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; + muT = muT_Inf; + } + + if (freesurface) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; + muT = muT_Inf; + } + + /*--- Instantiate the solution at this node, note that the eddy viscosity should be recomputed ---*/ + node[iPoint_Local] = new CTurbSAVariable(Solution[0], muT, nDim, nVar, config); + } + iPoint_Global++; + } + + /*--- Instantiate the variable class with an arbitrary solution + at any halo/periodic nodes. The initial solution can be arbitrary, + because a send/recv is performed immediately in the solver. ---*/ + for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { + node[iPoint] = new CTurbSAVariable(Solution[0], muT_Inf, nDim, nVar, config); + } + + /*--- Close the restart file ---*/ + restart_file.close(); + + /*--- Free memory needed for the transformation ---*/ + delete [] Global2Local; + } + + /*--- MPI solution ---*/ + Set_MPI_Solution(geometry, config); + +} + +CTurbSASolver::~CTurbSASolver(void) { + +} + +void CTurbSASolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { + + unsigned long iPoint; + + unsigned long ExtIter = config->GetExtIter(); + bool limiter_flow = ((config->GetSpatialOrder_Flow() == SECOND_ORDER_LIMITER) && (ExtIter <= config->GetLimiterIter())); + + for (iPoint = 0; iPoint < nPoint; iPoint ++) { + + /*--- Initialize the residual vector ---*/ + + LinSysRes.SetBlock_Zero(iPoint); + + } + + /*--- Initialize the Jacobian matrices ---*/ + + Jacobian.SetValZero(); + + if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); + + /*--- Upwind second order reconstruction ---*/ + + if (config->GetSpatialOrder() == SECOND_ORDER_LIMITER) SetSolution_Limiter(geometry, config); + + if (limiter_flow) solver_container[FLOW_SOL]->SetPrimitive_Limiter(geometry, config); + +} + +void CTurbSASolver::Postprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh) { + + su2double rho = 0.0, mu = 0.0, nu, *nu_hat, muT, Ji, Ji_3, fv1; + su2double cv1_3 = 7.1*7.1*7.1; + unsigned long iPoint; + + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool neg_spalart_allmaras = (config->GetKind_Turb_Model() == SA_NEG); + + + /*--- Compute eddy viscosity ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint ++) { + + if (compressible) { + rho = solver_container[FLOW_SOL]->node[iPoint]->GetDensity(); + mu = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); + } + if (incompressible || freesurface) { + rho = solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); + mu = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosityInc(); + } + + nu = mu/rho; + nu_hat = node[iPoint]->GetSolution(); + + Ji = nu_hat[0]/nu; + Ji_3 = Ji*Ji*Ji; + fv1 = Ji_3/(Ji_3+cv1_3); + + muT = rho*fv1*nu_hat[0]; + + if (neg_spalart_allmaras && (muT < 0.0)) muT = 0.0; + + node[iPoint]->SetmuT(muT); + + } + +} + +void CTurbSASolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, + CConfig *config, unsigned short iMesh) { + unsigned long iPoint; + su2double LevelSet; + unsigned short iVar; + + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool time_spectral = (config->GetUnsteady_Simulation() == TIME_SPECTRAL); + bool transition = (config->GetKind_Trans_Model() == LM); + su2double epsilon = config->GetFreeSurface_Thickness(); + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Conservative variables w/o reconstruction ---*/ + + numerics->SetPrimitive(solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(), NULL); + + /*--- Gradient of the primitive and conservative variables ---*/ + + numerics->SetPrimVarGradient(solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(), NULL); + + /*--- Set vorticity and strain rate magnitude ---*/ + + numerics->SetVorticity(solver_container[FLOW_SOL]->node[iPoint]->GetVorticity(), NULL); + + numerics->SetStrainMag(solver_container[FLOW_SOL]->node[iPoint]->GetStrainMag(), 0.0); + + /*--- Set intermittency ---*/ + + if (transition) { + numerics->SetIntermittency(solver_container[TRANS_SOL]->node[iPoint]->GetIntermittency()); + } + + /*--- Turbulent variables w/o reconstruction, and its gradient ---*/ + + numerics->SetTurbVar(node[iPoint]->GetSolution(), NULL); + numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), NULL); + + /*--- Set volume ---*/ + + numerics->SetVolume(geometry->node[iPoint]->GetVolume()); + + /*--- Set distance to the surface ---*/ + + numerics->SetDistance(geometry->node[iPoint]->GetWall_Distance(), 0.0); + + /*--- Compute the source term ---*/ + + numerics->ComputeResidual(Residual, Jacobian_i, NULL, config); + + /*--- Don't add source term in the interface or air ---*/ + + if (freesurface) { + LevelSet = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(nDim+1); + if (LevelSet > -epsilon) for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; + } + + /*--- Subtract residual and the Jacobian ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual); + + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + + if (time_spectral) { + + su2double Volume, Source; + unsigned short nVar_Turb = solver_container[TURB_SOL]->GetnVar(); + + /*--- Loop over points ---*/ + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Get control volume ---*/ + + Volume = geometry->node[iPoint]->GetVolume(); + + /*--- Access stored time spectral source term ---*/ + + for (unsigned short iVar = 0; iVar < nVar_Turb; iVar++) { + Source = node[iPoint]->GetTimeSpectral_Source(iVar); + Residual[iVar] = Source*Volume; + } + + /*--- Add Residual ---*/ + + LinSysRes.AddBlock(iPoint, Residual); + + } + } + +} + +void CTurbSASolver::Source_Template(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config, unsigned short iMesh) { + +} + +void CTurbSASolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + unsigned long iPoint, iVertex; + unsigned short iVar; + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Get the velocity vector ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = 0.0; + + node[iPoint]->SetSolution_Old(Solution); + LinSysRes.SetBlock_Zero(iPoint); + + /*--- includes 1 in the diagonal ---*/ + + Jacobian.DeleteValsRowi(iPoint); + } + } + +} + +void CTurbSASolver::BC_Isothermal_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, + unsigned short val_marker) { + unsigned long iPoint, iVertex; + unsigned short iVar; + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Get the velocity vector ---*/ + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = 0.0; + + node[iPoint]->SetSolution_Old(Solution); + LinSysRes.SetBlock_Zero(iPoint); + + /*--- Includes 1 in the diagonal ---*/ + + Jacobian.DeleteValsRowi(iPoint); + } + } + +} + +void CTurbSASolver::BC_Far_Field(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned long iPoint, iVertex; + unsigned short iVar, iDim; + su2double *Normal, *V_infty, *V_domain; + + bool grid_movement = config->GetGrid_Movement(); + + Normal = new su2double[nDim]; + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Allocate the value at the infinity ---*/ + + V_infty = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); + + /*--- Retrieve solution at the farfield boundary node ---*/ + + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + /*--- Grid Movement ---*/ + + if (grid_movement) + conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[iPoint]->GetGridVel()); + + conv_numerics->SetPrimitive(V_domain, V_infty); + + /*--- Set turbulent variable at the wall, and at infinity ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Solution_i[iVar] = node[iPoint]->GetSolution(iVar); + Solution_j[0] = nu_tilde_Inf; + conv_numerics->SetTurbVar(Solution_i, Solution_j); + + /*--- Set Normal (it is necessary to change the sign) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) + Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + /*--- Compute residuals and Jacobians ---*/ + + conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Add residuals and Jacobians ---*/ + + LinSysRes.AddBlock(iPoint, Residual); + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + } + } + + delete [] Normal; + +} + +void CTurbSASolver::BC_Inlet(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned short iDim; + unsigned long iVertex, iPoint, Point_Normal; + su2double *V_inlet, *V_domain, *Normal; + + Normal = new su2double[nDim]; + + bool grid_movement = config->GetGrid_Movement(); + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Index of the closest interior node ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + + /*--- Allocate the value at the inlet ---*/ + + V_inlet = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); + + /*--- Retrieve solution at the farfield boundary node ---*/ + + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + /*--- Set various quantities in the solver class ---*/ + + conv_numerics->SetPrimitive(V_domain, V_inlet); + + /*--- Set the turbulent variable states (prescribed for an inflow) ---*/ + + Solution_i[0] = node[iPoint]->GetSolution(0); + Solution_j[0] = nu_tilde_Inf; + + conv_numerics->SetTurbVar(Solution_i, Solution_j); + + /*--- Set various other quantities in the conv_numerics class ---*/ + + conv_numerics->SetNormal(Normal); + + if (grid_movement) + conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), + geometry->node[iPoint]->GetGridVel()); + + /*--- Compute the residual using an upwind scheme ---*/ + + conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + /*--- Viscous contribution ---*/ + + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + visc_numerics->SetNormal(Normal); + + /*--- Conservative variables w/o reconstruction ---*/ + + visc_numerics->SetPrimitive(V_domain, V_inlet); + + /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ + + visc_numerics->SetTurbVar(Solution_i, Solution_j); + visc_numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); + + /*--- Compute residual, and Jacobians ---*/ + + visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Subtract residual, and update Jacobians ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual); + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + } + + /*--- Free locally allocated memory ---*/ + delete[] Normal; + +} + +void CTurbSASolver::BC_Outlet(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, + CConfig *config, unsigned short val_marker) { + unsigned long iPoint, iVertex, Point_Normal; + unsigned short iVar, iDim; + su2double *V_outlet, *V_domain, *Normal; + + bool grid_movement = config->GetGrid_Movement(); + + Normal = new su2double[nDim]; + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Index of the closest interior node ---*/ + + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Allocate the value at the outlet ---*/ + + V_outlet = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); + + /*--- Retrieve solution at the farfield boundary node ---*/ + + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + /*--- Set various quantities in the solver class ---*/ + + conv_numerics->SetPrimitive(V_domain, V_outlet); + + /*--- Set the turbulent variables. Here we use a Neumann BC such + that the turbulent variable is copied from the interior of the + domain to the outlet before computing the residual. + Solution_i --> TurbVar_internal, + Solution_j --> TurbVar_outlet ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + Solution_i[iVar] = node[iPoint]->GetSolution(iVar); + Solution_j[iVar] = node[iPoint]->GetSolution(iVar); + } + conv_numerics->SetTurbVar(Solution_i, Solution_j); + + /*--- Set Normal (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) + Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + if (grid_movement) + conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), + geometry->node[iPoint]->GetGridVel()); + + /*--- Compute the residual using an upwind scheme ---*/ + + conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + /*--- Viscous contribution ---*/ + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + visc_numerics->SetNormal(Normal); + + /*--- Conservative variables w/o reconstruction ---*/ + + visc_numerics->SetPrimitive(V_domain, V_outlet); + + /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ + + visc_numerics->SetTurbVar(Solution_i, Solution_j); + visc_numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); + + /*--- Compute residual, and Jacobians ---*/ + + visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Subtract residual, and update Jacobians ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual); + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + } + + /*--- Free locally allocated memory ---*/ + + delete[] Normal; + +} + +void CTurbSASolver::BC_Engine_Inflow(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned long iPoint, iVertex; + unsigned short iDim; + su2double *V_inflow, *V_domain, *Normal; + + Normal = new su2double[nDim]; + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Allocate the value at the infinity ---*/ + + V_inflow = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); + + /*--- Retrieve solution at the farfield boundary node ---*/ + + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + /*--- Set various quantities in the solver class ---*/ + + conv_numerics->SetPrimitive(V_domain, V_inflow); + + /*--- Set the turbulent variables. Here we use a Neumann BC such + that the turbulent variable is copied from the interior of the + domain to the outlet before computing the residual. ---*/ + + conv_numerics->SetTurbVar(node[iPoint]->GetSolution(), node[iPoint]->GetSolution()); + + /*--- Set Normal (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) + Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + /*--- Compute the residual using an upwind scheme ---*/ + + conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + /*--- Viscous contribution ---*/ + + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[iPoint]->GetCoord()); + visc_numerics->SetNormal(Normal); + + /*--- Conservative variables w/o reconstruction ---*/ + + visc_numerics->SetPrimitive(V_domain, V_inflow); + + /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ + + visc_numerics->SetTurbVar(node[iPoint]->GetSolution(), node[iPoint]->GetSolution()); + visc_numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); + + /*--- Compute residual, and Jacobians ---*/ + + visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Subtract residual, and update Jacobians ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual); + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + } + + /*--- Free locally allocated memory ---*/ + + delete[] Normal; + +} + +void CTurbSASolver::BC_Engine_Exhaust(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned short iDim; + unsigned long iVertex, iPoint; + su2double *V_exhaust, *V_domain, *Normal; + + Normal = new su2double[nDim]; + + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + + /*--- Allocate the value at the infinity ---*/ + + V_exhaust = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); + + /*--- Retrieve solution at the farfield boundary node ---*/ + + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + /*--- Set various quantities in the solver class ---*/ + + conv_numerics->SetPrimitive(V_domain, V_exhaust); + + /*--- Set the turbulent variable states (prescribed for an inflow) ---*/ + + Solution_i[0] = node[iPoint]->GetSolution(0); + Solution_j[0] = nu_tilde_Engine; + + conv_numerics->SetTurbVar(Solution_i, Solution_j); + + /*--- Set various other quantities in the conv_numerics class ---*/ + + conv_numerics->SetNormal(Normal); + + /*--- Compute the residual using an upwind scheme ---*/ + + conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + /*--- Viscous contribution ---*/ + + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[iPoint]->GetCoord()); + visc_numerics->SetNormal(Normal); + + /*--- Conservative variables w/o reconstruction ---*/ + + visc_numerics->SetPrimitive(V_domain, V_exhaust); + + /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ + + visc_numerics->SetTurbVar(Solution_i, Solution_j); + visc_numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); + + /*--- Compute residual, and Jacobians ---*/ + + visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Subtract residual, and update Jacobians ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual); + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + } + + /*--- Free locally allocated memory ---*/ + + delete[] Normal; + +} + +void CTurbSASolver::BC_Engine_Bleed(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned short iDim; + unsigned long iVertex, iPoint; + su2double *V_bleed, *V_domain, *Normal; + + Normal = new su2double[nDim]; + + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + + /*--- Loop over all the vertices on this boundary marker ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + + /*--- Allocate the value at the infinity ---*/ + + V_bleed = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); + + /*--- Retrieve solution at the farfield boundary node ---*/ + + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + /*--- Set various quantities in the solver class ---*/ + + conv_numerics->SetPrimitive(V_domain, V_bleed); + + /*--- Set the turbulent variable states (prescribed for an inflow) ---*/ + + Solution_i[0] = node[iPoint]->GetSolution(0); + Solution_j[0] = nu_tilde_Engine; + + conv_numerics->SetTurbVar(Solution_i, Solution_j); + + /*--- Set various other quantities in the conv_numerics class ---*/ + + conv_numerics->SetNormal(Normal); + + /*--- Compute the residual using an upwind scheme ---*/ + + conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + /*--- Viscous contribution ---*/ + + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[iPoint]->GetCoord()); + visc_numerics->SetNormal(Normal); + + /*--- Conservative variables w/o reconstruction ---*/ + + visc_numerics->SetPrimitive(V_domain, V_bleed); + + /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ + + visc_numerics->SetTurbVar(Solution_i, Solution_j); + visc_numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); + + /*--- Compute residual, and Jacobians ---*/ + + visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Subtract residual, and update Jacobians ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual); + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + } + + /*--- Free locally allocated memory ---*/ + + delete[] Normal; + +} + +void CTurbSASolver::BC_Interface_Boundary(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config) { + // unsigned long iVertex, iPoint, jPoint; + // unsigned short iVar, iDim; + // + // su2double *Vector = new su2double[nDim]; + // + //#ifndef HAVE_MPI + // + // for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + // iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + // + // if (geometry->node[iPoint]->GetDomain()) { + // + // /*--- Find the associate pair to the original node ---*/ + // jPoint = geometry->vertex[val_marker][iVertex]->GetDonorPoint(); + // + // if (iPoint != jPoint) { + // + // /*--- Store the solution for both points ---*/ + // for (iVar = 0; iVar < nVar; iVar++) { + // Solution_i[iVar] = node[iPoint]->GetSolution(iVar); + // Solution_j[iVar] = node[jPoint]->GetSolution(iVar); + // } + // + // /*--- Set Conservative Variables ---*/ + // numerics->SetTurbVar(Solution_i, Solution_j); + // + // /*--- Retrieve flow solution for both points ---*/ + // for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { + // FlowPrimVar_i[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); + // FlowPrimVar_j[iVar] = solver_container[FLOW_SOL]->node[jPoint]->GetSolution(iVar); + // } + // + // /*--- Set Flow Variables ---*/ + // numerics->SetConservative(FlowPrimVar_i, FlowPrimVar_j); + // + // /*--- Set the normal vector ---*/ + // geometry->vertex[val_marker][iVertex]->GetNormal(Vector); + // for (iDim = 0; iDim < nDim; iDim++) + // Vector[iDim] = -Vector[iDim]; + // numerics->SetNormal(Vector); + // + // /*--- Add Residuals and Jacobians ---*/ + // numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + // LinSysRes.AddBlock(iPoint, Residual); + // Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + // + // } + // } + // } + // + //#else + // + // int rank = MPI::COMM_WORLD.Get_rank(), jProcessor; + // su2double *Conserv_Var, *Flow_Var; + // bool compute; + // + // unsigned short Buffer_Size = nVar+solver_container[FLOW_SOL]->GetnVar(); + // su2double *Buffer_Send_U = new su2double [Buffer_Size]; + // su2double *Buffer_Receive_U = new su2double [Buffer_Size]; + // + // /*--- Do the send process, by the moment we are sending each + // node individually, this must be changed ---*/ + // for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + // iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + // if (geometry->node[iPoint]->GetDomain()) { + // + // /*--- Find the associate pair to the original node ---*/ + // jPoint = geometry->vertex[val_marker][iVertex]->GetPeriodicPointDomain()[0]; + // jProcessor = geometry->vertex[val_marker][iVertex]->GetPeriodicPointDomain()[1]; + // + // if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; + // else compute = true; + // + // /*--- We only send the information that belong to other boundary ---*/ + // if ((jProcessor != rank) && compute) { + // + // Conserv_Var = node[iPoint]->GetSolution(); + // Flow_Var = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); + // + // for (iVar = 0; iVar < nVar; iVar++) + // Buffer_Send_U[iVar] = Conserv_Var[iVar]; + // + // for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) + // Buffer_Send_U[nVar+iVar] = Flow_Var[iVar]; + // + // MPI::COMM_WORLD.Bsend(Buffer_Send_U, Buffer_Size, MPI::DOUBLE, jProcessor, iPoint); + // + // } + // } + // } + // + // for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + // + // iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + // + // if (geometry->node[iPoint]->GetDomain()) { + // + // /*--- Find the associate pair to the original node ---*/ + // jPoint = geometry->vertex[val_marker][iVertex]->GetPeriodicPointDomain()[0]; + // jProcessor = geometry->vertex[val_marker][iVertex]->GetPeriodicPointDomain()[1]; + // + // if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; + // else compute = true; + // + // if (compute) { + // + // /*--- We only receive the information that belong to other boundary ---*/ + // if (jProcessor != rank) { + // MPI::COMM_WORLD.Recv(Buffer_Receive_U, Buffer_Size, MPI::DOUBLE, jProcessor, jPoint); + // } + // else { + // + // for (iVar = 0; iVar < nVar; iVar++) + // Buffer_Receive_U[iVar] = node[jPoint]->GetSolution(iVar); + // + // for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) + // Buffer_Send_U[nVar+iVar] = solver_container[FLOW_SOL]->node[jPoint]->GetSolution(iVar); + // + // } + // + // /*--- Store the solution for both points ---*/ + // for (iVar = 0; iVar < nVar; iVar++) { + // Solution_i[iVar] = node[iPoint]->GetSolution(iVar); + // Solution_j[iVar] = Buffer_Receive_U[iVar]; + // } + // + // /*--- Set Turbulent Variables ---*/ + // numerics->SetTurbVar(Solution_i, Solution_j); + // + // /*--- Retrieve flow solution for both points ---*/ + // for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { + // FlowPrimVar_i[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); + // FlowPrimVar_j[iVar] = Buffer_Receive_U[nVar + iVar]; + // } + // + // /*--- Set Flow Variables ---*/ + // numerics->SetConservative(FlowPrimVar_i, FlowPrimVar_j); + // + // geometry->vertex[val_marker][iVertex]->GetNormal(Vector); + // for (iDim = 0; iDim < nDim; iDim++) + // Vector[iDim] = -Vector[iDim]; + // numerics->SetNormal(Vector); + // + // numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + // LinSysRes.AddBlock(iPoint, Residual); + // Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + // + // } + // } + // } + // + // delete[] Buffer_Send_U; + // delete[] Buffer_Receive_U; + // + //#endif + // + // delete[] Vector; + // +} + +void CTurbSASolver::BC_NearField_Boundary(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config) { + // unsigned long iVertex, iPoint, jPoint; + // unsigned short iVar, iDim; + // + // su2double *Vector = new su2double[nDim]; + // + //#ifndef HAVE_MPI + // + // for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + // iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + // + // if (geometry->node[iPoint]->GetDomain()) { + // + // /*--- Find the associate pair to the original node ---*/ + // jPoint = geometry->vertex[val_marker][iVertex]->GetDonorPoint(); + // + // if (iPoint != jPoint) { + // + // /*--- Store the solution for both points ---*/ + // for (iVar = 0; iVar < nVar; iVar++) { + // Solution_i[iVar] = node[iPoint]->GetSolution(iVar); + // Solution_j[iVar] = node[jPoint]->GetSolution(iVar); + // } + // + // /*--- Set Conservative Variables ---*/ + // numerics->SetTurbVar(Solution_i, Solution_j); + // + // /*--- Retrieve flow solution for both points ---*/ + // for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { + // FlowPrimVar_i[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); + // FlowPrimVar_j[iVar] = solver_container[FLOW_SOL]->node[jPoint]->GetSolution(iVar); + // } + // + // /*--- Set Flow Variables ---*/ + // numerics->SetConservative(FlowPrimVar_i, FlowPrimVar_j); + // + // /*--- Set the normal vector ---*/ + // geometry->vertex[val_marker][iVertex]->GetNormal(Vector); + // for (iDim = 0; iDim < nDim; iDim++) + // Vector[iDim] = -Vector[iDim]; + // numerics->SetNormal(Vector); + // + // /*--- Add Residuals and Jacobians ---*/ + // numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + // LinSysRes.AddBlock(iPoint, Residual); + // Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + // + // } + // } + // } + // + //#else + // + // int rank = MPI::COMM_WORLD.Get_rank(), jProcessor; + // su2double *Conserv_Var, *Flow_Var; + // bool compute; + // + // unsigned short Buffer_Size = nVar+solver_container[FLOW_SOL]->GetnVar(); + // su2double *Buffer_Send_U = new su2double [Buffer_Size]; + // su2double *Buffer_Receive_U = new su2double [Buffer_Size]; + // + // /*--- Do the send process, by the moment we are sending each + // node individually, this must be changed ---*/ + // for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + // iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + // if (geometry->node[iPoint]->GetDomain()) { + // + // /*--- Find the associate pair to the original node ---*/ + // jPoint = geometry->vertex[val_marker][iVertex]->GetPeriodicPointDomain()[0]; + // jProcessor = geometry->vertex[val_marker][iVertex]->GetPeriodicPointDomain()[1]; + // + // if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; + // else compute = true; + // + // /*--- We only send the information that belong to other boundary ---*/ + // if ((jProcessor != rank) && compute) { + // + // Conserv_Var = node[iPoint]->GetSolution(); + // Flow_Var = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(); + // + // for (iVar = 0; iVar < nVar; iVar++) + // Buffer_Send_U[iVar] = Conserv_Var[iVar]; + // + // for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) + // Buffer_Send_U[nVar+iVar] = Flow_Var[iVar]; + // + // MPI::COMM_WORLD.Bsend(Buffer_Send_U, Buffer_Size, MPI::DOUBLE, jProcessor, iPoint); + // + // } + // } + // } + // + // for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + // + // iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + // + // if (geometry->node[iPoint]->GetDomain()) { + // + // /*--- Find the associate pair to the original node ---*/ + // jPoint = geometry->vertex[val_marker][iVertex]->GetPeriodicPointDomain()[0]; + // jProcessor = geometry->vertex[val_marker][iVertex]->GetPeriodicPointDomain()[1]; + // + // if ((iPoint == jPoint) && (jProcessor == rank)) compute = false; + // else compute = true; + // + // if (compute) { + // + // /*--- We only receive the information that belong to other boundary ---*/ + // if (jProcessor != rank) { + // MPI::COMM_WORLD.Recv(Buffer_Receive_U, Buffer_Size, MPI::DOUBLE, jProcessor, jPoint); + // } + // else { + // + // for (iVar = 0; iVar < nVar; iVar++) + // Buffer_Receive_U[iVar] = node[jPoint]->GetSolution(iVar); + // + // for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) + // Buffer_Send_U[nVar+iVar] = solver_container[FLOW_SOL]->node[jPoint]->GetSolution(iVar); + // + // } + // + // /*--- Store the solution for both points ---*/ + // for (iVar = 0; iVar < nVar; iVar++) { + // Solution_i[iVar] = node[iPoint]->GetSolution(iVar); + // Solution_j[iVar] = Buffer_Receive_U[iVar]; + // } + // + // /*--- Set Turbulent Variables ---*/ + // numerics->SetTurbVar(Solution_i, Solution_j); + // + // /*--- Retrieve flow solution for both points ---*/ + // for (iVar = 0; iVar < solver_container[FLOW_SOL]->GetnVar(); iVar++) { + // FlowPrimVar_i[iVar] = solver_container[FLOW_SOL]->node[iPoint]->GetSolution(iVar); + // FlowPrimVar_j[iVar] = Buffer_Receive_U[nVar + iVar]; + // } + // + // /*--- Set Flow Variables ---*/ + // numerics->SetConservative(FlowPrimVar_i, FlowPrimVar_j); + // + // geometry->vertex[val_marker][iVertex]->GetNormal(Vector); + // for (iDim = 0; iDim < nDim; iDim++) + // Vector[iDim] = -Vector[iDim]; + // numerics->SetNormal(Vector); + // + // numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + // LinSysRes.AddBlock(iPoint, Residual); + // Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + // + // } + // } + // } + // + // delete[] Buffer_Send_U; + // delete[] Buffer_Receive_U; + // + //#endif + // + // delete[] Vector; + // +} + +void CTurbSASolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig *config, int val_iter) { + + /*--- Restart the solution from file information ---*/ + unsigned short iVar, iMesh; + unsigned long iPoint, index, iChildren, Point_Fine; + su2double dull_val, Area_Children, Area_Parent, *Solution_Fine; + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + string UnstExt, text_line; + ifstream restart_file; + string restart_filename = config->GetSolution_FlowFileName(); + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Modify file name for an unsteady restart ---*/ + if (dual_time) + restart_filename = config->GetUnsteady_FileName(restart_filename, val_iter); + + /*--- Open the restart file, throw an error if this fails. ---*/ + restart_file.open(restart_filename.data(), ios::in); + if (restart_file.fail()) { + if (rank == MASTER_NODE) + cout << "There is no flow restart file!! " << restart_filename.data() << "."<< endl; + exit(EXIT_FAILURE); + } + + /*--- In case this is a parallel simulation, we need to perform the + Global2Local index transformation first. ---*/ + long *Global2Local = NULL; + Global2Local = new long[geometry[MESH_0]->GetGlobal_nPointDomain()]; + /*--- First, set all indices to a negative value by default ---*/ + for (iPoint = 0; iPoint < geometry[MESH_0]->GetGlobal_nPointDomain(); iPoint++) { + Global2Local[iPoint] = -1; + } + + /*--- Now fill array with the transform values only for local points ---*/ + for (iPoint = 0; iPoint < geometry[MESH_0]->GetnPointDomain(); iPoint++) { + Global2Local[geometry[MESH_0]->node[iPoint]->GetGlobalIndex()] = iPoint; + } + + /*--- Read all lines in the restart file ---*/ + long iPoint_Local = 0; unsigned long iPoint_Global = 0; + + /*--- The first line is the header ---*/ + getline (restart_file, text_line); + + while (getline (restart_file, text_line)) { + istringstream point_line(text_line); + + /*--- Retrieve local index. If this node from the restart file lives + on a different processor, the value of iPoint_Local will be -1, as + initialized above. Otherwise, the local index for this node on the + current processor will be returned and used to instantiate the vars. ---*/ + iPoint_Local = Global2Local[iPoint_Global]; + if (iPoint_Local >= 0) { + + if (compressible) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; + } + if (incompressible) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; + } + if (freesurface) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0]; + } + + + node[iPoint_Local]->SetSolution(Solution); + + } + iPoint_Global++; + } + + /*--- Close the restart file ---*/ + restart_file.close(); + + /*--- Free memory needed for the transformation ---*/ + delete [] Global2Local; + + /*--- MPI solution and compute the eddy viscosity ---*/ + solver[MESH_0][TURB_SOL]->Set_MPI_Solution(geometry[MESH_0], config); + solver[MESH_0][TURB_SOL]->Postprocessing(geometry[MESH_0], solver[MESH_0], config, MESH_0); + + /*--- Interpolate the solution down to the coarse multigrid levels ---*/ + for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++) { + for (iPoint = 0; iPoint < geometry[iMesh]->GetnPoint(); iPoint++) { + Area_Parent = geometry[iMesh]->node[iPoint]->GetVolume(); + for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = 0.0; + for (iChildren = 0; iChildren < geometry[iMesh]->node[iPoint]->GetnChildren_CV(); iChildren++) { + Point_Fine = geometry[iMesh]->node[iPoint]->GetChildren_CV(iChildren); + Area_Children = geometry[iMesh-1]->node[Point_Fine]->GetVolume(); + Solution_Fine = solver[iMesh-1][TURB_SOL]->node[Point_Fine]->GetSolution(); + for (iVar = 0; iVar < nVar; iVar++) { + Solution[iVar] += Solution_Fine[iVar]*Area_Children/Area_Parent; + } + } + solver[iMesh][TURB_SOL]->node[iPoint]->SetSolution(Solution); + } + solver[iMesh][TURB_SOL]->Set_MPI_Solution(geometry[iMesh], config); + solver[iMesh][TURB_SOL]->Postprocessing(geometry[iMesh], solver[iMesh], config, iMesh); + } + +} + +CTurbSSTSolver::CTurbSSTSolver(void) : CTurbSolver() { + + /*--- Array initialization ---*/ + constants = NULL; + +} + +CTurbSSTSolver::CTurbSSTSolver(CGeometry *geometry, CConfig *config, unsigned short iMesh) : CTurbSolver() { + unsigned short iVar, iDim, nLineLets; + unsigned long iPoint, index; + su2double dull_val; + ifstream restart_file; + string text_line; + + unsigned short iZone = config->GetiZone(); + unsigned short nZone = geometry->GetnZone(); + bool restart = (config->GetRestart() || config->GetRestart_Flow()); + bool adjoint = config->GetAdjoint(); + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Array initialization ---*/ + + constants = NULL; + + Gamma = config->GetGamma(); + Gamma_Minus_One = Gamma - 1.0; + + /*--- Dimension of the problem --> dependent of the turbulent model ---*/ + + nVar = 2; + nPoint = geometry->GetnPoint(); + nPointDomain = geometry->GetnPointDomain(); + + /*--- Define geometry constants in the solver structure ---*/ + + nDim = geometry->GetnDim(); + node = new CVariable*[nPoint]; + + /*--- Single grid simulation ---*/ + + if (iMesh == MESH_0) { + + /*--- Define some auxiliary vector related with the residual ---*/ + + Residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual[iVar] = 0.0; + Residual_RMS = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_RMS[iVar] = 0.0; + Residual_i = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_i[iVar] = 0.0; + Residual_j = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_j[iVar] = 0.0; + Residual_Max = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) Residual_Max[iVar] = 0.0; + + /*--- Define some structures for locating max residuals ---*/ + + Point_Max = new unsigned long[nVar]; + for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; + Point_Max_Coord = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Point_Max_Coord[iVar] = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; + } + + /*--- Define some auxiliary vector related with the solution ---*/ + + Solution = new su2double[nVar]; + Solution_i = new su2double[nVar]; Solution_j = new su2double[nVar]; + + /*--- Define some auxiliary vector related with the geometry ---*/ + + Vector_i = new su2double[nDim]; Vector_j = new su2double[nDim]; + + /*--- Define some auxiliary vector related with the flow solution ---*/ + + FlowPrimVar_i = new su2double [nDim+7]; FlowPrimVar_j = new su2double [nDim+7]; + + /*--- Jacobians and vector structures for implicit computations ---*/ + + Jacobian_i = new su2double* [nVar]; + Jacobian_j = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Jacobian_i[iVar] = new su2double [nVar]; + Jacobian_j[iVar] = new su2double [nVar]; + } + + /*--- Initialization of the structure of the whole Jacobian ---*/ + + if (rank == MASTER_NODE) cout << "Initialize Jacobian structure (SST model)." << endl; + Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); + + if ((config->GetKind_Linear_Solver_Prec() == LINELET) || + (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { + nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); + if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; + } + + LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); + LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); + } + + /*--- Computation of gradients by least squares ---*/ + + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { + /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ + Smatrix = new su2double* [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Smatrix[iDim] = new su2double [nDim]; + /*--- c vector := transpose(WA)*(Wb) ---*/ + cvector = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + cvector[iVar] = new su2double [nDim]; + } + + /*--- Initialize value for model constants ---*/ + constants = new su2double[10]; + constants[0] = 0.85; //sigma_k1 + constants[1] = 1.0; //sigma_k2 + constants[2] = 0.5; //sigma_om1 + constants[3] = 0.856; //sigma_om2 + constants[4] = 0.075; //beta_1 + constants[5] = 0.0828; //beta_2 + constants[6] = 0.09; //betaStar + constants[7] = 0.31; //a1 + constants[8] = constants[4]/constants[6] - constants[2]*0.41*0.41/sqrt(constants[6]); //alfa_1 + constants[9] = constants[5]/constants[6] - constants[3]*0.41*0.41/sqrt(constants[6]); //alfa_2 + + /*--- Initialize lower and upper limits---*/ + lowerlimit = new su2double[nVar]; + upperlimit = new su2double[nVar]; + + lowerlimit[0] = 1.0e-10; + upperlimit[0] = 1.0e10; + + lowerlimit[1] = 1.0e-4; + upperlimit[1] = 1.0e15; + + /*--- Flow infinity initialization stuff ---*/ + su2double rhoInf, *VelInf, muLamInf, Intensity, viscRatio, muT_Inf; + + rhoInf = config->GetDensity_FreeStreamND(); + VelInf = config->GetVelocity_FreeStreamND(); + muLamInf = config->GetViscosity_FreeStreamND(); + Intensity = config->GetTurbulenceIntensity_FreeStream(); + viscRatio = config->GetTurb2LamViscRatio_FreeStream(); + + su2double VelMag = 0; + for (iDim = 0; iDim < nDim; iDim++) + VelMag += VelInf[iDim]*VelInf[iDim]; + VelMag = sqrt(VelMag); + + kine_Inf = 3.0/2.0*(VelMag*VelMag*Intensity*Intensity); + omega_Inf = rhoInf*kine_Inf/(muLamInf*viscRatio); + + /*--- Eddy viscosity, initialized without stress limiter at the infinity ---*/ + muT_Inf = rhoInf*kine_Inf/omega_Inf; + + /*--- Restart the solution from file information ---*/ + if (!restart || (iMesh != MESH_0)) { + for (iPoint = 0; iPoint < nPoint; iPoint++) + node[iPoint] = new CTurbSSTVariable(kine_Inf, omega_Inf, muT_Inf, nDim, nVar, constants, config); + } + else { + + /*--- Restart the solution from file information ---*/ + ifstream restart_file; + string filename = config->GetSolution_FlowFileName(); + + /*--- Modify file name for an unsteady restart ---*/ + if (dual_time) { + int Unst_RestartIter; + if (adjoint) { + Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_AdjointIter()) - 1; + } else if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_RestartIter())-1; + else + Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_RestartIter())-2; + filename = config->GetUnsteady_FileName(filename, Unst_RestartIter); + } + if (nZone >1) + filename= config->GetRestart_FlowFileName(filename, iZone); + + + /*--- Open the restart file, throw an error if this fails. ---*/ + restart_file.open(filename.data(), ios::in); + if (restart_file.fail()) { + cout << "There is no turbulent restart file!!" << endl; + exit(EXIT_FAILURE); + } + + /*--- In case this is a parallel simulation, we need to perform the + Global2Local index transformation first. ---*/ + long *Global2Local; + Global2Local = new long[geometry->GetGlobal_nPointDomain()]; + /*--- First, set all indices to a negative value by default ---*/ + for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) { + Global2Local[iPoint] = -1; + } + /*--- Now fill array with the transform values only for local points ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; + } + + /*--- Read all lines in the restart file ---*/ + long iPoint_Local; unsigned long iPoint_Global = 0; string text_line; + + /*--- The first line is the header ---*/ + getline (restart_file, text_line); + + + while (getline (restart_file, text_line)) { + istringstream point_line(text_line); + + /*--- Retrieve local index. If this node from the restart file lives + on a different processor, the value of iPoint_Local will be -1. + Otherwise, the local index for this node on the current processor + will be returned and used to instantiate the vars. ---*/ + iPoint_Local = Global2Local[iPoint_Global]; + if (iPoint_Local >= 0) { + + if (compressible) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1]; + } + if (incompressible) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1]; + } + if (freesurface) { + if (nDim == 2) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1]; + if (nDim == 3) point_line >> index >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> dull_val >> Solution[0] >> Solution[1]; + } + + /*--- Instantiate the solution at this node, note that the muT_Inf should recomputed ---*/ + node[iPoint_Local] = new CTurbSSTVariable(Solution[0], Solution[1], muT_Inf, nDim, nVar, constants, config); + } + iPoint_Global++; + } + + /*--- Instantiate the variable class with an arbitrary solution + at any halo/periodic nodes. The initial solution can be arbitrary, + because a send/recv is performed immediately in the solver. ---*/ + for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { + node[iPoint] = new CTurbSSTVariable(Solution[0], Solution[1], muT_Inf, nDim, nVar, constants, config); + } + + /*--- Close the restart file ---*/ + restart_file.close(); + + /*--- Free memory needed for the transformation ---*/ + delete [] Global2Local; + } + + /*--- MPI solution ---*/ + Set_MPI_Solution(geometry, config); + +} + +CTurbSSTSolver::~CTurbSSTSolver(void) { + + if (constants != NULL) delete [] constants; + +} + +void CTurbSSTSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { + + unsigned long iPoint; + + unsigned long ExtIter = config->GetExtIter(); + bool limiter_flow = ((config->GetSpatialOrder_Flow() == SECOND_ORDER_LIMITER) && (ExtIter <= config->GetLimiterIter())); + + for (iPoint = 0; iPoint < nPoint; iPoint ++) { + + /*--- Initialize the residual vector ---*/ + + LinSysRes.SetBlock_Zero(iPoint); + + } + + /*--- Initialize the Jacobian matrices ---*/ + + Jacobian.SetValZero(); + + /*--- Upwind second order reconstruction ---*/ + + if (config->GetKind_Gradient_Method() == GREEN_GAUSS) SetSolution_Gradient_GG(geometry, config); + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) SetSolution_Gradient_LS(geometry, config); + + if (config->GetSpatialOrder() == SECOND_ORDER_LIMITER) SetSolution_Limiter(geometry, config); + + if (limiter_flow) solver_container[FLOW_SOL]->SetPrimitive_Limiter(geometry, config); + +} + +void CTurbSSTSolver::Postprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh) { + su2double rho = 0.0, mu = 0.0, dist, omega, kine, strMag, F2, muT, zeta; + su2double a1 = constants[7]; + unsigned long iPoint; + + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + + /*--- Compute mean flow and turbulence gradients ---*/ + + if (config->GetKind_Gradient_Method() == GREEN_GAUSS) { +// solver_container[FLOW_SOL]->SetPrimitive_Gradient_GG(geometry, config); + SetSolution_Gradient_GG(geometry, config); + } + if (config->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) { +// solver_container[FLOW_SOL]->SetPrimitive_Gradient_LS(geometry, config); + SetSolution_Gradient_LS(geometry, config); + } + + for (iPoint = 0; iPoint < nPoint; iPoint ++) { + + /*--- Compute blending functions and cross diffusion ---*/ + + if (compressible) { + rho = solver_container[FLOW_SOL]->node[iPoint]->GetDensity(); + mu = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosity(); + } + if (incompressible || freesurface) { + rho = solver_container[FLOW_SOL]->node[iPoint]->GetDensityInc(); + mu = solver_container[FLOW_SOL]->node[iPoint]->GetLaminarViscosityInc(); + } + + dist = geometry->node[iPoint]->GetWall_Distance(); + + strMag = solver_container[FLOW_SOL]->node[iPoint]->GetStrainMag(); + + node[iPoint]->SetBlendingFunc(mu, dist, rho); + + F2 = node[iPoint]->GetF2blending(); + + /*--- Compute the eddy viscosity ---*/ + + kine = node[iPoint]->GetSolution(0); + omega = node[iPoint]->GetSolution(1); + zeta = min(1.0/omega, a1/(strMag*F2)); + muT = min(max(rho*kine*zeta,0.0),1.0); + node[iPoint]->SetmuT(muT); + + } + +} + +void CTurbSSTSolver::Source_Residual(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CNumerics *second_numerics, CConfig *config, unsigned short iMesh) { + + unsigned long iPoint; + + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + + /*--- Conservative variables w/o reconstruction ---*/ + + numerics->SetPrimitive(solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(), NULL); + + /*--- Gradient of the primitive and conservative variables ---*/ + + numerics->SetPrimVarGradient(solver_container[FLOW_SOL]->node[iPoint]->GetGradient_Primitive(), NULL); + + /*--- Turbulent variables w/o reconstruction, and its gradient ---*/ + + numerics->SetTurbVar(node[iPoint]->GetSolution(), NULL); + numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), NULL); + + /*--- Set volume ---*/ + + numerics->SetVolume(geometry->node[iPoint]->GetVolume()); + + /*--- Set distance to the surface ---*/ + + numerics->SetDistance(geometry->node[iPoint]->GetWall_Distance(), 0.0); + + /*--- Menter's first blending function ---*/ + + numerics->SetF1blending(node[iPoint]->GetF1blending(),0.0); + + /*--- Menter's second blending function ---*/ + + numerics->SetF2blending(node[iPoint]->GetF2blending(),0.0); + + /*--- Set vorticity and strain rate magnitude ---*/ + + numerics->SetVorticity(solver_container[FLOW_SOL]->node[iPoint]->GetVorticity(), NULL); + + numerics->SetStrainMag(solver_container[FLOW_SOL]->node[iPoint]->GetStrainMag(), 0.0); + + /*--- Cross diffusion ---*/ + + numerics->SetCrossDiff(node[iPoint]->GetCrossDiff(),0.0); + + /*--- Compute the source term ---*/ + + numerics->ComputeResidual(Residual, Jacobian_i, NULL, config); + + /*--- Subtract residual and the Jacobian ---*/ + + LinSysRes.SubtractBlock(iPoint, Residual); + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + +} + +void CTurbSSTSolver::Source_Template(CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, + CConfig *config, unsigned short iMesh) { + +} + +void CTurbSSTSolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned long iPoint, jPoint, iVertex, total_index; + unsigned short iDim, iVar; + su2double distance, density = 0.0, laminar_viscosity = 0.0, beta_1; + + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ + if (geometry->node[iPoint]->GetDomain()) { + + /*--- distance to closest neighbor ---*/ + jPoint = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + distance = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + distance += (geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim))* + (geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim)); + } + distance = sqrt(distance); + + /*--- Set wall values ---*/ + if (compressible) { + density = solver_container[FLOW_SOL]->node[jPoint]->GetDensity(); + laminar_viscosity = solver_container[FLOW_SOL]->node[jPoint]->GetLaminarViscosity(); + } + if (incompressible || freesurface) { + density = solver_container[FLOW_SOL]->node[jPoint]->GetDensityInc(); + laminar_viscosity = solver_container[FLOW_SOL]->node[jPoint]->GetLaminarViscosityInc(); + } + + beta_1 = constants[4]; + + Solution[0] = 0.0; + Solution[1] = 60.0*laminar_viscosity/(density*beta_1*distance*distance); + + /*--- Set the solution values and zero the residual ---*/ + node[iPoint]->SetSolution_Old(Solution); + node[iPoint]->SetSolution(Solution); + LinSysRes.SetBlock_Zero(iPoint); + + /*--- Change rows of the Jacobian (includes 1 in the diagonal) ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + Jacobian.DeleteValsRowi(total_index); + } + + } + } + +} + +void CTurbSSTSolver::BC_Isothermal_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, + unsigned short val_marker) { + + unsigned long iPoint, jPoint, iVertex, total_index; + unsigned short iDim, iVar; + su2double distance, density = 0.0, laminar_viscosity = 0.0, beta_1; + + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ + if (geometry->node[iPoint]->GetDomain()) { + + /*--- distance to closest neighbor ---*/ + jPoint = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + distance = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + distance += (geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim))* + (geometry->node[iPoint]->GetCoord(iDim) - geometry->node[jPoint]->GetCoord(iDim)); + } + distance = sqrt(distance); + + /*--- Set wall values ---*/ + if (compressible) { + density = solver_container[FLOW_SOL]->node[jPoint]->GetDensity(); + laminar_viscosity = solver_container[FLOW_SOL]->node[jPoint]->GetLaminarViscosity(); + } + if (incompressible || freesurface) { + density = solver_container[FLOW_SOL]->node[jPoint]->GetDensityInc(); + laminar_viscosity = solver_container[FLOW_SOL]->node[jPoint]->GetLaminarViscosityInc(); + } + + beta_1 = constants[4]; + + Solution[0] = 0.0; + Solution[1] = 60.0*laminar_viscosity/(density*beta_1*distance*distance); + + /*--- Set the solution values and zero the residual ---*/ + node[iPoint]->SetSolution_Old(Solution); + node[iPoint]->SetSolution(Solution); + LinSysRes.SetBlock_Zero(iPoint); + + /*--- Change rows of the Jacobian (includes 1 in the diagonal) ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + Jacobian.DeleteValsRowi(total_index); + } + + } + } + +} + +void CTurbSSTSolver::BC_Far_Field(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned long iPoint, iVertex; + su2double *Normal, *V_infty, *V_domain; + unsigned short iVar, iDim; + + bool grid_movement = config->GetGrid_Movement(); + + Normal = new su2double[nDim]; + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Allocate the value at the infinity ---*/ + + V_infty = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); + + /*--- Retrieve solution at the farfield boundary node ---*/ + + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + conv_numerics->SetPrimitive(V_domain, V_infty); + + /*--- Set turbulent variable at the wall, and at infinity ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Solution_i[iVar] = node[iPoint]->GetSolution(iVar); + + Solution_j[0] = kine_Inf; + Solution_j[1] = omega_Inf; + + conv_numerics->SetTurbVar(Solution_i, Solution_j); + + /*--- Set Normal (it is necessary to change the sign) ---*/ + + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) + Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + /*--- Grid Movement ---*/ + + if (grid_movement) + conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), geometry->node[iPoint]->GetGridVel()); + + /*--- Compute residuals and Jacobians ---*/ + + conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Add residuals and Jacobians ---*/ + + LinSysRes.AddBlock(iPoint, Residual); + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + } + } + + delete [] Normal; + +} + +void CTurbSSTSolver::BC_Inlet(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, + unsigned short val_marker) { + + unsigned short iVar, iDim; + unsigned long iVertex, iPoint, Point_Normal; + su2double *V_inlet, *V_domain, *Normal; + + Normal = new su2double[nDim]; + + bool grid_movement = config->GetGrid_Movement(); + + string Marker_Tag = config->GetMarker_All_TagBound(val_marker); + + /*--- Loop over all the vertices on this boundary marker ---*/ + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Index of the closest interior node ---*/ + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Normal vector for this vertex (negate for outward convention) ---*/ + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + + /*--- Allocate the value at the inlet ---*/ + V_inlet = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); + + /*--- Retrieve solution at the farfield boundary node ---*/ + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + /*--- Set various quantities in the solver class ---*/ + conv_numerics->SetPrimitive(V_domain, V_inlet); + + /*--- Set the turbulent variable states. Use free-stream SST + values for the turbulent state at the inflow. ---*/ + for (iVar = 0; iVar < nVar; iVar++) + Solution_i[iVar] = node[iPoint]->GetSolution(iVar); + + Solution_j[0]= kine_Inf; + Solution_j[1]= omega_Inf; + + conv_numerics->SetTurbVar(Solution_i, Solution_j); + + /*--- Set various other quantities in the solver class ---*/ + conv_numerics->SetNormal(Normal); + + if (grid_movement) + conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), + geometry->node[iPoint]->GetGridVel()); + + /*--- Compute the residual using an upwind scheme ---*/ + conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + /*--- Viscous contribution ---*/ + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + visc_numerics->SetNormal(Normal); + + /*--- Conservative variables w/o reconstruction ---*/ + visc_numerics->SetPrimitive(V_domain, V_inlet); + + /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ + visc_numerics->SetTurbVar(Solution_i, Solution_j); + visc_numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); + + /*--- Menter's first blending function ---*/ + visc_numerics->SetF1blending(node[iPoint]->GetF1blending(), node[iPoint]->GetF1blending()); + + /*--- Compute residual, and Jacobians ---*/ + visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Subtract residual, and update Jacobians ---*/ + LinSysRes.SubtractBlock(iPoint, Residual); + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + } + + /*--- Free locally allocated memory ---*/ + delete[] Normal; + +} + +void CTurbSSTSolver::BC_Outlet(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { + + unsigned long iPoint, iVertex, Point_Normal; + unsigned short iVar, iDim; + su2double *V_outlet, *V_domain, *Normal; + + bool grid_movement = config->GetGrid_Movement(); + + Normal = new su2double[nDim]; + + /*--- Loop over all the vertices on this boundary marker ---*/ + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + /*--- Check if the node belongs to the domain (i.e., not a halo node) ---*/ + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Index of the closest interior node ---*/ + Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + /*--- Allocate the value at the outlet ---*/ + V_outlet = solver_container[FLOW_SOL]->GetCharacPrimVar(val_marker, iVertex); + + /*--- Retrieve solution at the farfield boundary node ---*/ + V_domain = solver_container[FLOW_SOL]->node[iPoint]->GetPrimitive(); + + /*--- Set various quantities in the solver class ---*/ + conv_numerics->SetPrimitive(V_domain, V_outlet); + + /*--- Set the turbulent variables. Here we use a Neumann BC such + that the turbulent variable is copied from the interior of the + domain to the outlet before computing the residual. + Solution_i --> TurbVar_internal, + Solution_j --> TurbVar_outlet ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + Solution_i[iVar] = node[iPoint]->GetSolution(iVar); + Solution_j[iVar] = node[iPoint]->GetSolution(iVar); + } + conv_numerics->SetTurbVar(Solution_i, Solution_j); + + /*--- Set Normal (negate for outward convention) ---*/ + geometry->vertex[val_marker][iVertex]->GetNormal(Normal); + for (iDim = 0; iDim < nDim; iDim++) + Normal[iDim] = -Normal[iDim]; + conv_numerics->SetNormal(Normal); + + if (grid_movement) + conv_numerics->SetGridVel(geometry->node[iPoint]->GetGridVel(), + geometry->node[iPoint]->GetGridVel()); + + /*--- Compute the residual using an upwind scheme ---*/ + conv_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + LinSysRes.AddBlock(iPoint, Residual); + + /*--- Jacobian contribution for implicit integration ---*/ + Jacobian.AddBlock(iPoint, iPoint, Jacobian_i); + + /*--- Viscous contribution ---*/ + visc_numerics->SetCoord(geometry->node[iPoint]->GetCoord(), geometry->node[Point_Normal]->GetCoord()); + visc_numerics->SetNormal(Normal); + + /*--- Conservative variables w/o reconstruction ---*/ + visc_numerics->SetPrimitive(V_domain, V_outlet); + + /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ + visc_numerics->SetTurbVar(Solution_i, Solution_j); + visc_numerics->SetTurbVarGradient(node[iPoint]->GetGradient(), node[iPoint]->GetGradient()); + + /*--- Menter's first blending function ---*/ + visc_numerics->SetF1blending(node[iPoint]->GetF1blending(), node[iPoint]->GetF1blending()); + + /*--- Compute residual, and Jacobians ---*/ + visc_numerics->ComputeResidual(Residual, Jacobian_i, Jacobian_j, config); + + /*--- Subtract residual, and update Jacobians ---*/ + LinSysRes.SubtractBlock(iPoint, Residual); + Jacobian.SubtractBlock(iPoint, iPoint, Jacobian_i); + + } + } + + /*--- Free locally allocated memory ---*/ + delete[] Normal; + +} + +su2double* CTurbSSTSolver::GetConstants() { + return constants; +} diff --git a/SU2_CFD/src/solver_direct_wave.cpp b/SU2_CFD/src/solver_direct_wave.cpp index 9c4f874a1c8..54e29735c67 100644 --- a/SU2_CFD/src/solver_direct_wave.cpp +++ b/SU2_CFD/src/solver_direct_wave.cpp @@ -1,779 +1,779 @@ -/*! - * \file solution_direct_wave.cpp - * \brief Main subrotuines for solving the wave equation. - * \author T. Economon, F. Palacios - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/solver_structure.hpp" - -CWaveSolver::CWaveSolver(void) : CSolver() { } - -CWaveSolver::CWaveSolver(CGeometry *geometry, - CConfig *config) : CSolver() { - unsigned short iDim, iVar, nLineLets; - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - nPoint = geometry->GetnPoint(); - nPointDomain = geometry->GetnPointDomain(); - nDim = geometry->GetnDim(); - node = new CVariable*[nPoint]; - nVar = 2; // solve as a 2 eq. system - - Residual = new su2double[nVar]; Residual_RMS = new su2double[nVar]; - Solution = new su2double[nVar]; - Res_Sour = new su2double[nVar]; - Residual_Max = new su2double[nVar]; - - /*--- Define some structures for locating max residuals ---*/ - Point_Max = new unsigned long[nVar]; - for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; - Point_Max_Coord = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Point_Max_Coord[iVar] = new su2double[nDim]; - for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; - } - - /*--- Point to point stiffness matrix (only for triangles)---*/ - StiffMatrix_Elem = new su2double*[nDim+1]; - for (iVar = 0; iVar < nDim+1; iVar++) { - StiffMatrix_Elem[iVar] = new su2double [nDim+1]; - } - - StiffMatrix_Node = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - StiffMatrix_Node[iVar] = new su2double [nVar]; - } - - /*--- Initialization of matrix structures ---*/ - StiffMatrixSpace.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); - StiffMatrixTime.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); - Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); - - if ((config->GetKind_Linear_Solver_Prec() == LINELET) || - (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { - nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); - if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; - } - - /*--- Initialization of linear solver structures ---*/ - LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); - - /* Wave strength coefficient for all of the markers */ - - CWave = new su2double[config->GetnMarker_All()]; - Total_CWave = 0.0; - - /* Check for a restart (not really used), initialize from zero otherwise */ - - bool restart = (config->GetRestart()); - if (!restart) { - - for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { - - /*--- Zero initial condition for testing source terms & forcing BCs ---*/ - Solution[0] = 0.0; - Solution[1] = 0.0; - - node[iPoint] = new CWaveVariable(Solution, nDim, nVar, config); - - /* Copy solution to old containers if using dual time */ - - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) { - node[iPoint]->Set_Solution_time_n(); - } else if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) { - node[iPoint]->Set_Solution_time_n(); - node[iPoint]->Set_Solution_time_n1(); - } - - } - } else { - - cout << "Wave restart file not currently configured!!" << endl; - - string mesh_filename = config->GetSolution_FlowFileName(); - ifstream restart_file; - - char *cstr; cstr = new char [mesh_filename.size()+1]; - strcpy (cstr, mesh_filename.c_str()); - restart_file.open(cstr, ios::in); - - if (restart_file.fail()) { - if (rank == MASTER_NODE) - cout << "There is no wave restart file!!" << endl; - exit(EXIT_FAILURE); - } - unsigned long index; - string text_line; - - for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { - getline(restart_file, text_line); - istringstream point_line(text_line); - point_line >> index >> Solution[0] >> Solution[1]; - node[iPoint] = new CWaveVariable(Solution, nDim, nVar, config); - } - restart_file.close(); - } - -} - -CWaveSolver::~CWaveSolver(void) { - - unsigned short iVar; - - delete [] Residual; - delete [] Residual_Max; - delete [] Solution; - - for (iVar = 0; iVar < nDim+1; iVar++) - delete [] StiffMatrix_Elem[iVar]; - - - for (iVar = 0; iVar < nVar; iVar++) - delete [] StiffMatrix_Node[iVar]; - - delete [] StiffMatrix_Elem; - delete [] StiffMatrix_Node; - -} - -void CWaveSolver::Preprocessing(CGeometry *geometry, - CSolver **solver_container, - CConfig *config, - unsigned short iMesh, - unsigned short iRKStep, - unsigned short RunTime_EqSystem, bool Output) { - - /* Set residuals and matrix entries to zero */ - - for (unsigned long iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { - LinSysRes.SetBlock_Zero(iPoint); - } - - /* Zero out the entries in the various matrices */ - - StiffMatrixSpace.SetValZero(); - StiffMatrixTime.SetValZero(); - Jacobian.SetValZero(); - -} - -void CWaveSolver::Source_Residual(CGeometry *geometry, - CSolver **solver_container, - CNumerics *numerics, CNumerics *second_numerics, - CConfig *config, - unsigned short iMesh) { - - unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0; - su2double a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}, Area_Local, Time_Num; - su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL; - unsigned short iDim; - - /*--- Numerical time step. This system is unconditionally stable, - so a very big step can be used. ---*/ - if (config->GetUnsteady_Simulation() == TIME_STEPPING) - Time_Num = config->GetDelta_UnstTimeND(); - else Time_Num = 1E+30; - - /* Loop through elements to compute contributions from the matrix */ - /* blocks involving time. These contributions are also added to the */ - /* Jacobian w/ the time step. Spatial source terms are also computed. */ - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - /* Get node numbers and their coordinate vectors */ - - Point_0 = geometry->elem[iElem]->GetNode(0); - Point_1 = geometry->elem[iElem]->GetNode(1); - Point_2 = geometry->elem[iElem]->GetNode(2); - - Coord_0 = geometry->node[Point_0]->GetCoord(); - Coord_1 = geometry->node[Point_1]->GetCoord(); - Coord_2 = geometry->node[Point_2]->GetCoord(); - - /* Compute triangle area (2-D) */ - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = Coord_0[iDim]-Coord_2[iDim]; - b[iDim] = Coord_1[iDim]-Coord_2[iDim]; - } - Area_Local = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); - - /*--- Block contributions to the Jacobian (includes time step) ---*/ - - StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; - StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (2.0/12.0)*(Area_Local/Time_Num); - Jacobian.AddBlock(Point_0, Point_0, StiffMatrix_Node); - - StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; - StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (1.0/12.0)*(Area_Local/Time_Num); - Jacobian.AddBlock(Point_0, Point_1, StiffMatrix_Node); - - StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; - StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (1.0/12.0)*(Area_Local/Time_Num); - Jacobian.AddBlock(Point_0, Point_2, StiffMatrix_Node); - - StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; - StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (1.0/12.0)*(Area_Local/Time_Num); - Jacobian.AddBlock(Point_1, Point_0, StiffMatrix_Node); - - StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; - StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (2.0/12.0)*(Area_Local/Time_Num); - Jacobian.AddBlock(Point_1, Point_1, StiffMatrix_Node); - - StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; - StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (1.0/12.0)*(Area_Local/Time_Num); - Jacobian.AddBlock(Point_1, Point_2, StiffMatrix_Node); - - StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; - StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (1.0/12.0)*(Area_Local/Time_Num); - Jacobian.AddBlock(Point_2, Point_0, StiffMatrix_Node); - - StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; - StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (1.0/12.0)*(Area_Local/Time_Num); - Jacobian.AddBlock(Point_2, Point_1, StiffMatrix_Node); - - StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; - StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (2.0/12.0)*(Area_Local/Time_Num); - Jacobian.AddBlock(Point_2, Point_2, StiffMatrix_Node); - - } - -} - - -void CWaveSolver::Source_Template(CGeometry *geometry, - CSolver **solver_container, - CNumerics *numerics, - CConfig *config, - unsigned short iMesh) { - -} - -void CWaveSolver::Viscous_Residual(CGeometry *geometry, - CSolver **solver_container, - CNumerics *numerics, - CConfig *config, - unsigned short iMesh, unsigned short iRKStep) { - - unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, iPoint, total_index; - su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, wave_speed_2; - unsigned short iVar; - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - Point_0 = geometry->elem[iElem]->GetNode(0); - Point_1 = geometry->elem[iElem]->GetNode(1); - Point_2 = geometry->elem[iElem]->GetNode(2); - - Coord_0 = geometry->node[Point_0]->GetCoord(); - Coord_1 = geometry->node[Point_1]->GetCoord(); - Coord_2 = geometry->node[Point_2]->GetCoord(); - - numerics->SetCoord(Coord_0, Coord_1, Coord_2); - - numerics->ComputeResidual(StiffMatrix_Elem, config); - - /*--- Compute the square of the wave speed ---*/ - wave_speed_2 = config->GetWaveSpeed()*config->GetWaveSpeed(); - - StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; - StiffMatrix_Node[1][0] = StiffMatrix_Elem[0][0]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; - StiffMatrixSpace.AddBlock(Point_0, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_0, StiffMatrix_Node); - - StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; - StiffMatrix_Node[1][0] = StiffMatrix_Elem[0][1]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; - StiffMatrixSpace.AddBlock(Point_0, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_1, StiffMatrix_Node); - - StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; - StiffMatrix_Node[1][0] = StiffMatrix_Elem[0][2]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; - StiffMatrixSpace.AddBlock(Point_0, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_2, StiffMatrix_Node); - - StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; - StiffMatrix_Node[1][0] = StiffMatrix_Elem[1][0]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; - StiffMatrixSpace.AddBlock(Point_1, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_0, StiffMatrix_Node); - - StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; - StiffMatrix_Node[1][0] = StiffMatrix_Elem[1][1]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; - StiffMatrixSpace.AddBlock(Point_1, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_1, StiffMatrix_Node); - - StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; - StiffMatrix_Node[1][0] = StiffMatrix_Elem[1][2]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; - StiffMatrixSpace.AddBlock(Point_1, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_2, StiffMatrix_Node); - - StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; - StiffMatrix_Node[1][0] = StiffMatrix_Elem[2][0]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; - StiffMatrixSpace.AddBlock(Point_2, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_0, StiffMatrix_Node); - - StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; - StiffMatrix_Node[1][0] = StiffMatrix_Elem[2][1]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; - StiffMatrixSpace.AddBlock(Point_2, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_1, StiffMatrix_Node); - - StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; - StiffMatrix_Node[1][0] = StiffMatrix_Elem[2][2]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; - StiffMatrixSpace.AddBlock(Point_2, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_2, StiffMatrix_Node); - - } - - /* Prepare solution vector for multiplication */ - - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - LinSysSol[total_index] = node[iPoint]->GetSolution(iVar); - LinSysRes[total_index] = 0.0; - } - - StiffMatrixSpace.MatrixVectorProduct(LinSysSol, LinSysRes); - - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - Residual[iVar] = LinSysRes[total_index]; - } - LinSysRes.SubtractBlock(iPoint, Residual); - } - - - -} - -void CWaveSolver::BC_Euler_Wall(CGeometry *geometry, - CSolver **solver_container, - CNumerics *numerics, - CConfig *config, - unsigned short val_marker) { - - unsigned long iPoint, iVertex, total_index, iter; - su2double deltaT, omega, time, ampl, *wave_sol; - unsigned short iVar; - - /*--- Set the values needed for periodic forcing ---*/ - - deltaT = config->GetDelta_UnstTimeND(); - iter = config->GetExtIter(); - time = static_cast(iter)*deltaT; - omega = 1.0; - ampl = 1.0; - - wave_sol = new su2double [nVar]; - - for (iVar = 0; iVar < nVar; iVar++) { - wave_sol[iVar] = 0.0; - } - - /*--- Compute sin wave forcing at the boundary ---*/ - - wave_sol[0] = ampl*sin(omega*time); - wave_sol[1] = 0.0; //-ampl*cos(omega*time_new)*omega; - - /*--- Set the solution at the boundary nodes and zero the residual ---*/ - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); - - for (iVar = 0; iVar < nVar; iVar++) { - Solution[iVar] = wave_sol[iVar]; - Residual[iVar] = 0.0; - } - node[iPoint]->SetSolution(Solution); - node[iPoint]->SetSolution_Old(Solution); - LinSysRes.SetBlock(iPoint, Residual); - LinSysRes.SetBlock(iPoint, Residual); - for (unsigned short iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - Jacobian.DeleteValsRowi(total_index); - } - } - - delete [] wave_sol; - -} - -void CWaveSolver::BC_Far_Field(CGeometry *geometry, CSolver **solver_container, - CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, - unsigned short val_marker) { - - /*--- Do nothing at the moment ---*/ - -} - - - -void CWaveSolver::Wave_Strength(CGeometry *geometry, CConfig *config) { - - unsigned long iPoint, iVertex; - unsigned short iMarker, Boundary, Monitoring; - su2double WaveSol, WaveStrength = 0.0, factor; - - /* Multiplying rho' by c^2 gives the acoustic pressure, p' */ - factor = config->GetWaveSpeed()*config->GetWaveSpeed(); - - /* Initialize wave strength to zero */ - - Total_CWave = 0.0; AllBound_CWave = 0.0; - - /*--- Loop over the wave far-field markers ---*/ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Boundary = config->GetMarker_All_KindBC(iMarker); - Monitoring = config->GetMarker_All_Monitoring(iMarker); - - if (Boundary == FAR_FIELD) { - - WaveStrength = 0.0; - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - /* Wave solution from the first array position */ - WaveSol = node[iPoint]->GetSolution(0); - - /* Add contribution to total strength */ - WaveStrength += factor*WaveSol*WaveSol; - } - - if (Monitoring == YES) { - CWave[iMarker] = WaveStrength; - AllBound_CWave += CWave[iMarker]; - } - - } - } - - Total_CWave += AllBound_CWave; - -} - -void CWaveSolver::SetResidual_DualTime(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iRKStep, - unsigned short iMesh, unsigned short RunTime_EqSystem) { - - unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0; - su2double a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}, Area_Local, Time_Num; - su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL; - unsigned short iDim, iVar, jVar; - su2double TimeJac = 0.0; - - /*--- Numerical time step (this system is uncoditional stable... a very big number can be used) ---*/ - Time_Num = config->GetDelta_UnstTimeND(); - - /*--- Loop through elements to compute contributions from the matrix - blocks involving time. These contributions are also added to the - Jacobian w/ the time step. Spatial source terms are also computed. ---*/ - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - /* Get node numbers and their coordinate vectors */ - - Point_0 = geometry->elem[iElem]->GetNode(0); - Point_1 = geometry->elem[iElem]->GetNode(1); - Point_2 = geometry->elem[iElem]->GetNode(2); - - Coord_0 = geometry->node[Point_0]->GetCoord(); - Coord_1 = geometry->node[Point_1]->GetCoord(); - Coord_2 = geometry->node[Point_2]->GetCoord(); - - /* Compute triangle area (2-D) */ - - for (iDim = 0; iDim < nDim; iDim++) { - a[iDim] = Coord_0[iDim]-Coord_2[iDim]; - b[iDim] = Coord_1[iDim]-Coord_2[iDim]; - } - Area_Local = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); - - - /*----------------------------------------------------------------*/ - /*--- Block contributions to the Jacobian (includes time step) ---*/ - /*----------------------------------------------------------------*/ - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) - StiffMatrix_Node[iVar][jVar] = 0.0; - - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) TimeJac = 1.0/Time_Num; - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) TimeJac = 3.0/(2.0*Time_Num); - - /*--- Diagonal value identity matrix ---*/ - StiffMatrix_Node[0][0] = 1.0*TimeJac; - - - /*--- Diagonal value ---*/ - StiffMatrix_Node[1][1] = (2.0/12.0)*(Area_Local*TimeJac); - - Jacobian.AddBlock(Point_0, Point_0, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_0, Point_0, StiffMatrix_Node); - Jacobian.AddBlock(Point_1, Point_1, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_1, Point_1, StiffMatrix_Node); - Jacobian.AddBlock(Point_2, Point_2, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_2, Point_2, StiffMatrix_Node); - - /*--- Off Diagonal value ---*/ - StiffMatrix_Node[1][1] = (1.0/12.0)*(Area_Local*TimeJac); - - Jacobian.AddBlock(Point_0, Point_1, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_0, Point_1, StiffMatrix_Node); - Jacobian.AddBlock(Point_0, Point_2, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_0, Point_2, StiffMatrix_Node); - Jacobian.AddBlock(Point_1, Point_0, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_1, Point_0, StiffMatrix_Node); - Jacobian.AddBlock(Point_1, Point_2, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_1, Point_2, StiffMatrix_Node); - Jacobian.AddBlock(Point_2, Point_0, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_2, Point_0, StiffMatrix_Node); - Jacobian.AddBlock(Point_2, Point_1, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_2, Point_1, StiffMatrix_Node); - - - } - - unsigned long iPoint, total_index; - su2double *U_time_nM1, *U_time_n, *U_time_nP1; - - /*--- loop over points ---*/ - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { - - /*--- Solution at time n-1, n and n+1 ---*/ - U_time_nM1 = node[iPoint]->GetSolution_time_n1(); - U_time_n = node[iPoint]->GetSolution_time_n(); - U_time_nP1 = node[iPoint]->GetSolution(); - - /*--- Compute Residual ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - LinSysRes[total_index] = 0.0; - if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) - LinSysSol[total_index] = (U_time_nP1[iVar] - U_time_n[iVar]); - if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) - LinSysSol[total_index] = (U_time_nP1[iVar] - (4.0/3.0)*U_time_n[iVar] + (1.0/3.0)*U_time_nM1[iVar]); - } - } - - StiffMatrixTime.MatrixVectorProduct(LinSysSol, LinSysRes); - - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - Residual[iVar] = LinSysRes[total_index]; - } - LinSysRes.SubtractBlock(iPoint, Residual); - } - -} - - -void CWaveSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { - - unsigned short iVar; - unsigned long iPoint, total_index; - - /*--- Set maximum residual to zero ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - SetRes_RMS(iVar, 0.0); - SetRes_Max(iVar, 0.0, 0); - } - - /*--- Build implicit system ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { - - /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; - LinSysSol[total_index] = 0.0; - AddRes_RMS(iVar, LinSysRes[total_index]*LinSysRes[total_index]); - AddRes_Max(iVar, fabs(LinSysRes[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); - } - } - - /*--- Initialize residual and solution at the ghost points ---*/ - - for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar + iVar; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - } - } - - /*--- Solve or smooth the linear system ---*/ - - CSysSolve system; - system.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); - - /*--- Update solution (system written in terms of increments) ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - node[iPoint]->AddSolution(iVar, LinSysSol[iPoint*nVar+iVar]); - } - } - - /*--- MPI solution ---*/ - - Set_MPI_Solution(geometry, config); - - /*--- Compute the root mean square residual ---*/ - - SetResidual_RMS(geometry, config); - -} - - -void CWaveSolver::SetSpace_Matrix(CGeometry *geometry, - CConfig *config) { - -// /* Local variables and initialization */ -// -// unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, iPoint, total_index; -// su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, wave_speed_2; -// unsigned short iVar; -// -// for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { -// -// Point_0 = geometry->elem[iElem]->GetNode(0); -// Point_1 = geometry->elem[iElem]->GetNode(1); -// Point_2 = geometry->elem[iElem]->GetNode(2); -// -// Coord_0 = geometry->node[Point_0]->GetCoord(); -// Coord_1 = geometry->node[Point_1]->GetCoord(); -// Coord_2 = geometry->node[Point_2]->GetCoord(); -// -// numerics->SetCoord(Coord_0, Coord_1, Coord_2); -// -// numerics->ComputeResidual(StiffMatrix_Elem, config); -// -// /*--- Compute the square of the wave speed ---*/ -// wave_speed_2 = config->GetWaveSpeed()*config->GetWaveSpeed(); -// -// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; -// StiffMatrix_Node[1][0] = StiffMatrix_Elem[0][0]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; -// StiffMatrixSpace.AddBlock(Point_0, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_0, StiffMatrix_Node); -// -// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; -// StiffMatrix_Node[1][0] = StiffMatrix_Elem[0][1]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; -// StiffMatrixSpace.AddBlock(Point_0, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_1, StiffMatrix_Node); -// -// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; -// StiffMatrix_Node[1][0] = StiffMatrix_Elem[0][2]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; -// StiffMatrixSpace.AddBlock(Point_0, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_2, StiffMatrix_Node); -// -// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; -// StiffMatrix_Node[1][0] = StiffMatrix_Elem[1][0]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; -// StiffMatrixSpace.AddBlock(Point_1, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_0, StiffMatrix_Node); -// -// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; -// StiffMatrix_Node[1][0] = StiffMatrix_Elem[1][1]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; -// StiffMatrixSpace.AddBlock(Point_1, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_1, StiffMatrix_Node); -// -// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; -// StiffMatrix_Node[1][0] = StiffMatrix_Elem[1][2]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; -// StiffMatrixSpace.AddBlock(Point_1, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_2, StiffMatrix_Node); -// -// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; -// StiffMatrix_Node[1][0] = StiffMatrix_Elem[2][0]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; -// StiffMatrixSpace.AddBlock(Point_2, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_0, StiffMatrix_Node); -// -// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; -// StiffMatrix_Node[1][0] = StiffMatrix_Elem[2][1]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; -// StiffMatrixSpace.AddBlock(Point_2, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_1, StiffMatrix_Node); -// -// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; -// StiffMatrix_Node[1][0] = StiffMatrix_Elem[2][2]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; -// StiffMatrixSpace.AddBlock(Point_2, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_2, StiffMatrix_Node); -// -// } - -} - - -void CWaveSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig *config, int val_iter) { - - int rank; - -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#else - rank = MASTER_NODE; -#endif - - /*--- Restart the solution from file information ---*/ - string restart_filename = config->GetRestart_WaveFileName(); - unsigned long iPoint, index, nFlowIter, adjIter, flowIter; - char buffer[50]; - string UnstExt, text_line; - ifstream restart_file; - - /*--- For the unsteady adjoint, we integrate backwards through - physical time, so load in the direct solution files in reverse. ---*/ - if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { - nFlowIter = config->GetnExtIter(); - adjIter = config->GetExtIter(); - flowIter = nFlowIter - adjIter - 1; - unsigned short lastindex = restart_filename.find_last_of("."); - restart_filename = restart_filename.substr(0, lastindex); - if ((SU2_TYPE::Int(flowIter) >= 0) && (SU2_TYPE::Int(flowIter) < 10)) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(flowIter)); - if ((SU2_TYPE::Int(flowIter) >= 10) && (SU2_TYPE::Int(flowIter) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(flowIter)); - if ((SU2_TYPE::Int(flowIter) >= 100) && (SU2_TYPE::Int(flowIter) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(flowIter)); - if ((SU2_TYPE::Int(flowIter) >= 1000) && (SU2_TYPE::Int(flowIter) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(flowIter)); - if (SU2_TYPE::Int(flowIter) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(flowIter)); - UnstExt = string(buffer); - restart_filename.append(UnstExt); - } else { - flowIter =config->GetExtIter(); - unsigned short lastindex = restart_filename.find_last_of("."); - restart_filename = restart_filename.substr(0, lastindex); - if ((SU2_TYPE::Int(flowIter) >= 0) && (SU2_TYPE::Int(flowIter) < 10)) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(flowIter)); - if ((SU2_TYPE::Int(flowIter) >= 10) && (SU2_TYPE::Int(flowIter) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(flowIter)); - if ((SU2_TYPE::Int(flowIter) >= 100) && (SU2_TYPE::Int(flowIter) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(flowIter)); - if ((SU2_TYPE::Int(flowIter) >= 1000) && (SU2_TYPE::Int(flowIter) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(flowIter)); - if (SU2_TYPE::Int(flowIter) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(flowIter)); - UnstExt = string(buffer); - restart_filename.append(UnstExt); - } - - /*--- Open the flow solution from the restart file ---*/ - if (rank == MASTER_NODE) - cout << "Reading in the direct wave solution from iteration " << flowIter << "." << endl;; - restart_file.open(restart_filename.data(), ios::in); - - /*--- In case there is no file ---*/ - if (restart_file.fail()) { - if (rank == MASTER_NODE) - cout << "There is no wave restart file!!" << endl; - exit(EXIT_FAILURE); - } - - /*--- Read the restart file ---*/ - for (iPoint = 0; iPoint < geometry[MESH_0]->GetnPoint(); iPoint++) { - getline(restart_file, text_line); - istringstream point_line(text_line); - point_line >> index >> Solution[0] >> Solution[1]; - node[iPoint]->SetSolution_Direct(Solution); - } - - /*--- Close the restart file ---*/ - restart_file.close(); - -} +/*! + * \file solution_direct_wave.cpp + * \brief Main subrotuines for solving the wave equation. + * \author T. Economon, F. Palacios + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/solver_structure.hpp" + +CWaveSolver::CWaveSolver(void) : CSolver() { } + +CWaveSolver::CWaveSolver(CGeometry *geometry, + CConfig *config) : CSolver() { + unsigned short iDim, iVar, nLineLets; + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + nPoint = geometry->GetnPoint(); + nPointDomain = geometry->GetnPointDomain(); + nDim = geometry->GetnDim(); + node = new CVariable*[nPoint]; + nVar = 2; // solve as a 2 eq. system + + Residual = new su2double[nVar]; Residual_RMS = new su2double[nVar]; + Solution = new su2double[nVar]; + Res_Sour = new su2double[nVar]; + Residual_Max = new su2double[nVar]; + + /*--- Define some structures for locating max residuals ---*/ + Point_Max = new unsigned long[nVar]; + for (iVar = 0; iVar < nVar; iVar++) Point_Max[iVar] = 0; + Point_Max_Coord = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Point_Max_Coord[iVar] = new su2double[nDim]; + for (iDim = 0; iDim < nDim; iDim++) Point_Max_Coord[iVar][iDim] = 0.0; + } + + /*--- Point to point stiffness matrix (only for triangles)---*/ + StiffMatrix_Elem = new su2double*[nDim+1]; + for (iVar = 0; iVar < nDim+1; iVar++) { + StiffMatrix_Elem[iVar] = new su2double [nDim+1]; + } + + StiffMatrix_Node = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + StiffMatrix_Node[iVar] = new su2double [nVar]; + } + + /*--- Initialization of matrix structures ---*/ + StiffMatrixSpace.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); + StiffMatrixTime.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); + Jacobian.Initialize(nPoint, nPointDomain, nVar, nVar, true, geometry, config); + + if ((config->GetKind_Linear_Solver_Prec() == LINELET) || + (config->GetKind_Linear_Solver() == SMOOTHER_LINELET)) { + nLineLets = Jacobian.BuildLineletPreconditioner(geometry, config); + if (rank == MASTER_NODE) cout << "Compute linelet structure. " << nLineLets << " elements in each line (average)." << endl; + } + + /*--- Initialization of linear solver structures ---*/ + LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); + LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); + + /* Wave strength coefficient for all of the markers */ + + CWave = new su2double[config->GetnMarker_All()]; + Total_CWave = 0.0; + + /* Check for a restart (not really used), initialize from zero otherwise */ + + bool restart = (config->GetRestart()); + if (!restart) { + + for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { + + /*--- Zero initial condition for testing source terms & forcing BCs ---*/ + Solution[0] = 0.0; + Solution[1] = 0.0; + + node[iPoint] = new CWaveVariable(Solution, nDim, nVar, config); + + /* Copy solution to old containers if using dual time */ + + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) { + node[iPoint]->Set_Solution_time_n(); + } else if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) { + node[iPoint]->Set_Solution_time_n(); + node[iPoint]->Set_Solution_time_n1(); + } + + } + } else { + + cout << "Wave restart file not currently configured!!" << endl; + + string mesh_filename = config->GetSolution_FlowFileName(); + ifstream restart_file; + + char *cstr; cstr = new char [mesh_filename.size()+1]; + strcpy (cstr, mesh_filename.c_str()); + restart_file.open(cstr, ios::in); + + if (restart_file.fail()) { + if (rank == MASTER_NODE) + cout << "There is no wave restart file!!" << endl; + exit(EXIT_FAILURE); + } + unsigned long index; + string text_line; + + for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { + getline(restart_file, text_line); + istringstream point_line(text_line); + point_line >> index >> Solution[0] >> Solution[1]; + node[iPoint] = new CWaveVariable(Solution, nDim, nVar, config); + } + restart_file.close(); + } + +} + +CWaveSolver::~CWaveSolver(void) { + + unsigned short iVar; + + delete [] Residual; + delete [] Residual_Max; + delete [] Solution; + + for (iVar = 0; iVar < nDim+1; iVar++) + delete [] StiffMatrix_Elem[iVar]; + + + for (iVar = 0; iVar < nVar; iVar++) + delete [] StiffMatrix_Node[iVar]; + + delete [] StiffMatrix_Elem; + delete [] StiffMatrix_Node; + +} + +void CWaveSolver::Preprocessing(CGeometry *geometry, + CSolver **solver_container, + CConfig *config, + unsigned short iMesh, + unsigned short iRKStep, + unsigned short RunTime_EqSystem, bool Output) { + + /* Set residuals and matrix entries to zero */ + + for (unsigned long iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) { + LinSysRes.SetBlock_Zero(iPoint); + } + + /* Zero out the entries in the various matrices */ + + StiffMatrixSpace.SetValZero(); + StiffMatrixTime.SetValZero(); + Jacobian.SetValZero(); + +} + +void CWaveSolver::Source_Residual(CGeometry *geometry, + CSolver **solver_container, + CNumerics *numerics, CNumerics *second_numerics, + CConfig *config, + unsigned short iMesh) { + + unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0; + su2double a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}, Area_Local, Time_Num; + su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL; + unsigned short iDim; + + /*--- Numerical time step. This system is unconditionally stable, + so a very big step can be used. ---*/ + if (config->GetUnsteady_Simulation() == TIME_STEPPING) + Time_Num = config->GetDelta_UnstTimeND(); + else Time_Num = 1E+30; + + /* Loop through elements to compute contributions from the matrix */ + /* blocks involving time. These contributions are also added to the */ + /* Jacobian w/ the time step. Spatial source terms are also computed. */ + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + /* Get node numbers and their coordinate vectors */ + + Point_0 = geometry->elem[iElem]->GetNode(0); + Point_1 = geometry->elem[iElem]->GetNode(1); + Point_2 = geometry->elem[iElem]->GetNode(2); + + Coord_0 = geometry->node[Point_0]->GetCoord(); + Coord_1 = geometry->node[Point_1]->GetCoord(); + Coord_2 = geometry->node[Point_2]->GetCoord(); + + /* Compute triangle area (2-D) */ + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = Coord_0[iDim]-Coord_2[iDim]; + b[iDim] = Coord_1[iDim]-Coord_2[iDim]; + } + Area_Local = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); + + /*--- Block contributions to the Jacobian (includes time step) ---*/ + + StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; + StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (2.0/12.0)*(Area_Local/Time_Num); + Jacobian.AddBlock(Point_0, Point_0, StiffMatrix_Node); + + StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; + StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (1.0/12.0)*(Area_Local/Time_Num); + Jacobian.AddBlock(Point_0, Point_1, StiffMatrix_Node); + + StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; + StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (1.0/12.0)*(Area_Local/Time_Num); + Jacobian.AddBlock(Point_0, Point_2, StiffMatrix_Node); + + StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; + StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (1.0/12.0)*(Area_Local/Time_Num); + Jacobian.AddBlock(Point_1, Point_0, StiffMatrix_Node); + + StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; + StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (2.0/12.0)*(Area_Local/Time_Num); + Jacobian.AddBlock(Point_1, Point_1, StiffMatrix_Node); + + StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; + StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (1.0/12.0)*(Area_Local/Time_Num); + Jacobian.AddBlock(Point_1, Point_2, StiffMatrix_Node); + + StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; + StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (1.0/12.0)*(Area_Local/Time_Num); + Jacobian.AddBlock(Point_2, Point_0, StiffMatrix_Node); + + StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; + StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (1.0/12.0)*(Area_Local/Time_Num); + Jacobian.AddBlock(Point_2, Point_1, StiffMatrix_Node); + + StiffMatrix_Node[0][0] = 1.0/Time_Num; StiffMatrix_Node[0][1] = 0.0; + StiffMatrix_Node[1][0] = 0.0; StiffMatrix_Node[1][1] = (2.0/12.0)*(Area_Local/Time_Num); + Jacobian.AddBlock(Point_2, Point_2, StiffMatrix_Node); + + } + +} + + +void CWaveSolver::Source_Template(CGeometry *geometry, + CSolver **solver_container, + CNumerics *numerics, + CConfig *config, + unsigned short iMesh) { + +} + +void CWaveSolver::Viscous_Residual(CGeometry *geometry, + CSolver **solver_container, + CNumerics *numerics, + CConfig *config, + unsigned short iMesh, unsigned short iRKStep) { + + unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, iPoint, total_index; + su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, wave_speed_2; + unsigned short iVar; + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + Point_0 = geometry->elem[iElem]->GetNode(0); + Point_1 = geometry->elem[iElem]->GetNode(1); + Point_2 = geometry->elem[iElem]->GetNode(2); + + Coord_0 = geometry->node[Point_0]->GetCoord(); + Coord_1 = geometry->node[Point_1]->GetCoord(); + Coord_2 = geometry->node[Point_2]->GetCoord(); + + numerics->SetCoord(Coord_0, Coord_1, Coord_2); + + numerics->ComputeResidual(StiffMatrix_Elem, config); + + /*--- Compute the square of the wave speed ---*/ + wave_speed_2 = config->GetWaveSpeed()*config->GetWaveSpeed(); + + StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; + StiffMatrix_Node[1][0] = StiffMatrix_Elem[0][0]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; + StiffMatrixSpace.AddBlock(Point_0, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_0, StiffMatrix_Node); + + StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; + StiffMatrix_Node[1][0] = StiffMatrix_Elem[0][1]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; + StiffMatrixSpace.AddBlock(Point_0, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_1, StiffMatrix_Node); + + StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; + StiffMatrix_Node[1][0] = StiffMatrix_Elem[0][2]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; + StiffMatrixSpace.AddBlock(Point_0, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_2, StiffMatrix_Node); + + StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; + StiffMatrix_Node[1][0] = StiffMatrix_Elem[1][0]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; + StiffMatrixSpace.AddBlock(Point_1, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_0, StiffMatrix_Node); + + StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; + StiffMatrix_Node[1][0] = StiffMatrix_Elem[1][1]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; + StiffMatrixSpace.AddBlock(Point_1, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_1, StiffMatrix_Node); + + StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; + StiffMatrix_Node[1][0] = StiffMatrix_Elem[1][2]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; + StiffMatrixSpace.AddBlock(Point_1, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_2, StiffMatrix_Node); + + StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; + StiffMatrix_Node[1][0] = StiffMatrix_Elem[2][0]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; + StiffMatrixSpace.AddBlock(Point_2, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_0, StiffMatrix_Node); + + StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; + StiffMatrix_Node[1][0] = StiffMatrix_Elem[2][1]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; + StiffMatrixSpace.AddBlock(Point_2, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_1, StiffMatrix_Node); + + StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; + StiffMatrix_Node[1][0] = StiffMatrix_Elem[2][2]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; + StiffMatrixSpace.AddBlock(Point_2, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_2, StiffMatrix_Node); + + } + + /* Prepare solution vector for multiplication */ + + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + LinSysSol[total_index] = node[iPoint]->GetSolution(iVar); + LinSysRes[total_index] = 0.0; + } + + StiffMatrixSpace.MatrixVectorProduct(LinSysSol, LinSysRes); + + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + Residual[iVar] = LinSysRes[total_index]; + } + LinSysRes.SubtractBlock(iPoint, Residual); + } + + + +} + +void CWaveSolver::BC_Euler_Wall(CGeometry *geometry, + CSolver **solver_container, + CNumerics *numerics, + CConfig *config, + unsigned short val_marker) { + + unsigned long iPoint, iVertex, total_index, iter; + su2double deltaT, omega, time, ampl, *wave_sol; + unsigned short iVar; + + /*--- Set the values needed for periodic forcing ---*/ + + deltaT = config->GetDelta_UnstTimeND(); + iter = config->GetExtIter(); + time = static_cast(iter)*deltaT; + omega = 1.0; + ampl = 1.0; + + wave_sol = new su2double [nVar]; + + for (iVar = 0; iVar < nVar; iVar++) { + wave_sol[iVar] = 0.0; + } + + /*--- Compute sin wave forcing at the boundary ---*/ + + wave_sol[0] = ampl*sin(omega*time); + wave_sol[1] = 0.0; //-ampl*cos(omega*time_new)*omega; + + /*--- Set the solution at the boundary nodes and zero the residual ---*/ + + for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { + iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + + for (iVar = 0; iVar < nVar; iVar++) { + Solution[iVar] = wave_sol[iVar]; + Residual[iVar] = 0.0; + } + node[iPoint]->SetSolution(Solution); + node[iPoint]->SetSolution_Old(Solution); + LinSysRes.SetBlock(iPoint, Residual); + LinSysRes.SetBlock(iPoint, Residual); + for (unsigned short iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + Jacobian.DeleteValsRowi(total_index); + } + } + + delete [] wave_sol; + +} + +void CWaveSolver::BC_Far_Field(CGeometry *geometry, CSolver **solver_container, + CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, + unsigned short val_marker) { + + /*--- Do nothing at the moment ---*/ + +} + + + +void CWaveSolver::Wave_Strength(CGeometry *geometry, CConfig *config) { + + unsigned long iPoint, iVertex; + unsigned short iMarker, Boundary, Monitoring; + su2double WaveSol, WaveStrength = 0.0, factor; + + /* Multiplying rho' by c^2 gives the acoustic pressure, p' */ + factor = config->GetWaveSpeed()*config->GetWaveSpeed(); + + /* Initialize wave strength to zero */ + + Total_CWave = 0.0; AllBound_CWave = 0.0; + + /*--- Loop over the wave far-field markers ---*/ + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + Boundary = config->GetMarker_All_KindBC(iMarker); + Monitoring = config->GetMarker_All_Monitoring(iMarker); + + if (Boundary == FAR_FIELD) { + + WaveStrength = 0.0; + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + /* Wave solution from the first array position */ + WaveSol = node[iPoint]->GetSolution(0); + + /* Add contribution to total strength */ + WaveStrength += factor*WaveSol*WaveSol; + } + + if (Monitoring == YES) { + CWave[iMarker] = WaveStrength; + AllBound_CWave += CWave[iMarker]; + } + + } + } + + Total_CWave += AllBound_CWave; + +} + +void CWaveSolver::SetResidual_DualTime(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iRKStep, + unsigned short iMesh, unsigned short RunTime_EqSystem) { + + unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0; + su2double a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}, Area_Local, Time_Num; + su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL; + unsigned short iDim, iVar, jVar; + su2double TimeJac = 0.0; + + /*--- Numerical time step (this system is uncoditional stable... a very big number can be used) ---*/ + Time_Num = config->GetDelta_UnstTimeND(); + + /*--- Loop through elements to compute contributions from the matrix + blocks involving time. These contributions are also added to the + Jacobian w/ the time step. Spatial source terms are also computed. ---*/ + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + + /* Get node numbers and their coordinate vectors */ + + Point_0 = geometry->elem[iElem]->GetNode(0); + Point_1 = geometry->elem[iElem]->GetNode(1); + Point_2 = geometry->elem[iElem]->GetNode(2); + + Coord_0 = geometry->node[Point_0]->GetCoord(); + Coord_1 = geometry->node[Point_1]->GetCoord(); + Coord_2 = geometry->node[Point_2]->GetCoord(); + + /* Compute triangle area (2-D) */ + + for (iDim = 0; iDim < nDim; iDim++) { + a[iDim] = Coord_0[iDim]-Coord_2[iDim]; + b[iDim] = Coord_1[iDim]-Coord_2[iDim]; + } + Area_Local = 0.5*fabs(a[0]*b[1]-a[1]*b[0]); + + + /*----------------------------------------------------------------*/ + /*--- Block contributions to the Jacobian (includes time step) ---*/ + /*----------------------------------------------------------------*/ + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) + StiffMatrix_Node[iVar][jVar] = 0.0; + + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) TimeJac = 1.0/Time_Num; + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) TimeJac = 3.0/(2.0*Time_Num); + + /*--- Diagonal value identity matrix ---*/ + StiffMatrix_Node[0][0] = 1.0*TimeJac; + + + /*--- Diagonal value ---*/ + StiffMatrix_Node[1][1] = (2.0/12.0)*(Area_Local*TimeJac); + + Jacobian.AddBlock(Point_0, Point_0, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_0, Point_0, StiffMatrix_Node); + Jacobian.AddBlock(Point_1, Point_1, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_1, Point_1, StiffMatrix_Node); + Jacobian.AddBlock(Point_2, Point_2, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_2, Point_2, StiffMatrix_Node); + + /*--- Off Diagonal value ---*/ + StiffMatrix_Node[1][1] = (1.0/12.0)*(Area_Local*TimeJac); + + Jacobian.AddBlock(Point_0, Point_1, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_0, Point_1, StiffMatrix_Node); + Jacobian.AddBlock(Point_0, Point_2, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_0, Point_2, StiffMatrix_Node); + Jacobian.AddBlock(Point_1, Point_0, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_1, Point_0, StiffMatrix_Node); + Jacobian.AddBlock(Point_1, Point_2, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_1, Point_2, StiffMatrix_Node); + Jacobian.AddBlock(Point_2, Point_0, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_2, Point_0, StiffMatrix_Node); + Jacobian.AddBlock(Point_2, Point_1, StiffMatrix_Node); StiffMatrixTime.AddBlock(Point_2, Point_1, StiffMatrix_Node); + + + } + + unsigned long iPoint, total_index; + su2double *U_time_nM1, *U_time_n, *U_time_nP1; + + /*--- loop over points ---*/ + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { + + /*--- Solution at time n-1, n and n+1 ---*/ + U_time_nM1 = node[iPoint]->GetSolution_time_n1(); + U_time_n = node[iPoint]->GetSolution_time_n(); + U_time_nP1 = node[iPoint]->GetSolution(); + + /*--- Compute Residual ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + LinSysRes[total_index] = 0.0; + if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST) + LinSysSol[total_index] = (U_time_nP1[iVar] - U_time_n[iVar]); + if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) + LinSysSol[total_index] = (U_time_nP1[iVar] - (4.0/3.0)*U_time_n[iVar] + (1.0/3.0)*U_time_nM1[iVar]); + } + } + + StiffMatrixTime.MatrixVectorProduct(LinSysSol, LinSysRes); + + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + Residual[iVar] = LinSysRes[total_index]; + } + LinSysRes.SubtractBlock(iPoint, Residual); + } + +} + + +void CWaveSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { + + unsigned short iVar; + unsigned long iPoint, total_index; + + /*--- Set maximum residual to zero ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + SetRes_RMS(iVar, 0.0); + SetRes_Max(iVar, 0.0, 0); + } + + /*--- Build implicit system ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { + + /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar+iVar; + LinSysSol[total_index] = 0.0; + AddRes_RMS(iVar, LinSysRes[total_index]*LinSysRes[total_index]); + AddRes_Max(iVar, fabs(LinSysRes[total_index]), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); + } + } + + /*--- Initialize residual and solution at the ghost points ---*/ + + for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + total_index = iPoint*nVar + iVar; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + } + } + + /*--- Solve or smooth the linear system ---*/ + + CSysSolve system; + system.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); + + /*--- Update solution (system written in terms of increments) ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + node[iPoint]->AddSolution(iVar, LinSysSol[iPoint*nVar+iVar]); + } + } + + /*--- MPI solution ---*/ + + Set_MPI_Solution(geometry, config); + + /*--- Compute the root mean square residual ---*/ + + SetResidual_RMS(geometry, config); + +} + + +void CWaveSolver::SetSpace_Matrix(CGeometry *geometry, + CConfig *config) { + +// /* Local variables and initialization */ +// +// unsigned long iElem, Point_0 = 0, Point_1 = 0, Point_2 = 0, iPoint, total_index; +// su2double *Coord_0 = NULL, *Coord_1= NULL, *Coord_2= NULL, wave_speed_2; +// unsigned short iVar; +// +// for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { +// +// Point_0 = geometry->elem[iElem]->GetNode(0); +// Point_1 = geometry->elem[iElem]->GetNode(1); +// Point_2 = geometry->elem[iElem]->GetNode(2); +// +// Coord_0 = geometry->node[Point_0]->GetCoord(); +// Coord_1 = geometry->node[Point_1]->GetCoord(); +// Coord_2 = geometry->node[Point_2]->GetCoord(); +// +// numerics->SetCoord(Coord_0, Coord_1, Coord_2); +// +// numerics->ComputeResidual(StiffMatrix_Elem, config); +// +// /*--- Compute the square of the wave speed ---*/ +// wave_speed_2 = config->GetWaveSpeed()*config->GetWaveSpeed(); +// +// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; +// StiffMatrix_Node[1][0] = StiffMatrix_Elem[0][0]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; +// StiffMatrixSpace.AddBlock(Point_0, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_0, StiffMatrix_Node); +// +// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; +// StiffMatrix_Node[1][0] = StiffMatrix_Elem[0][1]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; +// StiffMatrixSpace.AddBlock(Point_0, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_1, StiffMatrix_Node); +// +// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; +// StiffMatrix_Node[1][0] = StiffMatrix_Elem[0][2]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; +// StiffMatrixSpace.AddBlock(Point_0, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_0, Point_2, StiffMatrix_Node); +// +// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; +// StiffMatrix_Node[1][0] = StiffMatrix_Elem[1][0]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; +// StiffMatrixSpace.AddBlock(Point_1, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_0, StiffMatrix_Node); +// +// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; +// StiffMatrix_Node[1][0] = StiffMatrix_Elem[1][1]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; +// StiffMatrixSpace.AddBlock(Point_1, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_1, StiffMatrix_Node); +// +// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; +// StiffMatrix_Node[1][0] = StiffMatrix_Elem[1][2]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; +// StiffMatrixSpace.AddBlock(Point_1, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_1, Point_2, StiffMatrix_Node); +// +// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; +// StiffMatrix_Node[1][0] = StiffMatrix_Elem[2][0]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; +// StiffMatrixSpace.AddBlock(Point_2, Point_0, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_0, StiffMatrix_Node); +// +// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; +// StiffMatrix_Node[1][0] = StiffMatrix_Elem[2][1]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; +// StiffMatrixSpace.AddBlock(Point_2, Point_1, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_1, StiffMatrix_Node); +// +// StiffMatrix_Node[0][0] = 0.0; StiffMatrix_Node[0][1] = -1.0; +// StiffMatrix_Node[1][0] = StiffMatrix_Elem[2][2]*wave_speed_2; StiffMatrix_Node[1][1] = 0.0; +// StiffMatrixSpace.AddBlock(Point_2, Point_2, StiffMatrix_Node); Jacobian.AddBlock(Point_2, Point_2, StiffMatrix_Node); +// +// } + +} + + +void CWaveSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig *config, int val_iter) { + + int rank; + +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#else + rank = MASTER_NODE; +#endif + + /*--- Restart the solution from file information ---*/ + string restart_filename = config->GetRestart_WaveFileName(); + unsigned long iPoint, index, nFlowIter, adjIter, flowIter; + char buffer[50]; + string UnstExt, text_line; + ifstream restart_file; + + /*--- For the unsteady adjoint, we integrate backwards through + physical time, so load in the direct solution files in reverse. ---*/ + if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) { + nFlowIter = config->GetnExtIter(); + adjIter = config->GetExtIter(); + flowIter = nFlowIter - adjIter - 1; + unsigned short lastindex = restart_filename.find_last_of("."); + restart_filename = restart_filename.substr(0, lastindex); + if ((SU2_TYPE::Int(flowIter) >= 0) && (SU2_TYPE::Int(flowIter) < 10)) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(flowIter)); + if ((SU2_TYPE::Int(flowIter) >= 10) && (SU2_TYPE::Int(flowIter) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(flowIter)); + if ((SU2_TYPE::Int(flowIter) >= 100) && (SU2_TYPE::Int(flowIter) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(flowIter)); + if ((SU2_TYPE::Int(flowIter) >= 1000) && (SU2_TYPE::Int(flowIter) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(flowIter)); + if (SU2_TYPE::Int(flowIter) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(flowIter)); + UnstExt = string(buffer); + restart_filename.append(UnstExt); + } else { + flowIter =config->GetExtIter(); + unsigned short lastindex = restart_filename.find_last_of("."); + restart_filename = restart_filename.substr(0, lastindex); + if ((SU2_TYPE::Int(flowIter) >= 0) && (SU2_TYPE::Int(flowIter) < 10)) SPRINTF (buffer, "_0000%d.dat", SU2_TYPE::Int(flowIter)); + if ((SU2_TYPE::Int(flowIter) >= 10) && (SU2_TYPE::Int(flowIter) < 100)) SPRINTF (buffer, "_000%d.dat", SU2_TYPE::Int(flowIter)); + if ((SU2_TYPE::Int(flowIter) >= 100) && (SU2_TYPE::Int(flowIter) < 1000)) SPRINTF (buffer, "_00%d.dat", SU2_TYPE::Int(flowIter)); + if ((SU2_TYPE::Int(flowIter) >= 1000) && (SU2_TYPE::Int(flowIter) < 10000)) SPRINTF (buffer, "_0%d.dat", SU2_TYPE::Int(flowIter)); + if (SU2_TYPE::Int(flowIter) >= 10000) SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(flowIter)); + UnstExt = string(buffer); + restart_filename.append(UnstExt); + } + + /*--- Open the flow solution from the restart file ---*/ + if (rank == MASTER_NODE) + cout << "Reading in the direct wave solution from iteration " << flowIter << "." << endl;; + restart_file.open(restart_filename.data(), ios::in); + + /*--- In case there is no file ---*/ + if (restart_file.fail()) { + if (rank == MASTER_NODE) + cout << "There is no wave restart file!!" << endl; + exit(EXIT_FAILURE); + } + + /*--- Read the restart file ---*/ + for (iPoint = 0; iPoint < geometry[MESH_0]->GetnPoint(); iPoint++) { + getline(restart_file, text_line); + istringstream point_line(text_line); + point_line >> index >> Solution[0] >> Solution[1]; + node[iPoint]->SetSolution_Direct(Solution); + } + + /*--- Close the restart file ---*/ + restart_file.close(); + +} diff --git a/SU2_CFD/src/solver_structure.cpp b/SU2_CFD/src/solver_structure.cpp index 29534d555da..89bc5f7bda2 100644 --- a/SU2_CFD/src/solver_structure.cpp +++ b/SU2_CFD/src/solver_structure.cpp @@ -1,1997 +1,1997 @@ -/*! - * \file solver_structure.cpp - * \brief Main subrotuines for solving direct, adjoint and linearized problems. - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/solver_structure.hpp" - -CSolver::CSolver(void) { - - /*--- Array initialization ---*/ - OutputHeadingNames = NULL; - Residual_RMS = NULL; - Residual_Max = NULL; - Residual = NULL; - Residual_i = NULL; - Residual_j = NULL; - Point_Max = NULL; - Point_Max_Coord = NULL; - Solution = NULL; - Solution_i = NULL; - Solution_j = NULL; - Vector = NULL; - Vector_i = NULL; - Vector_j = NULL; - Res_Conv = NULL; - Res_Visc = NULL; - Res_Sour = NULL; - Res_Conv_i = NULL; - Res_Visc_i = NULL; - Res_Conv_j = NULL; - Res_Visc_j = NULL; - Jacobian_i = NULL; - Jacobian_j = NULL; - Jacobian_ii = NULL; - Jacobian_ij = NULL; - Jacobian_ji = NULL; - Jacobian_jj = NULL; - Smatrix = NULL; - cvector = NULL; - node = NULL; - nOutputVariables = 0; - -} - -CSolver::~CSolver(void) { - if ( OutputHeadingNames != NULL) { - delete []OutputHeadingNames; - } - // delete [] OutputHeadingNames; - /* unsigned short iVar, iDim; - unsigned long iPoint; - - if (Residual_RMS != NULL) delete [] Residual_RMS; - if (Residual_Max != NULL) delete [] Residual_Max; - if (Residual != NULL) delete [] Residual; - if (Residual_i != NULL) delete [] Residual_i; - if (Residual_j != NULL) delete [] Residual_j; - if (Point_Max != NULL) delete [] Point_Max; - - if (Point_Max_Coord != NULL) { - for (iVar = 0; iVar < nVar; iVar++) - delete Point_Max_Coord[iVar]; - delete [] Point_Max_Coord; - } - - if (Solution != NULL) delete [] Solution; - if (Solution_i != NULL) delete [] Solution_i; - if (Solution_j != NULL) delete [] Solution_j; - if (Vector != NULL) delete [] Vector; - if (Vector_i != NULL) delete [] Vector_i; - if (Vector_j != NULL) delete [] Vector_j; - if (Res_Conv != NULL) delete [] Res_Conv; - if (Res_Visc != NULL) delete [] Res_Visc; - if (Res_Sour != NULL) delete [] Res_Sour; - if (Res_Conv_i != NULL) delete [] Res_Conv_i; - if (Res_Visc_i != NULL) delete [] Res_Visc_i; - if (Res_Visc_j != NULL) delete [] Res_Visc_j; - if (Res_Sour_j != NULL) delete [] Res_Sour_j; - if (rhs != NULL) delete [] rhs; - - if (Jacobian_i != NULL) { - for (iVar = 0; iVar < nVar; iVar++) - delete Jacobian_i[iVar]; - delete [] Jacobian_i; - } - - if (Jacobian_j != NULL) { - for (iVar = 0; iVar < nVar; iVar++) - delete Jacobian_j[iVar]; - delete [] Jacobian_j; - } - - if (Jacobian_MeanFlow_j != NULL) { - for (iVar = 0; iVar < nVar; iVar++) - delete Jacobian_MeanFlow_j[iVar]; - delete [] Jacobian_MeanFlow_j; - } - - if (Jacobian_ii != NULL) { - for (iVar = 0; iVar < nVar; iVar++) - delete Jacobian_ii[iVar]; - delete [] Jacobian_ii; - } - - if (Jacobian_ij != NULL) { - for (iVar = 0; iVar < nVar; iVar++) - delete Jacobian_ij[iVar]; - delete [] Jacobian_ij; - } - - if (Jacobian_ji != NULL) { - for (iVar = 0; iVar < nVar; iVar++) - delete Jacobian_ji[iVar]; - delete [] Jacobian_ji; - } - - if (Jacobian_jj != NULL) { - for (iVar = 0; iVar < nVar; iVar++) - delete Jacobian_jj[iVar]; - delete [] Jacobian_jj; - } - - if (Smatrix != NULL) { - for (iDim = 0; iDim < nDim; iDim++) - delete Smatrix[iDim]; - delete [] Smatrix; - } - - if (cvector != NULL) { - for (iVar = 0; iVar < nVar; iVar++) - delete cvector[iVar]; - delete [] cvector; - } - - if (node != NULL) { - for (iPoint = 0; iPoint < nPoint; iPoint++) { - delete node[iPoint]; - } - delete [] node; - } - - // delete [] **StiffMatrix_Elem; - // delete [] **StiffMatrix_Node;*/ - -} - -void CSolver::SetResidual_RMS(CGeometry *geometry, CConfig *config) { - unsigned short iVar; - -#ifndef HAVE_MPI - - for (iVar = 0; iVar < nVar; iVar++) { - - if (GetRes_RMS(iVar) != GetRes_RMS(iVar)) { - cout << "\n !!! Error: SU2 has diverged. Now exiting... !!! \n" << endl; - exit(EXIT_FAILURE); - } - - SetRes_RMS(iVar, max(EPS*EPS, sqrt(GetRes_RMS(iVar)/geometry->GetnPoint()))); - - } - -#else - - int nProcessor, iProcessor, rank; - MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - su2double *sbuf_residual, *rbuf_residual, *sbuf_coord, *rbuf_coord, *Coord; - unsigned long *sbuf_point, *rbuf_point, Local_nPointDomain, Global_nPointDomain; - unsigned short iDim; - - /*--- Set the L2 Norm residual in all the processors ---*/ - - sbuf_residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) sbuf_residual[iVar] = 0.0; - rbuf_residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) rbuf_residual[iVar] = 0.0; - - for (iVar = 0; iVar < nVar; iVar++) sbuf_residual[iVar] = GetRes_RMS(iVar); - Local_nPointDomain = geometry->GetnPointDomain(); - - - SU2_MPI::Allreduce(sbuf_residual, rbuf_residual, nVar, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&Local_nPointDomain, &Global_nPointDomain, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - - - for (iVar = 0; iVar < nVar; iVar++) { - - if (rbuf_residual[iVar] != rbuf_residual[iVar]) { - - if (rank == MASTER_NODE) - cout << "\n !!! Error: SU2 has diverged. Now exiting... !!! \n" << endl; - - MPI_Abort(MPI_COMM_WORLD,1); - - } - - SetRes_RMS(iVar, max(EPS*EPS, sqrt(rbuf_residual[iVar]/Global_nPointDomain))); - - } - - delete [] sbuf_residual; - delete [] rbuf_residual; - - /*--- Set the Maximum residual in all the processors ---*/ - sbuf_residual = new su2double [nVar]; for (iVar = 0; iVar < nVar; iVar++) sbuf_residual[iVar] = 0.0; - sbuf_point = new unsigned long [nVar]; for (iVar = 0; iVar < nVar; iVar++) sbuf_point[iVar] = 0; - sbuf_coord = new su2double[nVar*nDim]; for (iVar = 0; iVar < nVar*nDim; iVar++) sbuf_coord[iVar] = 0.0; - - rbuf_residual = new su2double [nProcessor*nVar]; for (iVar = 0; iVar < nProcessor*nVar; iVar++) rbuf_residual[iVar] = 0.0; - rbuf_point = new unsigned long [nProcessor*nVar]; for (iVar = 0; iVar < nProcessor*nVar; iVar++) rbuf_point[iVar] = 0; - rbuf_coord = new su2double[nProcessor*nVar*nDim]; for (iVar = 0; iVar < nProcessor*nVar*nDim; iVar++) rbuf_coord[iVar] = 0.0; - - for (iVar = 0; iVar < nVar; iVar++) { - sbuf_residual[iVar] = GetRes_Max(iVar); - sbuf_point[iVar] = GetPoint_Max(iVar); - Coord = GetPoint_Max_Coord(iVar); - for (iDim = 0; iDim < nDim; iDim++) - sbuf_coord[iVar*nDim+iDim] = Coord[iDim]; - } - - SU2_MPI::Allgather(sbuf_residual, nVar, MPI_DOUBLE, rbuf_residual, nVar, MPI_DOUBLE, MPI_COMM_WORLD); - SU2_MPI::Allgather(sbuf_point, nVar, MPI_UNSIGNED_LONG, rbuf_point, nVar, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(sbuf_coord, nVar*nDim, MPI_DOUBLE, rbuf_coord, nVar*nDim, MPI_DOUBLE, MPI_COMM_WORLD); - - for (iVar = 0; iVar < nVar; iVar++) { - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - AddRes_Max(iVar, rbuf_residual[iProcessor*nVar+iVar], rbuf_point[iProcessor*nVar+iVar], &rbuf_coord[iProcessor*nVar*nDim+iVar*nDim]); - } - } - - delete [] sbuf_residual; - delete [] rbuf_residual; - - delete [] sbuf_point; - delete [] rbuf_point; - - delete [] sbuf_coord; - delete [] rbuf_coord; - -#endif - -} - -void CSolver::SetGrid_Movement_Residual (CGeometry *geometry, CConfig *config) { - - unsigned short nDim = geometry->GetnDim(); - unsigned short nVar = GetnVar(); - su2double ProjGridVel, *Normal; - - // Loop interior edges - for (unsigned long iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - const unsigned long iPoint = geometry->edge[iEdge]->GetNode(0); - const unsigned long jPoint = geometry->edge[iEdge]->GetNode(1); - - // Solution at each edge point - su2double *Solution_i = node[iPoint]->GetSolution(); - su2double *Solution_j = node[jPoint]->GetSolution(); - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = 0.5* (Solution_i[iVar] + Solution_j[iVar]); - - // Grid Velocity at each edge point - su2double *GridVel_i = geometry->node[iPoint]->GetGridVel(); - su2double *GridVel_j = geometry->node[jPoint]->GetGridVel(); - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Vector[iDim] = 0.5* (GridVel_i[iDim] + GridVel_j[iDim]); - - Normal = geometry->edge[iEdge]->GetNormal(); - // dS = geometry->edge[iEdge]->GetArea_or_Length(); - - ProjGridVel = 0.0; - for (unsigned short iDim = 0; iDim < nDim; iDim++) - ProjGridVel += Vector[iDim]*Normal[iDim]; - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Residual[iVar] = ProjGridVel*Solution[iVar]; - - LinSysRes.SubtractBlock(iPoint, Residual); - LinSysRes.AddBlock(jPoint, Residual); - - } - - // Loop boundary edges - for (unsigned short iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - for (unsigned long iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - const unsigned long Point = geometry->vertex[iMarker][iVertex]->GetNode(); - - // Solution at each edge point - su2double *Solution = node[Point]->GetSolution(); - - // Grid Velocity at each edge point - su2double *GridVel = geometry->node[Point]->GetGridVel(); - - // Summed normal components - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - // dS = geometry->vertex[iMarker][iVertex]->GetArea_or_Length(); - - ProjGridVel = 0.0; - for (unsigned short iDim = 0; iDim < nDim; iDim++) - ProjGridVel -= GridVel[iDim]*Normal[iDim]; - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Residual[iVar] = ProjGridVel*Solution[iVar]; - - LinSysRes.AddBlock(Point, Residual); - } - } -} - -void CSolver::SetAuxVar_Gradient_GG(CGeometry *geometry) { - - // Internal variables - unsigned long Point = 0, iPoint = 0, jPoint = 0, iEdge, iVertex; - unsigned short nDim = geometry->GetnDim(), iDim, iMarker; - - su2double AuxVar_Vertex, AuxVar_i, AuxVar_j, AuxVar_Average; - su2double *Gradient, DualArea, Partial_Res, Grad_Val, *Normal; - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - node[iPoint]->SetAuxVarGradientZero(); // Set Gradient to Zero - - // Loop interior edges - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - - AuxVar_i = node[iPoint]->GetAuxVar(); - AuxVar_j = node[jPoint]->GetAuxVar(); - - Normal = geometry->edge[iEdge]->GetNormal(); - AuxVar_Average = 0.5 * ( AuxVar_i + AuxVar_j); - for (iDim = 0; iDim < nDim; iDim++) { - Partial_Res = AuxVar_Average*Normal[iDim]; - node[iPoint]->AddAuxVarGradient(iDim, Partial_Res); - node[jPoint]->SubtractAuxVarGradient(iDim, Partial_Res); - } - } - - // Loop boundary edges - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - Point = geometry->vertex[iMarker][iVertex]->GetNode(); - AuxVar_Vertex = node[Point]->GetAuxVar(); - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - for (iDim = 0; iDim < nDim; iDim++) { - Partial_Res = AuxVar_Vertex*Normal[iDim]; - node[Point]->SubtractAuxVarGradient(iDim, Partial_Res); - } - } - - for (iPoint=0; iPointGetnPoint(); iPoint++) - for (iDim = 0; iDim < nDim; iDim++) { - Gradient = node[iPoint]->GetAuxVarGradient(); - DualArea = geometry->node[iPoint]->GetVolume(); - Grad_Val = Gradient[iDim]/(DualArea+EPS); - node[iPoint]->SetAuxVarGradient(iDim, Grad_Val); - } -} - -void CSolver::SetAuxVar_Gradient_LS(CGeometry *geometry, CConfig *config) { - - unsigned short iDim, jDim, iNeigh; - unsigned short nDim = geometry->GetnDim(); - unsigned long iPoint, jPoint; - su2double *Coord_i, *Coord_j, AuxVar_i, AuxVar_j, weight, r11, r12, r13, r22, r23, r23_a, - r23_b, r33, z11, z12, z13, z22, z23, z33, detR2, product; - bool singular = false; - - su2double *cvector = new su2double [nDim]; - - /*--- Loop over points of the grid ---*/ - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - Coord_i = geometry->node[iPoint]->GetCoord(); - AuxVar_i = node[iPoint]->GetAuxVar(); - - /*--- Inizialization of variables ---*/ - for (iDim = 0; iDim < nDim; iDim++) - cvector[iDim] = 0.0; - - r11 = 0.0; r12 = 0.0; r13 = 0.0; r22 = 0.0; - r23 = 0.0; r23_a = 0.0; r23_b = 0.0; r33 = 0.0; - - for (iNeigh = 0; iNeigh < geometry->node[iPoint]->GetnPoint(); iNeigh++) { - jPoint = geometry->node[iPoint]->GetPoint(iNeigh); - Coord_j = geometry->node[jPoint]->GetCoord(); - AuxVar_j = node[jPoint]->GetAuxVar(); - - weight = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - weight += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); - - /*--- Sumations for entries of upper triangular matrix R ---*/ - - if (fabs(weight) > EPS) { - r11 += (Coord_j[0]-Coord_i[0])*(Coord_j[0]-Coord_i[0])/weight; - r12 += (Coord_j[0]-Coord_i[0])*(Coord_j[1]-Coord_i[1])/weight; - r22 += (Coord_j[1]-Coord_i[1])*(Coord_j[1]-Coord_i[1])/weight; - if (nDim == 3) { - r13 += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; - r23_a += (Coord_j[1]-Coord_i[1])*(Coord_j[2]-Coord_i[2])/weight; - r23_b += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; - r33 += (Coord_j[2]-Coord_i[2])*(Coord_j[2]-Coord_i[2])/weight; - } - - /*--- Entries of c:= transpose(A)*b ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - cvector[iDim] += (Coord_j[iDim]-Coord_i[iDim])*(AuxVar_j-AuxVar_i)/(weight); - } - - } - - /*--- Entries of upper triangular matrix R ---*/ - - if (fabs(r11) < EPS) r11 = EPS; - r11 = sqrt(r11); - r12 = r12/r11; - r22 = sqrt(r22-r12*r12); - if (fabs(r22) < EPS) r22 = EPS; - if (nDim == 3) { - r13 = r13/r11; - r23 = r23_a/(r22) - r23_b*r12/(r11*r22); - r33 = sqrt(r33-r23*r23-r13*r13); - } - - /*--- Compute determinant ---*/ - - if (nDim == 2) detR2 = (r11*r22)*(r11*r22); - else detR2 = (r11*r22*r33)*(r11*r22*r33); - - /*--- Detect singular matrices ---*/ - - if (fabs(detR2) < EPS) singular = true; - - /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ - - if (singular) { - for (iDim = 0; iDim < nDim; iDim++) - for (jDim = 0; jDim < nDim; jDim++) - Smatrix[iDim][jDim] = 0.0; - } - else { - if (nDim == 2) { - Smatrix[0][0] = (r12*r12+r22*r22)/detR2; - Smatrix[0][1] = -r11*r12/detR2; - Smatrix[1][0] = Smatrix[0][1]; - Smatrix[1][1] = r11*r11/detR2; - } - else { - z11 = r22*r33; z12 = -r12*r33; z13 = r12*r23-r13*r22; - z22 = r11*r33; z23 = -r11*r23; z33 = r11*r22; - Smatrix[0][0] = (z11*z11+z12*z12+z13*z13)/detR2; - Smatrix[0][1] = (z12*z22+z13*z23)/detR2; - Smatrix[0][2] = (z13*z33)/detR2; - Smatrix[1][0] = Smatrix[0][1]; - Smatrix[1][1] = (z22*z22+z23*z23)/detR2; - Smatrix[1][2] = (z23*z33)/detR2; - Smatrix[2][0] = Smatrix[0][2]; - Smatrix[2][1] = Smatrix[1][2]; - Smatrix[2][2] = (z33*z33)/detR2; - } - } - - /*--- Computation of the gradient: S*c ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - product = 0.0; - for (jDim = 0; jDim < nDim; jDim++) - product += Smatrix[iDim][jDim]*cvector[jDim]; - if (geometry->node[iPoint]->GetDomain()) - node[iPoint]->SetAuxVarGradient(iDim, product); - } - } - - delete [] cvector; - -} - -void CSolver::SetSolution_Gradient_GG(CGeometry *geometry, CConfig *config) { - unsigned long Point = 0, iPoint = 0, jPoint = 0, iEdge, iVertex; - unsigned short iVar, iDim, iMarker; - su2double *Solution_Vertex, *Solution_i, *Solution_j, Solution_Average, **Gradient, DualArea, - Partial_Res, Grad_Val, *Normal; - - /*--- Set Gradient to Zero ---*/ - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) - node[iPoint]->SetGradientZero(); - - /*--- Loop interior edges ---*/ - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - - Solution_i = node[iPoint]->GetSolution(); - Solution_j = node[jPoint]->GetSolution(); - Normal = geometry->edge[iEdge]->GetNormal(); - for (iVar = 0; iVar< nVar; iVar++) { - Solution_Average = 0.5 * (Solution_i[iVar] + Solution_j[iVar]); - for (iDim = 0; iDim < nDim; iDim++) { - Partial_Res = Solution_Average*Normal[iDim]; - if (geometry->node[iPoint]->GetDomain()) - node[iPoint]->AddGradient(iVar, iDim, Partial_Res); - if (geometry->node[jPoint]->GetDomain()) - node[jPoint]->SubtractGradient(iVar, iDim, Partial_Res); - } - } - } - - /*--- Loop boundary edges ---*/ - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - Point = geometry->vertex[iMarker][iVertex]->GetNode(); - Solution_Vertex = node[Point]->GetSolution(); - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) { - Partial_Res = Solution_Vertex[iVar]*Normal[iDim]; - if (geometry->node[Point]->GetDomain()) - node[Point]->SubtractGradient(iVar, iDim, Partial_Res); - } - } - } - - /*--- Compute gradient ---*/ - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) { - Gradient = node[iPoint]->GetGradient(); - DualArea = geometry->node[iPoint]->GetVolume(); - Grad_Val = Gradient[iVar][iDim] / (DualArea+EPS); - node[iPoint]->SetGradient(iVar, iDim, Grad_Val); - } - - /*--- Gradient MPI ---*/ - Set_MPI_Solution_Gradient(geometry, config); - -} - -void CSolver::SetSolution_Gradient_LS(CGeometry *geometry, CConfig *config) { - - unsigned short iDim, jDim, iVar, iNeigh; - unsigned long iPoint, jPoint; - su2double *Coord_i, *Coord_j, *Solution_i, *Solution_j, - r11, r12, r13, r22, r23, r23_a, r23_b, r33, weight, detR2, z11, z12, z13, - z22, z23, z33, product; - bool singular = false; - - su2double **cvector = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - cvector[iVar] = new su2double [nDim]; - - /*--- Loop over points of the grid ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { - - /*--- Get coordinates ---*/ - - Coord_i = geometry->node[iPoint]->GetCoord(); - - /*--- Get consevative solution ---*/ - - Solution_i = node[iPoint]->GetSolution(); - - /*--- Inizialization of variables ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - cvector[iVar][iDim] = 0.0; - - r11 = 0.0; r12 = 0.0; r13 = 0.0; r22 = 0.0; - r23 = 0.0; r23_a = 0.0; r23_b = 0.0; r33 = 0.0; - - for (iNeigh = 0; iNeigh < geometry->node[iPoint]->GetnPoint(); iNeigh++) { - jPoint = geometry->node[iPoint]->GetPoint(iNeigh); - Coord_j = geometry->node[jPoint]->GetCoord(); - - Solution_j = node[jPoint]->GetSolution(); - - weight = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - weight += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); - - /*--- Sumations for entries of upper triangular matrix R ---*/ - - if (fabs(weight) > EPS) { - r11 += (Coord_j[0]-Coord_i[0])*(Coord_j[0]-Coord_i[0])/weight; - r12 += (Coord_j[0]-Coord_i[0])*(Coord_j[1]-Coord_i[1])/weight; - r22 += (Coord_j[1]-Coord_i[1])*(Coord_j[1]-Coord_i[1])/weight; - if (nDim == 3) { - r13 += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; - r23_a += (Coord_j[1]-Coord_i[1])*(Coord_j[2]-Coord_i[2])/weight; - r23_b += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; - r33 += (Coord_j[2]-Coord_i[2])*(Coord_j[2]-Coord_i[2])/weight; - } - - /*--- Entries of c:= transpose(A)*b ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - cvector[iVar][iDim] += (Coord_j[iDim]-Coord_i[iDim])*(Solution_j[iVar]-Solution_i[iVar])/weight; - } - - } - - /*--- Entries of upper triangular matrix R ---*/ - - if (fabs(r11) < EPS) r11 = EPS; - r11 = sqrt(r11); - r12 = r12/(r11); - r22 = sqrt(r22-r12*r12); - if (fabs(r22) < EPS) r22 = EPS; - if (nDim == 3) { - r13 = r13/(r11); - r23 = r23_a/(r22) - r23_b*r12/(r11*r22); - r33 = sqrt(r33-r23*r23-r13*r13); - } - - /*--- Compute determinant ---*/ - - if (nDim == 2) detR2 = (r11*r22)*(r11*r22); - else detR2 = (r11*r22*r33)*(r11*r22*r33); - - /*--- Detect singular matrices ---*/ - - if (fabs(detR2) < EPS) singular = true; - - /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ - - if (singular) { - for (iDim = 0; iDim < nDim; iDim++) - for (jDim = 0; jDim < nDim; jDim++) - Smatrix[iDim][jDim] = 0.0; - } - else { - if (nDim == 2) { - Smatrix[0][0] = (r12*r12+r22*r22)/detR2; - Smatrix[0][1] = -r11*r12/detR2; - Smatrix[1][0] = Smatrix[0][1]; - Smatrix[1][1] = r11*r11/detR2; - } - else { - z11 = r22*r33; z12 = -r12*r33; z13 = r12*r23-r13*r22; - z22 = r11*r33; z23 = -r11*r23; z33 = r11*r22; - Smatrix[0][0] = (z11*z11+z12*z12+z13*z13)/detR2; - Smatrix[0][1] = (z12*z22+z13*z23)/detR2; - Smatrix[0][2] = (z13*z33)/detR2; - Smatrix[1][0] = Smatrix[0][1]; - Smatrix[1][1] = (z22*z22+z23*z23)/detR2; - Smatrix[1][2] = (z23*z33)/detR2; - Smatrix[2][0] = Smatrix[0][2]; - Smatrix[2][1] = Smatrix[1][2]; - Smatrix[2][2] = (z33*z33)/detR2; - } - } - - /*--- Computation of the gradient: S*c ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - for (iDim = 0; iDim < nDim; iDim++) { - product = 0.0; - for (jDim = 0; jDim < nDim; jDim++) - product += Smatrix[iDim][jDim]*cvector[iVar][jDim]; - node[iPoint]->SetGradient(iVar, iDim, product); - } - } - - } - - /*--- Deallocate memory ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - delete [] cvector[iVar]; - delete [] cvector; - - /*--- Gradient MPI ---*/ - - Set_MPI_Solution_Gradient(geometry, config); - -} - -void CSolver::SetGridVel_Gradient(CGeometry *geometry, CConfig *config) { - unsigned short iDim, jDim, iVar, iNeigh; - unsigned long iPoint, jPoint; - su2double *Coord_i, *Coord_j, *Solution_i, *Solution_j, Smatrix[3][3], - r11, r12, r13, r22, r23, r23_a, r23_b, r33, weight, detR2, z11, z12, z13, - z22, z23, z33, product; - su2double **cvector; - - /*--- Note that all nVar entries in this routine have been changed to nDim ---*/ - cvector = new su2double* [nDim]; - for (iVar = 0; iVar < nDim; iVar++) - cvector[iVar] = new su2double [nDim]; - - /*--- Loop over points of the grid ---*/ - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { - - Coord_i = geometry->node[iPoint]->GetCoord(); - Solution_i = geometry->node[iPoint]->GetGridVel(); - - /*--- Inizialization of variables ---*/ - for (iVar = 0; iVar < nDim; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - cvector[iVar][iDim] = 0.0; - r11 = 0.0; r12 = 0.0; r13 = 0.0; r22 = 0.0; r23 = 0.0; r23_a = 0.0; r23_b = 0.0; r33 = 0.0; - - for (iNeigh = 0; iNeigh < geometry->node[iPoint]->GetnPoint(); iNeigh++) { - jPoint = geometry->node[iPoint]->GetPoint(iNeigh); - Coord_j = geometry->node[jPoint]->GetCoord(); - Solution_j = geometry->node[jPoint]->GetGridVel(); - - weight = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - weight += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); - - /*--- Sumations for entries of upper triangular matrix R ---*/ - r11 += (Coord_j[0]-Coord_i[0])*(Coord_j[0]-Coord_i[0])/(weight); - r12 += (Coord_j[0]-Coord_i[0])*(Coord_j[1]-Coord_i[1])/(weight); - r22 += (Coord_j[1]-Coord_i[1])*(Coord_j[1]-Coord_i[1])/(weight); - if (nDim == 3) { - r13 += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/(weight); - r23_a += (Coord_j[1]-Coord_i[1])*(Coord_j[2]-Coord_i[2])/(weight); - r23_b += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/(weight); - r33 += (Coord_j[2]-Coord_i[2])*(Coord_j[2]-Coord_i[2])/(weight); - } - - /*--- Entries of c:= transpose(A)*b ---*/ - for (iVar = 0; iVar < nDim; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - cvector[iVar][iDim] += (Coord_j[iDim]-Coord_i[iDim])*(Solution_j[iVar]-Solution_i[iVar])/(weight); - } - - /*--- Entries of upper triangular matrix R ---*/ - r11 = sqrt(r11); - r12 = r12/(r11); - r22 = sqrt(r22-r12*r12); - if (nDim == 3) { - r13 = r13/(r11); - r23 = r23_a/(r22) - r23_b*r12/(r11*r22); - r33 = sqrt(r33-r23*r23-r13*r13); - } - /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ - if (nDim == 2) { - detR2 = (r11*r22)*(r11*r22); - Smatrix[0][0] = (r12*r12+r22*r22)/(detR2); - Smatrix[0][1] = -r11*r12/(detR2); - Smatrix[1][0] = Smatrix[0][1]; - Smatrix[1][1] = r11*r11/(detR2); - } - else { - detR2 = (r11*r22*r33)*(r11*r22*r33); - z11 = r22*r33; - z12 = -r12*r33; - z13 = r12*r23-r13*r22; - z22 = r11*r33; - z23 = -r11*r23; - z33 = r11*r22; - Smatrix[0][0] = (z11*z11+z12*z12+z13*z13)/(detR2); - Smatrix[0][1] = (z12*z22+z13*z23)/(detR2); - Smatrix[0][2] = (z13*z33)/(detR2); - Smatrix[1][0] = Smatrix[0][1]; - Smatrix[1][1] = (z22*z22+z23*z23)/(detR2); - Smatrix[1][2] = (z23*z33)/(detR2); - Smatrix[2][0] = Smatrix[0][2]; - Smatrix[2][1] = Smatrix[1][2]; - Smatrix[2][2] = (z33*z33)/(detR2); - } - /*--- Computation of the gradient: S*c ---*/ - for (iVar = 0; iVar < nDim; iVar++) { - for (iDim = 0; iDim < nDim; iDim++) { - product = 0.0; - for (jDim = 0; jDim < nDim; jDim++) - product += Smatrix[iDim][jDim]*cvector[iVar][jDim]; - geometry->node[iPoint]->SetGridVel_Grad(iVar, iDim, product); - } - } - } - - /*--- Deallocate memory ---*/ - for (iVar = 0; iVar < nDim; iVar++) - delete [] cvector[iVar]; - delete [] cvector; - - /*--- Gradient MPI ---*/ - // TO DO!!! - //Set_MPI_Solution_Gradient(geometry, config); - -} - -void CSolver::SetAuxVar_Surface_Gradient(CGeometry *geometry, CConfig *config) { - - unsigned short iDim, jDim, iNeigh, iMarker, Boundary; - unsigned short nDim = geometry->GetnDim(); - unsigned long iPoint, jPoint, iVertex; - su2double *Coord_i, *Coord_j, AuxVar_i, AuxVar_j; - su2double **Smatrix, *cvector; - - Smatrix = new su2double* [nDim]; - cvector = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Smatrix[iDim] = new su2double [nDim]; - - - /*--- Loop over boundary markers to select those for Euler or NS walls ---*/ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Boundary = config->GetMarker_All_KindBC(iMarker); - switch (Boundary) { - case EULER_WALL: - case HEAT_FLUX: - case ISOTHERMAL: - - /*--- Loop over points on the surface (Least-Squares approximation) ---*/ - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if (geometry->node[iPoint]->GetDomain()) { - Coord_i = geometry->node[iPoint]->GetCoord(); - AuxVar_i = node[iPoint]->GetAuxVar(); - - /*--- Inizialization of variables ---*/ - for (iDim = 0; iDim < nDim; iDim++) - cvector[iDim] = 0.0; - su2double r11 = 0.0, r12 = 0.0, r13 = 0.0, r22 = 0.0, r23 = 0.0, r23_a = 0.0, r23_b = 0.0, r33 = 0.0; - - for (iNeigh = 0; iNeigh < geometry->node[iPoint]->GetnPoint(); iNeigh++) { - jPoint = geometry->node[iPoint]->GetPoint(iNeigh); - Coord_j = geometry->node[jPoint]->GetCoord(); - AuxVar_j = node[jPoint]->GetAuxVar(); - - su2double weight = 0; - for (iDim = 0; iDim < nDim; iDim++) - weight += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); - - /*--- Sumations for entries of upper triangular matrix R ---*/ - r11 += (Coord_j[0]-Coord_i[0])*(Coord_j[0]-Coord_i[0])/weight; - r12 += (Coord_j[0]-Coord_i[0])*(Coord_j[1]-Coord_i[1])/weight; - r22 += (Coord_j[1]-Coord_i[1])*(Coord_j[1]-Coord_i[1])/weight; - if (nDim == 3) { - r13 += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; - r23_a += (Coord_j[1]-Coord_i[1])*(Coord_j[2]-Coord_i[2])/weight; - r23_b += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; - r33 += (Coord_j[2]-Coord_i[2])*(Coord_j[2]-Coord_i[2])/weight; - } - - /*--- Entries of c:= transpose(A)*b ---*/ - for (iDim = 0; iDim < nDim; iDim++) - cvector[iDim] += (Coord_j[iDim]-Coord_i[iDim])*(AuxVar_j-AuxVar_i)/weight; - } - - /*--- Entries of upper triangular matrix R ---*/ - r11 = sqrt(r11); - r12 = r12/r11; - r22 = sqrt(r22-r12*r12); - if (nDim == 3) { - r13 = r13/r11; - r23 = r23_a/r22 - r23_b*r12/(r11*r22); - r33 = sqrt(r33-r23*r23-r13*r13); - } - /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ - if (nDim == 2) { - su2double detR2 = (r11*r22)*(r11*r22); - Smatrix[0][0] = (r12*r12+r22*r22)/detR2; - Smatrix[0][1] = -r11*r12/detR2; - Smatrix[1][0] = Smatrix[0][1]; - Smatrix[1][1] = r11*r11/detR2; - } - else { - su2double detR2 = (r11*r22*r33)*(r11*r22*r33); - su2double z11, z12, z13, z22, z23, z33; // aux vars - z11 = r22*r33; - z12 = -r12*r33; - z13 = r12*r23-r13*r22; - z22 = r11*r33; - z23 = -r11*r23; - z33 = r11*r22; - Smatrix[0][0] = (z11*z11+z12*z12+z13*z13)/detR2; - Smatrix[0][1] = (z12*z22+z13*z23)/detR2; - Smatrix[0][2] = (z13*z33)/detR2; - Smatrix[1][0] = Smatrix[0][1]; - Smatrix[1][1] = (z22*z22+z23*z23)/detR2; - Smatrix[1][2] = (z23*z33)/detR2; - Smatrix[2][0] = Smatrix[0][2]; - Smatrix[2][1] = Smatrix[1][2]; - Smatrix[2][2] = (z33*z33)/detR2; - } - /*--- Computation of the gradient: S*c ---*/ - su2double product; - for (iDim = 0; iDim < nDim; iDim++) { - product = 0.0; - for (jDim = 0; jDim < nDim; jDim++) - product += Smatrix[iDim][jDim]*cvector[jDim]; - node[iPoint]->SetAuxVarGradient(iDim, product); - } - } - } /*--- End of loop over surface points ---*/ - break; - default: - break; - } - } - - /*--- Memory deallocation ---*/ - for (iDim = 0; iDim < nDim; iDim++) - delete [] Smatrix[iDim]; - delete [] cvector; - delete [] Smatrix; -} - -void CSolver::SetSolution_Limiter(CGeometry *geometry, CConfig *config) { - - unsigned long iEdge, iPoint, jPoint; - unsigned short iVar, iDim; - su2double **Gradient_i, **Gradient_j, *Coord_i, *Coord_j, *Solution_i, *Solution_j, - dave, LimK, eps1, eps2, dm, dp, du, ds, limiter, SharpEdge_Distance; - - /*--- Initialize solution max and solution min in the entire domain --*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - node[iPoint]->SetSolution_Max(iVar, -EPS); - node[iPoint]->SetSolution_Min(iVar, EPS); - } - } - - /*--- Establish bounds for Spekreijse monotonicity by finding max & min values of neighbor variables --*/ - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - /*--- Point identification, Normal vector and area ---*/ - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - - /*--- Get the conserved variables ---*/ - - Solution_i = node[iPoint]->GetSolution(); - Solution_j = node[jPoint]->GetSolution(); - - /*--- Compute the maximum, and minimum values for nodes i & j ---*/ - - for (iVar = 0; iVar < nVar; iVar++) { - du = (Solution_j[iVar] - Solution_i[iVar]); - node[iPoint]->SetSolution_Min(iVar, min(node[iPoint]->GetSolution_Min(iVar), du)); - node[iPoint]->SetSolution_Max(iVar, max(node[iPoint]->GetSolution_Max(iVar), du)); - node[jPoint]->SetSolution_Min(iVar, min(node[jPoint]->GetSolution_Min(iVar), -du)); - node[jPoint]->SetSolution_Max(iVar, max(node[jPoint]->GetSolution_Max(iVar), -du)); - } - - } - - /*--- Initialize the limiter --*/ - - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - node[iPoint]->SetLimiter(iVar, 2.0); - } - } - - /*--- Venkatakrishnan limiter ---*/ - - if (config->GetKind_SlopeLimit() == VENKATAKRISHNAN) { - - /*-- Get limiter parameters from the configuration file ---*/ - - dave = config->GetRefElemLength(); - LimK = config->GetLimiterCoeff(); - eps1 = LimK*dave; - eps2 = eps1*eps1*eps1; - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - Gradient_i = node[iPoint]->GetGradient(); - Gradient_j = node[jPoint]->GetGradient(); - Coord_i = geometry->node[iPoint]->GetCoord(); - Coord_j = geometry->node[jPoint]->GetCoord(); - - for (iVar = 0; iVar < nVar; iVar++) { - - /*--- Calculate the interface left gradient, delta- (dm) ---*/ - - dm = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - dm += 0.5*(Coord_j[iDim]-Coord_i[iDim])*Gradient_i[iVar][iDim]; - - /*--- Calculate the interface right gradient, delta+ (dp) ---*/ - - if ( dm > 0.0 ) dp = node[iPoint]->GetSolution_Max(iVar); - else dp = node[iPoint]->GetSolution_Min(iVar); - - limiter = ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); - - if (limiter < node[iPoint]->GetLimiter(iVar)) - node[iPoint]->SetLimiter(iVar, limiter); - - /*-- Repeat for point j on the edge ---*/ - - dm = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - dm += 0.5*(Coord_i[iDim]-Coord_j[iDim])*Gradient_j[iVar][iDim]; - - if ( dm > 0.0 ) dp = node[jPoint]->GetSolution_Max(iVar); - else dp = node[jPoint]->GetSolution_Min(iVar); - - limiter = ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); - - if (limiter < node[jPoint]->GetLimiter(iVar)) - node[jPoint]->SetLimiter(iVar, limiter); - } - } - } - - /*--- Sharp edges limiter ---*/ - - if (config->GetKind_SlopeLimit() == SHARP_EDGES) { - - /*-- Get limiter parameters from the configuration file ---*/ - - dave = config->GetRefElemLength(); - LimK = config->GetLimiterCoeff(); - eps1 = LimK*dave; - eps2 = eps1*eps1*eps1; - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - Gradient_i = node[iPoint]->GetGradient(); - Gradient_j = node[jPoint]->GetGradient(); - Coord_i = geometry->node[iPoint]->GetCoord(); - Coord_j = geometry->node[jPoint]->GetCoord(); - - for (iVar = 0; iVar < nVar; iVar++) { - - /*--- Calculate the interface left gradient, delta- (dm) ---*/ - - dm = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - dm += 0.5*(Coord_j[iDim]-Coord_i[iDim])*Gradient_i[iVar][iDim]; - - /*--- Calculate the interface right gradient, delta+ (dp) ---*/ - - if ( dm > 0.0 ) dp = node[iPoint]->GetSolution_Max(iVar); - else dp = node[iPoint]->GetSolution_Min(iVar); - - /*--- Compute the distance to a sharp edge ---*/ - - SharpEdge_Distance = (geometry->node[iPoint]->GetSharpEdge_Distance() - config->GetSharpEdgesCoeff()*eps1); - ds = 0.0; - if (SharpEdge_Distance < -eps1) ds = 0.0; - if (fabs(SharpEdge_Distance) <= eps1) ds = 0.5*(1.0+(SharpEdge_Distance/eps1)+(1.0/PI_NUMBER)*sin(PI_NUMBER*SharpEdge_Distance/eps1)); - if (SharpEdge_Distance > eps1) ds = 1.0; - - limiter = ds * ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); - - if (limiter < node[iPoint]->GetLimiter(iVar)) - node[iPoint]->SetLimiter(iVar, limiter); - - /*-- Repeat for point j on the edge ---*/ - - dm = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - dm += 0.5*(Coord_i[iDim]-Coord_j[iDim])*Gradient_j[iVar][iDim]; - - if ( dm > 0.0 ) dp = node[jPoint]->GetSolution_Max(iVar); - else dp = node[jPoint]->GetSolution_Min(iVar); - - /*--- Compute the distance to a sharp edge ---*/ - - SharpEdge_Distance = (geometry->node[jPoint]->GetSharpEdge_Distance() - config->GetSharpEdgesCoeff()*eps1); - ds = 0.0; - if (SharpEdge_Distance < -eps1) ds = 0.0; - if (fabs(SharpEdge_Distance) <= eps1) ds = 0.5*(1.0+(SharpEdge_Distance/eps1)+(1.0/PI_NUMBER)*sin(PI_NUMBER*SharpEdge_Distance/eps1)); - if (SharpEdge_Distance > eps1) ds = 1.0; - - limiter = ds * ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); - - if (limiter < node[jPoint]->GetLimiter(iVar)) - node[jPoint]->SetLimiter(iVar, limiter); - - } - } - } - - /*--- Sharp edges limiter ---*/ - - if (config->GetKind_SlopeLimit() == SOLID_WALL_DISTANCE) { - - /*-- Get limiter parameters from the configuration file ---*/ - - dave = config->GetRefElemLength(); - LimK = config->GetLimiterCoeff(); - eps1 = LimK*dave; - eps2 = eps1*eps1*eps1; - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - Gradient_i = node[iPoint]->GetGradient(); - Gradient_j = node[jPoint]->GetGradient(); - Coord_i = geometry->node[iPoint]->GetCoord(); - Coord_j = geometry->node[jPoint]->GetCoord(); - - for (iVar = 0; iVar < nVar; iVar++) { - - /*--- Calculate the interface left gradient, delta- (dm) ---*/ - - dm = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - dm += 0.5*(Coord_j[iDim]-Coord_i[iDim])*Gradient_i[iVar][iDim]; - - /*--- Calculate the interface right gradient, delta+ (dp) ---*/ - - if ( dm > 0.0 ) dp = node[iPoint]->GetSolution_Max(iVar); - else dp = node[iPoint]->GetSolution_Min(iVar); - - /*--- Compute the distance to a sharp edge ---*/ - - SharpEdge_Distance = (geometry->node[iPoint]->GetWall_Distance() - config->GetSharpEdgesCoeff()*eps1); - ds = 0.0; - if (SharpEdge_Distance < -eps1) ds = 0.0; - if (fabs(SharpEdge_Distance) <= eps1) ds = 0.5*(1.0+(SharpEdge_Distance/eps1)+(1.0/PI_NUMBER)*sin(PI_NUMBER*SharpEdge_Distance/eps1)); - if (SharpEdge_Distance > eps1) ds = 1.0; - - limiter = ds * ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); - - if (limiter < node[iPoint]->GetLimiter(iVar)) - node[iPoint]->SetLimiter(iVar, limiter); - - /*-- Repeat for point j on the edge ---*/ - - dm = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - dm += 0.5*(Coord_i[iDim]-Coord_j[iDim])*Gradient_j[iVar][iDim]; - - if ( dm > 0.0 ) dp = node[jPoint]->GetSolution_Max(iVar); - else dp = node[jPoint]->GetSolution_Min(iVar); - - /*--- Compute the distance to a sharp edge ---*/ - - SharpEdge_Distance = (geometry->node[jPoint]->GetWall_Distance() - config->GetSharpEdgesCoeff()*eps1); - ds = 0.0; - if (SharpEdge_Distance < -eps1) ds = 0.0; - if (fabs(SharpEdge_Distance) <= eps1) ds = 0.5*(1.0+(SharpEdge_Distance/eps1)+(1.0/PI_NUMBER)*sin(PI_NUMBER*SharpEdge_Distance/eps1)); - if (SharpEdge_Distance > eps1) ds = 1.0; - - limiter = ds * ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); - - if (limiter < node[jPoint]->GetLimiter(iVar)) - node[jPoint]->SetLimiter(iVar, limiter); - - } - } - } - - - /*--- Limiter MPI ---*/ - - Set_MPI_Solution_Limiter(geometry, config); - -} - -void CSolver::SetPressureLaplacian(CGeometry *geometry, su2double *PressureLaplacian) { - - unsigned long Point = 0, iPoint = 0, jPoint = 0, iEdge, iVertex; - unsigned short iMarker, iVar; - su2double DualArea, Partial_Res, *Normal; - su2double **UxVar_Gradient, **UyVar_Gradient; - - UxVar_Gradient = new su2double* [geometry->GetnPoint()]; - UyVar_Gradient = new su2double* [geometry->GetnPoint()]; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - UxVar_Gradient[iPoint] = new su2double [2]; - UyVar_Gradient[iPoint] = new su2double [2]; - } - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - for (iVar = 0; iVar < 2; iVar++) { - UxVar_Gradient[iPoint][iVar] = 0.0; - UyVar_Gradient[iPoint][iVar] = 0.0; - } - - /*--- Loop interior edges ---*/ - - for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { - iPoint = geometry->edge[iEdge]->GetNode(0); - jPoint = geometry->edge[iEdge]->GetNode(1); - Normal = geometry->edge[iEdge]->GetNormal(); - - Partial_Res = 0.5 * ( node[iPoint]->GetSolution(1) + node[jPoint]->GetSolution(1)) * Normal[0]; - UxVar_Gradient[iPoint][0] += Partial_Res; - UxVar_Gradient[jPoint][0] -= Partial_Res; - - Partial_Res = 0.5 * ( node[iPoint]->GetSolution(1) + node[jPoint]->GetSolution(1)) * Normal[1]; - UxVar_Gradient[iPoint][1] += Partial_Res; - UxVar_Gradient[jPoint][1] -= Partial_Res; - - Partial_Res = 0.5 * ( node[iPoint]->GetSolution(2) + node[jPoint]->GetSolution(2)) * Normal[0]; - UyVar_Gradient[iPoint][0] += Partial_Res; - UyVar_Gradient[jPoint][0] -= Partial_Res; - - Partial_Res = 0.5 * ( node[iPoint]->GetSolution(2) + node[jPoint]->GetSolution(2)) * Normal[1]; - UyVar_Gradient[iPoint][1] += Partial_Res; - UyVar_Gradient[jPoint][1] -= Partial_Res; - - } - - /*--- Loop boundary edges ---*/ - - for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { - Point = geometry->vertex[iMarker][iVertex]->GetNode(); - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - - Partial_Res = node[Point]->GetSolution(1) * Normal[0]; - UxVar_Gradient[Point][0] -= Partial_Res; - - Partial_Res = node[Point]->GetSolution(1) * Normal[1]; - UxVar_Gradient[Point][1] -= Partial_Res; - - Partial_Res = node[Point]->GetSolution(2) * Normal[0]; - UyVar_Gradient[Point][0] -= Partial_Res; - - Partial_Res = node[Point]->GetSolution(2) * Normal[1]; - UyVar_Gradient[Point][1] -= Partial_Res; - } - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - DualArea = geometry->node[iPoint]->GetVolume(); - PressureLaplacian[iPoint] = (UxVar_Gradient[iPoint][0]*UxVar_Gradient[iPoint][0] + UyVar_Gradient[iPoint][1]*UyVar_Gradient[iPoint][1] + - UxVar_Gradient[iPoint][1]*UyVar_Gradient[iPoint][0] + UxVar_Gradient[iPoint][0]*UyVar_Gradient[iPoint][1])/DualArea ; - - } - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - delete[] UxVar_Gradient[iPoint]; - delete[] UyVar_Gradient[iPoint]; - } - - delete[] UxVar_Gradient; - delete[] UyVar_Gradient; - -} - -void CSolver::Gauss_Elimination(su2double** A, su2double* rhs, unsigned short nVar) { - - short iVar, jVar, kVar; - su2double weight, aux; - - if (nVar == 1) - rhs[0] /= A[0][0]; - else { - - /*--- Transform system in Upper Matrix ---*/ - - for (iVar = 1; iVar < (short)nVar; iVar++) { - for (jVar = 0; jVar < iVar; jVar++) { - weight = A[iVar][jVar]/A[jVar][jVar]; - for (kVar = jVar; kVar < (short)nVar; kVar++) - A[iVar][kVar] -= weight*A[jVar][kVar]; - rhs[iVar] -= weight*rhs[jVar]; - } - } - - /*--- Backwards substitution ---*/ - - rhs[nVar-1] = rhs[nVar-1]/A[nVar-1][nVar-1]; - for (iVar = (short)nVar-2; iVar >= 0; iVar--) { - aux = 0; - for (jVar = iVar+1; jVar < (short)nVar; jVar++) - aux += A[iVar][jVar]*rhs[jVar]; - rhs[iVar] = (rhs[iVar]-aux)/A[iVar][iVar]; - if (iVar == 0) break; - } - } - -} - -void CSolver::Aeroelastic(CSurfaceMovement *surface_movement, CGeometry *geometry, CConfig *config, unsigned long ExtIter) { - - /*--- Variables used for Aeroelastic case ---*/ - - su2double Cl, Cd, Cn, Ct, Cm, Cn_rot; - su2double Alpha = config->GetAoA()*PI_NUMBER/180.0; - vector structural_solution(4,0.0); //contains solution(displacements and rates) of typical section wing model. - - unsigned short iMarker, iMarker_Monitoring, Monitoring; - string Marker_Tag, Monitoring_Tag; - - /*--- Loop over markers and find the ones being monitored. ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Monitoring = config->GetMarker_All_Monitoring(iMarker); - if (Monitoring == YES) { - - /*--- Find the particular marker being monitored and get the forces acting on it. ---*/ - - for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { - Monitoring_Tag = config->GetMarker_Monitoring(iMarker_Monitoring); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); - if (Marker_Tag == Monitoring_Tag) { - - Cl = GetSurface_CLift(iMarker_Monitoring); - Cd = GetSurface_CDrag(iMarker_Monitoring); - - /*--- For typical section wing model want the force normal to the airfoil (in the direction of the spring) ---*/ - Cn = Cl*cos(Alpha) + Cd*sin(Alpha); - Ct = -Cl*sin(Alpha) + Cd*cos(Alpha); - - Cm = GetSurface_CMz(iMarker_Monitoring); - - /*--- Calculate forces for the Typical Section Wing Model taking into account rotation ---*/ - - /*--- Note that the calculation of the forces and the subsequent displacements ... - is only correct for the airfoil that starts at the 0 degree position ---*/ - - if (config->GetKind_GridMovement(ZONE_0) == AEROELASTIC_RIGID_MOTION) { - su2double Omega, dt, psi; - dt = config->GetDelta_UnstTimeND(); - Omega = (config->GetRotation_Rate_Z(ZONE_0)/config->GetOmega_Ref()); - psi = Omega*(dt*ExtIter); - - /*--- Correct for the airfoil starting position (This is hardcoded in here) ---*/ - if (Monitoring_Tag == "Airfoil1") { - psi = psi + 0.0; - } - else if (Monitoring_Tag == "Airfoil2") { - psi = psi + 2.0/3.0*PI_NUMBER; - } - else if (Monitoring_Tag == "Airfoil3") { - psi = psi + 4.0/3.0*PI_NUMBER; - } - else - cout << "WARNING: There is a marker that we are monitoring that doesn't match the values hardcoded above!" << endl; - - cout << Monitoring_Tag << " position " << psi*180.0/PI_NUMBER << " degrees. " << endl; - - Cn_rot = Cn*cos(psi) - Ct*sin(psi); //Note the signs are different for accounting for the AOA. - Cn = Cn_rot; - } - - /*--- Solve the aeroelastic equations for the particular marker(surface) ---*/ - - SolveTypicalSectionWingModel(geometry, Cn, Cm, config, iMarker_Monitoring, structural_solution); - - break; - } - } - - /*--- Compute the new surface node locations ---*/ - surface_movement->AeroelasticDeform(geometry, config, ExtIter, iMarker, iMarker_Monitoring, structural_solution); - - } - - } - -} - -void CSolver::SetUpTypicalSectionWingModel(vector >& Phi, vector& omega, CConfig *config) { - - /*--- Retrieve values from the config file ---*/ - su2double w_h = config->GetAeroelastic_Frequency_Plunge(); - su2double w_a = config->GetAeroelastic_Frequency_Pitch(); - su2double x_a = config->GetAeroelastic_CG_Location(); - su2double r_a = sqrt(config->GetAeroelastic_Radius_Gyration_Squared()); - su2double w = w_h/w_a; - - // Mass Matrix - vector > M(2,vector(2,0.0)); - M[0][0] = 1; - M[0][1] = x_a; - M[1][0] = x_a; - M[1][1] = r_a*r_a; - - // Stiffness Matrix - // vector > K(2,vector(2,0.0)); - // K[0][0] = (w_h/w_a)*(w_h/w_a); - // K[0][1] = 0.0; - // K[1][0] = 0.0; - // K[1][1] = r_a*r_a; - - /* Eigenvector and Eigenvalue Matrices of the Generalized EigenValue Problem. */ - - vector > Omega2(2,vector(2,0.0)); - su2double aux; // auxiliary variable - aux = sqrt(pow(r_a,2)*pow(w,4) - 2*pow(r_a,2)*pow(w,2) + pow(r_a,2) + 4*pow(x_a,2)*pow(w,2)); - Phi[0][0] = (r_a * (r_a - r_a*pow(w,2) + aux)) / (2*x_a*pow(w, 2)); - Phi[0][1] = (r_a * (r_a - r_a*pow(w,2) - aux)) / (2*x_a*pow(w, 2)); - Phi[1][0] = 1.0; - Phi[1][1] = 1.0; - - Omega2[0][0] = (r_a * (r_a + r_a*pow(w,2) - aux)) / (2*(pow(r_a, 2) - pow(x_a, 2))); - Omega2[0][1] = 0; - Omega2[1][0] = 0; - Omega2[1][1] = (r_a * (r_a + r_a*pow(w,2) + aux)) / (2*(pow(r_a, 2) - pow(x_a, 2))); - - /* Nondimesionalize the Eigenvectors such that Phi'*M*Phi = I and PHI'*K*PHI = Omega */ - // Phi'*M*Phi = D - // D^(-1/2)*Phi'*M*Phi*D^(-1/2) = D^(-1/2)*D^(1/2)*D^(1/2)*D^(-1/2) = I, D^(-1/2) = inv(sqrt(D)) - // Phi = Phi*D^(-1/2) - - vector > Aux(2,vector(2,0.0)); - vector > D(2,vector(2,0.0)); - // Aux = M*Phi - for (int i=0; i<2; i++) { - for (int j=0; j<2; j++) { - Aux[i][j] = 0; - for (int k=0; k<2; k++) { - Aux[i][j] += M[i][k]*Phi[k][j]; - } - } - } - - // D = Phi'*Aux - for (int i=0; i<2; i++) { - for (int j=0; j<2; j++) { - D[i][j] = 0; - for (int k=0; k<2; k++) { - D[i][j] += Phi[k][i]*Aux[k][j]; //PHI transpose - } - } - } - - //Modify the first column - Phi[0][0] = Phi[0][0] * 1/sqrt(D[0][0]); - Phi[1][0] = Phi[1][0] * 1/sqrt(D[0][0]); - //Modify the second column - Phi[0][1] = Phi[0][1] * 1/sqrt(D[1][1]); - Phi[1][1] = Phi[1][1] * 1/sqrt(D[1][1]); - - // Sqrt of the eigenvalues (frequency of vibration of the modes) - omega[0] = sqrt(Omega2[0][0]); - omega[1] = sqrt(Omega2[1][1]); - -} - -void CSolver::SolveTypicalSectionWingModel(CGeometry *geometry, su2double Cl, su2double Cm, CConfig *config, unsigned short iMarker, vector& displacements) { - - /*--- The aeroelastic model solved in this routine is the typical section wing model - The details of the implementation are similar to those found in J.J. Alonso - "Fully-Implicit Time-Marching Aeroelastic Solutions" 1994. ---*/ - - /*--- Retrieve values from the config file ---*/ - su2double w_alpha = config->GetAeroelastic_Frequency_Pitch(); - su2double vf = config->GetAeroelastic_Flutter_Speed_Index(); - su2double b = config->GetLength_Reynolds()/2.0; // airfoil semichord, Reynolds length is by defaul 1.0 - su2double dt = config->GetDelta_UnstTimeND(); - dt = dt*w_alpha; //Non-dimensionalize the structural time. - - /*--- Structural Equation damping ---*/ - vector xi(2,0.0); - - /*--- Eigenvectors and Eigenvalues of the Generalized EigenValue Problem. ---*/ - vector > Phi(2,vector(2,0.0)); // generalized eigenvectors. - vector w(2,0.0); // sqrt of the generalized eigenvalues (frequency of vibration of the modes). - SetUpTypicalSectionWingModel(Phi, w, config); - - /*--- Solving the Decoupled Aeroelastic Problem with second order time discretization Eq (9) ---*/ - - /*--- Solution variables description. //x[j][i], j-entry, i-equation. // Time (n+1)->np1, n->n, (n-1)->n1 ---*/ - vector > x_np1(2,vector(2,0.0)); - - /*--- Values from previous movement of spring at true time step n+1 - We use this values because we are solving for delta changes not absolute changes ---*/ - vector > x_np1_old = config->GetAeroelastic_np1(iMarker); - - /*--- Values at previous timesteps. ---*/ - vector > x_n = config->GetAeroelastic_n(iMarker); - vector > x_n1 = config->GetAeroelastic_n1(iMarker); - - /*--- Set up of variables used to solve the structural problem. ---*/ - vector f_tilde(2,0.0); - vector > A_inv(2,vector(2,0.0)); - su2double detA; - su2double s1, s2; - vector rhs(2,0.0); //right hand side - vector eta(2,0.0); - vector eta_dot(2,0.0); - - /*--- Forcing Term ---*/ - su2double cons = vf*vf/PI_NUMBER; - vector f(2,0.0); - f[0] = cons*(-Cl); - f[1] = cons*(2*-Cm); - - //f_tilde = Phi'*f - for (int i=0; i<2; i++) { - f_tilde[i] = 0; - for (int k=0; k<2; k++) { - f_tilde[i] += Phi[k][i]*f[k]; //PHI transpose - } - } - - /*--- solve each decoupled equation (The inverse of the 2x2 matrix is provided) ---*/ - for (int i=0; i<2; i++) { - /* Matrix Inverse */ - detA = 9.0/(4.0*dt*dt) + 3*w[i]*xi[i]/(dt) + w[i]*w[i]; - A_inv[0][0] = 1/detA * (3/(2.0*dt) + 2*xi[i]*w[i]); - A_inv[0][1] = 1/detA * 1; - A_inv[1][0] = 1/detA * -w[i]*w[i]; - A_inv[1][1] = 1/detA * 3/(2.0*dt); - - /* Source Terms from previous iterations */ - s1 = (-4*x_n[0][i] + x_n1[0][i])/(2.0*dt); - s2 = (-4*x_n[1][i] + x_n1[1][i])/(2.0*dt); - - /* Problem Right Hand Side */ - rhs[0] = -s1; - rhs[1] = f_tilde[i]-s2; - - /* Solve the equations */ - x_np1[0][i] = A_inv[0][0]*rhs[0] + A_inv[0][1]*rhs[1]; - x_np1[1][i] = A_inv[1][0]*rhs[0] + A_inv[1][1]*rhs[1]; - - eta[i] = x_np1[0][i]-x_np1_old[0][i]; // For displacements, the change(deltas) is used. - eta_dot[i] = x_np1[1][i]; // For velocities, absolute values are used. - } - - /*--- Transform back from the generalized coordinates to get the actual displacements in plunge and pitch q = Phi*eta ---*/ - vector q(2,0.0); - vector q_dot(2,0.0); - for (int i=0; i<2; i++) { - q[i] = 0; - q_dot[i] = 0; - for (int k=0; k<2; k++) { - q[i] += Phi[i][k]*eta[k]; - q_dot[i] += Phi[i][k]*eta_dot[k]; - } - } - - su2double dh = b*q[0]; - su2double dalpha = q[1]; - - su2double h_dot = w_alpha*b*q_dot[0]; //The w_a brings it back to actual time. - su2double alpha_dot = w_alpha*q_dot[1]; - - /*--- Set the solution of the structural equations ---*/ - displacements[0] = dh; - displacements[1] = dalpha; - displacements[2] = h_dot; - displacements[3] = alpha_dot; - - /*--- Calculate the total plunge and total pitch displacements for the unsteady step by summing the displacement at each sudo time step ---*/ - su2double pitch, plunge; - pitch = config->GetAeroelastic_pitch(iMarker); - plunge = config->GetAeroelastic_plunge(iMarker); - - config->SetAeroelastic_pitch(iMarker , pitch+dalpha); - config->SetAeroelastic_plunge(iMarker , plunge+dh/b); - - /*--- Set the Aeroelastic solution at time n+1. This gets update every sudo time step - and after convering the sudo time step the solution at n+1 get moved to the solution at n - in SetDualTime_Solver method ---*/ - - config->SetAeroelastic_np1(iMarker, x_np1); - -} - -CBaselineSolver::CBaselineSolver(void) : CSolver() { } - -CBaselineSolver::CBaselineSolver(CGeometry *geometry, CConfig *config, unsigned short iMesh) : CSolver() { - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - unsigned long iPoint, index, iPoint_Global; - long iPoint_Local; - unsigned short iField, iVar; - string Tag, text_line, AdjExt, UnstExt; - unsigned long iExtIter = config->GetExtIter(); - - /*--- Define geometry constants in the solver structure ---*/ - - nDim = geometry->GetnDim(); - - /*--- Allocate the node variables ---*/ - - node = new CVariable*[geometry->GetnPoint()]; - - /*--- Restart the solution from file information ---*/ - - ifstream restart_file; - string filename; - - /*--- Retrieve filename from config ---*/ - - if (config->GetAdjoint() || config->GetDiscrete_Adjoint()) { - filename = config->GetSolution_AdjFileName(); - filename = config->GetObjFunc_Extension(filename); - } else { - filename = config->GetSolution_FlowFileName(); - } - - /*--- Unsteady problems require an iteration number to be appended. ---*/ - - if (config->GetWrt_Unsteady() || config->GetUnsteady_Simulation() == TIME_SPECTRAL) { - filename = config->GetUnsteady_FileName(filename, SU2_TYPE::Int(iExtIter)); - } - - /*--- Open the restart file ---*/ - - restart_file.open(filename.data(), ios::in); - - /*--- In case there is no restart file ---*/ - - if (restart_file.fail()) { - if (rank == MASTER_NODE) - cout << "SU2 flow file " << filename << " not found" << endl; - -#ifndef HAVE_MPI - exit(EXIT_FAILURE); -#else - MPI_Abort(MPI_COMM_WORLD,1); - MPI_Finalize(); -#endif - - } - - /*--- Output the file name to the console. ---*/ - - if (rank == MASTER_NODE) - cout << "Reading and storing the solution from " << filename << "." << endl; - - /*--- In case this is a parallel simulation, we need to perform the - Global2Local index transformation first. ---*/ - - long *Global2Local = new long[geometry->GetGlobal_nPointDomain()]; - - /*--- First, set all indices to a negative value by default ---*/ - - for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) - Global2Local[iPoint] = -1; - - /*--- Now fill array with the transform values only for local points ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) - Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; - - - /*--- Identify the number of fields (and names) in the restart file ---*/ - - getline (restart_file, text_line); - stringstream ss(text_line); - while (ss >> Tag) { - config->fields.push_back(Tag); - if (ss.peek() == ',') ss.ignore(); - } - - /*--- Set the number of variables, one per field in the - restart file (without including the PointID) ---*/ - - nVar = config->fields.size() - 1; - su2double *Solution = new su2double[nVar]; - - /*--- Read all lines in the restart file ---*/ - - iPoint_Global = 0; - while (getline (restart_file, text_line)) { - istringstream point_line(text_line); - - /*--- Retrieve local index. If this node from the restart file lives - on a different processor, the value of iPoint_Local will be -1. - Otherwise, the local index for this node on the current processor - will be returned and used to instantiate the vars. ---*/ - - iPoint_Local = Global2Local[iPoint_Global]; - if (iPoint_Local >= 0) { - - /*--- The PointID is not stored --*/ - point_line >> index; - - /*--- Store the solution (starting with node coordinates) --*/ - for (iField = 0; iField < nVar; iField++) - point_line >> Solution[iField]; - - node[iPoint_Local] = new CBaselineVariable(Solution, nVar, config); - } - iPoint_Global++; - } - - /*--- Instantiate the variable class with an arbitrary solution - at any halo/periodic nodes. The initial solution can be arbitrary, - because a send/recv is performed immediately in the solver. ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = 0.0; - - for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) - node[iPoint] = new CBaselineVariable(Solution, nVar, config); - - /*--- Close the restart file ---*/ - - restart_file.close(); - - /*--- Free memory needed for the transformation ---*/ - - delete [] Global2Local; - delete [] Solution; - - /*--- MPI solution ---*/ - - Set_MPI_Solution(geometry, config); - -} - -void CBaselineSolver::Set_MPI_Solution(CGeometry *geometry, CConfig *config) { - unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; - unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; - su2double rotMatrix[3][3], *transl, *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL, *Solution = NULL; - - Solution = new su2double[nVar]; - -#ifdef HAVE_MPI - int send_to, receive_from; - MPI_Status status; -#endif - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; - -#endif - - nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; - nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; - - /*--- Allocate Receive and send buffers ---*/ - - Buffer_Receive_U = new su2double [nBufferR_Vector]; - Buffer_Send_U = new su2double[nBufferS_Vector]; - - /*--- Copy the solution that should be sended ---*/ - - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution(iVar); - } - -#ifdef HAVE_MPI - - /*--- Send/Receive information using Sendrecv ---*/ - - SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, - Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); - -#else - - /*--- Receive information without MPI ---*/ - - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - for (iVar = 0; iVar < nVar; iVar++) - Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; - } - -#endif - - /*--- Deallocate send buffer ---*/ - - delete [] Buffer_Send_U; - - /*--- Do the coordinate transformation ---*/ - - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Find point and its type of transformation ---*/ - - iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); - iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); - - /*--- Retrieve the supplied periodic information. ---*/ - - transl = config->GetPeriodicTranslate(iPeriodic_Index); - angles = config->GetPeriodicRotation(iPeriodic_Index); - - /*--- Store angles separately for clarity. ---*/ - - theta = angles[0]; phi = angles[1]; psi = angles[2]; - cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); - sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, - then z-axis. Note that this is the transpose of the matrix - used during the preprocessing stage. ---*/ - - rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; - - /*--- Copy conserved variables before performing transformation. ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = Buffer_Receive_U[iVar*nVertexR+iVertex]; - - /*--- Rotate the spatial coordinates & momentum. ---*/ - - if (nDim == 2) { - - /*--- Coords ---*/ - - Solution[0] = (rotMatrix[0][0]*Buffer_Receive_U[0*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_U[1*nVertexR+iVertex] - transl[0]); - Solution[1] = (rotMatrix[1][0]*Buffer_Receive_U[0*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_U[1*nVertexR+iVertex] - transl[1]); - /*--- Momentum ---*/ - - Solution[nDim+1] = (rotMatrix[0][0]*Buffer_Receive_U[(nDim+1)*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_U[(nDim+2)*nVertexR+iVertex]); - Solution[nDim+2] = (rotMatrix[1][0]*Buffer_Receive_U[(nDim+1)*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_U[(nDim+2)*nVertexR+iVertex]); - } else { - - /*--- Coords ---*/ - - Solution[0] = (rotMatrix[0][0]*Buffer_Receive_U[0*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[0][2]*Buffer_Receive_U[2*nVertexR+iVertex] - transl[0]); - Solution[1] = (rotMatrix[1][0]*Buffer_Receive_U[0*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[1][2]*Buffer_Receive_U[2*nVertexR+iVertex] - transl[1]); - Solution[2] = (rotMatrix[2][0]*Buffer_Receive_U[0*nVertexR+iVertex] + - rotMatrix[2][1]*Buffer_Receive_U[1*nVertexR+iVertex] + - rotMatrix[2][2]*Buffer_Receive_U[2*nVertexR+iVertex] - transl[2]); - - /*--- Momentum ---*/ - - Solution[nDim+1] = (rotMatrix[0][0]*Buffer_Receive_U[nDim+1*nVertexR+iVertex] + - rotMatrix[0][1]*Buffer_Receive_U[nDim+2*nVertexR+iVertex] + - rotMatrix[0][2]*Buffer_Receive_U[nDim+3*nVertexR+iVertex]); - Solution[nDim+2] = (rotMatrix[1][0]*Buffer_Receive_U[nDim+1*nVertexR+iVertex] + - rotMatrix[1][1]*Buffer_Receive_U[nDim+2*nVertexR+iVertex] + - rotMatrix[1][2]*Buffer_Receive_U[nDim+3*nVertexR+iVertex]); - Solution[nDim+3] = (rotMatrix[2][0]*Buffer_Receive_U[nDim+1*nVertexR+iVertex] + - rotMatrix[2][1]*Buffer_Receive_U[nDim+2*nVertexR+iVertex] + - rotMatrix[2][2]*Buffer_Receive_U[nDim+3*nVertexR+iVertex]); - } - - /*--- Copy transformed conserved variables back into buffer. ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - node[iPoint]->SetSolution(iVar, Solution[iVar]); - - } - - /*--- Deallocate receive buffer ---*/ - - delete [] Buffer_Receive_U; - - } - - } - - delete [] Solution; - -} - -void CBaselineSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig *config, int val_iter) { - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Restart the solution from file information ---*/ - string filename; - unsigned long iPoint, index; - string UnstExt, text_line, AdjExt; - ifstream solution_file; - unsigned short iField; - unsigned long iExtIter = config->GetExtIter(); - - /*--- Retrieve filename from config ---*/ - if (config->GetAdjoint()) { - filename = config->GetSolution_AdjFileName(); - filename = config->GetObjFunc_Extension(filename); - } else { - filename = config->GetSolution_FlowFileName(); - } - - /*--- Unsteady problems require an iteration number to be appended. ---*/ - if (config->GetWrt_Unsteady() || config->GetUnsteady_Simulation() == TIME_SPECTRAL) { - filename = config->GetUnsteady_FileName(filename, SU2_TYPE::Int(iExtIter)); - } - - /*--- Open the restart file ---*/ - solution_file.open(filename.data(), ios::in); - - /*--- In case there is no file ---*/ - if (solution_file.fail()) { - if (rank == MASTER_NODE) - cout << "There is no SU2 restart file!!" << endl; - exit(EXIT_FAILURE); - } - - /*--- Output the file name to the console. ---*/ - if (rank == MASTER_NODE) - cout << "Reading and storing the solution from " << filename - << "." << endl; - - /*--- Set the number of variables, one per field in the - restart file (without including the PointID) ---*/ - nVar = config->fields.size() - 1; - su2double *Solution = new su2double[nVar]; - - /*--- In case this is a parallel simulation, we need to perform the - Global2Local index transformation first. ---*/ - long *Global2Local = NULL; - Global2Local = new long[geometry[ZONE_0]->GetGlobal_nPointDomain()]; - /*--- First, set all indices to a negative value by default ---*/ - for (iPoint = 0; iPoint < geometry[ZONE_0]->GetGlobal_nPointDomain(); iPoint++) { - Global2Local[iPoint] = -1; - } - - /*--- Now fill array with the transform values only for local points ---*/ - for (iPoint = 0; iPoint < geometry[ZONE_0]->GetnPointDomain(); iPoint++) { - Global2Local[geometry[ZONE_0]->node[iPoint]->GetGlobalIndex()] = iPoint; - } - - /*--- Read all lines in the restart file ---*/ - long iPoint_Local = 0; unsigned long iPoint_Global = 0; - - /*--- The first line is the header ---*/ - getline (solution_file, text_line); - - while (getline (solution_file, text_line)) { - istringstream point_line(text_line); - - /*--- Retrieve local index. If this node from the restart file lives - on a different processor, the value of iPoint_Local will be -1, as - initialized above. Otherwise, the local index for this node on the - current processor will be returned and used to instantiate the vars. ---*/ - iPoint_Local = Global2Local[iPoint_Global]; - if (iPoint_Local >= 0) { - - /*--- The PointID is not stored --*/ - point_line >> index; - - /*--- Store the solution (starting with node coordinates) --*/ - for (iField = 0; iField < nVar; iField++) - point_line >> Solution[iField]; - - node[iPoint_Local]->SetSolution(Solution); - - - } - iPoint_Global++; - } - - /*--- Close the restart file ---*/ - solution_file.close(); - - /*--- Free memory needed for the transformation ---*/ - delete [] Global2Local; - delete [] Solution; - -} - -CBaselineSolver::~CBaselineSolver(void) { } +/*! + * \file solver_structure.cpp + * \brief Main subrotuines for solving direct, adjoint and linearized problems. + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/solver_structure.hpp" + +CSolver::CSolver(void) { + + /*--- Array initialization ---*/ + OutputHeadingNames = NULL; + Residual_RMS = NULL; + Residual_Max = NULL; + Residual = NULL; + Residual_i = NULL; + Residual_j = NULL; + Point_Max = NULL; + Point_Max_Coord = NULL; + Solution = NULL; + Solution_i = NULL; + Solution_j = NULL; + Vector = NULL; + Vector_i = NULL; + Vector_j = NULL; + Res_Conv = NULL; + Res_Visc = NULL; + Res_Sour = NULL; + Res_Conv_i = NULL; + Res_Visc_i = NULL; + Res_Conv_j = NULL; + Res_Visc_j = NULL; + Jacobian_i = NULL; + Jacobian_j = NULL; + Jacobian_ii = NULL; + Jacobian_ij = NULL; + Jacobian_ji = NULL; + Jacobian_jj = NULL; + Smatrix = NULL; + cvector = NULL; + node = NULL; + nOutputVariables = 0; + +} + +CSolver::~CSolver(void) { + if ( OutputHeadingNames != NULL) { + delete []OutputHeadingNames; + } + // delete [] OutputHeadingNames; + /* unsigned short iVar, iDim; + unsigned long iPoint; + + if (Residual_RMS != NULL) delete [] Residual_RMS; + if (Residual_Max != NULL) delete [] Residual_Max; + if (Residual != NULL) delete [] Residual; + if (Residual_i != NULL) delete [] Residual_i; + if (Residual_j != NULL) delete [] Residual_j; + if (Point_Max != NULL) delete [] Point_Max; + + if (Point_Max_Coord != NULL) { + for (iVar = 0; iVar < nVar; iVar++) + delete Point_Max_Coord[iVar]; + delete [] Point_Max_Coord; + } + + if (Solution != NULL) delete [] Solution; + if (Solution_i != NULL) delete [] Solution_i; + if (Solution_j != NULL) delete [] Solution_j; + if (Vector != NULL) delete [] Vector; + if (Vector_i != NULL) delete [] Vector_i; + if (Vector_j != NULL) delete [] Vector_j; + if (Res_Conv != NULL) delete [] Res_Conv; + if (Res_Visc != NULL) delete [] Res_Visc; + if (Res_Sour != NULL) delete [] Res_Sour; + if (Res_Conv_i != NULL) delete [] Res_Conv_i; + if (Res_Visc_i != NULL) delete [] Res_Visc_i; + if (Res_Visc_j != NULL) delete [] Res_Visc_j; + if (Res_Sour_j != NULL) delete [] Res_Sour_j; + if (rhs != NULL) delete [] rhs; + + if (Jacobian_i != NULL) { + for (iVar = 0; iVar < nVar; iVar++) + delete Jacobian_i[iVar]; + delete [] Jacobian_i; + } + + if (Jacobian_j != NULL) { + for (iVar = 0; iVar < nVar; iVar++) + delete Jacobian_j[iVar]; + delete [] Jacobian_j; + } + + if (Jacobian_MeanFlow_j != NULL) { + for (iVar = 0; iVar < nVar; iVar++) + delete Jacobian_MeanFlow_j[iVar]; + delete [] Jacobian_MeanFlow_j; + } + + if (Jacobian_ii != NULL) { + for (iVar = 0; iVar < nVar; iVar++) + delete Jacobian_ii[iVar]; + delete [] Jacobian_ii; + } + + if (Jacobian_ij != NULL) { + for (iVar = 0; iVar < nVar; iVar++) + delete Jacobian_ij[iVar]; + delete [] Jacobian_ij; + } + + if (Jacobian_ji != NULL) { + for (iVar = 0; iVar < nVar; iVar++) + delete Jacobian_ji[iVar]; + delete [] Jacobian_ji; + } + + if (Jacobian_jj != NULL) { + for (iVar = 0; iVar < nVar; iVar++) + delete Jacobian_jj[iVar]; + delete [] Jacobian_jj; + } + + if (Smatrix != NULL) { + for (iDim = 0; iDim < nDim; iDim++) + delete Smatrix[iDim]; + delete [] Smatrix; + } + + if (cvector != NULL) { + for (iVar = 0; iVar < nVar; iVar++) + delete cvector[iVar]; + delete [] cvector; + } + + if (node != NULL) { + for (iPoint = 0; iPoint < nPoint; iPoint++) { + delete node[iPoint]; + } + delete [] node; + } + + // delete [] **StiffMatrix_Elem; + // delete [] **StiffMatrix_Node;*/ + +} + +void CSolver::SetResidual_RMS(CGeometry *geometry, CConfig *config) { + unsigned short iVar; + +#ifndef HAVE_MPI + + for (iVar = 0; iVar < nVar; iVar++) { + + if (GetRes_RMS(iVar) != GetRes_RMS(iVar)) { + cout << "\n !!! Error: SU2 has diverged. Now exiting... !!! \n" << endl; + exit(EXIT_FAILURE); + } + + SetRes_RMS(iVar, max(EPS*EPS, sqrt(GetRes_RMS(iVar)/geometry->GetnPoint()))); + + } + +#else + + int nProcessor, iProcessor, rank; + MPI_Comm_size(MPI_COMM_WORLD, &nProcessor); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + su2double *sbuf_residual, *rbuf_residual, *sbuf_coord, *rbuf_coord, *Coord; + unsigned long *sbuf_point, *rbuf_point, Local_nPointDomain, Global_nPointDomain; + unsigned short iDim; + + /*--- Set the L2 Norm residual in all the processors ---*/ + + sbuf_residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) sbuf_residual[iVar] = 0.0; + rbuf_residual = new su2double[nVar]; for (iVar = 0; iVar < nVar; iVar++) rbuf_residual[iVar] = 0.0; + + for (iVar = 0; iVar < nVar; iVar++) sbuf_residual[iVar] = GetRes_RMS(iVar); + Local_nPointDomain = geometry->GetnPointDomain(); + + + SU2_MPI::Allreduce(sbuf_residual, rbuf_residual, nVar, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&Local_nPointDomain, &Global_nPointDomain, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + + + for (iVar = 0; iVar < nVar; iVar++) { + + if (rbuf_residual[iVar] != rbuf_residual[iVar]) { + + if (rank == MASTER_NODE) + cout << "\n !!! Error: SU2 has diverged. Now exiting... !!! \n" << endl; + + MPI_Abort(MPI_COMM_WORLD,1); + + } + + SetRes_RMS(iVar, max(EPS*EPS, sqrt(rbuf_residual[iVar]/Global_nPointDomain))); + + } + + delete [] sbuf_residual; + delete [] rbuf_residual; + + /*--- Set the Maximum residual in all the processors ---*/ + sbuf_residual = new su2double [nVar]; for (iVar = 0; iVar < nVar; iVar++) sbuf_residual[iVar] = 0.0; + sbuf_point = new unsigned long [nVar]; for (iVar = 0; iVar < nVar; iVar++) sbuf_point[iVar] = 0; + sbuf_coord = new su2double[nVar*nDim]; for (iVar = 0; iVar < nVar*nDim; iVar++) sbuf_coord[iVar] = 0.0; + + rbuf_residual = new su2double [nProcessor*nVar]; for (iVar = 0; iVar < nProcessor*nVar; iVar++) rbuf_residual[iVar] = 0.0; + rbuf_point = new unsigned long [nProcessor*nVar]; for (iVar = 0; iVar < nProcessor*nVar; iVar++) rbuf_point[iVar] = 0; + rbuf_coord = new su2double[nProcessor*nVar*nDim]; for (iVar = 0; iVar < nProcessor*nVar*nDim; iVar++) rbuf_coord[iVar] = 0.0; + + for (iVar = 0; iVar < nVar; iVar++) { + sbuf_residual[iVar] = GetRes_Max(iVar); + sbuf_point[iVar] = GetPoint_Max(iVar); + Coord = GetPoint_Max_Coord(iVar); + for (iDim = 0; iDim < nDim; iDim++) + sbuf_coord[iVar*nDim+iDim] = Coord[iDim]; + } + + SU2_MPI::Allgather(sbuf_residual, nVar, MPI_DOUBLE, rbuf_residual, nVar, MPI_DOUBLE, MPI_COMM_WORLD); + SU2_MPI::Allgather(sbuf_point, nVar, MPI_UNSIGNED_LONG, rbuf_point, nVar, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + SU2_MPI::Allgather(sbuf_coord, nVar*nDim, MPI_DOUBLE, rbuf_coord, nVar*nDim, MPI_DOUBLE, MPI_COMM_WORLD); + + for (iVar = 0; iVar < nVar; iVar++) { + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + AddRes_Max(iVar, rbuf_residual[iProcessor*nVar+iVar], rbuf_point[iProcessor*nVar+iVar], &rbuf_coord[iProcessor*nVar*nDim+iVar*nDim]); + } + } + + delete [] sbuf_residual; + delete [] rbuf_residual; + + delete [] sbuf_point; + delete [] rbuf_point; + + delete [] sbuf_coord; + delete [] rbuf_coord; + +#endif + +} + +void CSolver::SetGrid_Movement_Residual (CGeometry *geometry, CConfig *config) { + + unsigned short nDim = geometry->GetnDim(); + unsigned short nVar = GetnVar(); + su2double ProjGridVel, *Normal; + + // Loop interior edges + for (unsigned long iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + const unsigned long iPoint = geometry->edge[iEdge]->GetNode(0); + const unsigned long jPoint = geometry->edge[iEdge]->GetNode(1); + + // Solution at each edge point + su2double *Solution_i = node[iPoint]->GetSolution(); + su2double *Solution_j = node[jPoint]->GetSolution(); + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = 0.5* (Solution_i[iVar] + Solution_j[iVar]); + + // Grid Velocity at each edge point + su2double *GridVel_i = geometry->node[iPoint]->GetGridVel(); + su2double *GridVel_j = geometry->node[jPoint]->GetGridVel(); + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Vector[iDim] = 0.5* (GridVel_i[iDim] + GridVel_j[iDim]); + + Normal = geometry->edge[iEdge]->GetNormal(); + // dS = geometry->edge[iEdge]->GetArea_or_Length(); + + ProjGridVel = 0.0; + for (unsigned short iDim = 0; iDim < nDim; iDim++) + ProjGridVel += Vector[iDim]*Normal[iDim]; + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Residual[iVar] = ProjGridVel*Solution[iVar]; + + LinSysRes.SubtractBlock(iPoint, Residual); + LinSysRes.AddBlock(jPoint, Residual); + + } + + // Loop boundary edges + for (unsigned short iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + for (unsigned long iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + const unsigned long Point = geometry->vertex[iMarker][iVertex]->GetNode(); + + // Solution at each edge point + su2double *Solution = node[Point]->GetSolution(); + + // Grid Velocity at each edge point + su2double *GridVel = geometry->node[Point]->GetGridVel(); + + // Summed normal components + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + // dS = geometry->vertex[iMarker][iVertex]->GetArea_or_Length(); + + ProjGridVel = 0.0; + for (unsigned short iDim = 0; iDim < nDim; iDim++) + ProjGridVel -= GridVel[iDim]*Normal[iDim]; + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Residual[iVar] = ProjGridVel*Solution[iVar]; + + LinSysRes.AddBlock(Point, Residual); + } + } +} + +void CSolver::SetAuxVar_Gradient_GG(CGeometry *geometry) { + + // Internal variables + unsigned long Point = 0, iPoint = 0, jPoint = 0, iEdge, iVertex; + unsigned short nDim = geometry->GetnDim(), iDim, iMarker; + + su2double AuxVar_Vertex, AuxVar_i, AuxVar_j, AuxVar_Average; + su2double *Gradient, DualArea, Partial_Res, Grad_Val, *Normal; + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + node[iPoint]->SetAuxVarGradientZero(); // Set Gradient to Zero + + // Loop interior edges + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + + AuxVar_i = node[iPoint]->GetAuxVar(); + AuxVar_j = node[jPoint]->GetAuxVar(); + + Normal = geometry->edge[iEdge]->GetNormal(); + AuxVar_Average = 0.5 * ( AuxVar_i + AuxVar_j); + for (iDim = 0; iDim < nDim; iDim++) { + Partial_Res = AuxVar_Average*Normal[iDim]; + node[iPoint]->AddAuxVarGradient(iDim, Partial_Res); + node[jPoint]->SubtractAuxVarGradient(iDim, Partial_Res); + } + } + + // Loop boundary edges + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + Point = geometry->vertex[iMarker][iVertex]->GetNode(); + AuxVar_Vertex = node[Point]->GetAuxVar(); + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + for (iDim = 0; iDim < nDim; iDim++) { + Partial_Res = AuxVar_Vertex*Normal[iDim]; + node[Point]->SubtractAuxVarGradient(iDim, Partial_Res); + } + } + + for (iPoint=0; iPointGetnPoint(); iPoint++) + for (iDim = 0; iDim < nDim; iDim++) { + Gradient = node[iPoint]->GetAuxVarGradient(); + DualArea = geometry->node[iPoint]->GetVolume(); + Grad_Val = Gradient[iDim]/(DualArea+EPS); + node[iPoint]->SetAuxVarGradient(iDim, Grad_Val); + } +} + +void CSolver::SetAuxVar_Gradient_LS(CGeometry *geometry, CConfig *config) { + + unsigned short iDim, jDim, iNeigh; + unsigned short nDim = geometry->GetnDim(); + unsigned long iPoint, jPoint; + su2double *Coord_i, *Coord_j, AuxVar_i, AuxVar_j, weight, r11, r12, r13, r22, r23, r23_a, + r23_b, r33, z11, z12, z13, z22, z23, z33, detR2, product; + bool singular = false; + + su2double *cvector = new su2double [nDim]; + + /*--- Loop over points of the grid ---*/ + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + + Coord_i = geometry->node[iPoint]->GetCoord(); + AuxVar_i = node[iPoint]->GetAuxVar(); + + /*--- Inizialization of variables ---*/ + for (iDim = 0; iDim < nDim; iDim++) + cvector[iDim] = 0.0; + + r11 = 0.0; r12 = 0.0; r13 = 0.0; r22 = 0.0; + r23 = 0.0; r23_a = 0.0; r23_b = 0.0; r33 = 0.0; + + for (iNeigh = 0; iNeigh < geometry->node[iPoint]->GetnPoint(); iNeigh++) { + jPoint = geometry->node[iPoint]->GetPoint(iNeigh); + Coord_j = geometry->node[jPoint]->GetCoord(); + AuxVar_j = node[jPoint]->GetAuxVar(); + + weight = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + weight += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); + + /*--- Sumations for entries of upper triangular matrix R ---*/ + + if (fabs(weight) > EPS) { + r11 += (Coord_j[0]-Coord_i[0])*(Coord_j[0]-Coord_i[0])/weight; + r12 += (Coord_j[0]-Coord_i[0])*(Coord_j[1]-Coord_i[1])/weight; + r22 += (Coord_j[1]-Coord_i[1])*(Coord_j[1]-Coord_i[1])/weight; + if (nDim == 3) { + r13 += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; + r23_a += (Coord_j[1]-Coord_i[1])*(Coord_j[2]-Coord_i[2])/weight; + r23_b += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; + r33 += (Coord_j[2]-Coord_i[2])*(Coord_j[2]-Coord_i[2])/weight; + } + + /*--- Entries of c:= transpose(A)*b ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + cvector[iDim] += (Coord_j[iDim]-Coord_i[iDim])*(AuxVar_j-AuxVar_i)/(weight); + } + + } + + /*--- Entries of upper triangular matrix R ---*/ + + if (fabs(r11) < EPS) r11 = EPS; + r11 = sqrt(r11); + r12 = r12/r11; + r22 = sqrt(r22-r12*r12); + if (fabs(r22) < EPS) r22 = EPS; + if (nDim == 3) { + r13 = r13/r11; + r23 = r23_a/(r22) - r23_b*r12/(r11*r22); + r33 = sqrt(r33-r23*r23-r13*r13); + } + + /*--- Compute determinant ---*/ + + if (nDim == 2) detR2 = (r11*r22)*(r11*r22); + else detR2 = (r11*r22*r33)*(r11*r22*r33); + + /*--- Detect singular matrices ---*/ + + if (fabs(detR2) < EPS) singular = true; + + /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ + + if (singular) { + for (iDim = 0; iDim < nDim; iDim++) + for (jDim = 0; jDim < nDim; jDim++) + Smatrix[iDim][jDim] = 0.0; + } + else { + if (nDim == 2) { + Smatrix[0][0] = (r12*r12+r22*r22)/detR2; + Smatrix[0][1] = -r11*r12/detR2; + Smatrix[1][0] = Smatrix[0][1]; + Smatrix[1][1] = r11*r11/detR2; + } + else { + z11 = r22*r33; z12 = -r12*r33; z13 = r12*r23-r13*r22; + z22 = r11*r33; z23 = -r11*r23; z33 = r11*r22; + Smatrix[0][0] = (z11*z11+z12*z12+z13*z13)/detR2; + Smatrix[0][1] = (z12*z22+z13*z23)/detR2; + Smatrix[0][2] = (z13*z33)/detR2; + Smatrix[1][0] = Smatrix[0][1]; + Smatrix[1][1] = (z22*z22+z23*z23)/detR2; + Smatrix[1][2] = (z23*z33)/detR2; + Smatrix[2][0] = Smatrix[0][2]; + Smatrix[2][1] = Smatrix[1][2]; + Smatrix[2][2] = (z33*z33)/detR2; + } + } + + /*--- Computation of the gradient: S*c ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + product = 0.0; + for (jDim = 0; jDim < nDim; jDim++) + product += Smatrix[iDim][jDim]*cvector[jDim]; + if (geometry->node[iPoint]->GetDomain()) + node[iPoint]->SetAuxVarGradient(iDim, product); + } + } + + delete [] cvector; + +} + +void CSolver::SetSolution_Gradient_GG(CGeometry *geometry, CConfig *config) { + unsigned long Point = 0, iPoint = 0, jPoint = 0, iEdge, iVertex; + unsigned short iVar, iDim, iMarker; + su2double *Solution_Vertex, *Solution_i, *Solution_j, Solution_Average, **Gradient, DualArea, + Partial_Res, Grad_Val, *Normal; + + /*--- Set Gradient to Zero ---*/ + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) + node[iPoint]->SetGradientZero(); + + /*--- Loop interior edges ---*/ + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + + Solution_i = node[iPoint]->GetSolution(); + Solution_j = node[jPoint]->GetSolution(); + Normal = geometry->edge[iEdge]->GetNormal(); + for (iVar = 0; iVar< nVar; iVar++) { + Solution_Average = 0.5 * (Solution_i[iVar] + Solution_j[iVar]); + for (iDim = 0; iDim < nDim; iDim++) { + Partial_Res = Solution_Average*Normal[iDim]; + if (geometry->node[iPoint]->GetDomain()) + node[iPoint]->AddGradient(iVar, iDim, Partial_Res); + if (geometry->node[jPoint]->GetDomain()) + node[jPoint]->SubtractGradient(iVar, iDim, Partial_Res); + } + } + } + + /*--- Loop boundary edges ---*/ + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + Point = geometry->vertex[iMarker][iVertex]->GetNode(); + Solution_Vertex = node[Point]->GetSolution(); + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) { + Partial_Res = Solution_Vertex[iVar]*Normal[iDim]; + if (geometry->node[Point]->GetDomain()) + node[Point]->SubtractGradient(iVar, iDim, Partial_Res); + } + } + } + + /*--- Compute gradient ---*/ + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) { + Gradient = node[iPoint]->GetGradient(); + DualArea = geometry->node[iPoint]->GetVolume(); + Grad_Val = Gradient[iVar][iDim] / (DualArea+EPS); + node[iPoint]->SetGradient(iVar, iDim, Grad_Val); + } + + /*--- Gradient MPI ---*/ + Set_MPI_Solution_Gradient(geometry, config); + +} + +void CSolver::SetSolution_Gradient_LS(CGeometry *geometry, CConfig *config) { + + unsigned short iDim, jDim, iVar, iNeigh; + unsigned long iPoint, jPoint; + su2double *Coord_i, *Coord_j, *Solution_i, *Solution_j, + r11, r12, r13, r22, r23, r23_a, r23_b, r33, weight, detR2, z11, z12, z13, + z22, z23, z33, product; + bool singular = false; + + su2double **cvector = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + cvector[iVar] = new su2double [nDim]; + + /*--- Loop over points of the grid ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { + + /*--- Get coordinates ---*/ + + Coord_i = geometry->node[iPoint]->GetCoord(); + + /*--- Get consevative solution ---*/ + + Solution_i = node[iPoint]->GetSolution(); + + /*--- Inizialization of variables ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + cvector[iVar][iDim] = 0.0; + + r11 = 0.0; r12 = 0.0; r13 = 0.0; r22 = 0.0; + r23 = 0.0; r23_a = 0.0; r23_b = 0.0; r33 = 0.0; + + for (iNeigh = 0; iNeigh < geometry->node[iPoint]->GetnPoint(); iNeigh++) { + jPoint = geometry->node[iPoint]->GetPoint(iNeigh); + Coord_j = geometry->node[jPoint]->GetCoord(); + + Solution_j = node[jPoint]->GetSolution(); + + weight = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + weight += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); + + /*--- Sumations for entries of upper triangular matrix R ---*/ + + if (fabs(weight) > EPS) { + r11 += (Coord_j[0]-Coord_i[0])*(Coord_j[0]-Coord_i[0])/weight; + r12 += (Coord_j[0]-Coord_i[0])*(Coord_j[1]-Coord_i[1])/weight; + r22 += (Coord_j[1]-Coord_i[1])*(Coord_j[1]-Coord_i[1])/weight; + if (nDim == 3) { + r13 += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; + r23_a += (Coord_j[1]-Coord_i[1])*(Coord_j[2]-Coord_i[2])/weight; + r23_b += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; + r33 += (Coord_j[2]-Coord_i[2])*(Coord_j[2]-Coord_i[2])/weight; + } + + /*--- Entries of c:= transpose(A)*b ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + cvector[iVar][iDim] += (Coord_j[iDim]-Coord_i[iDim])*(Solution_j[iVar]-Solution_i[iVar])/weight; + } + + } + + /*--- Entries of upper triangular matrix R ---*/ + + if (fabs(r11) < EPS) r11 = EPS; + r11 = sqrt(r11); + r12 = r12/(r11); + r22 = sqrt(r22-r12*r12); + if (fabs(r22) < EPS) r22 = EPS; + if (nDim == 3) { + r13 = r13/(r11); + r23 = r23_a/(r22) - r23_b*r12/(r11*r22); + r33 = sqrt(r33-r23*r23-r13*r13); + } + + /*--- Compute determinant ---*/ + + if (nDim == 2) detR2 = (r11*r22)*(r11*r22); + else detR2 = (r11*r22*r33)*(r11*r22*r33); + + /*--- Detect singular matrices ---*/ + + if (fabs(detR2) < EPS) singular = true; + + /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ + + if (singular) { + for (iDim = 0; iDim < nDim; iDim++) + for (jDim = 0; jDim < nDim; jDim++) + Smatrix[iDim][jDim] = 0.0; + } + else { + if (nDim == 2) { + Smatrix[0][0] = (r12*r12+r22*r22)/detR2; + Smatrix[0][1] = -r11*r12/detR2; + Smatrix[1][0] = Smatrix[0][1]; + Smatrix[1][1] = r11*r11/detR2; + } + else { + z11 = r22*r33; z12 = -r12*r33; z13 = r12*r23-r13*r22; + z22 = r11*r33; z23 = -r11*r23; z33 = r11*r22; + Smatrix[0][0] = (z11*z11+z12*z12+z13*z13)/detR2; + Smatrix[0][1] = (z12*z22+z13*z23)/detR2; + Smatrix[0][2] = (z13*z33)/detR2; + Smatrix[1][0] = Smatrix[0][1]; + Smatrix[1][1] = (z22*z22+z23*z23)/detR2; + Smatrix[1][2] = (z23*z33)/detR2; + Smatrix[2][0] = Smatrix[0][2]; + Smatrix[2][1] = Smatrix[1][2]; + Smatrix[2][2] = (z33*z33)/detR2; + } + } + + /*--- Computation of the gradient: S*c ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + for (iDim = 0; iDim < nDim; iDim++) { + product = 0.0; + for (jDim = 0; jDim < nDim; jDim++) + product += Smatrix[iDim][jDim]*cvector[iVar][jDim]; + node[iPoint]->SetGradient(iVar, iDim, product); + } + } + + } + + /*--- Deallocate memory ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + delete [] cvector[iVar]; + delete [] cvector; + + /*--- Gradient MPI ---*/ + + Set_MPI_Solution_Gradient(geometry, config); + +} + +void CSolver::SetGridVel_Gradient(CGeometry *geometry, CConfig *config) { + unsigned short iDim, jDim, iVar, iNeigh; + unsigned long iPoint, jPoint; + su2double *Coord_i, *Coord_j, *Solution_i, *Solution_j, Smatrix[3][3], + r11, r12, r13, r22, r23, r23_a, r23_b, r33, weight, detR2, z11, z12, z13, + z22, z23, z33, product; + su2double **cvector; + + /*--- Note that all nVar entries in this routine have been changed to nDim ---*/ + cvector = new su2double* [nDim]; + for (iVar = 0; iVar < nDim; iVar++) + cvector[iVar] = new su2double [nDim]; + + /*--- Loop over points of the grid ---*/ + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { + + Coord_i = geometry->node[iPoint]->GetCoord(); + Solution_i = geometry->node[iPoint]->GetGridVel(); + + /*--- Inizialization of variables ---*/ + for (iVar = 0; iVar < nDim; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + cvector[iVar][iDim] = 0.0; + r11 = 0.0; r12 = 0.0; r13 = 0.0; r22 = 0.0; r23 = 0.0; r23_a = 0.0; r23_b = 0.0; r33 = 0.0; + + for (iNeigh = 0; iNeigh < geometry->node[iPoint]->GetnPoint(); iNeigh++) { + jPoint = geometry->node[iPoint]->GetPoint(iNeigh); + Coord_j = geometry->node[jPoint]->GetCoord(); + Solution_j = geometry->node[jPoint]->GetGridVel(); + + weight = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + weight += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); + + /*--- Sumations for entries of upper triangular matrix R ---*/ + r11 += (Coord_j[0]-Coord_i[0])*(Coord_j[0]-Coord_i[0])/(weight); + r12 += (Coord_j[0]-Coord_i[0])*(Coord_j[1]-Coord_i[1])/(weight); + r22 += (Coord_j[1]-Coord_i[1])*(Coord_j[1]-Coord_i[1])/(weight); + if (nDim == 3) { + r13 += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/(weight); + r23_a += (Coord_j[1]-Coord_i[1])*(Coord_j[2]-Coord_i[2])/(weight); + r23_b += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/(weight); + r33 += (Coord_j[2]-Coord_i[2])*(Coord_j[2]-Coord_i[2])/(weight); + } + + /*--- Entries of c:= transpose(A)*b ---*/ + for (iVar = 0; iVar < nDim; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + cvector[iVar][iDim] += (Coord_j[iDim]-Coord_i[iDim])*(Solution_j[iVar]-Solution_i[iVar])/(weight); + } + + /*--- Entries of upper triangular matrix R ---*/ + r11 = sqrt(r11); + r12 = r12/(r11); + r22 = sqrt(r22-r12*r12); + if (nDim == 3) { + r13 = r13/(r11); + r23 = r23_a/(r22) - r23_b*r12/(r11*r22); + r33 = sqrt(r33-r23*r23-r13*r13); + } + /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ + if (nDim == 2) { + detR2 = (r11*r22)*(r11*r22); + Smatrix[0][0] = (r12*r12+r22*r22)/(detR2); + Smatrix[0][1] = -r11*r12/(detR2); + Smatrix[1][0] = Smatrix[0][1]; + Smatrix[1][1] = r11*r11/(detR2); + } + else { + detR2 = (r11*r22*r33)*(r11*r22*r33); + z11 = r22*r33; + z12 = -r12*r33; + z13 = r12*r23-r13*r22; + z22 = r11*r33; + z23 = -r11*r23; + z33 = r11*r22; + Smatrix[0][0] = (z11*z11+z12*z12+z13*z13)/(detR2); + Smatrix[0][1] = (z12*z22+z13*z23)/(detR2); + Smatrix[0][2] = (z13*z33)/(detR2); + Smatrix[1][0] = Smatrix[0][1]; + Smatrix[1][1] = (z22*z22+z23*z23)/(detR2); + Smatrix[1][2] = (z23*z33)/(detR2); + Smatrix[2][0] = Smatrix[0][2]; + Smatrix[2][1] = Smatrix[1][2]; + Smatrix[2][2] = (z33*z33)/(detR2); + } + /*--- Computation of the gradient: S*c ---*/ + for (iVar = 0; iVar < nDim; iVar++) { + for (iDim = 0; iDim < nDim; iDim++) { + product = 0.0; + for (jDim = 0; jDim < nDim; jDim++) + product += Smatrix[iDim][jDim]*cvector[iVar][jDim]; + geometry->node[iPoint]->SetGridVel_Grad(iVar, iDim, product); + } + } + } + + /*--- Deallocate memory ---*/ + for (iVar = 0; iVar < nDim; iVar++) + delete [] cvector[iVar]; + delete [] cvector; + + /*--- Gradient MPI ---*/ + // TO DO!!! + //Set_MPI_Solution_Gradient(geometry, config); + +} + +void CSolver::SetAuxVar_Surface_Gradient(CGeometry *geometry, CConfig *config) { + + unsigned short iDim, jDim, iNeigh, iMarker, Boundary; + unsigned short nDim = geometry->GetnDim(); + unsigned long iPoint, jPoint, iVertex; + su2double *Coord_i, *Coord_j, AuxVar_i, AuxVar_j; + su2double **Smatrix, *cvector; + + Smatrix = new su2double* [nDim]; + cvector = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Smatrix[iDim] = new su2double [nDim]; + + + /*--- Loop over boundary markers to select those for Euler or NS walls ---*/ + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + Boundary = config->GetMarker_All_KindBC(iMarker); + switch (Boundary) { + case EULER_WALL: + case HEAT_FLUX: + case ISOTHERMAL: + + /*--- Loop over points on the surface (Least-Squares approximation) ---*/ + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if (geometry->node[iPoint]->GetDomain()) { + Coord_i = geometry->node[iPoint]->GetCoord(); + AuxVar_i = node[iPoint]->GetAuxVar(); + + /*--- Inizialization of variables ---*/ + for (iDim = 0; iDim < nDim; iDim++) + cvector[iDim] = 0.0; + su2double r11 = 0.0, r12 = 0.0, r13 = 0.0, r22 = 0.0, r23 = 0.0, r23_a = 0.0, r23_b = 0.0, r33 = 0.0; + + for (iNeigh = 0; iNeigh < geometry->node[iPoint]->GetnPoint(); iNeigh++) { + jPoint = geometry->node[iPoint]->GetPoint(iNeigh); + Coord_j = geometry->node[jPoint]->GetCoord(); + AuxVar_j = node[jPoint]->GetAuxVar(); + + su2double weight = 0; + for (iDim = 0; iDim < nDim; iDim++) + weight += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); + + /*--- Sumations for entries of upper triangular matrix R ---*/ + r11 += (Coord_j[0]-Coord_i[0])*(Coord_j[0]-Coord_i[0])/weight; + r12 += (Coord_j[0]-Coord_i[0])*(Coord_j[1]-Coord_i[1])/weight; + r22 += (Coord_j[1]-Coord_i[1])*(Coord_j[1]-Coord_i[1])/weight; + if (nDim == 3) { + r13 += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; + r23_a += (Coord_j[1]-Coord_i[1])*(Coord_j[2]-Coord_i[2])/weight; + r23_b += (Coord_j[0]-Coord_i[0])*(Coord_j[2]-Coord_i[2])/weight; + r33 += (Coord_j[2]-Coord_i[2])*(Coord_j[2]-Coord_i[2])/weight; + } + + /*--- Entries of c:= transpose(A)*b ---*/ + for (iDim = 0; iDim < nDim; iDim++) + cvector[iDim] += (Coord_j[iDim]-Coord_i[iDim])*(AuxVar_j-AuxVar_i)/weight; + } + + /*--- Entries of upper triangular matrix R ---*/ + r11 = sqrt(r11); + r12 = r12/r11; + r22 = sqrt(r22-r12*r12); + if (nDim == 3) { + r13 = r13/r11; + r23 = r23_a/r22 - r23_b*r12/(r11*r22); + r33 = sqrt(r33-r23*r23-r13*r13); + } + /*--- S matrix := inv(R)*traspose(inv(R)) ---*/ + if (nDim == 2) { + su2double detR2 = (r11*r22)*(r11*r22); + Smatrix[0][0] = (r12*r12+r22*r22)/detR2; + Smatrix[0][1] = -r11*r12/detR2; + Smatrix[1][0] = Smatrix[0][1]; + Smatrix[1][1] = r11*r11/detR2; + } + else { + su2double detR2 = (r11*r22*r33)*(r11*r22*r33); + su2double z11, z12, z13, z22, z23, z33; // aux vars + z11 = r22*r33; + z12 = -r12*r33; + z13 = r12*r23-r13*r22; + z22 = r11*r33; + z23 = -r11*r23; + z33 = r11*r22; + Smatrix[0][0] = (z11*z11+z12*z12+z13*z13)/detR2; + Smatrix[0][1] = (z12*z22+z13*z23)/detR2; + Smatrix[0][2] = (z13*z33)/detR2; + Smatrix[1][0] = Smatrix[0][1]; + Smatrix[1][1] = (z22*z22+z23*z23)/detR2; + Smatrix[1][2] = (z23*z33)/detR2; + Smatrix[2][0] = Smatrix[0][2]; + Smatrix[2][1] = Smatrix[1][2]; + Smatrix[2][2] = (z33*z33)/detR2; + } + /*--- Computation of the gradient: S*c ---*/ + su2double product; + for (iDim = 0; iDim < nDim; iDim++) { + product = 0.0; + for (jDim = 0; jDim < nDim; jDim++) + product += Smatrix[iDim][jDim]*cvector[jDim]; + node[iPoint]->SetAuxVarGradient(iDim, product); + } + } + } /*--- End of loop over surface points ---*/ + break; + default: + break; + } + } + + /*--- Memory deallocation ---*/ + for (iDim = 0; iDim < nDim; iDim++) + delete [] Smatrix[iDim]; + delete [] cvector; + delete [] Smatrix; +} + +void CSolver::SetSolution_Limiter(CGeometry *geometry, CConfig *config) { + + unsigned long iEdge, iPoint, jPoint; + unsigned short iVar, iDim; + su2double **Gradient_i, **Gradient_j, *Coord_i, *Coord_j, *Solution_i, *Solution_j, + dave, LimK, eps1, eps2, dm, dp, du, ds, limiter, SharpEdge_Distance; + + /*--- Initialize solution max and solution min in the entire domain --*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + node[iPoint]->SetSolution_Max(iVar, -EPS); + node[iPoint]->SetSolution_Min(iVar, EPS); + } + } + + /*--- Establish bounds for Spekreijse monotonicity by finding max & min values of neighbor variables --*/ + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + /*--- Point identification, Normal vector and area ---*/ + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + + /*--- Get the conserved variables ---*/ + + Solution_i = node[iPoint]->GetSolution(); + Solution_j = node[jPoint]->GetSolution(); + + /*--- Compute the maximum, and minimum values for nodes i & j ---*/ + + for (iVar = 0; iVar < nVar; iVar++) { + du = (Solution_j[iVar] - Solution_i[iVar]); + node[iPoint]->SetSolution_Min(iVar, min(node[iPoint]->GetSolution_Min(iVar), du)); + node[iPoint]->SetSolution_Max(iVar, max(node[iPoint]->GetSolution_Max(iVar), du)); + node[jPoint]->SetSolution_Min(iVar, min(node[jPoint]->GetSolution_Min(iVar), -du)); + node[jPoint]->SetSolution_Max(iVar, max(node[jPoint]->GetSolution_Max(iVar), -du)); + } + + } + + /*--- Initialize the limiter --*/ + + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + node[iPoint]->SetLimiter(iVar, 2.0); + } + } + + /*--- Venkatakrishnan limiter ---*/ + + if (config->GetKind_SlopeLimit() == VENKATAKRISHNAN) { + + /*-- Get limiter parameters from the configuration file ---*/ + + dave = config->GetRefElemLength(); + LimK = config->GetLimiterCoeff(); + eps1 = LimK*dave; + eps2 = eps1*eps1*eps1; + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + Gradient_i = node[iPoint]->GetGradient(); + Gradient_j = node[jPoint]->GetGradient(); + Coord_i = geometry->node[iPoint]->GetCoord(); + Coord_j = geometry->node[jPoint]->GetCoord(); + + for (iVar = 0; iVar < nVar; iVar++) { + + /*--- Calculate the interface left gradient, delta- (dm) ---*/ + + dm = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + dm += 0.5*(Coord_j[iDim]-Coord_i[iDim])*Gradient_i[iVar][iDim]; + + /*--- Calculate the interface right gradient, delta+ (dp) ---*/ + + if ( dm > 0.0 ) dp = node[iPoint]->GetSolution_Max(iVar); + else dp = node[iPoint]->GetSolution_Min(iVar); + + limiter = ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); + + if (limiter < node[iPoint]->GetLimiter(iVar)) + node[iPoint]->SetLimiter(iVar, limiter); + + /*-- Repeat for point j on the edge ---*/ + + dm = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + dm += 0.5*(Coord_i[iDim]-Coord_j[iDim])*Gradient_j[iVar][iDim]; + + if ( dm > 0.0 ) dp = node[jPoint]->GetSolution_Max(iVar); + else dp = node[jPoint]->GetSolution_Min(iVar); + + limiter = ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); + + if (limiter < node[jPoint]->GetLimiter(iVar)) + node[jPoint]->SetLimiter(iVar, limiter); + } + } + } + + /*--- Sharp edges limiter ---*/ + + if (config->GetKind_SlopeLimit() == SHARP_EDGES) { + + /*-- Get limiter parameters from the configuration file ---*/ + + dave = config->GetRefElemLength(); + LimK = config->GetLimiterCoeff(); + eps1 = LimK*dave; + eps2 = eps1*eps1*eps1; + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + Gradient_i = node[iPoint]->GetGradient(); + Gradient_j = node[jPoint]->GetGradient(); + Coord_i = geometry->node[iPoint]->GetCoord(); + Coord_j = geometry->node[jPoint]->GetCoord(); + + for (iVar = 0; iVar < nVar; iVar++) { + + /*--- Calculate the interface left gradient, delta- (dm) ---*/ + + dm = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + dm += 0.5*(Coord_j[iDim]-Coord_i[iDim])*Gradient_i[iVar][iDim]; + + /*--- Calculate the interface right gradient, delta+ (dp) ---*/ + + if ( dm > 0.0 ) dp = node[iPoint]->GetSolution_Max(iVar); + else dp = node[iPoint]->GetSolution_Min(iVar); + + /*--- Compute the distance to a sharp edge ---*/ + + SharpEdge_Distance = (geometry->node[iPoint]->GetSharpEdge_Distance() - config->GetSharpEdgesCoeff()*eps1); + ds = 0.0; + if (SharpEdge_Distance < -eps1) ds = 0.0; + if (fabs(SharpEdge_Distance) <= eps1) ds = 0.5*(1.0+(SharpEdge_Distance/eps1)+(1.0/PI_NUMBER)*sin(PI_NUMBER*SharpEdge_Distance/eps1)); + if (SharpEdge_Distance > eps1) ds = 1.0; + + limiter = ds * ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); + + if (limiter < node[iPoint]->GetLimiter(iVar)) + node[iPoint]->SetLimiter(iVar, limiter); + + /*-- Repeat for point j on the edge ---*/ + + dm = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + dm += 0.5*(Coord_i[iDim]-Coord_j[iDim])*Gradient_j[iVar][iDim]; + + if ( dm > 0.0 ) dp = node[jPoint]->GetSolution_Max(iVar); + else dp = node[jPoint]->GetSolution_Min(iVar); + + /*--- Compute the distance to a sharp edge ---*/ + + SharpEdge_Distance = (geometry->node[jPoint]->GetSharpEdge_Distance() - config->GetSharpEdgesCoeff()*eps1); + ds = 0.0; + if (SharpEdge_Distance < -eps1) ds = 0.0; + if (fabs(SharpEdge_Distance) <= eps1) ds = 0.5*(1.0+(SharpEdge_Distance/eps1)+(1.0/PI_NUMBER)*sin(PI_NUMBER*SharpEdge_Distance/eps1)); + if (SharpEdge_Distance > eps1) ds = 1.0; + + limiter = ds * ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); + + if (limiter < node[jPoint]->GetLimiter(iVar)) + node[jPoint]->SetLimiter(iVar, limiter); + + } + } + } + + /*--- Sharp edges limiter ---*/ + + if (config->GetKind_SlopeLimit() == SOLID_WALL_DISTANCE) { + + /*-- Get limiter parameters from the configuration file ---*/ + + dave = config->GetRefElemLength(); + LimK = config->GetLimiterCoeff(); + eps1 = LimK*dave; + eps2 = eps1*eps1*eps1; + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + Gradient_i = node[iPoint]->GetGradient(); + Gradient_j = node[jPoint]->GetGradient(); + Coord_i = geometry->node[iPoint]->GetCoord(); + Coord_j = geometry->node[jPoint]->GetCoord(); + + for (iVar = 0; iVar < nVar; iVar++) { + + /*--- Calculate the interface left gradient, delta- (dm) ---*/ + + dm = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + dm += 0.5*(Coord_j[iDim]-Coord_i[iDim])*Gradient_i[iVar][iDim]; + + /*--- Calculate the interface right gradient, delta+ (dp) ---*/ + + if ( dm > 0.0 ) dp = node[iPoint]->GetSolution_Max(iVar); + else dp = node[iPoint]->GetSolution_Min(iVar); + + /*--- Compute the distance to a sharp edge ---*/ + + SharpEdge_Distance = (geometry->node[iPoint]->GetWall_Distance() - config->GetSharpEdgesCoeff()*eps1); + ds = 0.0; + if (SharpEdge_Distance < -eps1) ds = 0.0; + if (fabs(SharpEdge_Distance) <= eps1) ds = 0.5*(1.0+(SharpEdge_Distance/eps1)+(1.0/PI_NUMBER)*sin(PI_NUMBER*SharpEdge_Distance/eps1)); + if (SharpEdge_Distance > eps1) ds = 1.0; + + limiter = ds * ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); + + if (limiter < node[iPoint]->GetLimiter(iVar)) + node[iPoint]->SetLimiter(iVar, limiter); + + /*-- Repeat for point j on the edge ---*/ + + dm = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + dm += 0.5*(Coord_i[iDim]-Coord_j[iDim])*Gradient_j[iVar][iDim]; + + if ( dm > 0.0 ) dp = node[jPoint]->GetSolution_Max(iVar); + else dp = node[jPoint]->GetSolution_Min(iVar); + + /*--- Compute the distance to a sharp edge ---*/ + + SharpEdge_Distance = (geometry->node[jPoint]->GetWall_Distance() - config->GetSharpEdgesCoeff()*eps1); + ds = 0.0; + if (SharpEdge_Distance < -eps1) ds = 0.0; + if (fabs(SharpEdge_Distance) <= eps1) ds = 0.5*(1.0+(SharpEdge_Distance/eps1)+(1.0/PI_NUMBER)*sin(PI_NUMBER*SharpEdge_Distance/eps1)); + if (SharpEdge_Distance > eps1) ds = 1.0; + + limiter = ds * ( dp*dp + 2.0*dp*dm + eps2 )/( dp*dp + dp*dm + 2.0*dm*dm + eps2); + + if (limiter < node[jPoint]->GetLimiter(iVar)) + node[jPoint]->SetLimiter(iVar, limiter); + + } + } + } + + + /*--- Limiter MPI ---*/ + + Set_MPI_Solution_Limiter(geometry, config); + +} + +void CSolver::SetPressureLaplacian(CGeometry *geometry, su2double *PressureLaplacian) { + + unsigned long Point = 0, iPoint = 0, jPoint = 0, iEdge, iVertex; + unsigned short iMarker, iVar; + su2double DualArea, Partial_Res, *Normal; + su2double **UxVar_Gradient, **UyVar_Gradient; + + UxVar_Gradient = new su2double* [geometry->GetnPoint()]; + UyVar_Gradient = new su2double* [geometry->GetnPoint()]; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + UxVar_Gradient[iPoint] = new su2double [2]; + UyVar_Gradient[iPoint] = new su2double [2]; + } + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + for (iVar = 0; iVar < 2; iVar++) { + UxVar_Gradient[iPoint][iVar] = 0.0; + UyVar_Gradient[iPoint][iVar] = 0.0; + } + + /*--- Loop interior edges ---*/ + + for (iEdge = 0; iEdge < geometry->GetnEdge(); iEdge++) { + iPoint = geometry->edge[iEdge]->GetNode(0); + jPoint = geometry->edge[iEdge]->GetNode(1); + Normal = geometry->edge[iEdge]->GetNormal(); + + Partial_Res = 0.5 * ( node[iPoint]->GetSolution(1) + node[jPoint]->GetSolution(1)) * Normal[0]; + UxVar_Gradient[iPoint][0] += Partial_Res; + UxVar_Gradient[jPoint][0] -= Partial_Res; + + Partial_Res = 0.5 * ( node[iPoint]->GetSolution(1) + node[jPoint]->GetSolution(1)) * Normal[1]; + UxVar_Gradient[iPoint][1] += Partial_Res; + UxVar_Gradient[jPoint][1] -= Partial_Res; + + Partial_Res = 0.5 * ( node[iPoint]->GetSolution(2) + node[jPoint]->GetSolution(2)) * Normal[0]; + UyVar_Gradient[iPoint][0] += Partial_Res; + UyVar_Gradient[jPoint][0] -= Partial_Res; + + Partial_Res = 0.5 * ( node[iPoint]->GetSolution(2) + node[jPoint]->GetSolution(2)) * Normal[1]; + UyVar_Gradient[iPoint][1] += Partial_Res; + UyVar_Gradient[jPoint][1] -= Partial_Res; + + } + + /*--- Loop boundary edges ---*/ + + for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) { + Point = geometry->vertex[iMarker][iVertex]->GetNode(); + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + + Partial_Res = node[Point]->GetSolution(1) * Normal[0]; + UxVar_Gradient[Point][0] -= Partial_Res; + + Partial_Res = node[Point]->GetSolution(1) * Normal[1]; + UxVar_Gradient[Point][1] -= Partial_Res; + + Partial_Res = node[Point]->GetSolution(2) * Normal[0]; + UyVar_Gradient[Point][0] -= Partial_Res; + + Partial_Res = node[Point]->GetSolution(2) * Normal[1]; + UyVar_Gradient[Point][1] -= Partial_Res; + } + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + DualArea = geometry->node[iPoint]->GetVolume(); + PressureLaplacian[iPoint] = (UxVar_Gradient[iPoint][0]*UxVar_Gradient[iPoint][0] + UyVar_Gradient[iPoint][1]*UyVar_Gradient[iPoint][1] + + UxVar_Gradient[iPoint][1]*UyVar_Gradient[iPoint][0] + UxVar_Gradient[iPoint][0]*UyVar_Gradient[iPoint][1])/DualArea ; + + } + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + delete[] UxVar_Gradient[iPoint]; + delete[] UyVar_Gradient[iPoint]; + } + + delete[] UxVar_Gradient; + delete[] UyVar_Gradient; + +} + +void CSolver::Gauss_Elimination(su2double** A, su2double* rhs, unsigned short nVar) { + + short iVar, jVar, kVar; + su2double weight, aux; + + if (nVar == 1) + rhs[0] /= A[0][0]; + else { + + /*--- Transform system in Upper Matrix ---*/ + + for (iVar = 1; iVar < (short)nVar; iVar++) { + for (jVar = 0; jVar < iVar; jVar++) { + weight = A[iVar][jVar]/A[jVar][jVar]; + for (kVar = jVar; kVar < (short)nVar; kVar++) + A[iVar][kVar] -= weight*A[jVar][kVar]; + rhs[iVar] -= weight*rhs[jVar]; + } + } + + /*--- Backwards substitution ---*/ + + rhs[nVar-1] = rhs[nVar-1]/A[nVar-1][nVar-1]; + for (iVar = (short)nVar-2; iVar >= 0; iVar--) { + aux = 0; + for (jVar = iVar+1; jVar < (short)nVar; jVar++) + aux += A[iVar][jVar]*rhs[jVar]; + rhs[iVar] = (rhs[iVar]-aux)/A[iVar][iVar]; + if (iVar == 0) break; + } + } + +} + +void CSolver::Aeroelastic(CSurfaceMovement *surface_movement, CGeometry *geometry, CConfig *config, unsigned long ExtIter) { + + /*--- Variables used for Aeroelastic case ---*/ + + su2double Cl, Cd, Cn, Ct, Cm, Cn_rot; + su2double Alpha = config->GetAoA()*PI_NUMBER/180.0; + vector structural_solution(4,0.0); //contains solution(displacements and rates) of typical section wing model. + + unsigned short iMarker, iMarker_Monitoring, Monitoring; + string Marker_Tag, Monitoring_Tag; + + /*--- Loop over markers and find the ones being monitored. ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + Monitoring = config->GetMarker_All_Monitoring(iMarker); + if (Monitoring == YES) { + + /*--- Find the particular marker being monitored and get the forces acting on it. ---*/ + + for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { + Monitoring_Tag = config->GetMarker_Monitoring(iMarker_Monitoring); + Marker_Tag = config->GetMarker_All_TagBound(iMarker); + if (Marker_Tag == Monitoring_Tag) { + + Cl = GetSurface_CLift(iMarker_Monitoring); + Cd = GetSurface_CDrag(iMarker_Monitoring); + + /*--- For typical section wing model want the force normal to the airfoil (in the direction of the spring) ---*/ + Cn = Cl*cos(Alpha) + Cd*sin(Alpha); + Ct = -Cl*sin(Alpha) + Cd*cos(Alpha); + + Cm = GetSurface_CMz(iMarker_Monitoring); + + /*--- Calculate forces for the Typical Section Wing Model taking into account rotation ---*/ + + /*--- Note that the calculation of the forces and the subsequent displacements ... + is only correct for the airfoil that starts at the 0 degree position ---*/ + + if (config->GetKind_GridMovement(ZONE_0) == AEROELASTIC_RIGID_MOTION) { + su2double Omega, dt, psi; + dt = config->GetDelta_UnstTimeND(); + Omega = (config->GetRotation_Rate_Z(ZONE_0)/config->GetOmega_Ref()); + psi = Omega*(dt*ExtIter); + + /*--- Correct for the airfoil starting position (This is hardcoded in here) ---*/ + if (Monitoring_Tag == "Airfoil1") { + psi = psi + 0.0; + } + else if (Monitoring_Tag == "Airfoil2") { + psi = psi + 2.0/3.0*PI_NUMBER; + } + else if (Monitoring_Tag == "Airfoil3") { + psi = psi + 4.0/3.0*PI_NUMBER; + } + else + cout << "WARNING: There is a marker that we are monitoring that doesn't match the values hardcoded above!" << endl; + + cout << Monitoring_Tag << " position " << psi*180.0/PI_NUMBER << " degrees. " << endl; + + Cn_rot = Cn*cos(psi) - Ct*sin(psi); //Note the signs are different for accounting for the AOA. + Cn = Cn_rot; + } + + /*--- Solve the aeroelastic equations for the particular marker(surface) ---*/ + + SolveTypicalSectionWingModel(geometry, Cn, Cm, config, iMarker_Monitoring, structural_solution); + + break; + } + } + + /*--- Compute the new surface node locations ---*/ + surface_movement->AeroelasticDeform(geometry, config, ExtIter, iMarker, iMarker_Monitoring, structural_solution); + + } + + } + +} + +void CSolver::SetUpTypicalSectionWingModel(vector >& Phi, vector& omega, CConfig *config) { + + /*--- Retrieve values from the config file ---*/ + su2double w_h = config->GetAeroelastic_Frequency_Plunge(); + su2double w_a = config->GetAeroelastic_Frequency_Pitch(); + su2double x_a = config->GetAeroelastic_CG_Location(); + su2double r_a = sqrt(config->GetAeroelastic_Radius_Gyration_Squared()); + su2double w = w_h/w_a; + + // Mass Matrix + vector > M(2,vector(2,0.0)); + M[0][0] = 1; + M[0][1] = x_a; + M[1][0] = x_a; + M[1][1] = r_a*r_a; + + // Stiffness Matrix + // vector > K(2,vector(2,0.0)); + // K[0][0] = (w_h/w_a)*(w_h/w_a); + // K[0][1] = 0.0; + // K[1][0] = 0.0; + // K[1][1] = r_a*r_a; + + /* Eigenvector and Eigenvalue Matrices of the Generalized EigenValue Problem. */ + + vector > Omega2(2,vector(2,0.0)); + su2double aux; // auxiliary variable + aux = sqrt(pow(r_a,2)*pow(w,4) - 2*pow(r_a,2)*pow(w,2) + pow(r_a,2) + 4*pow(x_a,2)*pow(w,2)); + Phi[0][0] = (r_a * (r_a - r_a*pow(w,2) + aux)) / (2*x_a*pow(w, 2)); + Phi[0][1] = (r_a * (r_a - r_a*pow(w,2) - aux)) / (2*x_a*pow(w, 2)); + Phi[1][0] = 1.0; + Phi[1][1] = 1.0; + + Omega2[0][0] = (r_a * (r_a + r_a*pow(w,2) - aux)) / (2*(pow(r_a, 2) - pow(x_a, 2))); + Omega2[0][1] = 0; + Omega2[1][0] = 0; + Omega2[1][1] = (r_a * (r_a + r_a*pow(w,2) + aux)) / (2*(pow(r_a, 2) - pow(x_a, 2))); + + /* Nondimesionalize the Eigenvectors such that Phi'*M*Phi = I and PHI'*K*PHI = Omega */ + // Phi'*M*Phi = D + // D^(-1/2)*Phi'*M*Phi*D^(-1/2) = D^(-1/2)*D^(1/2)*D^(1/2)*D^(-1/2) = I, D^(-1/2) = inv(sqrt(D)) + // Phi = Phi*D^(-1/2) + + vector > Aux(2,vector(2,0.0)); + vector > D(2,vector(2,0.0)); + // Aux = M*Phi + for (int i=0; i<2; i++) { + for (int j=0; j<2; j++) { + Aux[i][j] = 0; + for (int k=0; k<2; k++) { + Aux[i][j] += M[i][k]*Phi[k][j]; + } + } + } + + // D = Phi'*Aux + for (int i=0; i<2; i++) { + for (int j=0; j<2; j++) { + D[i][j] = 0; + for (int k=0; k<2; k++) { + D[i][j] += Phi[k][i]*Aux[k][j]; //PHI transpose + } + } + } + + //Modify the first column + Phi[0][0] = Phi[0][0] * 1/sqrt(D[0][0]); + Phi[1][0] = Phi[1][0] * 1/sqrt(D[0][0]); + //Modify the second column + Phi[0][1] = Phi[0][1] * 1/sqrt(D[1][1]); + Phi[1][1] = Phi[1][1] * 1/sqrt(D[1][1]); + + // Sqrt of the eigenvalues (frequency of vibration of the modes) + omega[0] = sqrt(Omega2[0][0]); + omega[1] = sqrt(Omega2[1][1]); + +} + +void CSolver::SolveTypicalSectionWingModel(CGeometry *geometry, su2double Cl, su2double Cm, CConfig *config, unsigned short iMarker, vector& displacements) { + + /*--- The aeroelastic model solved in this routine is the typical section wing model + The details of the implementation are similar to those found in J.J. Alonso + "Fully-Implicit Time-Marching Aeroelastic Solutions" 1994. ---*/ + + /*--- Retrieve values from the config file ---*/ + su2double w_alpha = config->GetAeroelastic_Frequency_Pitch(); + su2double vf = config->GetAeroelastic_Flutter_Speed_Index(); + su2double b = config->GetLength_Reynolds()/2.0; // airfoil semichord, Reynolds length is by defaul 1.0 + su2double dt = config->GetDelta_UnstTimeND(); + dt = dt*w_alpha; //Non-dimensionalize the structural time. + + /*--- Structural Equation damping ---*/ + vector xi(2,0.0); + + /*--- Eigenvectors and Eigenvalues of the Generalized EigenValue Problem. ---*/ + vector > Phi(2,vector(2,0.0)); // generalized eigenvectors. + vector w(2,0.0); // sqrt of the generalized eigenvalues (frequency of vibration of the modes). + SetUpTypicalSectionWingModel(Phi, w, config); + + /*--- Solving the Decoupled Aeroelastic Problem with second order time discretization Eq (9) ---*/ + + /*--- Solution variables description. //x[j][i], j-entry, i-equation. // Time (n+1)->np1, n->n, (n-1)->n1 ---*/ + vector > x_np1(2,vector(2,0.0)); + + /*--- Values from previous movement of spring at true time step n+1 + We use this values because we are solving for delta changes not absolute changes ---*/ + vector > x_np1_old = config->GetAeroelastic_np1(iMarker); + + /*--- Values at previous timesteps. ---*/ + vector > x_n = config->GetAeroelastic_n(iMarker); + vector > x_n1 = config->GetAeroelastic_n1(iMarker); + + /*--- Set up of variables used to solve the structural problem. ---*/ + vector f_tilde(2,0.0); + vector > A_inv(2,vector(2,0.0)); + su2double detA; + su2double s1, s2; + vector rhs(2,0.0); //right hand side + vector eta(2,0.0); + vector eta_dot(2,0.0); + + /*--- Forcing Term ---*/ + su2double cons = vf*vf/PI_NUMBER; + vector f(2,0.0); + f[0] = cons*(-Cl); + f[1] = cons*(2*-Cm); + + //f_tilde = Phi'*f + for (int i=0; i<2; i++) { + f_tilde[i] = 0; + for (int k=0; k<2; k++) { + f_tilde[i] += Phi[k][i]*f[k]; //PHI transpose + } + } + + /*--- solve each decoupled equation (The inverse of the 2x2 matrix is provided) ---*/ + for (int i=0; i<2; i++) { + /* Matrix Inverse */ + detA = 9.0/(4.0*dt*dt) + 3*w[i]*xi[i]/(dt) + w[i]*w[i]; + A_inv[0][0] = 1/detA * (3/(2.0*dt) + 2*xi[i]*w[i]); + A_inv[0][1] = 1/detA * 1; + A_inv[1][0] = 1/detA * -w[i]*w[i]; + A_inv[1][1] = 1/detA * 3/(2.0*dt); + + /* Source Terms from previous iterations */ + s1 = (-4*x_n[0][i] + x_n1[0][i])/(2.0*dt); + s2 = (-4*x_n[1][i] + x_n1[1][i])/(2.0*dt); + + /* Problem Right Hand Side */ + rhs[0] = -s1; + rhs[1] = f_tilde[i]-s2; + + /* Solve the equations */ + x_np1[0][i] = A_inv[0][0]*rhs[0] + A_inv[0][1]*rhs[1]; + x_np1[1][i] = A_inv[1][0]*rhs[0] + A_inv[1][1]*rhs[1]; + + eta[i] = x_np1[0][i]-x_np1_old[0][i]; // For displacements, the change(deltas) is used. + eta_dot[i] = x_np1[1][i]; // For velocities, absolute values are used. + } + + /*--- Transform back from the generalized coordinates to get the actual displacements in plunge and pitch q = Phi*eta ---*/ + vector q(2,0.0); + vector q_dot(2,0.0); + for (int i=0; i<2; i++) { + q[i] = 0; + q_dot[i] = 0; + for (int k=0; k<2; k++) { + q[i] += Phi[i][k]*eta[k]; + q_dot[i] += Phi[i][k]*eta_dot[k]; + } + } + + su2double dh = b*q[0]; + su2double dalpha = q[1]; + + su2double h_dot = w_alpha*b*q_dot[0]; //The w_a brings it back to actual time. + su2double alpha_dot = w_alpha*q_dot[1]; + + /*--- Set the solution of the structural equations ---*/ + displacements[0] = dh; + displacements[1] = dalpha; + displacements[2] = h_dot; + displacements[3] = alpha_dot; + + /*--- Calculate the total plunge and total pitch displacements for the unsteady step by summing the displacement at each sudo time step ---*/ + su2double pitch, plunge; + pitch = config->GetAeroelastic_pitch(iMarker); + plunge = config->GetAeroelastic_plunge(iMarker); + + config->SetAeroelastic_pitch(iMarker , pitch+dalpha); + config->SetAeroelastic_plunge(iMarker , plunge+dh/b); + + /*--- Set the Aeroelastic solution at time n+1. This gets update every sudo time step + and after convering the sudo time step the solution at n+1 get moved to the solution at n + in SetDualTime_Solver method ---*/ + + config->SetAeroelastic_np1(iMarker, x_np1); + +} + +CBaselineSolver::CBaselineSolver(void) : CSolver() { } + +CBaselineSolver::CBaselineSolver(CGeometry *geometry, CConfig *config, unsigned short iMesh) : CSolver() { + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + unsigned long iPoint, index, iPoint_Global; + long iPoint_Local; + unsigned short iField, iVar; + string Tag, text_line, AdjExt, UnstExt; + unsigned long iExtIter = config->GetExtIter(); + + /*--- Define geometry constants in the solver structure ---*/ + + nDim = geometry->GetnDim(); + + /*--- Allocate the node variables ---*/ + + node = new CVariable*[geometry->GetnPoint()]; + + /*--- Restart the solution from file information ---*/ + + ifstream restart_file; + string filename; + + /*--- Retrieve filename from config ---*/ + + if (config->GetAdjoint() || config->GetDiscrete_Adjoint()) { + filename = config->GetSolution_AdjFileName(); + filename = config->GetObjFunc_Extension(filename); + } else { + filename = config->GetSolution_FlowFileName(); + } + + /*--- Unsteady problems require an iteration number to be appended. ---*/ + + if (config->GetWrt_Unsteady() || config->GetUnsteady_Simulation() == TIME_SPECTRAL) { + filename = config->GetUnsteady_FileName(filename, SU2_TYPE::Int(iExtIter)); + } + + /*--- Open the restart file ---*/ + + restart_file.open(filename.data(), ios::in); + + /*--- In case there is no restart file ---*/ + + if (restart_file.fail()) { + if (rank == MASTER_NODE) + cout << "SU2 flow file " << filename << " not found" << endl; + +#ifndef HAVE_MPI + exit(EXIT_FAILURE); +#else + MPI_Abort(MPI_COMM_WORLD,1); + MPI_Finalize(); +#endif + + } + + /*--- Output the file name to the console. ---*/ + + if (rank == MASTER_NODE) + cout << "Reading and storing the solution from " << filename << "." << endl; + + /*--- In case this is a parallel simulation, we need to perform the + Global2Local index transformation first. ---*/ + + long *Global2Local = new long[geometry->GetGlobal_nPointDomain()]; + + /*--- First, set all indices to a negative value by default ---*/ + + for (iPoint = 0; iPoint < geometry->GetGlobal_nPointDomain(); iPoint++) + Global2Local[iPoint] = -1; + + /*--- Now fill array with the transform values only for local points ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPointDomain(); iPoint++) + Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; + + + /*--- Identify the number of fields (and names) in the restart file ---*/ + + getline (restart_file, text_line); + stringstream ss(text_line); + while (ss >> Tag) { + config->fields.push_back(Tag); + if (ss.peek() == ',') ss.ignore(); + } + + /*--- Set the number of variables, one per field in the + restart file (without including the PointID) ---*/ + + nVar = config->fields.size() - 1; + su2double *Solution = new su2double[nVar]; + + /*--- Read all lines in the restart file ---*/ + + iPoint_Global = 0; + while (getline (restart_file, text_line)) { + istringstream point_line(text_line); + + /*--- Retrieve local index. If this node from the restart file lives + on a different processor, the value of iPoint_Local will be -1. + Otherwise, the local index for this node on the current processor + will be returned and used to instantiate the vars. ---*/ + + iPoint_Local = Global2Local[iPoint_Global]; + if (iPoint_Local >= 0) { + + /*--- The PointID is not stored --*/ + point_line >> index; + + /*--- Store the solution (starting with node coordinates) --*/ + for (iField = 0; iField < nVar; iField++) + point_line >> Solution[iField]; + + node[iPoint_Local] = new CBaselineVariable(Solution, nVar, config); + } + iPoint_Global++; + } + + /*--- Instantiate the variable class with an arbitrary solution + at any halo/periodic nodes. The initial solution can be arbitrary, + because a send/recv is performed immediately in the solver. ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = 0.0; + + for (iPoint = geometry->GetnPointDomain(); iPoint < geometry->GetnPoint(); iPoint++) + node[iPoint] = new CBaselineVariable(Solution, nVar, config); + + /*--- Close the restart file ---*/ + + restart_file.close(); + + /*--- Free memory needed for the transformation ---*/ + + delete [] Global2Local; + delete [] Solution; + + /*--- MPI solution ---*/ + + Set_MPI_Solution(geometry, config); + +} + +void CBaselineSolver::Set_MPI_Solution(CGeometry *geometry, CConfig *config) { + unsigned short iVar, iMarker, iPeriodic_Index, MarkerS, MarkerR; + unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector; + su2double rotMatrix[3][3], *transl, *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, *Buffer_Receive_U = NULL, *Buffer_Send_U = NULL, *Solution = NULL; + + Solution = new su2double[nVar]; + +#ifdef HAVE_MPI + int send_to, receive_from; + MPI_Status status; +#endif + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; + +#endif + + nVertexS = geometry->nVertex[MarkerS]; nVertexR = geometry->nVertex[MarkerR]; + nBufferS_Vector = nVertexS*nVar; nBufferR_Vector = nVertexR*nVar; + + /*--- Allocate Receive and send buffers ---*/ + + Buffer_Receive_U = new su2double [nBufferR_Vector]; + Buffer_Send_U = new su2double[nBufferS_Vector]; + + /*--- Copy the solution that should be sended ---*/ + + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = geometry->vertex[MarkerS][iVertex]->GetNode(); + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Send_U[iVar*nVertexS+iVertex] = node[iPoint]->GetSolution(iVar); + } + +#ifdef HAVE_MPI + + /*--- Send/Receive information using Sendrecv ---*/ + + SU2_MPI::Sendrecv(Buffer_Send_U, nBufferS_Vector, MPI_DOUBLE, send_to, 0, + Buffer_Receive_U, nBufferR_Vector, MPI_DOUBLE, receive_from, 0, MPI_COMM_WORLD, &status); + +#else + + /*--- Receive information without MPI ---*/ + + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + for (iVar = 0; iVar < nVar; iVar++) + Buffer_Receive_U[iVar*nVertexR+iVertex] = Buffer_Send_U[iVar*nVertexR+iVertex]; + } + +#endif + + /*--- Deallocate send buffer ---*/ + + delete [] Buffer_Send_U; + + /*--- Do the coordinate transformation ---*/ + + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Find point and its type of transformation ---*/ + + iPoint = geometry->vertex[MarkerR][iVertex]->GetNode(); + iPeriodic_Index = geometry->vertex[MarkerR][iVertex]->GetRotation_Type(); + + /*--- Retrieve the supplied periodic information. ---*/ + + transl = config->GetPeriodicTranslate(iPeriodic_Index); + angles = config->GetPeriodicRotation(iPeriodic_Index); + + /*--- Store angles separately for clarity. ---*/ + + theta = angles[0]; phi = angles[1]; psi = angles[2]; + cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi); + sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi); + + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, + then z-axis. Note that this is the transpose of the matrix + used during the preprocessing stage. ---*/ + + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi; + + /*--- Copy conserved variables before performing transformation. ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = Buffer_Receive_U[iVar*nVertexR+iVertex]; + + /*--- Rotate the spatial coordinates & momentum. ---*/ + + if (nDim == 2) { + + /*--- Coords ---*/ + + Solution[0] = (rotMatrix[0][0]*Buffer_Receive_U[0*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_U[1*nVertexR+iVertex] - transl[0]); + Solution[1] = (rotMatrix[1][0]*Buffer_Receive_U[0*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_U[1*nVertexR+iVertex] - transl[1]); + /*--- Momentum ---*/ + + Solution[nDim+1] = (rotMatrix[0][0]*Buffer_Receive_U[(nDim+1)*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_U[(nDim+2)*nVertexR+iVertex]); + Solution[nDim+2] = (rotMatrix[1][0]*Buffer_Receive_U[(nDim+1)*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_U[(nDim+2)*nVertexR+iVertex]); + } else { + + /*--- Coords ---*/ + + Solution[0] = (rotMatrix[0][0]*Buffer_Receive_U[0*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[0][2]*Buffer_Receive_U[2*nVertexR+iVertex] - transl[0]); + Solution[1] = (rotMatrix[1][0]*Buffer_Receive_U[0*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[1][2]*Buffer_Receive_U[2*nVertexR+iVertex] - transl[1]); + Solution[2] = (rotMatrix[2][0]*Buffer_Receive_U[0*nVertexR+iVertex] + + rotMatrix[2][1]*Buffer_Receive_U[1*nVertexR+iVertex] + + rotMatrix[2][2]*Buffer_Receive_U[2*nVertexR+iVertex] - transl[2]); + + /*--- Momentum ---*/ + + Solution[nDim+1] = (rotMatrix[0][0]*Buffer_Receive_U[nDim+1*nVertexR+iVertex] + + rotMatrix[0][1]*Buffer_Receive_U[nDim+2*nVertexR+iVertex] + + rotMatrix[0][2]*Buffer_Receive_U[nDim+3*nVertexR+iVertex]); + Solution[nDim+2] = (rotMatrix[1][0]*Buffer_Receive_U[nDim+1*nVertexR+iVertex] + + rotMatrix[1][1]*Buffer_Receive_U[nDim+2*nVertexR+iVertex] + + rotMatrix[1][2]*Buffer_Receive_U[nDim+3*nVertexR+iVertex]); + Solution[nDim+3] = (rotMatrix[2][0]*Buffer_Receive_U[nDim+1*nVertexR+iVertex] + + rotMatrix[2][1]*Buffer_Receive_U[nDim+2*nVertexR+iVertex] + + rotMatrix[2][2]*Buffer_Receive_U[nDim+3*nVertexR+iVertex]); + } + + /*--- Copy transformed conserved variables back into buffer. ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + node[iPoint]->SetSolution(iVar, Solution[iVar]); + + } + + /*--- Deallocate receive buffer ---*/ + + delete [] Buffer_Receive_U; + + } + + } + + delete [] Solution; + +} + +void CBaselineSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig *config, int val_iter) { + + int rank = MASTER_NODE; +#ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#endif + + /*--- Restart the solution from file information ---*/ + string filename; + unsigned long iPoint, index; + string UnstExt, text_line, AdjExt; + ifstream solution_file; + unsigned short iField; + unsigned long iExtIter = config->GetExtIter(); + + /*--- Retrieve filename from config ---*/ + if (config->GetAdjoint()) { + filename = config->GetSolution_AdjFileName(); + filename = config->GetObjFunc_Extension(filename); + } else { + filename = config->GetSolution_FlowFileName(); + } + + /*--- Unsteady problems require an iteration number to be appended. ---*/ + if (config->GetWrt_Unsteady() || config->GetUnsteady_Simulation() == TIME_SPECTRAL) { + filename = config->GetUnsteady_FileName(filename, SU2_TYPE::Int(iExtIter)); + } + + /*--- Open the restart file ---*/ + solution_file.open(filename.data(), ios::in); + + /*--- In case there is no file ---*/ + if (solution_file.fail()) { + if (rank == MASTER_NODE) + cout << "There is no SU2 restart file!!" << endl; + exit(EXIT_FAILURE); + } + + /*--- Output the file name to the console. ---*/ + if (rank == MASTER_NODE) + cout << "Reading and storing the solution from " << filename + << "." << endl; + + /*--- Set the number of variables, one per field in the + restart file (without including the PointID) ---*/ + nVar = config->fields.size() - 1; + su2double *Solution = new su2double[nVar]; + + /*--- In case this is a parallel simulation, we need to perform the + Global2Local index transformation first. ---*/ + long *Global2Local = NULL; + Global2Local = new long[geometry[ZONE_0]->GetGlobal_nPointDomain()]; + /*--- First, set all indices to a negative value by default ---*/ + for (iPoint = 0; iPoint < geometry[ZONE_0]->GetGlobal_nPointDomain(); iPoint++) { + Global2Local[iPoint] = -1; + } + + /*--- Now fill array with the transform values only for local points ---*/ + for (iPoint = 0; iPoint < geometry[ZONE_0]->GetnPointDomain(); iPoint++) { + Global2Local[geometry[ZONE_0]->node[iPoint]->GetGlobalIndex()] = iPoint; + } + + /*--- Read all lines in the restart file ---*/ + long iPoint_Local = 0; unsigned long iPoint_Global = 0; + + /*--- The first line is the header ---*/ + getline (solution_file, text_line); + + while (getline (solution_file, text_line)) { + istringstream point_line(text_line); + + /*--- Retrieve local index. If this node from the restart file lives + on a different processor, the value of iPoint_Local will be -1, as + initialized above. Otherwise, the local index for this node on the + current processor will be returned and used to instantiate the vars. ---*/ + iPoint_Local = Global2Local[iPoint_Global]; + if (iPoint_Local >= 0) { + + /*--- The PointID is not stored --*/ + point_line >> index; + + /*--- Store the solution (starting with node coordinates) --*/ + for (iField = 0; iField < nVar; iField++) + point_line >> Solution[iField]; + + node[iPoint_Local]->SetSolution(Solution); + + + } + iPoint_Global++; + } + + /*--- Close the restart file ---*/ + solution_file.close(); + + /*--- Free memory needed for the transformation ---*/ + delete [] Global2Local; + delete [] Solution; + +} + +CBaselineSolver::~CBaselineSolver(void) { } diff --git a/SU2_CFD/src/variable_adjoint_levelset.cpp b/SU2_CFD/src/variable_adjoint_levelset.cpp index 4a18914ae24..9e4b33020f0 100644 --- a/SU2_CFD/src/variable_adjoint_levelset.cpp +++ b/SU2_CFD/src/variable_adjoint_levelset.cpp @@ -1,80 +1,80 @@ -/*! - * \file variable_adjoint_levelset.cpp - * \brief Definition of the solution fields. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/variable_structure.hpp" - - -CAdjLevelSetVariable::CAdjLevelSetVariable(void) : CVariable() {} - -CAdjLevelSetVariable::CAdjLevelSetVariable(unsigned short val_nDim, unsigned short val_nvar, CConfig *config) -: CVariable(val_nDim, val_nvar, config) { - - /*--- Allocate residual structures ---*/ - - Residual_Sum = new su2double [nVar]; Residual_Old = new su2double [nVar]; - - /*--- Allocate limiter (upwind)---*/ - - if (config->GetSpatialOrder() == SECOND_ORDER_LIMITER) Limiter = new su2double [nVar]; - -} - -CAdjLevelSetVariable::CAdjLevelSetVariable(su2double val_levelset, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) -: CVariable(val_nDim, val_nvar, config) { - - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - - /*--- Allocate residual structures ---*/ - - Residual_Sum = new su2double [nVar]; Residual_Old = new su2double [nVar]; - - /*--- Allocate limiter (upwind)---*/ - - if (config->GetSpatialOrder() == SECOND_ORDER_LIMITER) Limiter = new su2double [nVar]; - - /*--- Solution and old solution initialization ---*/ - - Solution[0] = val_levelset; Solution_Old[0] = val_levelset; - - if (dual_time) { - Solution_time_n[0] = val_levelset; - Solution_time_n1[0] = val_levelset; - } - -} - -CAdjLevelSetVariable::~CAdjLevelSetVariable(void) { - - delete [] Residual_Sum; delete [] Residual_Old; - if (Limiter != NULL) delete [] Limiter; - -} +/*! + * \file variable_adjoint_levelset.cpp + * \brief Definition of the solution fields. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/variable_structure.hpp" + + +CAdjLevelSetVariable::CAdjLevelSetVariable(void) : CVariable() {} + +CAdjLevelSetVariable::CAdjLevelSetVariable(unsigned short val_nDim, unsigned short val_nvar, CConfig *config) +: CVariable(val_nDim, val_nvar, config) { + + /*--- Allocate residual structures ---*/ + + Residual_Sum = new su2double [nVar]; Residual_Old = new su2double [nVar]; + + /*--- Allocate limiter (upwind)---*/ + + if (config->GetSpatialOrder() == SECOND_ORDER_LIMITER) Limiter = new su2double [nVar]; + +} + +CAdjLevelSetVariable::CAdjLevelSetVariable(su2double val_levelset, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) +: CVariable(val_nDim, val_nvar, config) { + + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + + /*--- Allocate residual structures ---*/ + + Residual_Sum = new su2double [nVar]; Residual_Old = new su2double [nVar]; + + /*--- Allocate limiter (upwind)---*/ + + if (config->GetSpatialOrder() == SECOND_ORDER_LIMITER) Limiter = new su2double [nVar]; + + /*--- Solution and old solution initialization ---*/ + + Solution[0] = val_levelset; Solution_Old[0] = val_levelset; + + if (dual_time) { + Solution_time_n[0] = val_levelset; + Solution_time_n1[0] = val_levelset; + } + +} + +CAdjLevelSetVariable::~CAdjLevelSetVariable(void) { + + delete [] Residual_Sum; delete [] Residual_Old; + if (Limiter != NULL) delete [] Limiter; + +} diff --git a/SU2_CFD/src/variable_adjoint_mean.cpp b/SU2_CFD/src/variable_adjoint_mean.cpp index ac85da2a763..48f32479e5c 100644 --- a/SU2_CFD/src/variable_adjoint_mean.cpp +++ b/SU2_CFD/src/variable_adjoint_mean.cpp @@ -1,338 +1,338 @@ -/*! - * \file variable_adjoint_mean.cpp - * \brief Definition of the solution fields. - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/variable_structure.hpp" - -CAdjEulerVariable::CAdjEulerVariable(void) : CVariable() { - - /*--- Array initialization ---*/ - Psi = NULL; - ForceProj_Vector = NULL; - ObjFuncSource = NULL; - IntBoundary_Jump = NULL; - TS_Source = NULL; - -} - -CAdjEulerVariable::CAdjEulerVariable(su2double val_psirho, su2double *val_phi, su2double val_psie, unsigned short val_nDim, - unsigned short val_nvar, CConfig *config) : CVariable(val_nDim, val_nvar, config) { - unsigned short iVar, iDim, iMesh, nMGSmooth = 0; - - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - - /*--- Array initialization ---*/ - Psi = NULL; - ForceProj_Vector = NULL; - ObjFuncSource = NULL; - IntBoundary_Jump = NULL; - TS_Source = NULL; - - /*--- Allocate residual structures ---*/ - Res_TruncError = new su2double [nVar]; - - for (iVar = 0; iVar < nVar; iVar++) { - Res_TruncError[iVar] = 0.0; - } - - /*--- Only for residual smoothing (multigrid) ---*/ - for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) - nMGSmooth += config->GetMG_CorrecSmooth(iMesh); - - if (nMGSmooth > 0) { - Residual_Sum = new su2double [nVar]; - Residual_Old = new su2double [nVar]; - } - - /*--- Allocate undivided laplacian (centered) and limiter (upwind)---*/ - if (config->GetKind_ConvNumScheme_AdjFlow() == SPACE_CENTERED) - Undivided_Laplacian = new su2double [nVar]; - if (config->GetKind_ConvNumScheme_AdjFlow() == SPACE_UPWIND) { - Limiter = new su2double [nVar]; - Solution_Max = new su2double [nVar]; - Solution_Min = new su2double [nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Limiter[iVar] = 0.0; - Solution_Max[iVar] = 0.0; - Solution_Min[iVar] = 0.0; - } - } - - /*--- Allocate and initialize solution ---*/ - if (compressible) { - Solution[0] = val_psirho; Solution_Old[0] = val_psirho; - Solution[nVar-1] = val_psie; Solution_Old[nVar-1] = val_psie; - for (iDim = 0; iDim < nDim; iDim++) { - Solution[iDim+1] = val_phi[iDim]; - Solution_Old[iDim+1] = val_phi[iDim]; - } - } - if (incompressible || freesurface) { - Solution[0] = 0.0; Solution_Old[0] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Solution[iDim+1] = 0.0; - Solution_Old[iDim+1] = 0.0; - } - } - - - /*--- Allocate and initialize solution for dual time strategy ---*/ - if (dual_time) { - if (compressible) { - Solution_time_n[0] = val_psirho; - Solution_time_n1[0] = val_psirho; - for (iDim = 0; iDim < nDim; iDim++) { - Solution_time_n[iDim+1] = val_phi[iDim]; - Solution_time_n1[iDim+1] = val_phi[iDim]; - } - Solution_time_n[nVar-1] = val_psie; - Solution_time_n1[nVar-1] = val_psie; - } - if (incompressible || freesurface) { - Solution_time_n[0] = 0.0; - Solution_time_n1[0] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Solution_time_n[iDim+1] = 0.0; - Solution_time_n1[iDim+1] = 0.0; - } - } - - } - - /*--- Allocate auxiliar vector for sensitivity computation ---*/ - Grad_AuxVar = new su2double [nDim]; - - /*--- Allocate and initialize projection vector for wall boundary condition ---*/ - ForceProj_Vector = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - ForceProj_Vector[iDim] = 0.0; - - /*--- Allocate and initialize interior boundary jump vector for near field boundary condition ---*/ - IntBoundary_Jump = new su2double [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - IntBoundary_Jump[iVar] = 0.0; - - /*--- Allocate space for the time spectral source terms ---*/ - if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { - TS_Source = new su2double[nVar]; - for (iVar = 0; iVar < nVar; iVar++) - TS_Source[iVar] = 0.0; - } - -} - -CAdjEulerVariable::CAdjEulerVariable(su2double *val_solution, unsigned short val_nDim, - unsigned short val_nvar, CConfig *config) : CVariable(val_nDim, val_nvar, config) { - unsigned short iVar, iDim, iMesh, nMGSmooth = 0; - - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - - /*--- Array initialization ---*/ - Psi = NULL; - ForceProj_Vector = NULL; - ObjFuncSource = NULL; - IntBoundary_Jump = NULL; - TS_Source = NULL; - - /*--- Allocate residual structures ---*/ - Res_TruncError = new su2double [nVar]; - - for (iVar = 0; iVar < nVar; iVar++) { - Res_TruncError[iVar] = 0.0; - } - - /*--- Only for residual smoothing (multigrid) ---*/ - for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) - nMGSmooth += config->GetMG_CorrecSmooth(iMesh); - - if (nMGSmooth > 0) { - Residual_Sum = new su2double [nVar]; - Residual_Old = new su2double [nVar]; - } - - /*--- Allocate undivided laplacian (centered) and limiter (upwind)---*/ - if (config->GetKind_ConvNumScheme_AdjFlow() == SPACE_CENTERED) - Undivided_Laplacian = new su2double [nVar]; - if (config->GetKind_ConvNumScheme_AdjFlow() == SPACE_UPWIND) { - Limiter = new su2double [nVar]; - Solution_Max = new su2double [nVar]; - Solution_Min = new su2double [nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Limiter[iVar] = 0.0; - Solution_Max[iVar] = 0.0; - Solution_Min[iVar] = 0.0; - } - } - - /*--- Solution initialization ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - Solution[iVar] = val_solution[iVar]; - Solution_Old[iVar] = val_solution[iVar]; - } - - /*--- Allocate and initializate solution for dual time strategy ---*/ - if (dual_time) { - Solution_time_n = new su2double [nVar]; - Solution_time_n1 = new su2double [nVar]; - - for (iVar = 0; iVar < nVar; iVar++) { - Solution_time_n[iVar] = val_solution[iVar]; - Solution_time_n1[iVar] = val_solution[iVar]; - } - } - - /*--- Allocate auxiliar vector for sensitivity computation ---*/ - Grad_AuxVar = new su2double [nDim]; - - /*--- Allocate and initializate projection vector for wall boundary condition ---*/ - ForceProj_Vector = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - ForceProj_Vector[iDim] = 0.0; - - /*--- Allocate and initializate interior boundary jump vector for near field boundary condition ---*/ - IntBoundary_Jump = new su2double [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - IntBoundary_Jump[iVar] = 0.0; - - /*--- Allocate space for the time spectral source terms ---*/ - if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { - TS_Source = new su2double[nVar]; - for (iVar = 0; iVar < nVar; iVar++) - TS_Source[iVar] = 0.0; - } - -} - -CAdjEulerVariable::~CAdjEulerVariable(void) { - - if (Psi != NULL) delete [] Psi; - if (ForceProj_Vector != NULL) delete [] ForceProj_Vector; - if (ObjFuncSource != NULL) delete [] ObjFuncSource; - if (IntBoundary_Jump != NULL) delete [] IntBoundary_Jump; - if (TS_Source != NULL) delete [] TS_Source; - -} - -bool CAdjEulerVariable::SetPrimVar_Compressible(su2double SharpEdge_Distance, bool check, CConfig *config) { - unsigned short iVar; - bool check_dens = false, RightVol = true; - - su2double adj_limit = config->GetAdjointLimit(); - - check_dens = (fabs(Solution[0]) > adj_limit); - - /*--- Check that the adjoint solution is bounded ---*/ - - if (check_dens) { - - /*--- Copy the old solution ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = Solution_Old[iVar]; - - RightVol = false; - - } - - return RightVol; - -} - -bool CAdjEulerVariable::SetPrimVar_Incompressible(su2double SharpEdge_Distance, bool check, CConfig *config) { - unsigned short iVar; - bool check_press = false, RightVol = true; - - su2double adj_limit = config->GetAdjointLimit(); - - check_press = (fabs(Solution[0]) > adj_limit); - - /*--- Check that the adjoint solution is bounded ---*/ - - if (check_press) { - - /*--- Copy the old solution ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = Solution_Old[iVar]; - - RightVol = false; - - } - - return RightVol; - -} - -bool CAdjEulerVariable::SetPrimVar_FreeSurface(su2double SharpEdge_Distance, bool check, CConfig *config) { - unsigned short iVar; - bool check_press = false, RightVol = true; - - su2double adj_limit = config->GetAdjointLimit(); - su2double dist_limit = config->GetLimiterCoeff()*config->GetRefElemLength()*config->GetSharpEdgesCoeff(); - - if (SharpEdge_Distance < dist_limit) { - - check_press = (fabs(Solution[0]) > adj_limit); // Check adjoint pressure - - /*--- Check that the solution has a physical meaning ---*/ - if (check_press) { - - /*--- Copy the old solution ---*/ - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = Solution_Old[iVar]; - - RightVol = false; - - } - - } - - return RightVol; - -} - -CAdjNSVariable::CAdjNSVariable(void) : CAdjEulerVariable() { } - -CAdjNSVariable::CAdjNSVariable(su2double *val_solution, unsigned short val_nDim, - unsigned short val_nvar, CConfig *config) : CAdjEulerVariable(val_solution, val_nDim, val_nvar, config) { - -} - -CAdjNSVariable::CAdjNSVariable(su2double val_psirho, su2double *val_phi, su2double val_psie, - unsigned short val_nDim, unsigned short val_nvar, CConfig *config) : CAdjEulerVariable(val_psirho, val_phi, val_psie, val_nDim, val_nvar, config) { - -} - -CAdjNSVariable::~CAdjNSVariable(void) { } +/*! + * \file variable_adjoint_mean.cpp + * \brief Definition of the solution fields. + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/variable_structure.hpp" + +CAdjEulerVariable::CAdjEulerVariable(void) : CVariable() { + + /*--- Array initialization ---*/ + Psi = NULL; + ForceProj_Vector = NULL; + ObjFuncSource = NULL; + IntBoundary_Jump = NULL; + TS_Source = NULL; + +} + +CAdjEulerVariable::CAdjEulerVariable(su2double val_psirho, su2double *val_phi, su2double val_psie, unsigned short val_nDim, + unsigned short val_nvar, CConfig *config) : CVariable(val_nDim, val_nvar, config) { + unsigned short iVar, iDim, iMesh, nMGSmooth = 0; + + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + + /*--- Array initialization ---*/ + Psi = NULL; + ForceProj_Vector = NULL; + ObjFuncSource = NULL; + IntBoundary_Jump = NULL; + TS_Source = NULL; + + /*--- Allocate residual structures ---*/ + Res_TruncError = new su2double [nVar]; + + for (iVar = 0; iVar < nVar; iVar++) { + Res_TruncError[iVar] = 0.0; + } + + /*--- Only for residual smoothing (multigrid) ---*/ + for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) + nMGSmooth += config->GetMG_CorrecSmooth(iMesh); + + if (nMGSmooth > 0) { + Residual_Sum = new su2double [nVar]; + Residual_Old = new su2double [nVar]; + } + + /*--- Allocate undivided laplacian (centered) and limiter (upwind)---*/ + if (config->GetKind_ConvNumScheme_AdjFlow() == SPACE_CENTERED) + Undivided_Laplacian = new su2double [nVar]; + if (config->GetKind_ConvNumScheme_AdjFlow() == SPACE_UPWIND) { + Limiter = new su2double [nVar]; + Solution_Max = new su2double [nVar]; + Solution_Min = new su2double [nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Limiter[iVar] = 0.0; + Solution_Max[iVar] = 0.0; + Solution_Min[iVar] = 0.0; + } + } + + /*--- Allocate and initialize solution ---*/ + if (compressible) { + Solution[0] = val_psirho; Solution_Old[0] = val_psirho; + Solution[nVar-1] = val_psie; Solution_Old[nVar-1] = val_psie; + for (iDim = 0; iDim < nDim; iDim++) { + Solution[iDim+1] = val_phi[iDim]; + Solution_Old[iDim+1] = val_phi[iDim]; + } + } + if (incompressible || freesurface) { + Solution[0] = 0.0; Solution_Old[0] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Solution[iDim+1] = 0.0; + Solution_Old[iDim+1] = 0.0; + } + } + + + /*--- Allocate and initialize solution for dual time strategy ---*/ + if (dual_time) { + if (compressible) { + Solution_time_n[0] = val_psirho; + Solution_time_n1[0] = val_psirho; + for (iDim = 0; iDim < nDim; iDim++) { + Solution_time_n[iDim+1] = val_phi[iDim]; + Solution_time_n1[iDim+1] = val_phi[iDim]; + } + Solution_time_n[nVar-1] = val_psie; + Solution_time_n1[nVar-1] = val_psie; + } + if (incompressible || freesurface) { + Solution_time_n[0] = 0.0; + Solution_time_n1[0] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Solution_time_n[iDim+1] = 0.0; + Solution_time_n1[iDim+1] = 0.0; + } + } + + } + + /*--- Allocate auxiliar vector for sensitivity computation ---*/ + Grad_AuxVar = new su2double [nDim]; + + /*--- Allocate and initialize projection vector for wall boundary condition ---*/ + ForceProj_Vector = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + ForceProj_Vector[iDim] = 0.0; + + /*--- Allocate and initialize interior boundary jump vector for near field boundary condition ---*/ + IntBoundary_Jump = new su2double [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + IntBoundary_Jump[iVar] = 0.0; + + /*--- Allocate space for the time spectral source terms ---*/ + if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { + TS_Source = new su2double[nVar]; + for (iVar = 0; iVar < nVar; iVar++) + TS_Source[iVar] = 0.0; + } + +} + +CAdjEulerVariable::CAdjEulerVariable(su2double *val_solution, unsigned short val_nDim, + unsigned short val_nvar, CConfig *config) : CVariable(val_nDim, val_nvar, config) { + unsigned short iVar, iDim, iMesh, nMGSmooth = 0; + + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + + /*--- Array initialization ---*/ + Psi = NULL; + ForceProj_Vector = NULL; + ObjFuncSource = NULL; + IntBoundary_Jump = NULL; + TS_Source = NULL; + + /*--- Allocate residual structures ---*/ + Res_TruncError = new su2double [nVar]; + + for (iVar = 0; iVar < nVar; iVar++) { + Res_TruncError[iVar] = 0.0; + } + + /*--- Only for residual smoothing (multigrid) ---*/ + for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) + nMGSmooth += config->GetMG_CorrecSmooth(iMesh); + + if (nMGSmooth > 0) { + Residual_Sum = new su2double [nVar]; + Residual_Old = new su2double [nVar]; + } + + /*--- Allocate undivided laplacian (centered) and limiter (upwind)---*/ + if (config->GetKind_ConvNumScheme_AdjFlow() == SPACE_CENTERED) + Undivided_Laplacian = new su2double [nVar]; + if (config->GetKind_ConvNumScheme_AdjFlow() == SPACE_UPWIND) { + Limiter = new su2double [nVar]; + Solution_Max = new su2double [nVar]; + Solution_Min = new su2double [nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Limiter[iVar] = 0.0; + Solution_Max[iVar] = 0.0; + Solution_Min[iVar] = 0.0; + } + } + + /*--- Solution initialization ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + Solution[iVar] = val_solution[iVar]; + Solution_Old[iVar] = val_solution[iVar]; + } + + /*--- Allocate and initializate solution for dual time strategy ---*/ + if (dual_time) { + Solution_time_n = new su2double [nVar]; + Solution_time_n1 = new su2double [nVar]; + + for (iVar = 0; iVar < nVar; iVar++) { + Solution_time_n[iVar] = val_solution[iVar]; + Solution_time_n1[iVar] = val_solution[iVar]; + } + } + + /*--- Allocate auxiliar vector for sensitivity computation ---*/ + Grad_AuxVar = new su2double [nDim]; + + /*--- Allocate and initializate projection vector for wall boundary condition ---*/ + ForceProj_Vector = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + ForceProj_Vector[iDim] = 0.0; + + /*--- Allocate and initializate interior boundary jump vector for near field boundary condition ---*/ + IntBoundary_Jump = new su2double [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + IntBoundary_Jump[iVar] = 0.0; + + /*--- Allocate space for the time spectral source terms ---*/ + if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { + TS_Source = new su2double[nVar]; + for (iVar = 0; iVar < nVar; iVar++) + TS_Source[iVar] = 0.0; + } + +} + +CAdjEulerVariable::~CAdjEulerVariable(void) { + + if (Psi != NULL) delete [] Psi; + if (ForceProj_Vector != NULL) delete [] ForceProj_Vector; + if (ObjFuncSource != NULL) delete [] ObjFuncSource; + if (IntBoundary_Jump != NULL) delete [] IntBoundary_Jump; + if (TS_Source != NULL) delete [] TS_Source; + +} + +bool CAdjEulerVariable::SetPrimVar_Compressible(su2double SharpEdge_Distance, bool check, CConfig *config) { + unsigned short iVar; + bool check_dens = false, RightVol = true; + + su2double adj_limit = config->GetAdjointLimit(); + + check_dens = (fabs(Solution[0]) > adj_limit); + + /*--- Check that the adjoint solution is bounded ---*/ + + if (check_dens) { + + /*--- Copy the old solution ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = Solution_Old[iVar]; + + RightVol = false; + + } + + return RightVol; + +} + +bool CAdjEulerVariable::SetPrimVar_Incompressible(su2double SharpEdge_Distance, bool check, CConfig *config) { + unsigned short iVar; + bool check_press = false, RightVol = true; + + su2double adj_limit = config->GetAdjointLimit(); + + check_press = (fabs(Solution[0]) > adj_limit); + + /*--- Check that the adjoint solution is bounded ---*/ + + if (check_press) { + + /*--- Copy the old solution ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = Solution_Old[iVar]; + + RightVol = false; + + } + + return RightVol; + +} + +bool CAdjEulerVariable::SetPrimVar_FreeSurface(su2double SharpEdge_Distance, bool check, CConfig *config) { + unsigned short iVar; + bool check_press = false, RightVol = true; + + su2double adj_limit = config->GetAdjointLimit(); + su2double dist_limit = config->GetLimiterCoeff()*config->GetRefElemLength()*config->GetSharpEdgesCoeff(); + + if (SharpEdge_Distance < dist_limit) { + + check_press = (fabs(Solution[0]) > adj_limit); // Check adjoint pressure + + /*--- Check that the solution has a physical meaning ---*/ + if (check_press) { + + /*--- Copy the old solution ---*/ + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = Solution_Old[iVar]; + + RightVol = false; + + } + + } + + return RightVol; + +} + +CAdjNSVariable::CAdjNSVariable(void) : CAdjEulerVariable() { } + +CAdjNSVariable::CAdjNSVariable(su2double *val_solution, unsigned short val_nDim, + unsigned short val_nvar, CConfig *config) : CAdjEulerVariable(val_solution, val_nDim, val_nvar, config) { + +} + +CAdjNSVariable::CAdjNSVariable(su2double val_psirho, su2double *val_phi, su2double val_psie, + unsigned short val_nDim, unsigned short val_nvar, CConfig *config) : CAdjEulerVariable(val_psirho, val_phi, val_psie, val_nDim, val_nvar, config) { + +} + +CAdjNSVariable::~CAdjNSVariable(void) { } diff --git a/SU2_CFD/src/variable_adjoint_turbulent.cpp b/SU2_CFD/src/variable_adjoint_turbulent.cpp index 1dc7c5cf1f6..2537e065ad1 100644 --- a/SU2_CFD/src/variable_adjoint_turbulent.cpp +++ b/SU2_CFD/src/variable_adjoint_turbulent.cpp @@ -1,72 +1,72 @@ -/*! - * \file variable_adjoint_turbulent.cpp - * \brief Definition of the solution fields. - * \author F. Palacios, A. Bueno - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/variable_structure.hpp" - -CAdjTurbVariable::CAdjTurbVariable(void) : CVariable() { - - /*--- Array initialization ---*/ - - dmuT_dUTvar = NULL; - dRTstar_dUTvar = NULL; - dFT_dUTvar = NULL; - EddyViscSens = NULL; - -} - -CAdjTurbVariable::CAdjTurbVariable(su2double val_psinu_inf, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) : CVariable(val_nDim, val_nvar, config) { - - /*--- Array initialization ---*/ - - dmuT_dUTvar = NULL; - dRTstar_dUTvar = NULL; - dFT_dUTvar = NULL; - EddyViscSens = NULL; - - /*--- Initialization of variables ---*/ - - for (unsigned short iVar = 0; iVar < nVar; iVar++) { - Solution[iVar] = val_psinu_inf; - Solution_Old[iVar] = val_psinu_inf; - } - - Residual_Old = new su2double [nVar]; - - if (config->GetSpatialOrder() == SECOND_ORDER_LIMITER) Limiter = new su2double [nVar]; - -} - -CAdjTurbVariable::~CAdjTurbVariable(void) { - - if (dmuT_dUTvar != NULL) delete [] dmuT_dUTvar; - if (EddyViscSens != NULL) delete [] EddyViscSens; - -} +/*! + * \file variable_adjoint_turbulent.cpp + * \brief Definition of the solution fields. + * \author F. Palacios, A. Bueno + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/variable_structure.hpp" + +CAdjTurbVariable::CAdjTurbVariable(void) : CVariable() { + + /*--- Array initialization ---*/ + + dmuT_dUTvar = NULL; + dRTstar_dUTvar = NULL; + dFT_dUTvar = NULL; + EddyViscSens = NULL; + +} + +CAdjTurbVariable::CAdjTurbVariable(su2double val_psinu_inf, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) : CVariable(val_nDim, val_nvar, config) { + + /*--- Array initialization ---*/ + + dmuT_dUTvar = NULL; + dRTstar_dUTvar = NULL; + dFT_dUTvar = NULL; + EddyViscSens = NULL; + + /*--- Initialization of variables ---*/ + + for (unsigned short iVar = 0; iVar < nVar; iVar++) { + Solution[iVar] = val_psinu_inf; + Solution_Old[iVar] = val_psinu_inf; + } + + Residual_Old = new su2double [nVar]; + + if (config->GetSpatialOrder() == SECOND_ORDER_LIMITER) Limiter = new su2double [nVar]; + +} + +CAdjTurbVariable::~CAdjTurbVariable(void) { + + if (dmuT_dUTvar != NULL) delete [] dmuT_dUTvar; + if (EddyViscSens != NULL) delete [] EddyViscSens; + +} diff --git a/SU2_CFD/src/variable_direct_elasticity.cpp b/SU2_CFD/src/variable_direct_elasticity.cpp index 16f5176b5b8..07764ca1e9c 100644 --- a/SU2_CFD/src/variable_direct_elasticity.cpp +++ b/SU2_CFD/src/variable_direct_elasticity.cpp @@ -1,248 +1,248 @@ -/*! - * \file variable_direct_elasticity.cpp - * \brief Definition of the solution fields. - * \author F. Palacios, R. Sanchez - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/variable_structure.hpp" - -CFEAVariable::CFEAVariable(void) : CVariable() { } - -CFEAVariable::CFEAVariable(su2double *val_fea, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) -: CVariable(val_nDim, val_nvar, config) { - unsigned short iVar, iDim, jDim; - - dynamicFEA = (config->GetDynamic_Analysis() == DYNAMIC); - - /*--- Allocate residual structures ---*/ - Residual_Sum = new su2double [nVar]; Residual_Old = new su2double [nVar]; - - /*--- Initialization of variables ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - Solution[iVar] = val_fea[iVar]; - Solution_Old[iVar] = val_fea[iVar]; - } - - if (dynamicFEA){ - - /*--- Allocate solution structures ---*/ - Solution_Pred = new su2double [nVar]; - Solution_Pred_Old = new su2double [nVar]; - Solution_time_n = new su2double [nVar]; - Solution_Vel = new su2double [nVar]; - Solution_Vel_time_n = new su2double [nVar]; - Solution_Accel = new su2double [nVar]; - Solution_Accel_time_n = new su2double [nVar]; - - /*--- Initialization of variables for dynamic problem ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - Solution_Pred[iVar] = val_fea[iVar]; - Solution_Pred_Old[iVar] = val_fea[iVar]; - Solution_time_n[iVar] = val_fea[iVar]; - Solution_Vel[iVar] = val_fea[iVar]; - Solution_Vel_time_n[iVar] = val_fea[iVar]; - Solution_Accel[iVar] = val_fea[iVar]; - Solution_Accel_time_n[iVar] = val_fea[iVar]; - } - } - - - - /*--- Allocate stress tensor ---*/ - Stress = new su2double* [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Stress[iDim] = new su2double [nDim]; - - /*--- Initialize stress tensor---*/ - for (iDim = 0; iDim < nDim; iDim++){ - for (jDim = 0; jDim < nDim; jDim++){ - Stress[iDim][jDim]=0.0; - } - } -} - -CFEAVariable::~CFEAVariable(void) { - unsigned short iDim; - - for (iDim = 0; iDim < nDim; iDim++) - delete [] Stress[iDim]; - delete [] Stress; - delete [] Residual_Sum; - delete [] Residual_Old; - delete [] Solution; - - if (dynamicFEA){ - delete[] Solution_Pred; - delete[] Solution_Pred_Old; - delete[] Solution_time_n; - delete[] Solution_Vel; - delete[] Solution_Vel_time_n; - delete[] Solution_Accel; - delete[] Solution_Accel_time_n ; - } - - - -} - -void CFEAVariable::SetSolution_time_n(void) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution_time_n[iVar] = Solution[iVar]; - -} - -void CFEAVariable::SetSolution_time_n(su2double *val_solution_time_n) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution_time_n[iVar] = val_solution_time_n[iVar]; - -} - -void CFEAVariable::SetSolution_Vel(su2double *val_solution_vel) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution_Vel[iVar] = val_solution_vel[iVar]; - -} - -void CFEAVariable::SetSolution_Vel_time_n(su2double *val_solution_vel_time_n) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution_Vel_time_n[iVar] = val_solution_vel_time_n[iVar]; - -} - -void CFEAVariable::SetSolution_Vel_time_n(void) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution_Vel_time_n[iVar] = Solution_Vel[iVar]; - -} - -void CFEAVariable::SetSolution_Accel(su2double *val_solution_accel) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution_Accel[iVar] = val_solution_accel[iVar]; - -} - -void CFEAVariable::SetSolution_Accel_time_n(su2double *val_solution_accel_time_n) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution_Accel_time_n[iVar] = val_solution_accel_time_n[iVar]; - -} - -void CFEAVariable::SetSolution_Accel_time_n(void) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution_Accel_time_n[iVar] = Solution_Accel[iVar]; - -} - -void CFEAVariable::SetSolution_Pred(void){ - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution_Pred[iVar] = Solution[iVar]; - -} - -void CFEAVariable::SetSolution_Pred_Old(void){ - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution_Pred_Old[iVar] = Solution_Pred[iVar]; - -} - - -CFEABoundVariable::CFEABoundVariable(void) : CVariable() { } - -CFEABoundVariable::CFEABoundVariable(unsigned short val_nDim, unsigned short val_nvar, unsigned short val_nElBound, CConfig *config) -: CVariable(val_nDim, val_nvar, config) { - unsigned short iDim, jDim; - - /*--- Allocate residual structures ---*/ - Residual_Sum = new su2double [nVar]; Residual_Old = new su2double [nVar]; - - /*--- Allocate stress tensor ---*/ - if (nDim == 2){ - Traction = new su2double* [2*nDim]; - for (iDim = 0; iDim < 2*nDim ; iDim++) - Traction[iDim] = new su2double [val_nElBound]; - } - else if (nDim == 3){ - /*--- Allocate stress tensor ---*/ - Traction = new su2double* [4*nDim]; - for (iDim = 0; iDim < 4*nDim ; iDim++) - Traction[iDim] = new su2double [val_nElBound]; - } - - /*--- Initialize stress tensor ---*/ - if (nDim == 2){ - /*--- Initialize stress tensor---*/ - for (iDim = 0; iDim < 2*nDim; iDim++){ - for (jDim = 0; jDim < val_nElBound; jDim++){ - Traction[iDim][jDim]=0.0; - } - } - } - else if (nDim == 3){ - /*--- Initialize stress tensor---*/ - for (iDim = 0; iDim < 4*nDim; iDim++){ - for (jDim = 0; jDim < val_nElBound; jDim++){ - Traction[iDim][jDim]=0.0; - } - } - } - -} - -CFEABoundVariable::~CFEABoundVariable(void) { - unsigned short iDim; - - /*--- Initialize stress tensor ---*/ - if (nDim == 2){ - /*--- Initialize stress tensor---*/ - for (iDim = 0; iDim < 2*nDim; iDim++){ - delete [] Traction[iDim]; - } - } - else if (nDim == 3){ - /*--- Initialize stress tensor---*/ - for (iDim = 0; iDim < 4*nDim; iDim++){ - delete [] Traction[iDim]; - } - } - - delete [] Traction; - - delete [] Residual_Sum; - delete [] Residual_Old; - -} +/*! + * \file variable_direct_elasticity.cpp + * \brief Definition of the solution fields. + * \author F. Palacios, R. Sanchez + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/variable_structure.hpp" + +CFEAVariable::CFEAVariable(void) : CVariable() { } + +CFEAVariable::CFEAVariable(su2double *val_fea, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) +: CVariable(val_nDim, val_nvar, config) { + unsigned short iVar, iDim, jDim; + + dynamicFEA = (config->GetDynamic_Analysis() == DYNAMIC); + + /*--- Allocate residual structures ---*/ + Residual_Sum = new su2double [nVar]; Residual_Old = new su2double [nVar]; + + /*--- Initialization of variables ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + Solution[iVar] = val_fea[iVar]; + Solution_Old[iVar] = val_fea[iVar]; + } + + if (dynamicFEA){ + + /*--- Allocate solution structures ---*/ + Solution_Pred = new su2double [nVar]; + Solution_Pred_Old = new su2double [nVar]; + Solution_time_n = new su2double [nVar]; + Solution_Vel = new su2double [nVar]; + Solution_Vel_time_n = new su2double [nVar]; + Solution_Accel = new su2double [nVar]; + Solution_Accel_time_n = new su2double [nVar]; + + /*--- Initialization of variables for dynamic problem ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + Solution_Pred[iVar] = val_fea[iVar]; + Solution_Pred_Old[iVar] = val_fea[iVar]; + Solution_time_n[iVar] = val_fea[iVar]; + Solution_Vel[iVar] = val_fea[iVar]; + Solution_Vel_time_n[iVar] = val_fea[iVar]; + Solution_Accel[iVar] = val_fea[iVar]; + Solution_Accel_time_n[iVar] = val_fea[iVar]; + } + } + + + + /*--- Allocate stress tensor ---*/ + Stress = new su2double* [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Stress[iDim] = new su2double [nDim]; + + /*--- Initialize stress tensor---*/ + for (iDim = 0; iDim < nDim; iDim++){ + for (jDim = 0; jDim < nDim; jDim++){ + Stress[iDim][jDim]=0.0; + } + } +} + +CFEAVariable::~CFEAVariable(void) { + unsigned short iDim; + + for (iDim = 0; iDim < nDim; iDim++) + delete [] Stress[iDim]; + delete [] Stress; + delete [] Residual_Sum; + delete [] Residual_Old; + delete [] Solution; + + if (dynamicFEA){ + delete[] Solution_Pred; + delete[] Solution_Pred_Old; + delete[] Solution_time_n; + delete[] Solution_Vel; + delete[] Solution_Vel_time_n; + delete[] Solution_Accel; + delete[] Solution_Accel_time_n ; + } + + + +} + +void CFEAVariable::SetSolution_time_n(void) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution_time_n[iVar] = Solution[iVar]; + +} + +void CFEAVariable::SetSolution_time_n(su2double *val_solution_time_n) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution_time_n[iVar] = val_solution_time_n[iVar]; + +} + +void CFEAVariable::SetSolution_Vel(su2double *val_solution_vel) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution_Vel[iVar] = val_solution_vel[iVar]; + +} + +void CFEAVariable::SetSolution_Vel_time_n(su2double *val_solution_vel_time_n) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution_Vel_time_n[iVar] = val_solution_vel_time_n[iVar]; + +} + +void CFEAVariable::SetSolution_Vel_time_n(void) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution_Vel_time_n[iVar] = Solution_Vel[iVar]; + +} + +void CFEAVariable::SetSolution_Accel(su2double *val_solution_accel) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution_Accel[iVar] = val_solution_accel[iVar]; + +} + +void CFEAVariable::SetSolution_Accel_time_n(su2double *val_solution_accel_time_n) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution_Accel_time_n[iVar] = val_solution_accel_time_n[iVar]; + +} + +void CFEAVariable::SetSolution_Accel_time_n(void) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution_Accel_time_n[iVar] = Solution_Accel[iVar]; + +} + +void CFEAVariable::SetSolution_Pred(void){ + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution_Pred[iVar] = Solution[iVar]; + +} + +void CFEAVariable::SetSolution_Pred_Old(void){ + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution_Pred_Old[iVar] = Solution_Pred[iVar]; + +} + + +CFEABoundVariable::CFEABoundVariable(void) : CVariable() { } + +CFEABoundVariable::CFEABoundVariable(unsigned short val_nDim, unsigned short val_nvar, unsigned short val_nElBound, CConfig *config) +: CVariable(val_nDim, val_nvar, config) { + unsigned short iDim, jDim; + + /*--- Allocate residual structures ---*/ + Residual_Sum = new su2double [nVar]; Residual_Old = new su2double [nVar]; + + /*--- Allocate stress tensor ---*/ + if (nDim == 2){ + Traction = new su2double* [2*nDim]; + for (iDim = 0; iDim < 2*nDim ; iDim++) + Traction[iDim] = new su2double [val_nElBound]; + } + else if (nDim == 3){ + /*--- Allocate stress tensor ---*/ + Traction = new su2double* [4*nDim]; + for (iDim = 0; iDim < 4*nDim ; iDim++) + Traction[iDim] = new su2double [val_nElBound]; + } + + /*--- Initialize stress tensor ---*/ + if (nDim == 2){ + /*--- Initialize stress tensor---*/ + for (iDim = 0; iDim < 2*nDim; iDim++){ + for (jDim = 0; jDim < val_nElBound; jDim++){ + Traction[iDim][jDim]=0.0; + } + } + } + else if (nDim == 3){ + /*--- Initialize stress tensor---*/ + for (iDim = 0; iDim < 4*nDim; iDim++){ + for (jDim = 0; jDim < val_nElBound; jDim++){ + Traction[iDim][jDim]=0.0; + } + } + } + +} + +CFEABoundVariable::~CFEABoundVariable(void) { + unsigned short iDim; + + /*--- Initialize stress tensor ---*/ + if (nDim == 2){ + /*--- Initialize stress tensor---*/ + for (iDim = 0; iDim < 2*nDim; iDim++){ + delete [] Traction[iDim]; + } + } + else if (nDim == 3){ + /*--- Initialize stress tensor---*/ + for (iDim = 0; iDim < 4*nDim; iDim++){ + delete [] Traction[iDim]; + } + } + + delete [] Traction; + + delete [] Residual_Sum; + delete [] Residual_Old; + +} diff --git a/SU2_CFD/src/variable_direct_heat.cpp b/SU2_CFD/src/variable_direct_heat.cpp index 5a6aea03ea0..2c84a67bbd3 100644 --- a/SU2_CFD/src/variable_direct_heat.cpp +++ b/SU2_CFD/src/variable_direct_heat.cpp @@ -1,70 +1,70 @@ -/*! - * \file variable_direct_heat.cpp - * \brief Definition of the solution fields. - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/variable_structure.hpp" - -CHeatVariable::CHeatVariable(void) : CVariable() { - - /*--- Array initialization ---*/ - Solution_Direct = NULL; - -} - -CHeatVariable::CHeatVariable(su2double *val_heat, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) -: CVariable(val_nDim, val_nvar, config) { - unsigned short iVar; - - /*--- Array initialization ---*/ - Solution_Direct = NULL; - - /*--- Allocate residual structures ---*/ - Residual_Sum = new su2double [nVar]; Residual_Old = new su2double [nVar]; - - /*--- Allocate direct solution container for adjoint problem ---*/ - Solution_Direct = new su2double[nVar]; - - /*--- Allocate aux gradient vector ---*/ - Grad_AuxVar = new su2double [nDim]; - - /*--- Initialization of variables ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - Solution[iVar] = val_heat[iVar]; - Solution_Old[iVar] = val_heat[iVar]; - Solution_Direct[iVar] = 0.0; - } - -} - -CHeatVariable::~CHeatVariable(void) { - - if (Solution_Direct != NULL) delete [] Solution_Direct; - -} +/*! + * \file variable_direct_heat.cpp + * \brief Definition of the solution fields. + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/variable_structure.hpp" + +CHeatVariable::CHeatVariable(void) : CVariable() { + + /*--- Array initialization ---*/ + Solution_Direct = NULL; + +} + +CHeatVariable::CHeatVariable(su2double *val_heat, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) +: CVariable(val_nDim, val_nvar, config) { + unsigned short iVar; + + /*--- Array initialization ---*/ + Solution_Direct = NULL; + + /*--- Allocate residual structures ---*/ + Residual_Sum = new su2double [nVar]; Residual_Old = new su2double [nVar]; + + /*--- Allocate direct solution container for adjoint problem ---*/ + Solution_Direct = new su2double[nVar]; + + /*--- Allocate aux gradient vector ---*/ + Grad_AuxVar = new su2double [nDim]; + + /*--- Initialization of variables ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + Solution[iVar] = val_heat[iVar]; + Solution_Old[iVar] = val_heat[iVar]; + Solution_Direct[iVar] = 0.0; + } + +} + +CHeatVariable::~CHeatVariable(void) { + + if (Solution_Direct != NULL) delete [] Solution_Direct; + +} diff --git a/SU2_CFD/src/variable_direct_mean.cpp b/SU2_CFD/src/variable_direct_mean.cpp index fcfd99b003f..3d8147cc1e8 100644 --- a/SU2_CFD/src/variable_direct_mean.cpp +++ b/SU2_CFD/src/variable_direct_mean.cpp @@ -1,770 +1,770 @@ -/*! - * \file variable_direct_mean.cpp - * \brief Definition of the solution fields. - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/variable_structure.hpp" - -CEulerVariable::CEulerVariable(void) : CVariable() { - - /*--- Array initialization ---*/ - TS_Source = NULL; - Primitive = NULL; - Gradient_Primitive = NULL; - Limiter_Primitive = NULL; - WindGust = NULL; - WindGustDer = NULL; - -} - -CEulerVariable::CEulerVariable(su2double val_density, su2double *val_velocity, su2double val_energy, unsigned short val_nDim, - unsigned short val_nvar, CConfig *config) : CVariable(val_nDim, val_nvar, config) { - unsigned short iVar, iDim, iMesh, nMGSmooth = 0; - - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool low_fidelity = config->GetLowFidelitySim(); - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - bool viscous = config->GetViscous(); - bool windgust = config->GetWind_Gust(); - - /*--- Array initialization ---*/ - - TS_Source = NULL; - Primitive = NULL; - Gradient_Primitive = NULL; - Limiter_Primitive = NULL; - WindGust = NULL; - WindGustDer = NULL; - - /*--- Allocate and initialize the primitive variables and gradients ---*/ - - if (incompressible) { nPrimVar = nDim+5; nPrimVarGrad = nDim+3; } - if (freesurface) { nPrimVar = nDim+7; nPrimVarGrad = nDim+6; } - if (compressible) { nPrimVar = nDim+9; nPrimVarGrad = nDim+4; - if (viscous) { nSecondaryVar = 8; nSecondaryVarGrad = 2; } - else { nSecondaryVar = 2; nSecondaryVarGrad = 2; } - } - - /*--- Allocate residual structures ---*/ - - Res_TruncError = new su2double [nVar]; - - for (iVar = 0; iVar < nVar; iVar++) { - Res_TruncError[iVar] = 0.0; - } - - /*--- Only for residual smoothing (multigrid) ---*/ - - for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) - nMGSmooth += config->GetMG_CorrecSmooth(iMesh); - - if ((nMGSmooth > 0) || low_fidelity || freesurface) { - Residual_Sum = new su2double [nVar]; - Residual_Old = new su2double [nVar]; - } - - /*--- Allocate undivided laplacian (centered) and limiter (upwind)---*/ - - if (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED) { - Undivided_Laplacian = new su2double [nVar]; - } - - /*--- Always allocate the slope limiter, - and the auxiliar variables (check the logic - JST with 2nd order Turb model - ) ---*/ - - Limiter_Primitive = new su2double [nPrimVarGrad]; - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - Limiter_Primitive[iVar] = 0.0; - - if(compressible){ - Limiter_Secondary = new su2double [nSecondaryVarGrad]; - for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) - Limiter_Secondary[iVar] = 0.0; - } - - Limiter = new su2double [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - Limiter[iVar] = 0.0; - - Solution_Max = new su2double [nPrimVarGrad]; - Solution_Min = new su2double [nPrimVarGrad]; - for (iVar = 0; iVar < nPrimVarGrad; iVar++) { - Solution_Max[iVar] = 0.0; - Solution_Min[iVar] = 0.0; - } - - /*--- Solution and old solution initialization ---*/ - - if (compressible) { - Solution[0] = val_density; - Solution_Old[0] = val_density; - for (iDim = 0; iDim < nDim; iDim++) { - Solution[iDim+1] = val_density*val_velocity[iDim]; - Solution_Old[iDim+1] = val_density*val_velocity[iDim]; - } - Solution[nVar-1] = val_density*val_energy; - Solution_Old[nVar-1] = val_density*val_energy; - } - if (incompressible || freesurface) { - Solution[0] = config->GetPressure_FreeStreamND(); - Solution_Old[0] = config->GetPressure_FreeStreamND(); - for (iDim = 0; iDim < nDim; iDim++) { - Solution[iDim+1] = val_velocity[iDim]*config->GetDensity_FreeStreamND(); - Solution_Old[iDim+1] = val_velocity[iDim]*config->GetDensity_FreeStreamND(); - } - } - - /*--- Allocate and initialize solution for dual time strategy ---*/ - - if (dual_time) { - if (compressible) { - Solution_time_n[0] = val_density; - Solution_time_n1[0] = val_density; - for (iDim = 0; iDim < nDim; iDim++) { - Solution_time_n[iDim+1] = val_density*val_velocity[iDim]; - Solution_time_n1[iDim+1] = val_density*val_velocity[iDim]; - } - Solution_time_n[nVar-1] = val_density*val_energy; - Solution_time_n1[nVar-1] = val_density*val_energy; - } - if (incompressible || freesurface) { - Solution_time_n[0] = config->GetPressure_FreeStreamND(); - Solution_time_n1[0] = config->GetPressure_FreeStreamND(); - for (iDim = 0; iDim < nDim; iDim++) { - Solution_time_n[iDim+1] = val_velocity[iDim]*config->GetDensity_FreeStreamND(); - Solution_time_n1[iDim+1] = val_velocity[iDim]*config->GetDensity_FreeStreamND(); - } - } - } - - /*--- Allocate space for the time spectral source terms ---*/ - - if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { - TS_Source = new su2double[nVar]; - for (iVar = 0; iVar < nVar; iVar++) TS_Source[iVar] = 0.0; - } - - /*--- Allocate vector for wind gust and wind gust derivative field ---*/ - - if (windgust) { - WindGust = new su2double [nDim]; - WindGustDer = new su2double [nDim+1]; - } - - /*--- Allocate auxiliar vector for free surface source term ---*/ - - if (freesurface) Grad_AuxVar = new su2double [nDim]; - - /*--- Incompressible flow, primitive variables nDim+3, (P, vx, vy, vz, rho, beta), - FreeSurface Incompressible flow, primitive variables nDim+4, (P, vx, vy, vz, rho, beta, dist), - Compressible flow, primitive variables nDim+5, (T, vx, vy, vz, P, rho, h, c) ---*/ - - Primitive = new su2double [nPrimVar]; - for (iVar = 0; iVar < nPrimVar; iVar++) Primitive[iVar] = 0.0; - - if (compressible){ - Secondary = new su2double [nSecondaryVar]; - for (iVar = 0; iVar < nSecondaryVar; iVar++) Secondary[iVar] = 0.0; - } - - /*--- Incompressible flow, gradients primitive variables nDim+2, (P, vx, vy, vz, rho), - FreeSurface Incompressible flow, primitive variables nDim+3, (P, vx, vy, vz, rho, beta, dist), - Compressible flow, gradients primitive variables nDim+4, (T, vx, vy, vz, P, rho, h) - We need P, and rho for running the adjoint problem ---*/ - - Gradient_Primitive = new su2double* [nPrimVarGrad]; - for (iVar = 0; iVar < nPrimVarGrad; iVar++) { - Gradient_Primitive[iVar] = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Gradient_Primitive[iVar][iDim] = 0.0; - } - - if (compressible){ - Gradient_Secondary = new su2double* [nSecondaryVarGrad]; - for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { - Gradient_Secondary[iVar] = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Gradient_Secondary[iVar][iDim] = 0.0; - } - } -} - -CEulerVariable::CEulerVariable(su2double *val_solution, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) : CVariable(val_nDim, val_nvar, config) { - unsigned short iVar, iDim, iMesh, nMGSmooth = 0; - - bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); - bool freesurface = (config->GetKind_Regime() == FREESURFACE); - bool low_fidelity = config->GetLowFidelitySim(); - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - bool viscous = config->GetViscous(); - bool windgust = config->GetWind_Gust(); - - /*--- Array initialization ---*/ - TS_Source = NULL; - Primitive = NULL; - Gradient_Primitive = NULL; - Limiter_Primitive = NULL; - WindGust = NULL; - WindGustDer = NULL; - - /*--- Allocate and initialize the primitive variables and gradients ---*/ - if (incompressible) { nPrimVar = nDim+5; nPrimVarGrad = nDim+3; } - if (freesurface) { nPrimVar = nDim+7; nPrimVarGrad = nDim+6; } - if (compressible) { nPrimVar = nDim+9; nPrimVarGrad = nDim+4; - if (viscous) { nSecondaryVar = 8; nSecondaryVarGrad = 2; } - else { nSecondaryVar = 2; nSecondaryVarGrad = 2; } - } - - /*--- Allocate residual structures ---*/ - Res_TruncError = new su2double [nVar]; - - for (iVar = 0; iVar < nVar; iVar++) { - Res_TruncError[iVar] = 0.0; - } - - /*--- Only for residual smoothing (multigrid) ---*/ - for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) - nMGSmooth += config->GetMG_CorrecSmooth(iMesh); - - if ((nMGSmooth > 0) || low_fidelity || freesurface) { - Residual_Sum = new su2double [nVar]; - Residual_Old = new su2double [nVar]; - } - - /*--- Allocate undivided laplacian (centered) and limiter (upwind)---*/ - if (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED) - Undivided_Laplacian = new su2double [nVar]; - - /*--- Always allocate the slope limiter, - and the auxiliar variables (check the logic - JST with 2nd order Turb model - ) ---*/ - Limiter_Primitive = new su2double [nPrimVarGrad]; - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - Limiter_Primitive[iVar] = 0.0; - - if (compressible){ - Limiter_Secondary = new su2double [nSecondaryVarGrad]; - for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) - Limiter_Secondary[iVar] = 0.0; - } - - Limiter = new su2double [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - Limiter[iVar] = 0.0; - - Solution_Max = new su2double [nPrimVarGrad]; - Solution_Min = new su2double [nPrimVarGrad]; - for (iVar = 0; iVar < nPrimVarGrad; iVar++) { - Solution_Max[iVar] = 0.0; - Solution_Min[iVar] = 0.0; - } - - /*--- Solution initialization ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - Solution[iVar] = val_solution[iVar]; - Solution_Old[iVar] = val_solution[iVar]; - } - - /*--- Allocate and initializate solution for dual time strategy ---*/ - if (dual_time) { - Solution_time_n = new su2double [nVar]; - Solution_time_n1 = new su2double [nVar]; - - for (iVar = 0; iVar < nVar; iVar++) { - Solution_time_n[iVar] = val_solution[iVar]; - Solution_time_n1[iVar] = val_solution[iVar]; - } - } - - /*--- Allocate space for the time spectral source terms ---*/ - if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { - TS_Source = new su2double[nVar]; - for (iVar = 0; iVar < nVar; iVar++) TS_Source[iVar] = 0.0; - } - - /*--- Allocate vector for wind gust and wind gust derivative field ---*/ - if (windgust) { - WindGust = new su2double [nDim]; - WindGustDer = new su2double [nDim+1]; - } - - /*--- Allocate auxiliar vector for free surface source term ---*/ - if (freesurface) Grad_AuxVar = new su2double [nDim]; - - /*--- Incompressible flow, primitive variables nDim+3, (P, vx, vy, vz, rho, beta), - FreeSurface Incompressible flow, primitive variables nDim+4, (P, vx, vy, vz, rho, beta, dist), - Compressible flow, primitive variables nDim+5, (T, vx, vy, vz, P, rho, h, c) ---*/ - Primitive = new su2double [nPrimVar]; - for (iVar = 0; iVar < nPrimVar; iVar++) Primitive[iVar] = 0.0; - - if (compressible){ - Secondary = new su2double [nSecondaryVar]; - for (iVar = 0; iVar < nSecondaryVar; iVar++) Secondary[iVar] = 0.0; - } - - /*--- Incompressible flow, gradients primitive variables nDim+2, (P, vx, vy, vz, rho), - FreeSurface Incompressible flow, primitive variables nDim+4, (P, vx, vy, vz, rho, beta, dist), - Compressible flow, gradients primitive variables nDim+4, (T, vx, vy, vz, P, rho, h) - We need P, and rho for running the adjoint problem ---*/ - Gradient_Primitive = new su2double* [nPrimVarGrad]; - for (iVar = 0; iVar < nPrimVarGrad; iVar++) { - Gradient_Primitive[iVar] = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Gradient_Primitive[iVar][iDim] = 0.0; - } - - if (compressible){ - Gradient_Secondary = new su2double* [nSecondaryVarGrad]; - for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { - Gradient_Secondary[iVar] = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Gradient_Secondary[iVar][iDim] = 0.0; - } - } - -} - -CEulerVariable::~CEulerVariable(void) { - unsigned short iVar; - - if (TS_Source != NULL) delete [] TS_Source; - if (Primitive != NULL) delete [] Primitive; - if (Limiter_Primitive != NULL) delete [] Limiter_Primitive; - if (WindGust != NULL) delete [] WindGust; - if (WindGustDer != NULL) delete [] WindGustDer; - - if (Gradient_Primitive != NULL) { - for (iVar = 0; iVar < nPrimVarGrad; iVar++) - delete Gradient_Primitive[iVar]; - delete [] Gradient_Primitive; - } - -} - -void CEulerVariable::SetGradient_PrimitiveZero(unsigned short val_primvar) { - unsigned short iVar, iDim; - - for (iVar = 0; iVar < val_primvar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Gradient_Primitive[iVar][iDim] = 0.0; -} - -void CEulerVariable::SetGradient_SecondaryZero(unsigned short val_secondaryvar) { - unsigned short iVar, iDim; - - for (iVar = 0; iVar < val_secondaryvar; iVar++) - for (iDim = 0; iDim < nDim; iDim++) - Gradient_Secondary[iVar][iDim] = 0.0; -} - -su2double CEulerVariable::GetProjVel(su2double *val_vector) { - su2double ProjVel; - unsigned short iDim; - - ProjVel = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - ProjVel += Primitive[iDim+1]*val_vector[iDim]; - - return ProjVel; -} - -bool CEulerVariable::SetPrimVar_Compressible(CFluidModel *FluidModel) { - unsigned short iVar; - bool check_dens = false, check_press = false, check_sos = false, check_temp = false, RightVol = true; - - - SetVelocity(); // Computes velocity and velocity^2 - su2double density = GetDensity(); - su2double staticEnergy = GetEnergy()-0.5*Velocity2; - - /*--- Check will be moved inside fluid model plus error description strings ---*/ - - FluidModel->SetTDState_rhoe(density, staticEnergy); - - check_dens = SetDensity(); - check_press = SetPressure(FluidModel->GetPressure()); - check_sos = SetSoundSpeed(FluidModel->GetSoundSpeed2()); - check_temp = SetTemperature(FluidModel->GetTemperature()); - - /*--- Check that the solution has a physical meaning ---*/ - - if (check_dens || check_press || check_sos || check_temp) { - - /*--- Copy the old solution ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = Solution_Old[iVar]; - - /*--- Recompute the primitive variables ---*/ - - SetVelocity(); // Computes velocity and velocity^2 - su2double density = GetDensity(); - su2double staticEnergy = GetEnergy()-0.5*Velocity2; - /* check will be moved inside fluid model plus error description strings*/ - FluidModel->SetTDState_rhoe(density, staticEnergy); - - SetDensity(); - SetPressure(FluidModel->GetPressure()); - SetSoundSpeed(FluidModel->GetSoundSpeed2()); - SetTemperature(FluidModel->GetTemperature()); - - RightVol = false; - - } - - /*--- Set enthalpy ---*/ - - SetEnthalpy(); // Requires pressure computation. - - return RightVol; - -} - -void CEulerVariable::SetSecondaryVar_Compressible(CFluidModel *FluidModel) { - - /*--- Compute secondary thermo-physical properties (partial derivatives...) ---*/ - - SetdPdrho_e(FluidModel->GetdPdrho_e()); - SetdPde_rho(FluidModel->GetdPde_rho()); - -} - -bool CEulerVariable::SetPrimVar_Incompressible(su2double Density_Inf, CConfig *config) { - - su2double ArtComp_Factor = config->GetArtComp_Factor(); - - /*--- Set the value of the density ---*/ - - SetDensityInc(Density_Inf); - - /*--- Set the value of the velocity and velocity^2 (requires density) ---*/ - - SetVelocityInc(); - - /*--- Set the value of the pressure ---*/ - - SetPressureInc(); - - /*--- Set the value of the artificial compressibility factor ---*/ - - SetBetaInc2(ArtComp_Factor); - - return true; - -} - -bool CEulerVariable::SetPrimVar_FreeSurface(CConfig *config) { - - su2double Heaviside, lambda, DensityInc, LevelSet; - - su2double ArtComp_Factor = config->GetArtComp_Factor(); - su2double epsilon = config->GetFreeSurface_Thickness(); - - /*--- Set the value of the Level Set (already set in SetFreeSurface_Distance(geometry, config)) ---*/ - - LevelSet = Primitive[nDim+5]; - - /*--- Set the value of the Heaviside function ---*/ - - Heaviside = 0.0; - if (LevelSet < -epsilon) Heaviside = 1.0; - if (fabs(LevelSet) <= epsilon) Heaviside = 1.0 - (0.5*(1.0+(LevelSet/epsilon)+(1.0/PI_NUMBER)*sin(PI_NUMBER*LevelSet/epsilon))); - if (LevelSet > epsilon) Heaviside = 0.0; - - /*--- Set the value of the density ---*/ - - lambda = config->GetRatioDensity(); - DensityInc = (lambda + (1.0 - lambda)*Heaviside)*config->GetDensity_FreeStreamND(); - SetDensityInc(DensityInc); - - /*--- Set the value of the velocity and velocity^2 (requires density) ---*/ - - SetVelocityInc(); - - /*--- Set the value of the pressure ---*/ - - SetPressureInc(); - - /*--- Set the value of the artificial compressibility factor ---*/ - - SetBetaInc2(ArtComp_Factor); - - return true; - -} - -CNSVariable::CNSVariable(void) : CEulerVariable() { } - -CNSVariable::CNSVariable(su2double val_density, su2double *val_velocity, su2double val_energy, - unsigned short val_nDim, unsigned short val_nvar, - CConfig *config) : CEulerVariable(val_density, val_velocity, val_energy, val_nDim, val_nvar, config) { - - Temperature_Ref = config->GetTemperature_Ref(); - Viscosity_Ref = config->GetViscosity_Ref(); - Viscosity_Inf = config->GetViscosity_FreeStreamND(); - Prandtl_Lam = config->GetPrandtl_Lam(); - Prandtl_Turb = config->GetPrandtl_Turb(); - -} - -CNSVariable::CNSVariable(su2double *val_solution, unsigned short val_nDim, - unsigned short val_nvar, CConfig *config) : CEulerVariable(val_solution, val_nDim, val_nvar, config) { - - Temperature_Ref = config->GetTemperature_Ref(); - Viscosity_Ref = config->GetViscosity_Ref(); - Viscosity_Inf = config->GetViscosity_FreeStreamND(); - Prandtl_Lam = config->GetPrandtl_Lam(); - Prandtl_Turb = config->GetPrandtl_Turb(); -} - -CNSVariable::~CNSVariable(void) { } - -bool CNSVariable::SetVorticity(bool val_limiter) { - - Vorticity[0] = 0.0; Vorticity[1] = 0.0; - - Vorticity[2] = Gradient_Primitive[2][0]-Gradient_Primitive[1][1]; - - if (nDim == 3) { - Vorticity[0] = Gradient_Primitive[3][1]-Gradient_Primitive[2][2]; - Vorticity[1] = -(Gradient_Primitive[3][0]-Gradient_Primitive[1][2]); - } - - return false; - -} - -bool CNSVariable::SetStrainMag(bool val_limiter) { - - su2double Div; - unsigned short iDim; - - Div = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Div += Gradient_Primitive[iDim+1][iDim]; - } - - StrainMag = 0.0; - - /*--- Add diagonal part ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - StrainMag += pow(Gradient_Primitive[iDim+1][iDim] - 1.0/3.0*Div, 2.0); - } - - /*--- Add off diagonals ---*/ - - StrainMag += 2.0*pow(0.5*(Gradient_Primitive[1][1] + Gradient_Primitive[2][0]), 2.0); - - if (nDim == 3) { - StrainMag += 2.0*pow(0.5*(Gradient_Primitive[1][2] + Gradient_Primitive[3][0]), 2.0); - StrainMag += 2.0*pow(0.5*(Gradient_Primitive[2][2] + Gradient_Primitive[3][1]), 2.0); - } - - StrainMag = sqrt(2.0*StrainMag); - - return false; - -} - -bool CNSVariable::SetPrimVar_Compressible(su2double eddy_visc, su2double turb_ke, CFluidModel *FluidModel) { - - unsigned short iVar; - su2double density, staticEnergy; - bool check_dens = false, check_press = false, check_sos = false, - check_temp = false, RightVol = true; - - - SetVelocity(); // Computes velocity and velocity^2 - density = GetDensity(); - staticEnergy = GetEnergy()-0.5*Velocity2 - turb_ke; - - /*--- Check will be moved inside fluid model plus error description strings ---*/ - - FluidModel->SetTDState_rhoe(density, staticEnergy); - - check_dens = SetDensity(); - check_press = SetPressure(FluidModel->GetPressure()); - check_sos = SetSoundSpeed(FluidModel->GetSoundSpeed2()); - check_temp = SetTemperature(FluidModel->GetTemperature()); - - /*--- Check that the solution has a physical meaning ---*/ - - if (check_dens || check_press || check_sos || check_temp) { - - /*--- Copy the old solution ---*/ - - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = Solution_Old[iVar]; - - /*--- Recompute the primitive variables ---*/ - - SetVelocity(); // Computes velocity and velocity^2 - density = GetDensity(); - staticEnergy = GetEnergy()-0.5*Velocity2 - turb_ke; - - /*--- Check will be moved inside fluid model plus error description strings ---*/ - - FluidModel->SetTDState_rhoe(density, staticEnergy); - - SetDensity(); - SetPressure(FluidModel->GetPressure()); - SetSoundSpeed(FluidModel->GetSoundSpeed2()); - SetTemperature(FluidModel->GetTemperature()); - - RightVol = false; - - } - - /*--- Set enthalpy ---*/ - - SetEnthalpy(); // Requires pressure computation. - - /*--- Set laminar viscosity ---*/ - - SetLaminarViscosity(FluidModel->GetLaminarViscosity()); - - /*--- Set eddy viscosity ---*/ - - SetEddyViscosity(eddy_visc); - - /*--- Set thermal conductivity ---*/ - - SetThermalConductivity(FluidModel->GetThermalConductivity()); - - /*--- Set specific heat ---*/ - - SetSpecificHeatCp(FluidModel->GetCp()); - - return RightVol; - -} - -void CNSVariable::SetSecondaryVar_Compressible(CFluidModel *FluidModel) { - - /*--- Compute secondary thermodynamic properties (partial derivatives...) ---*/ - - SetdPdrho_e( FluidModel->GetdPdrho_e() ); - SetdPde_rho( FluidModel->GetdPde_rho() ); - - SetdTdrho_e( FluidModel->GetdTdrho_e() ); - SetdTde_rho( FluidModel->GetdTde_rho() ); - - /*--- Compute secondary thermo-physical properties (partial derivatives...) ---*/ - - Setdmudrho_T( FluidModel->Getdmudrho_T() ); - SetdmudT_rho( FluidModel->GetdmudT_rho() ); - - Setdktdrho_T( FluidModel->Getdktdrho_T() ); - SetdktdT_rho( FluidModel->GetdktdT_rho() ); - -} - -bool CNSVariable::SetPrimVar_Incompressible(su2double Density_Inf, su2double Viscosity_Inf, su2double eddy_visc, su2double turb_ke, CConfig *config) { - - su2double ArtComp_Factor = config->GetArtComp_Factor(); - - /*--- Set the value of the density and viscosity ---*/ - - SetDensityInc(Density_Inf); - SetLaminarViscosityInc(Viscosity_Inf); - - /*--- Set the value of the velocity and velocity^2 (requires density) ---*/ - - SetVelocityInc(); - - /*--- Set the value of the pressure ---*/ - - SetPressureInc(); - - /*--- Set the value of the artificial compressibility factor ---*/ - - SetBetaInc2(ArtComp_Factor); - - /*--- Set eddy viscosity ---*/ - - SetEddyViscosityInc(eddy_visc); - - return true; - -} - -bool CNSVariable::SetPrimVar_FreeSurface(su2double eddy_visc, su2double turb_ke, CConfig *config) { - - su2double Heaviside, lambda, DensityInc, ViscosityInc, LevelSet; - - su2double ArtComp_Factor = config->GetArtComp_Factor(); - su2double epsilon = config->GetFreeSurface_Thickness(); - - /*--- Set the value of the Level Set (already set in SetFreeSurface_Distance(geometry, config)) ---*/ - - LevelSet = Primitive[nDim+5]; - - /*--- Set the value of the Heaviside function ---*/ - - Heaviside = 0.0; - if (LevelSet < -epsilon) Heaviside = 1.0; - if (fabs(LevelSet) <= epsilon) Heaviside = 1.0 - (0.5*(1.0+(LevelSet/epsilon)+(1.0/PI_NUMBER)*sin(PI_NUMBER*LevelSet/epsilon))); - if (LevelSet > epsilon) Heaviside = 0.0; - - /*--- Set the value of the density ---*/ - - lambda = config->GetRatioDensity(); - DensityInc = (lambda + (1.0 - lambda)*Heaviside)*config->GetDensity_FreeStreamND(); - SetDensityInc(DensityInc); - - /*--- Set the value of the laminar viscosity ---*/ - - lambda = config->GetRatioViscosity(); - ViscosityInc = (lambda + (1.0 - lambda)*Heaviside)*config->GetViscosity_FreeStreamND(); - SetLaminarViscosityInc(ViscosityInc); - - /*--- Set the value of the velocity and velocity^2 (requires density) ---*/ - - SetVelocityInc(); - - /*--- Set the value of the pressure ---*/ - - SetPressureInc(); - - /*--- Set the value of the artificial compressibility factor ---*/ - - SetBetaInc2(ArtComp_Factor); - - /*--- Set eddy viscosity ---*/ - - SetEddyViscosityInc(eddy_visc); - - return true; - -} +/*! + * \file variable_direct_mean.cpp + * \brief Definition of the solution fields. + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/variable_structure.hpp" + +CEulerVariable::CEulerVariable(void) : CVariable() { + + /*--- Array initialization ---*/ + TS_Source = NULL; + Primitive = NULL; + Gradient_Primitive = NULL; + Limiter_Primitive = NULL; + WindGust = NULL; + WindGustDer = NULL; + +} + +CEulerVariable::CEulerVariable(su2double val_density, su2double *val_velocity, su2double val_energy, unsigned short val_nDim, + unsigned short val_nvar, CConfig *config) : CVariable(val_nDim, val_nvar, config) { + unsigned short iVar, iDim, iMesh, nMGSmooth = 0; + + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool low_fidelity = config->GetLowFidelitySim(); + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + bool viscous = config->GetViscous(); + bool windgust = config->GetWind_Gust(); + + /*--- Array initialization ---*/ + + TS_Source = NULL; + Primitive = NULL; + Gradient_Primitive = NULL; + Limiter_Primitive = NULL; + WindGust = NULL; + WindGustDer = NULL; + + /*--- Allocate and initialize the primitive variables and gradients ---*/ + + if (incompressible) { nPrimVar = nDim+5; nPrimVarGrad = nDim+3; } + if (freesurface) { nPrimVar = nDim+7; nPrimVarGrad = nDim+6; } + if (compressible) { nPrimVar = nDim+9; nPrimVarGrad = nDim+4; + if (viscous) { nSecondaryVar = 8; nSecondaryVarGrad = 2; } + else { nSecondaryVar = 2; nSecondaryVarGrad = 2; } + } + + /*--- Allocate residual structures ---*/ + + Res_TruncError = new su2double [nVar]; + + for (iVar = 0; iVar < nVar; iVar++) { + Res_TruncError[iVar] = 0.0; + } + + /*--- Only for residual smoothing (multigrid) ---*/ + + for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) + nMGSmooth += config->GetMG_CorrecSmooth(iMesh); + + if ((nMGSmooth > 0) || low_fidelity || freesurface) { + Residual_Sum = new su2double [nVar]; + Residual_Old = new su2double [nVar]; + } + + /*--- Allocate undivided laplacian (centered) and limiter (upwind)---*/ + + if (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED) { + Undivided_Laplacian = new su2double [nVar]; + } + + /*--- Always allocate the slope limiter, + and the auxiliar variables (check the logic - JST with 2nd order Turb model - ) ---*/ + + Limiter_Primitive = new su2double [nPrimVarGrad]; + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + Limiter_Primitive[iVar] = 0.0; + + if(compressible){ + Limiter_Secondary = new su2double [nSecondaryVarGrad]; + for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) + Limiter_Secondary[iVar] = 0.0; + } + + Limiter = new su2double [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + Limiter[iVar] = 0.0; + + Solution_Max = new su2double [nPrimVarGrad]; + Solution_Min = new su2double [nPrimVarGrad]; + for (iVar = 0; iVar < nPrimVarGrad; iVar++) { + Solution_Max[iVar] = 0.0; + Solution_Min[iVar] = 0.0; + } + + /*--- Solution and old solution initialization ---*/ + + if (compressible) { + Solution[0] = val_density; + Solution_Old[0] = val_density; + for (iDim = 0; iDim < nDim; iDim++) { + Solution[iDim+1] = val_density*val_velocity[iDim]; + Solution_Old[iDim+1] = val_density*val_velocity[iDim]; + } + Solution[nVar-1] = val_density*val_energy; + Solution_Old[nVar-1] = val_density*val_energy; + } + if (incompressible || freesurface) { + Solution[0] = config->GetPressure_FreeStreamND(); + Solution_Old[0] = config->GetPressure_FreeStreamND(); + for (iDim = 0; iDim < nDim; iDim++) { + Solution[iDim+1] = val_velocity[iDim]*config->GetDensity_FreeStreamND(); + Solution_Old[iDim+1] = val_velocity[iDim]*config->GetDensity_FreeStreamND(); + } + } + + /*--- Allocate and initialize solution for dual time strategy ---*/ + + if (dual_time) { + if (compressible) { + Solution_time_n[0] = val_density; + Solution_time_n1[0] = val_density; + for (iDim = 0; iDim < nDim; iDim++) { + Solution_time_n[iDim+1] = val_density*val_velocity[iDim]; + Solution_time_n1[iDim+1] = val_density*val_velocity[iDim]; + } + Solution_time_n[nVar-1] = val_density*val_energy; + Solution_time_n1[nVar-1] = val_density*val_energy; + } + if (incompressible || freesurface) { + Solution_time_n[0] = config->GetPressure_FreeStreamND(); + Solution_time_n1[0] = config->GetPressure_FreeStreamND(); + for (iDim = 0; iDim < nDim; iDim++) { + Solution_time_n[iDim+1] = val_velocity[iDim]*config->GetDensity_FreeStreamND(); + Solution_time_n1[iDim+1] = val_velocity[iDim]*config->GetDensity_FreeStreamND(); + } + } + } + + /*--- Allocate space for the time spectral source terms ---*/ + + if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { + TS_Source = new su2double[nVar]; + for (iVar = 0; iVar < nVar; iVar++) TS_Source[iVar] = 0.0; + } + + /*--- Allocate vector for wind gust and wind gust derivative field ---*/ + + if (windgust) { + WindGust = new su2double [nDim]; + WindGustDer = new su2double [nDim+1]; + } + + /*--- Allocate auxiliar vector for free surface source term ---*/ + + if (freesurface) Grad_AuxVar = new su2double [nDim]; + + /*--- Incompressible flow, primitive variables nDim+3, (P, vx, vy, vz, rho, beta), + FreeSurface Incompressible flow, primitive variables nDim+4, (P, vx, vy, vz, rho, beta, dist), + Compressible flow, primitive variables nDim+5, (T, vx, vy, vz, P, rho, h, c) ---*/ + + Primitive = new su2double [nPrimVar]; + for (iVar = 0; iVar < nPrimVar; iVar++) Primitive[iVar] = 0.0; + + if (compressible){ + Secondary = new su2double [nSecondaryVar]; + for (iVar = 0; iVar < nSecondaryVar; iVar++) Secondary[iVar] = 0.0; + } + + /*--- Incompressible flow, gradients primitive variables nDim+2, (P, vx, vy, vz, rho), + FreeSurface Incompressible flow, primitive variables nDim+3, (P, vx, vy, vz, rho, beta, dist), + Compressible flow, gradients primitive variables nDim+4, (T, vx, vy, vz, P, rho, h) + We need P, and rho for running the adjoint problem ---*/ + + Gradient_Primitive = new su2double* [nPrimVarGrad]; + for (iVar = 0; iVar < nPrimVarGrad; iVar++) { + Gradient_Primitive[iVar] = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Gradient_Primitive[iVar][iDim] = 0.0; + } + + if (compressible){ + Gradient_Secondary = new su2double* [nSecondaryVarGrad]; + for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { + Gradient_Secondary[iVar] = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Gradient_Secondary[iVar][iDim] = 0.0; + } + } +} + +CEulerVariable::CEulerVariable(su2double *val_solution, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) : CVariable(val_nDim, val_nvar, config) { + unsigned short iVar, iDim, iMesh, nMGSmooth = 0; + + bool compressible = (config->GetKind_Regime() == COMPRESSIBLE); + bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE); + bool freesurface = (config->GetKind_Regime() == FREESURFACE); + bool low_fidelity = config->GetLowFidelitySim(); + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + bool viscous = config->GetViscous(); + bool windgust = config->GetWind_Gust(); + + /*--- Array initialization ---*/ + TS_Source = NULL; + Primitive = NULL; + Gradient_Primitive = NULL; + Limiter_Primitive = NULL; + WindGust = NULL; + WindGustDer = NULL; + + /*--- Allocate and initialize the primitive variables and gradients ---*/ + if (incompressible) { nPrimVar = nDim+5; nPrimVarGrad = nDim+3; } + if (freesurface) { nPrimVar = nDim+7; nPrimVarGrad = nDim+6; } + if (compressible) { nPrimVar = nDim+9; nPrimVarGrad = nDim+4; + if (viscous) { nSecondaryVar = 8; nSecondaryVarGrad = 2; } + else { nSecondaryVar = 2; nSecondaryVarGrad = 2; } + } + + /*--- Allocate residual structures ---*/ + Res_TruncError = new su2double [nVar]; + + for (iVar = 0; iVar < nVar; iVar++) { + Res_TruncError[iVar] = 0.0; + } + + /*--- Only for residual smoothing (multigrid) ---*/ + for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) + nMGSmooth += config->GetMG_CorrecSmooth(iMesh); + + if ((nMGSmooth > 0) || low_fidelity || freesurface) { + Residual_Sum = new su2double [nVar]; + Residual_Old = new su2double [nVar]; + } + + /*--- Allocate undivided laplacian (centered) and limiter (upwind)---*/ + if (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED) + Undivided_Laplacian = new su2double [nVar]; + + /*--- Always allocate the slope limiter, + and the auxiliar variables (check the logic - JST with 2nd order Turb model - ) ---*/ + Limiter_Primitive = new su2double [nPrimVarGrad]; + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + Limiter_Primitive[iVar] = 0.0; + + if (compressible){ + Limiter_Secondary = new su2double [nSecondaryVarGrad]; + for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) + Limiter_Secondary[iVar] = 0.0; + } + + Limiter = new su2double [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + Limiter[iVar] = 0.0; + + Solution_Max = new su2double [nPrimVarGrad]; + Solution_Min = new su2double [nPrimVarGrad]; + for (iVar = 0; iVar < nPrimVarGrad; iVar++) { + Solution_Max[iVar] = 0.0; + Solution_Min[iVar] = 0.0; + } + + /*--- Solution initialization ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + Solution[iVar] = val_solution[iVar]; + Solution_Old[iVar] = val_solution[iVar]; + } + + /*--- Allocate and initializate solution for dual time strategy ---*/ + if (dual_time) { + Solution_time_n = new su2double [nVar]; + Solution_time_n1 = new su2double [nVar]; + + for (iVar = 0; iVar < nVar; iVar++) { + Solution_time_n[iVar] = val_solution[iVar]; + Solution_time_n1[iVar] = val_solution[iVar]; + } + } + + /*--- Allocate space for the time spectral source terms ---*/ + if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { + TS_Source = new su2double[nVar]; + for (iVar = 0; iVar < nVar; iVar++) TS_Source[iVar] = 0.0; + } + + /*--- Allocate vector for wind gust and wind gust derivative field ---*/ + if (windgust) { + WindGust = new su2double [nDim]; + WindGustDer = new su2double [nDim+1]; + } + + /*--- Allocate auxiliar vector for free surface source term ---*/ + if (freesurface) Grad_AuxVar = new su2double [nDim]; + + /*--- Incompressible flow, primitive variables nDim+3, (P, vx, vy, vz, rho, beta), + FreeSurface Incompressible flow, primitive variables nDim+4, (P, vx, vy, vz, rho, beta, dist), + Compressible flow, primitive variables nDim+5, (T, vx, vy, vz, P, rho, h, c) ---*/ + Primitive = new su2double [nPrimVar]; + for (iVar = 0; iVar < nPrimVar; iVar++) Primitive[iVar] = 0.0; + + if (compressible){ + Secondary = new su2double [nSecondaryVar]; + for (iVar = 0; iVar < nSecondaryVar; iVar++) Secondary[iVar] = 0.0; + } + + /*--- Incompressible flow, gradients primitive variables nDim+2, (P, vx, vy, vz, rho), + FreeSurface Incompressible flow, primitive variables nDim+4, (P, vx, vy, vz, rho, beta, dist), + Compressible flow, gradients primitive variables nDim+4, (T, vx, vy, vz, P, rho, h) + We need P, and rho for running the adjoint problem ---*/ + Gradient_Primitive = new su2double* [nPrimVarGrad]; + for (iVar = 0; iVar < nPrimVarGrad; iVar++) { + Gradient_Primitive[iVar] = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Gradient_Primitive[iVar][iDim] = 0.0; + } + + if (compressible){ + Gradient_Secondary = new su2double* [nSecondaryVarGrad]; + for (iVar = 0; iVar < nSecondaryVarGrad; iVar++) { + Gradient_Secondary[iVar] = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) + Gradient_Secondary[iVar][iDim] = 0.0; + } + } + +} + +CEulerVariable::~CEulerVariable(void) { + unsigned short iVar; + + if (TS_Source != NULL) delete [] TS_Source; + if (Primitive != NULL) delete [] Primitive; + if (Limiter_Primitive != NULL) delete [] Limiter_Primitive; + if (WindGust != NULL) delete [] WindGust; + if (WindGustDer != NULL) delete [] WindGustDer; + + if (Gradient_Primitive != NULL) { + for (iVar = 0; iVar < nPrimVarGrad; iVar++) + delete Gradient_Primitive[iVar]; + delete [] Gradient_Primitive; + } + +} + +void CEulerVariable::SetGradient_PrimitiveZero(unsigned short val_primvar) { + unsigned short iVar, iDim; + + for (iVar = 0; iVar < val_primvar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Gradient_Primitive[iVar][iDim] = 0.0; +} + +void CEulerVariable::SetGradient_SecondaryZero(unsigned short val_secondaryvar) { + unsigned short iVar, iDim; + + for (iVar = 0; iVar < val_secondaryvar; iVar++) + for (iDim = 0; iDim < nDim; iDim++) + Gradient_Secondary[iVar][iDim] = 0.0; +} + +su2double CEulerVariable::GetProjVel(su2double *val_vector) { + su2double ProjVel; + unsigned short iDim; + + ProjVel = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + ProjVel += Primitive[iDim+1]*val_vector[iDim]; + + return ProjVel; +} + +bool CEulerVariable::SetPrimVar_Compressible(CFluidModel *FluidModel) { + unsigned short iVar; + bool check_dens = false, check_press = false, check_sos = false, check_temp = false, RightVol = true; + + + SetVelocity(); // Computes velocity and velocity^2 + su2double density = GetDensity(); + su2double staticEnergy = GetEnergy()-0.5*Velocity2; + + /*--- Check will be moved inside fluid model plus error description strings ---*/ + + FluidModel->SetTDState_rhoe(density, staticEnergy); + + check_dens = SetDensity(); + check_press = SetPressure(FluidModel->GetPressure()); + check_sos = SetSoundSpeed(FluidModel->GetSoundSpeed2()); + check_temp = SetTemperature(FluidModel->GetTemperature()); + + /*--- Check that the solution has a physical meaning ---*/ + + if (check_dens || check_press || check_sos || check_temp) { + + /*--- Copy the old solution ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = Solution_Old[iVar]; + + /*--- Recompute the primitive variables ---*/ + + SetVelocity(); // Computes velocity and velocity^2 + su2double density = GetDensity(); + su2double staticEnergy = GetEnergy()-0.5*Velocity2; + /* check will be moved inside fluid model plus error description strings*/ + FluidModel->SetTDState_rhoe(density, staticEnergy); + + SetDensity(); + SetPressure(FluidModel->GetPressure()); + SetSoundSpeed(FluidModel->GetSoundSpeed2()); + SetTemperature(FluidModel->GetTemperature()); + + RightVol = false; + + } + + /*--- Set enthalpy ---*/ + + SetEnthalpy(); // Requires pressure computation. + + return RightVol; + +} + +void CEulerVariable::SetSecondaryVar_Compressible(CFluidModel *FluidModel) { + + /*--- Compute secondary thermo-physical properties (partial derivatives...) ---*/ + + SetdPdrho_e(FluidModel->GetdPdrho_e()); + SetdPde_rho(FluidModel->GetdPde_rho()); + +} + +bool CEulerVariable::SetPrimVar_Incompressible(su2double Density_Inf, CConfig *config) { + + su2double ArtComp_Factor = config->GetArtComp_Factor(); + + /*--- Set the value of the density ---*/ + + SetDensityInc(Density_Inf); + + /*--- Set the value of the velocity and velocity^2 (requires density) ---*/ + + SetVelocityInc(); + + /*--- Set the value of the pressure ---*/ + + SetPressureInc(); + + /*--- Set the value of the artificial compressibility factor ---*/ + + SetBetaInc2(ArtComp_Factor); + + return true; + +} + +bool CEulerVariable::SetPrimVar_FreeSurface(CConfig *config) { + + su2double Heaviside, lambda, DensityInc, LevelSet; + + su2double ArtComp_Factor = config->GetArtComp_Factor(); + su2double epsilon = config->GetFreeSurface_Thickness(); + + /*--- Set the value of the Level Set (already set in SetFreeSurface_Distance(geometry, config)) ---*/ + + LevelSet = Primitive[nDim+5]; + + /*--- Set the value of the Heaviside function ---*/ + + Heaviside = 0.0; + if (LevelSet < -epsilon) Heaviside = 1.0; + if (fabs(LevelSet) <= epsilon) Heaviside = 1.0 - (0.5*(1.0+(LevelSet/epsilon)+(1.0/PI_NUMBER)*sin(PI_NUMBER*LevelSet/epsilon))); + if (LevelSet > epsilon) Heaviside = 0.0; + + /*--- Set the value of the density ---*/ + + lambda = config->GetRatioDensity(); + DensityInc = (lambda + (1.0 - lambda)*Heaviside)*config->GetDensity_FreeStreamND(); + SetDensityInc(DensityInc); + + /*--- Set the value of the velocity and velocity^2 (requires density) ---*/ + + SetVelocityInc(); + + /*--- Set the value of the pressure ---*/ + + SetPressureInc(); + + /*--- Set the value of the artificial compressibility factor ---*/ + + SetBetaInc2(ArtComp_Factor); + + return true; + +} + +CNSVariable::CNSVariable(void) : CEulerVariable() { } + +CNSVariable::CNSVariable(su2double val_density, su2double *val_velocity, su2double val_energy, + unsigned short val_nDim, unsigned short val_nvar, + CConfig *config) : CEulerVariable(val_density, val_velocity, val_energy, val_nDim, val_nvar, config) { + + Temperature_Ref = config->GetTemperature_Ref(); + Viscosity_Ref = config->GetViscosity_Ref(); + Viscosity_Inf = config->GetViscosity_FreeStreamND(); + Prandtl_Lam = config->GetPrandtl_Lam(); + Prandtl_Turb = config->GetPrandtl_Turb(); + +} + +CNSVariable::CNSVariable(su2double *val_solution, unsigned short val_nDim, + unsigned short val_nvar, CConfig *config) : CEulerVariable(val_solution, val_nDim, val_nvar, config) { + + Temperature_Ref = config->GetTemperature_Ref(); + Viscosity_Ref = config->GetViscosity_Ref(); + Viscosity_Inf = config->GetViscosity_FreeStreamND(); + Prandtl_Lam = config->GetPrandtl_Lam(); + Prandtl_Turb = config->GetPrandtl_Turb(); +} + +CNSVariable::~CNSVariable(void) { } + +bool CNSVariable::SetVorticity(bool val_limiter) { + + Vorticity[0] = 0.0; Vorticity[1] = 0.0; + + Vorticity[2] = Gradient_Primitive[2][0]-Gradient_Primitive[1][1]; + + if (nDim == 3) { + Vorticity[0] = Gradient_Primitive[3][1]-Gradient_Primitive[2][2]; + Vorticity[1] = -(Gradient_Primitive[3][0]-Gradient_Primitive[1][2]); + } + + return false; + +} + +bool CNSVariable::SetStrainMag(bool val_limiter) { + + su2double Div; + unsigned short iDim; + + Div = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Div += Gradient_Primitive[iDim+1][iDim]; + } + + StrainMag = 0.0; + + /*--- Add diagonal part ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + StrainMag += pow(Gradient_Primitive[iDim+1][iDim] - 1.0/3.0*Div, 2.0); + } + + /*--- Add off diagonals ---*/ + + StrainMag += 2.0*pow(0.5*(Gradient_Primitive[1][1] + Gradient_Primitive[2][0]), 2.0); + + if (nDim == 3) { + StrainMag += 2.0*pow(0.5*(Gradient_Primitive[1][2] + Gradient_Primitive[3][0]), 2.0); + StrainMag += 2.0*pow(0.5*(Gradient_Primitive[2][2] + Gradient_Primitive[3][1]), 2.0); + } + + StrainMag = sqrt(2.0*StrainMag); + + return false; + +} + +bool CNSVariable::SetPrimVar_Compressible(su2double eddy_visc, su2double turb_ke, CFluidModel *FluidModel) { + + unsigned short iVar; + su2double density, staticEnergy; + bool check_dens = false, check_press = false, check_sos = false, + check_temp = false, RightVol = true; + + + SetVelocity(); // Computes velocity and velocity^2 + density = GetDensity(); + staticEnergy = GetEnergy()-0.5*Velocity2 - turb_ke; + + /*--- Check will be moved inside fluid model plus error description strings ---*/ + + FluidModel->SetTDState_rhoe(density, staticEnergy); + + check_dens = SetDensity(); + check_press = SetPressure(FluidModel->GetPressure()); + check_sos = SetSoundSpeed(FluidModel->GetSoundSpeed2()); + check_temp = SetTemperature(FluidModel->GetTemperature()); + + /*--- Check that the solution has a physical meaning ---*/ + + if (check_dens || check_press || check_sos || check_temp) { + + /*--- Copy the old solution ---*/ + + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = Solution_Old[iVar]; + + /*--- Recompute the primitive variables ---*/ + + SetVelocity(); // Computes velocity and velocity^2 + density = GetDensity(); + staticEnergy = GetEnergy()-0.5*Velocity2 - turb_ke; + + /*--- Check will be moved inside fluid model plus error description strings ---*/ + + FluidModel->SetTDState_rhoe(density, staticEnergy); + + SetDensity(); + SetPressure(FluidModel->GetPressure()); + SetSoundSpeed(FluidModel->GetSoundSpeed2()); + SetTemperature(FluidModel->GetTemperature()); + + RightVol = false; + + } + + /*--- Set enthalpy ---*/ + + SetEnthalpy(); // Requires pressure computation. + + /*--- Set laminar viscosity ---*/ + + SetLaminarViscosity(FluidModel->GetLaminarViscosity()); + + /*--- Set eddy viscosity ---*/ + + SetEddyViscosity(eddy_visc); + + /*--- Set thermal conductivity ---*/ + + SetThermalConductivity(FluidModel->GetThermalConductivity()); + + /*--- Set specific heat ---*/ + + SetSpecificHeatCp(FluidModel->GetCp()); + + return RightVol; + +} + +void CNSVariable::SetSecondaryVar_Compressible(CFluidModel *FluidModel) { + + /*--- Compute secondary thermodynamic properties (partial derivatives...) ---*/ + + SetdPdrho_e( FluidModel->GetdPdrho_e() ); + SetdPde_rho( FluidModel->GetdPde_rho() ); + + SetdTdrho_e( FluidModel->GetdTdrho_e() ); + SetdTde_rho( FluidModel->GetdTde_rho() ); + + /*--- Compute secondary thermo-physical properties (partial derivatives...) ---*/ + + Setdmudrho_T( FluidModel->Getdmudrho_T() ); + SetdmudT_rho( FluidModel->GetdmudT_rho() ); + + Setdktdrho_T( FluidModel->Getdktdrho_T() ); + SetdktdT_rho( FluidModel->GetdktdT_rho() ); + +} + +bool CNSVariable::SetPrimVar_Incompressible(su2double Density_Inf, su2double Viscosity_Inf, su2double eddy_visc, su2double turb_ke, CConfig *config) { + + su2double ArtComp_Factor = config->GetArtComp_Factor(); + + /*--- Set the value of the density and viscosity ---*/ + + SetDensityInc(Density_Inf); + SetLaminarViscosityInc(Viscosity_Inf); + + /*--- Set the value of the velocity and velocity^2 (requires density) ---*/ + + SetVelocityInc(); + + /*--- Set the value of the pressure ---*/ + + SetPressureInc(); + + /*--- Set the value of the artificial compressibility factor ---*/ + + SetBetaInc2(ArtComp_Factor); + + /*--- Set eddy viscosity ---*/ + + SetEddyViscosityInc(eddy_visc); + + return true; + +} + +bool CNSVariable::SetPrimVar_FreeSurface(su2double eddy_visc, su2double turb_ke, CConfig *config) { + + su2double Heaviside, lambda, DensityInc, ViscosityInc, LevelSet; + + su2double ArtComp_Factor = config->GetArtComp_Factor(); + su2double epsilon = config->GetFreeSurface_Thickness(); + + /*--- Set the value of the Level Set (already set in SetFreeSurface_Distance(geometry, config)) ---*/ + + LevelSet = Primitive[nDim+5]; + + /*--- Set the value of the Heaviside function ---*/ + + Heaviside = 0.0; + if (LevelSet < -epsilon) Heaviside = 1.0; + if (fabs(LevelSet) <= epsilon) Heaviside = 1.0 - (0.5*(1.0+(LevelSet/epsilon)+(1.0/PI_NUMBER)*sin(PI_NUMBER*LevelSet/epsilon))); + if (LevelSet > epsilon) Heaviside = 0.0; + + /*--- Set the value of the density ---*/ + + lambda = config->GetRatioDensity(); + DensityInc = (lambda + (1.0 - lambda)*Heaviside)*config->GetDensity_FreeStreamND(); + SetDensityInc(DensityInc); + + /*--- Set the value of the laminar viscosity ---*/ + + lambda = config->GetRatioViscosity(); + ViscosityInc = (lambda + (1.0 - lambda)*Heaviside)*config->GetViscosity_FreeStreamND(); + SetLaminarViscosityInc(ViscosityInc); + + /*--- Set the value of the velocity and velocity^2 (requires density) ---*/ + + SetVelocityInc(); + + /*--- Set the value of the pressure ---*/ + + SetPressureInc(); + + /*--- Set the value of the artificial compressibility factor ---*/ + + SetBetaInc2(ArtComp_Factor); + + /*--- Set eddy viscosity ---*/ + + SetEddyViscosityInc(eddy_visc); + + return true; + +} diff --git a/SU2_CFD/src/variable_direct_poisson.cpp b/SU2_CFD/src/variable_direct_poisson.cpp index f10fec848de..93faab32c2b 100644 --- a/SU2_CFD/src/variable_direct_poisson.cpp +++ b/SU2_CFD/src/variable_direct_poisson.cpp @@ -1,65 +1,65 @@ -/*! - * \file variable_direct_poisson.cpp - * \brief Definition of the solution fields. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/variable_structure.hpp" - -CPotentialVariable::CPotentialVariable(void) : CVariable() { - - /*--- Array initialization ---*/ - Charge_Density = NULL; - -} - -CPotentialVariable::CPotentialVariable(su2double val_potential, - unsigned short val_nDim, - unsigned short val_nvar, - CConfig *config) : CVariable(val_nDim, - val_nvar, - config) { - unsigned short iVar; - - Residual_Old = new su2double [nVar]; - Residual_Sum = new su2double [nVar]; - - /*--- Initialization of variables ---*/ - for (iVar = 0; iVar< nVar; iVar++) { - Solution[iVar] = val_potential; - Solution_Old[iVar] = val_potential; - } - Charge_Density = new su2double [2]; - -} - -CPotentialVariable::~CPotentialVariable(void) { - - if (Charge_Density != NULL) delete [] Charge_Density; - -} +/*! + * \file variable_direct_poisson.cpp + * \brief Definition of the solution fields. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/variable_structure.hpp" + +CPotentialVariable::CPotentialVariable(void) : CVariable() { + + /*--- Array initialization ---*/ + Charge_Density = NULL; + +} + +CPotentialVariable::CPotentialVariable(su2double val_potential, + unsigned short val_nDim, + unsigned short val_nvar, + CConfig *config) : CVariable(val_nDim, + val_nvar, + config) { + unsigned short iVar; + + Residual_Old = new su2double [nVar]; + Residual_Sum = new su2double [nVar]; + + /*--- Initialization of variables ---*/ + for (iVar = 0; iVar< nVar; iVar++) { + Solution[iVar] = val_potential; + Solution_Old[iVar] = val_potential; + } + Charge_Density = new su2double [2]; + +} + +CPotentialVariable::~CPotentialVariable(void) { + + if (Charge_Density != NULL) delete [] Charge_Density; + +} diff --git a/SU2_CFD/src/variable_direct_transition.cpp b/SU2_CFD/src/variable_direct_transition.cpp index 63dc9c71dd7..0b6cfd533f2 100644 --- a/SU2_CFD/src/variable_direct_transition.cpp +++ b/SU2_CFD/src/variable_direct_transition.cpp @@ -1,52 +1,52 @@ -/*! - * \file variable_direct_transition.cpp - * \brief Definition of the solution fields. - * \author A. Aranake - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/variable_structure.hpp" - -CTransLMVariable::CTransLMVariable(void) : CTurbVariable() {} - -CTransLMVariable::CTransLMVariable(su2double val_nu_tilde, su2double val_intermittency, su2double val_REth, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) -: CTurbVariable(val_nDim, val_nvar, config) { - - // Initialization of variables - Solution[0] = val_intermittency; Solution_Old[0] = val_intermittency; - Solution[1] = val_REth; Solution_Old[1] = val_REth; - -} - -CTransLMVariable::~CTransLMVariable(void) { } - -void CTransLMVariable::SetGammaEff() { - - /* -- Correction for separation-induced transition -- */ - Solution[0] = max(Solution[0], gamma_sep); - -} +/*! + * \file variable_direct_transition.cpp + * \brief Definition of the solution fields. + * \author A. Aranake + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/variable_structure.hpp" + +CTransLMVariable::CTransLMVariable(void) : CTurbVariable() {} + +CTransLMVariable::CTransLMVariable(su2double val_nu_tilde, su2double val_intermittency, su2double val_REth, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) +: CTurbVariable(val_nDim, val_nvar, config) { + + // Initialization of variables + Solution[0] = val_intermittency; Solution_Old[0] = val_intermittency; + Solution[1] = val_REth; Solution_Old[1] = val_REth; + +} + +CTransLMVariable::~CTransLMVariable(void) { } + +void CTransLMVariable::SetGammaEff() { + + /* -- Correction for separation-induced transition -- */ + Solution[0] = max(Solution[0], gamma_sep); + +} diff --git a/SU2_CFD/src/variable_direct_turbulent.cpp b/SU2_CFD/src/variable_direct_turbulent.cpp index abce60388c1..627988a7b0a 100644 --- a/SU2_CFD/src/variable_direct_turbulent.cpp +++ b/SU2_CFD/src/variable_direct_turbulent.cpp @@ -1,200 +1,200 @@ -/*! - * \file variable_direct_turbulent.cpp - * \brief Definition of the solution fields. - * \author F. Palacios, A. Bueno - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/variable_structure.hpp" - -CTurbVariable::CTurbVariable(void) : CVariable() { - - /*--- Array initialization ---*/ - TS_Source = NULL; - -} - -CTurbVariable::CTurbVariable(unsigned short val_nDim, unsigned short val_nvar, CConfig *config) -: CVariable(val_nDim, val_nvar, config) { - - unsigned short iVar; - - /*--- Array initialization ---*/ - - TS_Source = NULL; - - /*--- Allocate space for the time spectral source terms ---*/ - - if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { - TS_Source = new su2double[nVar]; - for (iVar = 0; iVar < nVar; iVar++) - TS_Source[iVar] = 0.0; - } - - /*--- Allocate space for the limiter ---*/ - - Limiter = new su2double [nVar]; - for (iVar = 0; iVar < nVar; iVar++) - Limiter[iVar] = 0.0; - - Solution_Max = new su2double [nVar]; - Solution_Min = new su2double [nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Solution_Max[iVar] = 0.0; - Solution_Min[iVar] = 0.0; - } - -} - -CTurbVariable::~CTurbVariable(void) { } - -su2double CTurbVariable::GetmuT() { return muT; } - -void CTurbVariable::SetmuT(su2double val_muT) { muT = val_muT; } - -CTurbSAVariable::CTurbSAVariable(void) : CTurbVariable() { } - -CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) -: CTurbVariable(val_nDim, val_nvar, config) { - - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - - /*--- Initialization of S-A variables ---*/ - Solution[0] = val_nu_tilde; Solution_Old[0] = val_nu_tilde; - - /*--- Initialization of the eddy viscosity ---*/ - muT = val_muT; - - /*--- Allocate and initialize solution for the dual time strategy ---*/ - if (dual_time) { - Solution_time_n[0] = val_nu_tilde; - Solution_time_n1[0] = val_nu_tilde; - } - -} - -CTurbSAVariable::~CTurbSAVariable(void) { - - if (TS_Source != NULL) delete [] TS_Source; - -} - -CTurbMLVariable::CTurbMLVariable(void) : CTurbVariable() { } - -CTurbMLVariable::CTurbMLVariable(su2double val_nu_tilde, su2double val_muT, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) -: CTurbVariable(val_nDim, val_nvar, config) { - - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - - /*--- Initialization of S-A variables ---*/ - Solution[0] = val_nu_tilde; Solution_Old[0] = val_nu_tilde; - - /*--- Initialization of the eddy viscosity ---*/ - muT = val_muT; - - /*--- Allocate and initialize solution for the dual time strategy ---*/ - if (dual_time) { - Solution_time_n[0] = val_nu_tilde; - Solution_time_n1[0] = val_nu_tilde; - } - -} - -CTurbMLVariable::~CTurbMLVariable(void) { - - if (TS_Source != NULL) delete [] TS_Source; - -} - -CTurbSSTVariable::CTurbSSTVariable(void) : CTurbVariable() { } - -CTurbSSTVariable::CTurbSSTVariable(su2double val_kine, su2double val_omega, su2double val_muT, unsigned short val_nDim, unsigned short val_nvar, - su2double *constants, CConfig *config) -: CTurbVariable(val_nDim, val_nvar, config) { - - bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || - (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); - - /*--- Initialization of variables ---*/ - - Solution[0] = val_kine; Solution_Old[0] = val_kine; - Solution[1] = val_omega; Solution_Old[1] = val_omega; - - sigma_om2 = constants[3]; - beta_star = constants[6]; - - F1 = 1.0; - F2 = 0.0; - CDkw = 0.0; - - /*--- Initialization of eddy viscosity ---*/ - - muT = val_muT; - - /*--- Allocate and initialize solution for the dual time strategy ---*/ - - if (dual_time) { - Solution_time_n[0] = val_kine; Solution_time_n[1] = val_omega; - Solution_time_n1[0] = val_kine; Solution_time_n1[1] = val_omega; - } - -} - -CTurbSSTVariable::~CTurbSSTVariable(void) { - - if (TS_Source != NULL) delete [] TS_Source; - -} - -void CTurbSSTVariable::SetBlendingFunc(su2double val_viscosity, su2double val_dist, su2double val_density) { - unsigned short iDim; - su2double arg2, arg2A, arg2B, arg1; - - /*--- Cross diffusion ---*/ - - CDkw = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - CDkw += Gradient[0][iDim]*Gradient[1][iDim]; - CDkw *= 2.0*val_density*sigma_om2/Solution[1]; - CDkw = max(CDkw, pow(10.0, -20.0)); - - /*--- F1 ---*/ - - arg2A = sqrt(Solution[0])/(beta_star*Solution[1]*val_dist); - arg2B = 500.0*val_viscosity / (val_density*val_dist*val_dist*Solution[1]); - arg2 = max(arg2A, arg2B); - arg1 = min(arg2, 4.0*val_density*sigma_om2*Solution[0] / (CDkw*val_dist*val_dist)); - F1 = tanh(pow(arg1, 4.0)); - - /*--- F2 ---*/ - - arg2 = max(2.0*arg2A, arg2B); - F2 = tanh(pow(arg2, 2.0)); - -} +/*! + * \file variable_direct_turbulent.cpp + * \brief Definition of the solution fields. + * \author F. Palacios, A. Bueno + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/variable_structure.hpp" + +CTurbVariable::CTurbVariable(void) : CVariable() { + + /*--- Array initialization ---*/ + TS_Source = NULL; + +} + +CTurbVariable::CTurbVariable(unsigned short val_nDim, unsigned short val_nvar, CConfig *config) +: CVariable(val_nDim, val_nvar, config) { + + unsigned short iVar; + + /*--- Array initialization ---*/ + + TS_Source = NULL; + + /*--- Allocate space for the time spectral source terms ---*/ + + if (config->GetUnsteady_Simulation() == TIME_SPECTRAL) { + TS_Source = new su2double[nVar]; + for (iVar = 0; iVar < nVar; iVar++) + TS_Source[iVar] = 0.0; + } + + /*--- Allocate space for the limiter ---*/ + + Limiter = new su2double [nVar]; + for (iVar = 0; iVar < nVar; iVar++) + Limiter[iVar] = 0.0; + + Solution_Max = new su2double [nVar]; + Solution_Min = new su2double [nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Solution_Max[iVar] = 0.0; + Solution_Min[iVar] = 0.0; + } + +} + +CTurbVariable::~CTurbVariable(void) { } + +su2double CTurbVariable::GetmuT() { return muT; } + +void CTurbVariable::SetmuT(su2double val_muT) { muT = val_muT; } + +CTurbSAVariable::CTurbSAVariable(void) : CTurbVariable() { } + +CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) +: CTurbVariable(val_nDim, val_nvar, config) { + + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + + /*--- Initialization of S-A variables ---*/ + Solution[0] = val_nu_tilde; Solution_Old[0] = val_nu_tilde; + + /*--- Initialization of the eddy viscosity ---*/ + muT = val_muT; + + /*--- Allocate and initialize solution for the dual time strategy ---*/ + if (dual_time) { + Solution_time_n[0] = val_nu_tilde; + Solution_time_n1[0] = val_nu_tilde; + } + +} + +CTurbSAVariable::~CTurbSAVariable(void) { + + if (TS_Source != NULL) delete [] TS_Source; + +} + +CTurbMLVariable::CTurbMLVariable(void) : CTurbVariable() { } + +CTurbMLVariable::CTurbMLVariable(su2double val_nu_tilde, su2double val_muT, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) +: CTurbVariable(val_nDim, val_nvar, config) { + + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + + /*--- Initialization of S-A variables ---*/ + Solution[0] = val_nu_tilde; Solution_Old[0] = val_nu_tilde; + + /*--- Initialization of the eddy viscosity ---*/ + muT = val_muT; + + /*--- Allocate and initialize solution for the dual time strategy ---*/ + if (dual_time) { + Solution_time_n[0] = val_nu_tilde; + Solution_time_n1[0] = val_nu_tilde; + } + +} + +CTurbMLVariable::~CTurbMLVariable(void) { + + if (TS_Source != NULL) delete [] TS_Source; + +} + +CTurbSSTVariable::CTurbSSTVariable(void) : CTurbVariable() { } + +CTurbSSTVariable::CTurbSSTVariable(su2double val_kine, su2double val_omega, su2double val_muT, unsigned short val_nDim, unsigned short val_nvar, + su2double *constants, CConfig *config) +: CTurbVariable(val_nDim, val_nvar, config) { + + bool dual_time = ((config->GetUnsteady_Simulation() == DT_STEPPING_1ST) || + (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)); + + /*--- Initialization of variables ---*/ + + Solution[0] = val_kine; Solution_Old[0] = val_kine; + Solution[1] = val_omega; Solution_Old[1] = val_omega; + + sigma_om2 = constants[3]; + beta_star = constants[6]; + + F1 = 1.0; + F2 = 0.0; + CDkw = 0.0; + + /*--- Initialization of eddy viscosity ---*/ + + muT = val_muT; + + /*--- Allocate and initialize solution for the dual time strategy ---*/ + + if (dual_time) { + Solution_time_n[0] = val_kine; Solution_time_n[1] = val_omega; + Solution_time_n1[0] = val_kine; Solution_time_n1[1] = val_omega; + } + +} + +CTurbSSTVariable::~CTurbSSTVariable(void) { + + if (TS_Source != NULL) delete [] TS_Source; + +} + +void CTurbSSTVariable::SetBlendingFunc(su2double val_viscosity, su2double val_dist, su2double val_density) { + unsigned short iDim; + su2double arg2, arg2A, arg2B, arg1; + + /*--- Cross diffusion ---*/ + + CDkw = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + CDkw += Gradient[0][iDim]*Gradient[1][iDim]; + CDkw *= 2.0*val_density*sigma_om2/Solution[1]; + CDkw = max(CDkw, pow(10.0, -20.0)); + + /*--- F1 ---*/ + + arg2A = sqrt(Solution[0])/(beta_star*Solution[1]*val_dist); + arg2B = 500.0*val_viscosity / (val_density*val_dist*val_dist*Solution[1]); + arg2 = max(arg2A, arg2B); + arg1 = min(arg2, 4.0*val_density*sigma_om2*Solution[0] / (CDkw*val_dist*val_dist)); + F1 = tanh(pow(arg1, 4.0)); + + /*--- F2 ---*/ + + arg2 = max(2.0*arg2A, arg2B); + F2 = tanh(pow(arg2, 2.0)); + +} diff --git a/SU2_CFD/src/variable_direct_wave.cpp b/SU2_CFD/src/variable_direct_wave.cpp index 92ab9e53c1b..1aea53b249f 100644 --- a/SU2_CFD/src/variable_direct_wave.cpp +++ b/SU2_CFD/src/variable_direct_wave.cpp @@ -1,70 +1,70 @@ -/*! - * \file variable_direct_wave.cpp - * \brief Definition of the solution fields. - * \author T. Economon, F. Palacios - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/variable_structure.hpp" - -CWaveVariable::CWaveVariable(void) : CVariable() { - - /*--- Array initialization ---*/ - Solution_Direct = NULL; - -} - -CWaveVariable::CWaveVariable(su2double *val_wave, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) -: CVariable(val_nDim, val_nvar, config) { - unsigned short iVar; - - /*--- Array initialization ---*/ - Solution_Direct = NULL; - - /*--- Allocate residual structures ---*/ - Residual_Sum = new su2double [nVar]; Residual_Old = new su2double [nVar]; - - /*--- Allocate direct solution container for adjoint problem ---*/ - Solution_Direct = new su2double[nVar]; - - /*--- Allocate aux gradient vector ---*/ - Grad_AuxVar = new su2double [nDim]; - - /*--- Initialization of variables ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - Solution[iVar] = val_wave[iVar]; - Solution_Old[iVar] = val_wave[iVar]; - Solution_Direct[iVar] = 0.0; - } - -} - -CWaveVariable::~CWaveVariable(void) { - - if (Solution_Direct != NULL) delete [] Solution_Direct; - -} +/*! + * \file variable_direct_wave.cpp + * \brief Definition of the solution fields. + * \author T. Economon, F. Palacios + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/variable_structure.hpp" + +CWaveVariable::CWaveVariable(void) : CVariable() { + + /*--- Array initialization ---*/ + Solution_Direct = NULL; + +} + +CWaveVariable::CWaveVariable(su2double *val_wave, unsigned short val_nDim, unsigned short val_nvar, CConfig *config) +: CVariable(val_nDim, val_nvar, config) { + unsigned short iVar; + + /*--- Array initialization ---*/ + Solution_Direct = NULL; + + /*--- Allocate residual structures ---*/ + Residual_Sum = new su2double [nVar]; Residual_Old = new su2double [nVar]; + + /*--- Allocate direct solution container for adjoint problem ---*/ + Solution_Direct = new su2double[nVar]; + + /*--- Allocate aux gradient vector ---*/ + Grad_AuxVar = new su2double [nDim]; + + /*--- Initialization of variables ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + Solution[iVar] = val_wave[iVar]; + Solution_Old[iVar] = val_wave[iVar]; + Solution_Direct[iVar] = 0.0; + } + +} + +CWaveVariable::~CWaveVariable(void) { + + if (Solution_Direct != NULL) delete [] Solution_Direct; + +} diff --git a/SU2_CFD/src/variable_structure.cpp b/SU2_CFD/src/variable_structure.cpp index 4620b8f3729..80332d78142 100644 --- a/SU2_CFD/src/variable_structure.cpp +++ b/SU2_CFD/src/variable_structure.cpp @@ -1,417 +1,417 @@ -/*! - * \file variable_structure.cpp - * \brief Definition of the solution fields. - * \author F. Palacios, T. Economon - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/variable_structure.hpp" - -unsigned short CVariable::nDim = 0; - -CVariable::CVariable(void) { - - /*--- Array initialization ---*/ - Solution = NULL; - Solution_Old = NULL; - Solution_time_n = NULL; - Solution_time_n1 = NULL; - Gradient = NULL; - Limiter = NULL; - Solution_Max = NULL; - Solution_Min = NULL; - Grad_AuxVar = NULL; - Undivided_Laplacian = NULL; - Res_TruncError = NULL; - Residual_Old = NULL; - Residual_Sum = NULL; - -} - -CVariable::CVariable(unsigned short val_nvar, CConfig *config) { - - /*--- Array initialization ---*/ - Solution = NULL; - Solution_Old = NULL; - Solution_time_n = NULL; - Solution_time_n1 = NULL; - Gradient = NULL; - Limiter = NULL; - Solution_Max = NULL; - Solution_Min = NULL; - Grad_AuxVar = NULL; - Undivided_Laplacian = NULL; - Res_TruncError = NULL; - Residual_Old = NULL; - Residual_Sum = NULL; - - /*--- Initialize the number of solution variables. This version - of the constructor will be used primarily for converting the - restart files into solution files (SU2_SOL). ---*/ - nVar = val_nvar; - - /*--- Allocate the solution array - here it is also possible - to allocate some extra flow variables that do not participate - in the simulation ---*/ - Solution = new su2double [nVar]; - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = 0.0; - -} - -CVariable::CVariable(unsigned short val_nDim, unsigned short val_nvar, CConfig *config) { - - unsigned short iVar, iDim; - - /*--- Array initialization ---*/ - Solution = NULL; - Solution_Old = NULL; - Solution_time_n = NULL; - Solution_time_n1 = NULL; - Gradient = NULL; - Limiter = NULL; - Solution_Max = NULL; - Solution_Min = NULL; - Grad_AuxVar = NULL; - Undivided_Laplacian = NULL; - Res_TruncError = NULL; - Residual_Old = NULL; - Residual_Sum = NULL; - - /*--- Initializate the number of dimension and number of variables ---*/ - nDim = val_nDim; - nVar = val_nvar; - - /*--- Allocate solution, solution old, residual and gradient - which is common for all the problems, here it is also possible - to allocate some extra flow variables that do not participate - in the simulation ---*/ - Solution = new su2double [nVar]; - - for (iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = 0.0; - - Solution_Old = new su2double [nVar]; - - Gradient = new su2double* [nVar]; - for (iVar = 0; iVar < nVar; iVar++) { - Gradient[iVar] = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim ++) - Gradient[iVar][iDim] = 0.0; - } - - if (config->GetUnsteady_Simulation() != NO) { - Solution_time_n = new su2double [nVar]; - Solution_time_n1 = new su2double [nVar]; - } - -} - -CVariable::~CVariable(void) { - unsigned short iVar; - - if (Solution != NULL) delete [] Solution; - if (Solution_Old != NULL) delete [] Solution_Old; - if (Solution_time_n != NULL) delete [] Solution_time_n; - if (Solution_time_n1 != NULL) delete [] Solution_time_n1; - if (Limiter != NULL) delete [] Limiter; - if (Solution_Max != NULL) delete [] Solution_Max; - if (Solution_Min != NULL) delete [] Solution_Min; - if (Grad_AuxVar != NULL) delete [] Grad_AuxVar; - if (Undivided_Laplacian != NULL) delete [] Undivided_Laplacian; - if (Res_TruncError != NULL) delete [] Res_TruncError; - if (Residual_Old != NULL) delete [] Residual_Old; - if (Residual_Sum != NULL) delete [] Residual_Sum; - - if (Gradient != NULL) { - for (iVar = 0; iVar < nVar; iVar++) - delete Gradient[iVar]; - delete [] Gradient; - } - -} - -void CVariable::AddUnd_Lapl(su2double *val_und_lapl) { - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Undivided_Laplacian[iVar] += val_und_lapl[iVar]; -} - -void CVariable::SubtractUnd_Lapl(su2double *val_und_lapl) { - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Undivided_Laplacian[iVar] -= val_und_lapl[iVar]; -} - -void CVariable::SubtractUnd_Lapl(unsigned short val_var, su2double val_und_lapl) { - Undivided_Laplacian[val_var] -= val_und_lapl; -} - -void CVariable::SetUnd_LaplZero(void) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Undivided_Laplacian[iVar] = 0.0; - -} - -void CVariable::SetUnd_Lapl(unsigned short val_var, su2double val_und_lapl) { - - Undivided_Laplacian[val_var] = val_und_lapl; - -} - -void CVariable::SetSolution(su2double *val_solution) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = val_solution[iVar]; - -} - -void CVariable::Set_OldSolution(void) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution_Old[iVar] = Solution[iVar]; - -} - -void CVariable::AddSolution(unsigned short val_var, su2double val_solution) { - - Solution[val_var] = Solution_Old[val_var] + val_solution; - -} - -void CVariable::AddClippedSolution(unsigned short val_var, su2double val_solution, - su2double lowerlimit, su2double upperlimit) { - - Solution[val_var] = min(max((Solution_Old[val_var] + val_solution), lowerlimit), upperlimit); - -} - -void CVariable::AddConservativeSolution(unsigned short val_var, su2double val_solution, - su2double val_density, su2double val_density_old, su2double lowerlimit, su2double upperlimit) { - - Solution[val_var] = min(max((Solution_Old[val_var]*val_density_old + val_solution)/val_density, - lowerlimit), upperlimit); - -} - -void CVariable::Set_Solution(void) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = Solution_Old[iVar]; - -} - -void CVariable::Set_Solution_time_n(void) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution_time_n[iVar] = Solution[iVar]; - -} - -void CVariable::Set_Solution_time_n1(void) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution_time_n1[iVar] = Solution_time_n[iVar]; - -} - -void CVariable::Set_Solution_time_n(su2double *val_sol) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution_time_n[iVar] = val_sol[iVar]; - -} - -void CVariable::Set_Solution_time_n1(su2double *val_sol) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution_time_n1[iVar] = val_sol[iVar]; - -} - -void CVariable::AddRes_TruncError(su2double *val_truncation_error) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Res_TruncError[iVar] += val_truncation_error[iVar]; - -} - -void CVariable::SubtractRes_TruncError(su2double *val_truncation_error) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Res_TruncError[iVar] -= val_truncation_error[iVar]; - -} - -void CVariable::SetResidual_Old(su2double *val_residual_old) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Residual_Old[iVar] = val_residual_old[iVar]; - -} - -void CVariable::SetSolution_Old(su2double *val_solution_old) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution_Old[iVar] = val_solution_old[iVar]; - -} - -void CVariable::SetSolution_time_n(su2double *val_solution_time_n) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution_time_n[iVar] = val_solution_time_n[iVar]; - -} - -void CVariable::AddResidual_Sum(su2double *val_residual) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Residual_Sum[iVar] += val_residual[iVar]; - -} - -void CVariable::SetVel_ResTruncError_Zero(void) { - - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Res_TruncError[iDim+1] = 0.0; - -} - -void CVariable::SetEnergy_ResTruncError_Zero(void) { - - Res_TruncError[nDim+1] = 0.0; - -} - -void CVariable::SetVelSolutionZero(void) { - - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Solution[iDim+1] = 0.0; - -} - -void CVariable::SetVelSolutionVector(su2double *val_vector) { - - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Solution[iDim+1] = val_vector[iDim]; - -} - -void CVariable::SetVelSolutionOldZero(void) { - - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Solution_Old[iDim+1] = 0.0; - -} - -void CVariable::SetVelSolutionOldVector(su2double *val_vector) { - - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Solution_Old[iDim+1] = val_vector[iDim]; - -} - -void CVariable::SetSolutionZero(void) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = 0.0; - -} - -void CVariable::SetSolutionZero(unsigned short val_var) { - - Solution[val_var] = 0.0; - -} - -void CVariable::SetResidualSumZero(void) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Residual_Sum[iVar] = 0.0; - -} - -void CVariable::SetGradientZero(void) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Gradient[iVar][iDim] = 0.0; - -} - -void CVariable::SetAuxVarGradientZero(void) { - - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Grad_AuxVar[iDim] = 0.0; - -} - -void CVariable::SetGradient(su2double **val_gradient) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - for (unsigned short iDim = 0; iDim < nDim; iDim++) - Gradient[iVar][iDim] = val_gradient[iVar][iDim]; - -} - -void CVariable::SetRes_TruncErrorZero(void) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Res_TruncError[iVar] = 0.0; - -} - -void CVariable::SetVal_ResTruncError_Zero(unsigned short val_var) { - - Res_TruncError[val_var] = 0.0; - -} - -void CVariable::GetResidual_Sum(su2double *val_residual) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - val_residual[iVar] = Residual_Sum[iVar]; - -} - -void CVariable::GetResTruncError(su2double *val_trunc_error) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - val_trunc_error[iVar] = Res_TruncError[iVar]; - -} - -CBaselineVariable::CBaselineVariable(void) : CVariable() { } - -CBaselineVariable::CBaselineVariable(su2double *val_solution, unsigned short val_nvar, CConfig *config) : CVariable(val_nvar, config) { - - for (unsigned short iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = val_solution[iVar]; - -} - -CBaselineVariable::~CBaselineVariable(void) { } +/*! + * \file variable_structure.cpp + * \brief Definition of the solution fields. + * \author F. Palacios, T. Economon + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/variable_structure.hpp" + +unsigned short CVariable::nDim = 0; + +CVariable::CVariable(void) { + + /*--- Array initialization ---*/ + Solution = NULL; + Solution_Old = NULL; + Solution_time_n = NULL; + Solution_time_n1 = NULL; + Gradient = NULL; + Limiter = NULL; + Solution_Max = NULL; + Solution_Min = NULL; + Grad_AuxVar = NULL; + Undivided_Laplacian = NULL; + Res_TruncError = NULL; + Residual_Old = NULL; + Residual_Sum = NULL; + +} + +CVariable::CVariable(unsigned short val_nvar, CConfig *config) { + + /*--- Array initialization ---*/ + Solution = NULL; + Solution_Old = NULL; + Solution_time_n = NULL; + Solution_time_n1 = NULL; + Gradient = NULL; + Limiter = NULL; + Solution_Max = NULL; + Solution_Min = NULL; + Grad_AuxVar = NULL; + Undivided_Laplacian = NULL; + Res_TruncError = NULL; + Residual_Old = NULL; + Residual_Sum = NULL; + + /*--- Initialize the number of solution variables. This version + of the constructor will be used primarily for converting the + restart files into solution files (SU2_SOL). ---*/ + nVar = val_nvar; + + /*--- Allocate the solution array - here it is also possible + to allocate some extra flow variables that do not participate + in the simulation ---*/ + Solution = new su2double [nVar]; + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = 0.0; + +} + +CVariable::CVariable(unsigned short val_nDim, unsigned short val_nvar, CConfig *config) { + + unsigned short iVar, iDim; + + /*--- Array initialization ---*/ + Solution = NULL; + Solution_Old = NULL; + Solution_time_n = NULL; + Solution_time_n1 = NULL; + Gradient = NULL; + Limiter = NULL; + Solution_Max = NULL; + Solution_Min = NULL; + Grad_AuxVar = NULL; + Undivided_Laplacian = NULL; + Res_TruncError = NULL; + Residual_Old = NULL; + Residual_Sum = NULL; + + /*--- Initializate the number of dimension and number of variables ---*/ + nDim = val_nDim; + nVar = val_nvar; + + /*--- Allocate solution, solution old, residual and gradient + which is common for all the problems, here it is also possible + to allocate some extra flow variables that do not participate + in the simulation ---*/ + Solution = new su2double [nVar]; + + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = 0.0; + + Solution_Old = new su2double [nVar]; + + Gradient = new su2double* [nVar]; + for (iVar = 0; iVar < nVar; iVar++) { + Gradient[iVar] = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim ++) + Gradient[iVar][iDim] = 0.0; + } + + if (config->GetUnsteady_Simulation() != NO) { + Solution_time_n = new su2double [nVar]; + Solution_time_n1 = new su2double [nVar]; + } + +} + +CVariable::~CVariable(void) { + unsigned short iVar; + + if (Solution != NULL) delete [] Solution; + if (Solution_Old != NULL) delete [] Solution_Old; + if (Solution_time_n != NULL) delete [] Solution_time_n; + if (Solution_time_n1 != NULL) delete [] Solution_time_n1; + if (Limiter != NULL) delete [] Limiter; + if (Solution_Max != NULL) delete [] Solution_Max; + if (Solution_Min != NULL) delete [] Solution_Min; + if (Grad_AuxVar != NULL) delete [] Grad_AuxVar; + if (Undivided_Laplacian != NULL) delete [] Undivided_Laplacian; + if (Res_TruncError != NULL) delete [] Res_TruncError; + if (Residual_Old != NULL) delete [] Residual_Old; + if (Residual_Sum != NULL) delete [] Residual_Sum; + + if (Gradient != NULL) { + for (iVar = 0; iVar < nVar; iVar++) + delete Gradient[iVar]; + delete [] Gradient; + } + +} + +void CVariable::AddUnd_Lapl(su2double *val_und_lapl) { + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Undivided_Laplacian[iVar] += val_und_lapl[iVar]; +} + +void CVariable::SubtractUnd_Lapl(su2double *val_und_lapl) { + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Undivided_Laplacian[iVar] -= val_und_lapl[iVar]; +} + +void CVariable::SubtractUnd_Lapl(unsigned short val_var, su2double val_und_lapl) { + Undivided_Laplacian[val_var] -= val_und_lapl; +} + +void CVariable::SetUnd_LaplZero(void) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Undivided_Laplacian[iVar] = 0.0; + +} + +void CVariable::SetUnd_Lapl(unsigned short val_var, su2double val_und_lapl) { + + Undivided_Laplacian[val_var] = val_und_lapl; + +} + +void CVariable::SetSolution(su2double *val_solution) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = val_solution[iVar]; + +} + +void CVariable::Set_OldSolution(void) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution_Old[iVar] = Solution[iVar]; + +} + +void CVariable::AddSolution(unsigned short val_var, su2double val_solution) { + + Solution[val_var] = Solution_Old[val_var] + val_solution; + +} + +void CVariable::AddClippedSolution(unsigned short val_var, su2double val_solution, + su2double lowerlimit, su2double upperlimit) { + + Solution[val_var] = min(max((Solution_Old[val_var] + val_solution), lowerlimit), upperlimit); + +} + +void CVariable::AddConservativeSolution(unsigned short val_var, su2double val_solution, + su2double val_density, su2double val_density_old, su2double lowerlimit, su2double upperlimit) { + + Solution[val_var] = min(max((Solution_Old[val_var]*val_density_old + val_solution)/val_density, + lowerlimit), upperlimit); + +} + +void CVariable::Set_Solution(void) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = Solution_Old[iVar]; + +} + +void CVariable::Set_Solution_time_n(void) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution_time_n[iVar] = Solution[iVar]; + +} + +void CVariable::Set_Solution_time_n1(void) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution_time_n1[iVar] = Solution_time_n[iVar]; + +} + +void CVariable::Set_Solution_time_n(su2double *val_sol) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution_time_n[iVar] = val_sol[iVar]; + +} + +void CVariable::Set_Solution_time_n1(su2double *val_sol) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution_time_n1[iVar] = val_sol[iVar]; + +} + +void CVariable::AddRes_TruncError(su2double *val_truncation_error) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Res_TruncError[iVar] += val_truncation_error[iVar]; + +} + +void CVariable::SubtractRes_TruncError(su2double *val_truncation_error) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Res_TruncError[iVar] -= val_truncation_error[iVar]; + +} + +void CVariable::SetResidual_Old(su2double *val_residual_old) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Residual_Old[iVar] = val_residual_old[iVar]; + +} + +void CVariable::SetSolution_Old(su2double *val_solution_old) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution_Old[iVar] = val_solution_old[iVar]; + +} + +void CVariable::SetSolution_time_n(su2double *val_solution_time_n) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution_time_n[iVar] = val_solution_time_n[iVar]; + +} + +void CVariable::AddResidual_Sum(su2double *val_residual) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Residual_Sum[iVar] += val_residual[iVar]; + +} + +void CVariable::SetVel_ResTruncError_Zero(void) { + + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Res_TruncError[iDim+1] = 0.0; + +} + +void CVariable::SetEnergy_ResTruncError_Zero(void) { + + Res_TruncError[nDim+1] = 0.0; + +} + +void CVariable::SetVelSolutionZero(void) { + + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Solution[iDim+1] = 0.0; + +} + +void CVariable::SetVelSolutionVector(su2double *val_vector) { + + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Solution[iDim+1] = val_vector[iDim]; + +} + +void CVariable::SetVelSolutionOldZero(void) { + + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Solution_Old[iDim+1] = 0.0; + +} + +void CVariable::SetVelSolutionOldVector(su2double *val_vector) { + + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Solution_Old[iDim+1] = val_vector[iDim]; + +} + +void CVariable::SetSolutionZero(void) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = 0.0; + +} + +void CVariable::SetSolutionZero(unsigned short val_var) { + + Solution[val_var] = 0.0; + +} + +void CVariable::SetResidualSumZero(void) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Residual_Sum[iVar] = 0.0; + +} + +void CVariable::SetGradientZero(void) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Gradient[iVar][iDim] = 0.0; + +} + +void CVariable::SetAuxVarGradientZero(void) { + + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Grad_AuxVar[iDim] = 0.0; + +} + +void CVariable::SetGradient(su2double **val_gradient) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Gradient[iVar][iDim] = val_gradient[iVar][iDim]; + +} + +void CVariable::SetRes_TruncErrorZero(void) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Res_TruncError[iVar] = 0.0; + +} + +void CVariable::SetVal_ResTruncError_Zero(unsigned short val_var) { + + Res_TruncError[val_var] = 0.0; + +} + +void CVariable::GetResidual_Sum(su2double *val_residual) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + val_residual[iVar] = Residual_Sum[iVar]; + +} + +void CVariable::GetResTruncError(su2double *val_trunc_error) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + val_trunc_error[iVar] = Res_TruncError[iVar]; + +} + +CBaselineVariable::CBaselineVariable(void) : CVariable() { } + +CBaselineVariable::CBaselineVariable(su2double *val_solution, unsigned short val_nvar, CConfig *config) : CVariable(val_nvar, config) { + + for (unsigned short iVar = 0; iVar < nVar; iVar++) + Solution[iVar] = val_solution[iVar]; + +} + +CBaselineVariable::~CBaselineVariable(void) { } diff --git a/SU2_CFD/src/variable_template.cpp b/SU2_CFD/src/variable_template.cpp index c185effefc6..73c2c43e463 100644 --- a/SU2_CFD/src/variable_template.cpp +++ b/SU2_CFD/src/variable_template.cpp @@ -1,39 +1,39 @@ -/*! - * \file variable_template.cpp - * \brief Definition of the solution fields. - * \author F. Palacios - * \version 4.0.1 "Cardinal" - * - * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). - * Dr. Thomas D. Economon (economon@stanford.edu). - * - * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. - * Prof. Piero Colonna's group at Delft University of Technology. - * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * Prof. Alberto Guardone's group at Polytechnic University of Milan. - * Prof. Rafael Palacios' group at Imperial College London. - * - * Copyright (C) 2012-2015 SU2, the open-source CFD code. - * - * 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/variable_structure.hpp" - -CTemplateVariable::CTemplateVariable(void) : CVariable() { } - -CTemplateVariable::CTemplateVariable(su2double val_Template, unsigned short val_nDim, - unsigned short val_nvar, CConfig *config) : CVariable(val_nDim, val_nvar, config) { } - -CTemplateVariable::~CTemplateVariable(void) { } +/*! + * \file variable_template.cpp + * \brief Definition of the solution fields. + * \author F. Palacios + * \version 4.0.1 "Cardinal" + * + * SU2 Lead Developers: Dr. Francisco Palacios (Francisco.D.Palacios@boeing.com). + * Dr. Thomas D. Economon (economon@stanford.edu). + * + * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. + * Prof. Piero Colonna's group at Delft University of Technology. + * Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. + * Prof. Alberto Guardone's group at Polytechnic University of Milan. + * Prof. Rafael Palacios' group at Imperial College London. + * + * Copyright (C) 2012-2015 SU2, the open-source CFD code. + * + * 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/variable_structure.hpp" + +CTemplateVariable::CTemplateVariable(void) : CVariable() { } + +CTemplateVariable::CTemplateVariable(su2double val_Template, unsigned short val_nDim, + unsigned short val_nvar, CConfig *config) : CVariable(val_nDim, val_nvar, config) { } + +CTemplateVariable::~CTemplateVariable(void) { } diff --git a/SU2_IDE/Xcode/SU2_CFD.xcodeproj/project.pbxproj b/SU2_IDE/Xcode/SU2_CFD.xcodeproj/project.pbxproj index 4f93684c366..dca1a454d46 100644 --- a/SU2_IDE/Xcode/SU2_CFD.xcodeproj/project.pbxproj +++ b/SU2_IDE/Xcode/SU2_CFD.xcodeproj/project.pbxproj @@ -92,106 +92,106 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 050698091AA6179100FF4F07 /* output_fieldview.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = output_fieldview.cpp; path = ../../SU2_CFD/src/output_fieldview.cpp; sourceTree = ""; }; - 0530E56717FDF79500733CE8 /* solver_direct_poisson.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = solver_direct_poisson.cpp; path = ../../SU2_CFD/src/solver_direct_poisson.cpp; sourceTree = ""; }; - 0530E56917FDF7AC00733CE8 /* solver_direct_elasticity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = solver_direct_elasticity.cpp; path = ../../SU2_CFD/src/solver_direct_elasticity.cpp; sourceTree = ""; }; - 0530E56B17FDF7BD00733CE8 /* variable_direct_poisson.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = variable_direct_poisson.cpp; path = ../../SU2_CFD/src/variable_direct_poisson.cpp; sourceTree = ""; }; - 0530E56D17FDF7C600733CE8 /* variable_direct_elasticity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = variable_direct_elasticity.cpp; path = ../../SU2_CFD/src/variable_direct_elasticity.cpp; sourceTree = ""; }; - 0530E56F17FDF7D300733CE8 /* numerics_direct_elasticity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = numerics_direct_elasticity.cpp; path = ../../SU2_CFD/src/numerics_direct_elasticity.cpp; sourceTree = ""; }; - 0530E57117FDF7D800733CE8 /* numerics_direct_poisson.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = numerics_direct_poisson.cpp; path = ../../SU2_CFD/src/numerics_direct_poisson.cpp; sourceTree = ""; }; + 050698091AA6179100FF4F07 /* output_fieldview.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = output_fieldview.cpp; path = ../../SU2_CFD/src/output_fieldview.cpp; sourceTree = ""; }; + 0530E56717FDF79500733CE8 /* solver_direct_poisson.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = solver_direct_poisson.cpp; path = ../../SU2_CFD/src/solver_direct_poisson.cpp; sourceTree = ""; }; + 0530E56917FDF7AC00733CE8 /* solver_direct_elasticity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = solver_direct_elasticity.cpp; path = ../../SU2_CFD/src/solver_direct_elasticity.cpp; sourceTree = ""; }; + 0530E56B17FDF7BD00733CE8 /* variable_direct_poisson.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = variable_direct_poisson.cpp; path = ../../SU2_CFD/src/variable_direct_poisson.cpp; sourceTree = ""; }; + 0530E56D17FDF7C600733CE8 /* variable_direct_elasticity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = variable_direct_elasticity.cpp; path = ../../SU2_CFD/src/variable_direct_elasticity.cpp; sourceTree = ""; }; + 0530E56F17FDF7D300733CE8 /* numerics_direct_elasticity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = numerics_direct_elasticity.cpp; path = ../../SU2_CFD/src/numerics_direct_elasticity.cpp; sourceTree = ""; }; + 0530E57117FDF7D800733CE8 /* numerics_direct_poisson.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = numerics_direct_poisson.cpp; path = ../../SU2_CFD/src/numerics_direct_poisson.cpp; sourceTree = ""; }; 0541ABEE1370F5A6002D668B /* SU2_CFD */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = SU2_CFD; sourceTree = BUILT_PRODUCTS_DIR; }; 0541C14E1A7EA6970095A680 /* config_template_basic.cfg */ = {isa = PBXFileReference; lastKnownFileType = text; name = config_template_basic.cfg; path = ../../config_template_basic.cfg; sourceTree = ""; }; - 05755F091A54AC4500600019 /* output_su2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = output_su2.cpp; path = ../../SU2_CFD/src/output_su2.cpp; sourceTree = ""; }; + 05755F091A54AC4500600019 /* output_su2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = output_su2.cpp; path = ../../SU2_CFD/src/output_su2.cpp; sourceTree = ""; }; 05AF9F1D1BE1E1830062E1F1 /* element_linear.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = element_linear.cpp; path = ../../Common/src/element_linear.cpp; sourceTree = ""; }; 05AF9F1E1BE1E1830062E1F1 /* element_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = element_structure.cpp; path = ../../Common/src/element_structure.cpp; sourceTree = ""; }; 05AF9F1F1BE1E1830062E1F1 /* gauss_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = gauss_structure.cpp; path = ../../Common/src/gauss_structure.cpp; sourceTree = ""; }; - 05E6DA9F17EB603F00FA1F7E /* config_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; name = config_structure.inl; path = ../../Common/include/config_structure.inl; sourceTree = ""; }; - 05E6DAA017EB603F00FA1F7E /* dual_grid_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; name = dual_grid_structure.inl; path = ../../Common/include/dual_grid_structure.inl; sourceTree = ""; }; - 05E6DAA117EB603F00FA1F7E /* geometry_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; name = geometry_structure.inl; path = ../../Common/include/geometry_structure.inl; sourceTree = ""; }; - 05E6DAA217EB603F00FA1F7E /* grid_adaptation_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; name = grid_adaptation_structure.inl; path = ../../Common/include/grid_adaptation_structure.inl; sourceTree = ""; }; - 05E6DAA317EB603F00FA1F7E /* grid_movement_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; name = grid_movement_structure.inl; path = ../../Common/include/grid_movement_structure.inl; sourceTree = ""; }; - 05E6DAA417EB603F00FA1F7E /* linear_solvers_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; name = linear_solvers_structure.inl; path = ../../Common/include/linear_solvers_structure.inl; sourceTree = ""; }; - 05E6DAA517EB603F00FA1F7E /* matrix_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; name = matrix_structure.inl; path = ../../Common/include/matrix_structure.inl; sourceTree = ""; }; - 05E6DAA617EB603F00FA1F7E /* primal_grid_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; name = primal_grid_structure.inl; path = ../../Common/include/primal_grid_structure.inl; sourceTree = ""; }; - 05E6DAA717EB603F00FA1F7E /* vector_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; name = vector_structure.inl; path = ../../Common/include/vector_structure.inl; sourceTree = ""; }; + 05E6DA9F17EB603F00FA1F7E /* config_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; name = config_structure.inl; path = ../../Common/include/config_structure.inl; sourceTree = ""; }; + 05E6DAA017EB603F00FA1F7E /* dual_grid_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; name = dual_grid_structure.inl; path = ../../Common/include/dual_grid_structure.inl; sourceTree = ""; }; + 05E6DAA117EB603F00FA1F7E /* geometry_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; name = geometry_structure.inl; path = ../../Common/include/geometry_structure.inl; sourceTree = ""; }; + 05E6DAA217EB603F00FA1F7E /* grid_adaptation_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; name = grid_adaptation_structure.inl; path = ../../Common/include/grid_adaptation_structure.inl; sourceTree = ""; }; + 05E6DAA317EB603F00FA1F7E /* grid_movement_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; name = grid_movement_structure.inl; path = ../../Common/include/grid_movement_structure.inl; sourceTree = ""; }; + 05E6DAA417EB603F00FA1F7E /* linear_solvers_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; name = linear_solvers_structure.inl; path = ../../Common/include/linear_solvers_structure.inl; sourceTree = ""; }; + 05E6DAA517EB603F00FA1F7E /* matrix_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; name = matrix_structure.inl; path = ../../Common/include/matrix_structure.inl; sourceTree = ""; }; + 05E6DAA617EB603F00FA1F7E /* primal_grid_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; name = primal_grid_structure.inl; path = ../../Common/include/primal_grid_structure.inl; sourceTree = ""; }; + 05E6DAA717EB603F00FA1F7E /* vector_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; name = vector_structure.inl; path = ../../Common/include/vector_structure.inl; sourceTree = ""; }; 05E6DAC517EB608000FA1F7E /* config_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = config_structure.hpp; path = ../../Common/include/config_structure.hpp; sourceTree = ""; }; - 05E6DAC617EB608000FA1F7E /* dual_grid_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = dual_grid_structure.hpp; path = ../../Common/include/dual_grid_structure.hpp; sourceTree = ""; }; + 05E6DAC617EB608000FA1F7E /* dual_grid_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; name = dual_grid_structure.hpp; path = ../../Common/include/dual_grid_structure.hpp; sourceTree = ""; }; 05E6DAC717EB608000FA1F7E /* geometry_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = geometry_structure.hpp; path = ../../Common/include/geometry_structure.hpp; sourceTree = ""; }; - 05E6DAC817EB608000FA1F7E /* grid_adaptation_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = grid_adaptation_structure.hpp; path = ../../Common/include/grid_adaptation_structure.hpp; sourceTree = ""; }; - 05E6DAC917EB608000FA1F7E /* grid_movement_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = grid_movement_structure.hpp; path = ../../Common/include/grid_movement_structure.hpp; sourceTree = ""; }; + 05E6DAC817EB608000FA1F7E /* grid_adaptation_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; name = grid_adaptation_structure.hpp; path = ../../Common/include/grid_adaptation_structure.hpp; sourceTree = ""; }; + 05E6DAC917EB608000FA1F7E /* grid_movement_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; name = grid_movement_structure.hpp; path = ../../Common/include/grid_movement_structure.hpp; sourceTree = ""; }; 05E6DACA17EB608000FA1F7E /* linear_solvers_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = linear_solvers_structure.hpp; path = ../../Common/include/linear_solvers_structure.hpp; sourceTree = ""; }; - 05E6DACB17EB608000FA1F7E /* matrix_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = matrix_structure.hpp; path = ../../Common/include/matrix_structure.hpp; sourceTree = ""; }; - 05E6DACC17EB608000FA1F7E /* option_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = option_structure.hpp; path = ../../Common/include/option_structure.hpp; sourceTree = ""; }; - 05E6DACD17EB608000FA1F7E /* primal_grid_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = primal_grid_structure.hpp; path = ../../Common/include/primal_grid_structure.hpp; sourceTree = ""; }; + 05E6DACB17EB608000FA1F7E /* matrix_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; name = matrix_structure.hpp; path = ../../Common/include/matrix_structure.hpp; sourceTree = ""; }; + 05E6DACC17EB608000FA1F7E /* option_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; name = option_structure.hpp; path = ../../Common/include/option_structure.hpp; sourceTree = ""; }; + 05E6DACD17EB608000FA1F7E /* primal_grid_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; name = primal_grid_structure.hpp; path = ../../Common/include/primal_grid_structure.hpp; sourceTree = ""; }; 05E6DACE17EB608000FA1F7E /* vector_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = vector_structure.hpp; path = ../../Common/include/vector_structure.hpp; sourceTree = ""; }; 05E6DB8917EB61E600FA1F7E /* config_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = config_structure.cpp; path = ../../Common/src/config_structure.cpp; sourceTree = ""; }; - 05E6DB8A17EB61E600FA1F7E /* dual_grid_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dual_grid_structure.cpp; path = ../../Common/src/dual_grid_structure.cpp; sourceTree = ""; }; - 05E6DB8B17EB61E600FA1F7E /* geometry_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = geometry_structure.cpp; path = ../../Common/src/geometry_structure.cpp; sourceTree = ""; }; - 05E6DB8C17EB61E600FA1F7E /* grid_adaptation_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = grid_adaptation_structure.cpp; path = ../../Common/src/grid_adaptation_structure.cpp; sourceTree = ""; }; - 05E6DB8D17EB61E600FA1F7E /* grid_movement_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = grid_movement_structure.cpp; path = ../../Common/src/grid_movement_structure.cpp; sourceTree = ""; }; + 05E6DB8A17EB61E600FA1F7E /* dual_grid_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = dual_grid_structure.cpp; path = ../../Common/src/dual_grid_structure.cpp; sourceTree = ""; }; + 05E6DB8B17EB61E600FA1F7E /* geometry_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = geometry_structure.cpp; path = ../../Common/src/geometry_structure.cpp; sourceTree = ""; }; + 05E6DB8C17EB61E600FA1F7E /* grid_adaptation_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = grid_adaptation_structure.cpp; path = ../../Common/src/grid_adaptation_structure.cpp; sourceTree = ""; }; + 05E6DB8D17EB61E600FA1F7E /* grid_movement_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = grid_movement_structure.cpp; path = ../../Common/src/grid_movement_structure.cpp; sourceTree = ""; }; 05E6DB8E17EB61E600FA1F7E /* linear_solvers_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = linear_solvers_structure.cpp; path = ../../Common/src/linear_solvers_structure.cpp; sourceTree = ""; }; - 05E6DB8F17EB61E600FA1F7E /* matrix_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = matrix_structure.cpp; path = ../../Common/src/matrix_structure.cpp; sourceTree = ""; }; - 05E6DB9017EB61E600FA1F7E /* primal_grid_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = primal_grid_structure.cpp; path = ../../Common/src/primal_grid_structure.cpp; sourceTree = ""; }; + 05E6DB8F17EB61E600FA1F7E /* matrix_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = matrix_structure.cpp; path = ../../Common/src/matrix_structure.cpp; sourceTree = ""; }; + 05E6DB9017EB61E600FA1F7E /* primal_grid_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = primal_grid_structure.cpp; path = ../../Common/src/primal_grid_structure.cpp; sourceTree = ""; }; 05E6DB9117EB61E600FA1F7E /* vector_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = vector_structure.cpp; path = ../../Common/src/vector_structure.cpp; sourceTree = ""; }; - 05E6DBB017EB624700FA1F7E /* integration_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; name = integration_structure.inl; path = ../../SU2_CFD/include/integration_structure.inl; sourceTree = ""; }; - 05E6DBB117EB624700FA1F7E /* numerics_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; name = numerics_structure.inl; path = ../../SU2_CFD/include/numerics_structure.inl; sourceTree = ""; }; - 05E6DBB217EB624700FA1F7E /* solver_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; name = solver_structure.inl; path = ../../SU2_CFD/include/solver_structure.inl; sourceTree = ""; }; - 05E6DBB317EB624700FA1F7E /* variable_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; name = variable_structure.inl; path = ../../SU2_CFD/include/variable_structure.inl; sourceTree = ""; }; + 05E6DBB017EB624700FA1F7E /* integration_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; name = integration_structure.inl; path = ../../SU2_CFD/include/integration_structure.inl; sourceTree = ""; }; + 05E6DBB117EB624700FA1F7E /* numerics_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; name = numerics_structure.inl; path = ../../SU2_CFD/include/numerics_structure.inl; sourceTree = ""; }; + 05E6DBB217EB624700FA1F7E /* solver_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; name = solver_structure.inl; path = ../../SU2_CFD/include/solver_structure.inl; sourceTree = ""; }; + 05E6DBB317EB624700FA1F7E /* variable_structure.inl */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; name = variable_structure.inl; path = ../../SU2_CFD/include/variable_structure.inl; sourceTree = ""; }; 05E6DBB417EB627400FA1F7E /* definition_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = definition_structure.hpp; path = ../../SU2_CFD/include/definition_structure.hpp; sourceTree = ""; }; - 05E6DBB517EB627400FA1F7E /* integration_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = integration_structure.hpp; path = ../../SU2_CFD/include/integration_structure.hpp; sourceTree = ""; }; + 05E6DBB517EB627400FA1F7E /* integration_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; name = integration_structure.hpp; path = ../../SU2_CFD/include/integration_structure.hpp; sourceTree = ""; }; 05E6DBB617EB627400FA1F7E /* iteration_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = iteration_structure.hpp; path = ../../SU2_CFD/include/iteration_structure.hpp; sourceTree = ""; }; - 05E6DBB717EB627400FA1F7E /* numerics_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = numerics_structure.hpp; path = ../../SU2_CFD/include/numerics_structure.hpp; sourceTree = ""; }; + 05E6DBB717EB627400FA1F7E /* numerics_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; name = numerics_structure.hpp; path = ../../SU2_CFD/include/numerics_structure.hpp; sourceTree = ""; }; 05E6DBB817EB627400FA1F7E /* output_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = output_structure.hpp; path = ../../SU2_CFD/include/output_structure.hpp; sourceTree = ""; }; 05E6DBB917EB627400FA1F7E /* solver_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = solver_structure.hpp; path = ../../SU2_CFD/include/solver_structure.hpp; sourceTree = ""; }; 05E6DBBA17EB627400FA1F7E /* SU2_CFD.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = SU2_CFD.hpp; path = ../../SU2_CFD/include/SU2_CFD.hpp; sourceTree = ""; }; - 05E6DBBB17EB627400FA1F7E /* variable_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = variable_structure.hpp; path = ../../SU2_CFD/include/variable_structure.hpp; sourceTree = ""; }; - 05E6DBBC17EB62A000FA1F7E /* definition_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = definition_structure.cpp; path = ../../SU2_CFD/src/definition_structure.cpp; sourceTree = ""; }; + 05E6DBBB17EB627400FA1F7E /* variable_structure.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; name = variable_structure.hpp; path = ../../SU2_CFD/include/variable_structure.hpp; sourceTree = ""; }; + 05E6DBBC17EB62A000FA1F7E /* definition_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = definition_structure.cpp; path = ../../SU2_CFD/src/definition_structure.cpp; sourceTree = ""; }; 05E6DBBE17EB62A100FA1F7E /* integration_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = integration_structure.cpp; path = ../../SU2_CFD/src/integration_structure.cpp; sourceTree = ""; }; - 05E6DBBF17EB62A100FA1F7E /* integration_time.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = integration_time.cpp; path = ../../SU2_CFD/src/integration_time.cpp; sourceTree = ""; }; - 05E6DBC017EB62A100FA1F7E /* iteration_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = iteration_structure.cpp; path = ../../SU2_CFD/src/iteration_structure.cpp; sourceTree = ""; }; - 05E6DBC217EB62A100FA1F7E /* numerics_adjoint_levelset.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = numerics_adjoint_levelset.cpp; path = ../../SU2_CFD/src/numerics_adjoint_levelset.cpp; sourceTree = ""; }; - 05E6DBC317EB62A100FA1F7E /* numerics_adjoint_mean.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = numerics_adjoint_mean.cpp; path = ../../SU2_CFD/src/numerics_adjoint_mean.cpp; sourceTree = ""; }; - 05E6DBC617EB62A100FA1F7E /* numerics_adjoint_turbulent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = numerics_adjoint_turbulent.cpp; path = ../../SU2_CFD/src/numerics_adjoint_turbulent.cpp; sourceTree = ""; }; - 05E6DBC917EB62A100FA1F7E /* numerics_direct_heat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = numerics_direct_heat.cpp; path = ../../SU2_CFD/src/numerics_direct_heat.cpp; sourceTree = ""; }; - 05E6DBCB17EB62A100FA1F7E /* numerics_direct_mean.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = numerics_direct_mean.cpp; path = ../../SU2_CFD/src/numerics_direct_mean.cpp; sourceTree = ""; }; - 05E6DBCE17EB62A100FA1F7E /* numerics_direct_transition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = numerics_direct_transition.cpp; path = ../../SU2_CFD/src/numerics_direct_transition.cpp; sourceTree = ""; }; - 05E6DBCF17EB62A100FA1F7E /* numerics_direct_turbulent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = numerics_direct_turbulent.cpp; path = ../../SU2_CFD/src/numerics_direct_turbulent.cpp; sourceTree = ""; }; - 05E6DBD017EB62A100FA1F7E /* numerics_direct_wave.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = numerics_direct_wave.cpp; path = ../../SU2_CFD/src/numerics_direct_wave.cpp; sourceTree = ""; }; - 05E6DBD317EB62A100FA1F7E /* numerics_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = numerics_structure.cpp; path = ../../SU2_CFD/src/numerics_structure.cpp; sourceTree = ""; }; - 05E6DBD417EB62A100FA1F7E /* numerics_template.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = numerics_template.cpp; path = ../../SU2_CFD/src/numerics_template.cpp; sourceTree = ""; }; - 05E6DBD517EB62A100FA1F7E /* output_cgns.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = output_cgns.cpp; path = ../../SU2_CFD/src/output_cgns.cpp; sourceTree = ""; }; + 05E6DBBF17EB62A100FA1F7E /* integration_time.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = integration_time.cpp; path = ../../SU2_CFD/src/integration_time.cpp; sourceTree = ""; }; + 05E6DBC017EB62A100FA1F7E /* iteration_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = iteration_structure.cpp; path = ../../SU2_CFD/src/iteration_structure.cpp; sourceTree = ""; }; + 05E6DBC217EB62A100FA1F7E /* numerics_adjoint_levelset.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = numerics_adjoint_levelset.cpp; path = ../../SU2_CFD/src/numerics_adjoint_levelset.cpp; sourceTree = ""; }; + 05E6DBC317EB62A100FA1F7E /* numerics_adjoint_mean.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = numerics_adjoint_mean.cpp; path = ../../SU2_CFD/src/numerics_adjoint_mean.cpp; sourceTree = ""; }; + 05E6DBC617EB62A100FA1F7E /* numerics_adjoint_turbulent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = numerics_adjoint_turbulent.cpp; path = ../../SU2_CFD/src/numerics_adjoint_turbulent.cpp; sourceTree = ""; }; + 05E6DBC917EB62A100FA1F7E /* numerics_direct_heat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = numerics_direct_heat.cpp; path = ../../SU2_CFD/src/numerics_direct_heat.cpp; sourceTree = ""; }; + 05E6DBCB17EB62A100FA1F7E /* numerics_direct_mean.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = numerics_direct_mean.cpp; path = ../../SU2_CFD/src/numerics_direct_mean.cpp; sourceTree = ""; }; + 05E6DBCE17EB62A100FA1F7E /* numerics_direct_transition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = numerics_direct_transition.cpp; path = ../../SU2_CFD/src/numerics_direct_transition.cpp; sourceTree = ""; }; + 05E6DBCF17EB62A100FA1F7E /* numerics_direct_turbulent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = numerics_direct_turbulent.cpp; path = ../../SU2_CFD/src/numerics_direct_turbulent.cpp; sourceTree = ""; }; + 05E6DBD017EB62A100FA1F7E /* numerics_direct_wave.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = numerics_direct_wave.cpp; path = ../../SU2_CFD/src/numerics_direct_wave.cpp; sourceTree = ""; }; + 05E6DBD317EB62A100FA1F7E /* numerics_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = numerics_structure.cpp; path = ../../SU2_CFD/src/numerics_structure.cpp; sourceTree = ""; }; + 05E6DBD417EB62A100FA1F7E /* numerics_template.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = numerics_template.cpp; path = ../../SU2_CFD/src/numerics_template.cpp; sourceTree = ""; }; + 05E6DBD517EB62A100FA1F7E /* output_cgns.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = output_cgns.cpp; path = ../../SU2_CFD/src/output_cgns.cpp; sourceTree = ""; }; 05E6DBD617EB62A100FA1F7E /* output_paraview.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = output_paraview.cpp; path = ../../SU2_CFD/src/output_paraview.cpp; sourceTree = ""; }; - 05E6DBD717EB62A100FA1F7E /* output_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = output_structure.cpp; path = ../../SU2_CFD/src/output_structure.cpp; sourceTree = ""; }; - 05E6DBD817EB62A100FA1F7E /* output_tecplot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = output_tecplot.cpp; path = ../../SU2_CFD/src/output_tecplot.cpp; sourceTree = ""; }; - 05E6DBD917EB62A100FA1F7E /* solver_adjoint_levelset.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = solver_adjoint_levelset.cpp; path = ../../SU2_CFD/src/solver_adjoint_levelset.cpp; sourceTree = ""; }; - 05E6DBDA17EB62A100FA1F7E /* solver_adjoint_mean.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = solver_adjoint_mean.cpp; path = ../../SU2_CFD/src/solver_adjoint_mean.cpp; sourceTree = ""; }; - 05E6DBDD17EB62A100FA1F7E /* solver_adjoint_turbulent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = solver_adjoint_turbulent.cpp; path = ../../SU2_CFD/src/solver_adjoint_turbulent.cpp; sourceTree = ""; }; - 05E6DBE017EB62A100FA1F7E /* solver_direct_heat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = solver_direct_heat.cpp; path = ../../SU2_CFD/src/solver_direct_heat.cpp; sourceTree = ""; }; - 05E6DBE217EB62A100FA1F7E /* solver_direct_mean.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = solver_direct_mean.cpp; path = ../../SU2_CFD/src/solver_direct_mean.cpp; sourceTree = ""; }; + 05E6DBD717EB62A100FA1F7E /* output_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = output_structure.cpp; path = ../../SU2_CFD/src/output_structure.cpp; sourceTree = ""; }; + 05E6DBD817EB62A100FA1F7E /* output_tecplot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = output_tecplot.cpp; path = ../../SU2_CFD/src/output_tecplot.cpp; sourceTree = ""; }; + 05E6DBD917EB62A100FA1F7E /* solver_adjoint_levelset.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = solver_adjoint_levelset.cpp; path = ../../SU2_CFD/src/solver_adjoint_levelset.cpp; sourceTree = ""; }; + 05E6DBDA17EB62A100FA1F7E /* solver_adjoint_mean.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = solver_adjoint_mean.cpp; path = ../../SU2_CFD/src/solver_adjoint_mean.cpp; sourceTree = ""; }; + 05E6DBDD17EB62A100FA1F7E /* solver_adjoint_turbulent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = solver_adjoint_turbulent.cpp; path = ../../SU2_CFD/src/solver_adjoint_turbulent.cpp; sourceTree = ""; }; + 05E6DBE017EB62A100FA1F7E /* solver_direct_heat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = solver_direct_heat.cpp; path = ../../SU2_CFD/src/solver_direct_heat.cpp; sourceTree = ""; }; + 05E6DBE217EB62A100FA1F7E /* solver_direct_mean.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = solver_direct_mean.cpp; path = ../../SU2_CFD/src/solver_direct_mean.cpp; sourceTree = ""; }; 05E6DBE517EB62A100FA1F7E /* solver_direct_transition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = solver_direct_transition.cpp; path = ../../SU2_CFD/src/solver_direct_transition.cpp; sourceTree = ""; }; - 05E6DBE617EB62A100FA1F7E /* solver_direct_turbulent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = solver_direct_turbulent.cpp; path = ../../SU2_CFD/src/solver_direct_turbulent.cpp; sourceTree = ""; }; - 05E6DBE717EB62A100FA1F7E /* solver_direct_wave.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = solver_direct_wave.cpp; path = ../../SU2_CFD/src/solver_direct_wave.cpp; sourceTree = ""; }; - 05E6DBEA17EB62A100FA1F7E /* solver_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = solver_structure.cpp; path = ../../SU2_CFD/src/solver_structure.cpp; sourceTree = ""; }; + 05E6DBE617EB62A100FA1F7E /* solver_direct_turbulent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = solver_direct_turbulent.cpp; path = ../../SU2_CFD/src/solver_direct_turbulent.cpp; sourceTree = ""; }; + 05E6DBE717EB62A100FA1F7E /* solver_direct_wave.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = solver_direct_wave.cpp; path = ../../SU2_CFD/src/solver_direct_wave.cpp; sourceTree = ""; }; + 05E6DBEA17EB62A100FA1F7E /* solver_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = solver_structure.cpp; path = ../../SU2_CFD/src/solver_structure.cpp; sourceTree = ""; }; 05E6DBEB17EB62A100FA1F7E /* solver_template.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = solver_template.cpp; path = ../../SU2_CFD/src/solver_template.cpp; sourceTree = ""; }; 05E6DBEC17EB62A100FA1F7E /* SU2_CFD.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SU2_CFD.cpp; path = ../../SU2_CFD/src/SU2_CFD.cpp; sourceTree = ""; }; - 05E6DBEE17EB62A100FA1F7E /* variable_adjoint_levelset.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = variable_adjoint_levelset.cpp; path = ../../SU2_CFD/src/variable_adjoint_levelset.cpp; sourceTree = ""; }; - 05E6DBEF17EB62A100FA1F7E /* variable_adjoint_mean.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = variable_adjoint_mean.cpp; path = ../../SU2_CFD/src/variable_adjoint_mean.cpp; sourceTree = ""; }; - 05E6DBF217EB62A100FA1F7E /* variable_adjoint_turbulent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = variable_adjoint_turbulent.cpp; path = ../../SU2_CFD/src/variable_adjoint_turbulent.cpp; sourceTree = ""; }; - 05E6DBF517EB62A100FA1F7E /* variable_direct_heat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = variable_direct_heat.cpp; path = ../../SU2_CFD/src/variable_direct_heat.cpp; sourceTree = ""; }; - 05E6DBF717EB62A100FA1F7E /* variable_direct_mean.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = variable_direct_mean.cpp; path = ../../SU2_CFD/src/variable_direct_mean.cpp; sourceTree = ""; }; - 05E6DBFA17EB62A100FA1F7E /* variable_direct_transition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = variable_direct_transition.cpp; path = ../../SU2_CFD/src/variable_direct_transition.cpp; sourceTree = ""; }; - 05E6DBFB17EB62A100FA1F7E /* variable_direct_turbulent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = variable_direct_turbulent.cpp; path = ../../SU2_CFD/src/variable_direct_turbulent.cpp; sourceTree = ""; }; - 05E6DBFC17EB62A100FA1F7E /* variable_direct_wave.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = variable_direct_wave.cpp; path = ../../SU2_CFD/src/variable_direct_wave.cpp; sourceTree = ""; }; - 05E6DBFF17EB62A100FA1F7E /* variable_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = variable_structure.cpp; path = ../../SU2_CFD/src/variable_structure.cpp; sourceTree = ""; }; - 05E6DC0017EB62A100FA1F7E /* variable_template.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = variable_template.cpp; path = ../../SU2_CFD/src/variable_template.cpp; sourceTree = ""; }; - 05F108961978D2AE00F2F288 /* fluid_model_pig.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = fluid_model_pig.cpp; path = ../../SU2_CFD/src/fluid_model_pig.cpp; sourceTree = ""; }; - 05F108971978D2AE00F2F288 /* fluid_model_ppr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = fluid_model_ppr.cpp; path = ../../SU2_CFD/src/fluid_model_ppr.cpp; sourceTree = ""; }; - 05F108981978D2AE00F2F288 /* fluid_model_pvdw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = fluid_model_pvdw.cpp; path = ../../SU2_CFD/src/fluid_model_pvdw.cpp; sourceTree = ""; }; - 05F108991978D2AE00F2F288 /* fluid_model.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = fluid_model.cpp; path = ../../SU2_CFD/src/fluid_model.cpp; sourceTree = ""; }; + 05E6DBEE17EB62A100FA1F7E /* variable_adjoint_levelset.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = variable_adjoint_levelset.cpp; path = ../../SU2_CFD/src/variable_adjoint_levelset.cpp; sourceTree = ""; }; + 05E6DBEF17EB62A100FA1F7E /* variable_adjoint_mean.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = variable_adjoint_mean.cpp; path = ../../SU2_CFD/src/variable_adjoint_mean.cpp; sourceTree = ""; }; + 05E6DBF217EB62A100FA1F7E /* variable_adjoint_turbulent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = variable_adjoint_turbulent.cpp; path = ../../SU2_CFD/src/variable_adjoint_turbulent.cpp; sourceTree = ""; }; + 05E6DBF517EB62A100FA1F7E /* variable_direct_heat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = variable_direct_heat.cpp; path = ../../SU2_CFD/src/variable_direct_heat.cpp; sourceTree = ""; }; + 05E6DBF717EB62A100FA1F7E /* variable_direct_mean.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = variable_direct_mean.cpp; path = ../../SU2_CFD/src/variable_direct_mean.cpp; sourceTree = ""; }; + 05E6DBFA17EB62A100FA1F7E /* variable_direct_transition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = variable_direct_transition.cpp; path = ../../SU2_CFD/src/variable_direct_transition.cpp; sourceTree = ""; }; + 05E6DBFB17EB62A100FA1F7E /* variable_direct_turbulent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = variable_direct_turbulent.cpp; path = ../../SU2_CFD/src/variable_direct_turbulent.cpp; sourceTree = ""; }; + 05E6DBFC17EB62A100FA1F7E /* variable_direct_wave.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = variable_direct_wave.cpp; path = ../../SU2_CFD/src/variable_direct_wave.cpp; sourceTree = ""; }; + 05E6DBFF17EB62A100FA1F7E /* variable_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = variable_structure.cpp; path = ../../SU2_CFD/src/variable_structure.cpp; sourceTree = ""; }; + 05E6DC0017EB62A100FA1F7E /* variable_template.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = variable_template.cpp; path = ../../SU2_CFD/src/variable_template.cpp; sourceTree = ""; }; + 05F108961978D2AE00F2F288 /* fluid_model_pig.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = fluid_model_pig.cpp; path = ../../SU2_CFD/src/fluid_model_pig.cpp; sourceTree = ""; }; + 05F108971978D2AE00F2F288 /* fluid_model_ppr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = fluid_model_ppr.cpp; path = ../../SU2_CFD/src/fluid_model_ppr.cpp; sourceTree = ""; }; + 05F108981978D2AE00F2F288 /* fluid_model_pvdw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = fluid_model_pvdw.cpp; path = ../../SU2_CFD/src/fluid_model_pvdw.cpp; sourceTree = ""; }; + 05F108991978D2AE00F2F288 /* fluid_model.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = fluid_model.cpp; path = ../../SU2_CFD/src/fluid_model.cpp; sourceTree = ""; }; 05F1089E1978D2CE00F2F288 /* fluid_model.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = fluid_model.hpp; path = ../../SU2_CFD/include/fluid_model.hpp; sourceTree = ""; }; 05F1089F1978D2CE00F2F288 /* transport_model.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = transport_model.hpp; path = ../../SU2_CFD/include/transport_model.hpp; sourceTree = ""; }; - 05F108A01978D2D700F2F288 /* fluid_model.inl */ = {isa = PBXFileReference; lastKnownFileType = text; name = fluid_model.inl; path = ../../SU2_CFD/include/fluid_model.inl; sourceTree = ""; }; - 05F108A11978D2D700F2F288 /* transport_model.inl */ = {isa = PBXFileReference; lastKnownFileType = text; name = transport_model.inl; path = ../../SU2_CFD/include/transport_model.inl; sourceTree = ""; }; + 05F108A01978D2D700F2F288 /* fluid_model.inl */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; name = fluid_model.inl; path = ../../SU2_CFD/include/fluid_model.inl; sourceTree = ""; }; + 05F108A11978D2D700F2F288 /* transport_model.inl */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; name = transport_model.inl; path = ../../SU2_CFD/include/transport_model.inl; sourceTree = ""; }; 05F108A31978D2F200F2F288 /* transport_model.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = transport_model.cpp; path = ../../SU2_CFD/src/transport_model.cpp; sourceTree = ""; }; E91CAC631B8C110D00EE3FCC /* .gitignore */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = .gitignore; sourceTree = ""; }; E91CAC651B8C110E00EE3FCC /* ActDisk_Euler.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ActDisk_Euler.cfg; sourceTree = ""; }; @@ -281,7 +281,7 @@ E941BB901B71D124005C6C06 /* linear_solvers_structure_b.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = linear_solvers_structure_b.cpp; path = ../../Common/src/linear_solvers_structure_b.cpp; sourceTree = ""; }; E941BB911B71D124005C6C06 /* mpi_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mpi_structure.cpp; path = ../../Common/src/mpi_structure.cpp; sourceTree = ""; }; E941BB951B71D1AB005C6C06 /* datatype_structure.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = datatype_structure.hpp; path = ../../Common/include/datatype_structure.hpp; sourceTree = ""; }; - E941BB961B71D1AB005C6C06 /* datatype_structure.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = datatype_structure.inl; path = ../../Common/include/datatype_structure.inl; sourceTree = ""; }; + E941BB961B71D1AB005C6C06 /* datatype_structure.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; name = datatype_structure.inl; path = ../../Common/include/datatype_structure.inl; sourceTree = ""; }; E941BB981B71D1AB005C6C06 /* adolc_forward_structure.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = adolc_forward_structure.hpp; sourceTree = ""; }; E941BB991B71D1AB005C6C06 /* adolc_forward_structure.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = adolc_forward_structure.inl; sourceTree = ""; }; E941BB9A1B71D1AB005C6C06 /* adolc_reverse_structure.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = adolc_reverse_structure.hpp; sourceTree = ""; }; @@ -296,11 +296,11 @@ E941BBA31B71D1AB005C6C06 /* primitive_structure.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = primitive_structure.inl; sourceTree = ""; }; E941BBA41B71D1AB005C6C06 /* linear_solvers_structure_b.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = linear_solvers_structure_b.hpp; path = ../../Common/include/linear_solvers_structure_b.hpp; sourceTree = ""; }; E941BBA51B71D1AB005C6C06 /* mpi_structure.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = mpi_structure.hpp; path = ../../Common/include/mpi_structure.hpp; sourceTree = ""; }; - E941BBA61B71D1AB005C6C06 /* mpi_structure.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = mpi_structure.inl; path = ../../Common/include/mpi_structure.inl; sourceTree = ""; }; - E941BBAD1B71D564005C6C06 /* variable_adjoint_discrete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = variable_adjoint_discrete.cpp; path = ../../SU2_CFD/src/variable_adjoint_discrete.cpp; sourceTree = ""; }; + E941BBA61B71D1AB005C6C06 /* mpi_structure.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; name = mpi_structure.inl; path = ../../Common/include/mpi_structure.inl; sourceTree = ""; }; + E941BBAD1B71D564005C6C06 /* variable_adjoint_discrete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = variable_adjoint_discrete.cpp; path = ../../SU2_CFD/src/variable_adjoint_discrete.cpp; sourceTree = ""; }; E97B6C8117F941800008255B /* config_template.cfg */ = {isa = PBXFileReference; lastKnownFileType = text; name = config_template.cfg; path = ../../config_template.cfg; sourceTree = ""; }; E9AA98A61BB3436900B7FE37 /* driver_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = driver_structure.cpp; path = ../../SU2_CFD/src/driver_structure.cpp; sourceTree = ""; }; - E9AA98A81BB3438F00B7FE37 /* driver_structure.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = driver_structure.hpp; path = ../../SU2_CFD/include/driver_structure.hpp; sourceTree = ""; }; + E9AA98A81BB3438F00B7FE37 /* driver_structure.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; name = driver_structure.hpp; path = ../../SU2_CFD/include/driver_structure.hpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1456,7 +1456,7 @@ CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 4.0.1; + CURRENT_PROJECT_VERSION = 4.0.2; GCC_DYNAMIC_NO_PIC = NO; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 3; @@ -1525,7 +1525,7 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CURRENT_PROJECT_VERSION = 4.0.1; + CURRENT_PROJECT_VERSION = 4.0.2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 3;